Merge pull request #7427 from roc-lang/const-write

avoid writing to readonly refcounts
This commit is contained in:
Brendan Hansknecht 2024-12-28 17:37:47 -08:00 committed by GitHub
commit 0ce43ffd1e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 23 additions and 6 deletions

View file

@ -582,6 +582,9 @@ impl Hash for U128 {
}
}
pub const ROC_REFCOUNT_CONSTANT: usize = 0;
pub const ROC_REFCOUNT_ONE: usize = isize::MIN as usize;
/// All Roc types that are refcounted must implement this trait.
///
/// For aggregate types, this must recurse down the structure.

View file

@ -14,7 +14,9 @@ use core::{
};
use std::{cmp::max, ops::Range};
use crate::{roc_alloc, roc_dealloc, roc_realloc, storage::Storage, RocRefcounted};
use crate::{
roc_alloc, roc_dealloc, roc_realloc, storage::Storage, RocRefcounted, ROC_REFCOUNT_CONSTANT,
};
#[cfg(feature = "serde")]
use core::marker::PhantomData;
@ -174,7 +176,10 @@ where
/// should be considered for marking read-only.
pub unsafe fn set_readonly(&mut self) {
if let Some((_, storage)) = self.elements_and_storage() {
storage.set(Storage::Readonly);
// Only safe to write to the pointer if it is not constant (0)
if !matches!(storage.get(), Storage::Readonly) {
storage.set(Storage::Readonly);
}
}
}
@ -676,7 +681,10 @@ where
let ptr = self.ptr_to_refcount();
unsafe {
let value = std::ptr::read(ptr);
std::ptr::write(ptr, Ord::max(0, ((value as isize) + 1) as usize));
// Only safe to write to the pointer if it is not constant (0)
if value != ROC_REFCOUNT_CONSTANT {
std::ptr::write(ptr, (value as isize + 1) as usize);
}
}
}

View file

@ -21,7 +21,7 @@ use core::{
use std::ffi::{CStr, CString};
use std::{ops::Range, ptr::NonNull};
use crate::{roc_realloc, RocList, RocRefcounted};
use crate::{roc_realloc, RocList, RocRefcounted, ROC_REFCOUNT_CONSTANT};
#[repr(transparent)]
pub struct RocStr(RocStrInner);
@ -943,14 +943,20 @@ impl BigString {
assert_ne!(self.capacity(), 0);
let ptr = self.ptr_to_refcount();
unsafe { std::ptr::write(ptr, 0) }
// Only safe to write to the pointer if it is not constant (0)
if unsafe { std::ptr::read(ptr) } != ROC_REFCOUNT_CONSTANT {
unsafe { std::ptr::write(ptr, ROC_REFCOUNT_CONSTANT) }
}
}
fn inc(&mut self) {
let ptr = self.ptr_to_refcount();
unsafe {
let value = std::ptr::read(ptr);
std::ptr::write(ptr, Ord::max(0, ((value as isize) + 1) as usize));
// Only safe to write to the pointer if it is not constant (0)
if value != ROC_REFCOUNT_CONSTANT {
std::ptr::write(ptr, (value as isize + 1) as usize);
}
}
}