Fix allocate_pstr randomly refusing to properly allocate memory
This one was a toughie: it turns out that using `ptr::align_of()`` was a bad idea, since the buffer in `Heap` itself is not aligned to `Heap::heap_cell_alignment()`, so `ptr::align_of()` would sometimes return lower values than expected. That made for an heisenbug: if the alignment of the heap happened to be 4, then the bug wouldn't trigger.
This commit is contained in:
@@ -2979,6 +2979,19 @@ mod tests {
|
|||||||
|
|
||||||
wam.machine_st.heap.clear();
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn heap_stackless_post_order_iter_pstr() {
|
||||||
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
let f_atom = atom!("f");
|
||||||
|
let a_atom = atom!("a");
|
||||||
|
let b_atom = atom!("b");
|
||||||
|
|
||||||
|
// clear the heap of resource error data etc
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
// first a 'dangling' partial string, later modified to be a
|
// first a 'dangling' partial string, later modified to be a
|
||||||
// two-part complete string, then a three-part cyclic string
|
// two-part complete string, then a three-part cyclic string
|
||||||
// involving an uncompacted list of chars.
|
// involving an uncompacted list of chars.
|
||||||
@@ -3004,9 +3017,13 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wam.machine_st.heap[2] = heap_loc_as_cell!(2);
|
wam.machine_st.heap[2] = heap_loc_as_cell!(2);
|
||||||
|
assert_eq!(wam.machine_st.heap.cell_len(), 3);
|
||||||
|
|
||||||
wam.machine_st.allocate_pstr("def").unwrap();
|
wam.machine_st.allocate_pstr("def").unwrap();
|
||||||
|
assert_eq!(wam.machine_st.heap.cell_len(), 4);
|
||||||
|
|
||||||
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
|
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
|
||||||
|
assert_eq!(wam.machine_st.heap.cell_len(), 5);
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4);
|
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4);
|
||||||
|
|||||||
@@ -353,15 +353,7 @@ impl<'a> ReservedHeapSection<'a> {
|
|||||||
|
|
||||||
let zero_region_idx = heap_index!(self.heap_cell_len) + str_byte_len;
|
let zero_region_idx = heap_index!(self.heap_cell_len) + str_byte_len;
|
||||||
|
|
||||||
let align_offset = self.heap_ptr
|
let align_offset = pstr_sentinel_length(zero_region_idx);
|
||||||
.add(zero_region_idx)
|
|
||||||
.align_offset(ALIGN_CELL);
|
|
||||||
|
|
||||||
let align_offset = if align_offset == 0 {
|
|
||||||
ALIGN_CELL
|
|
||||||
} else {
|
|
||||||
align_offset
|
|
||||||
};
|
|
||||||
|
|
||||||
ptr::write_bytes(
|
ptr::write_bytes(
|
||||||
self.heap_ptr.add(zero_region_idx),
|
self.heap_ptr.add(zero_region_idx),
|
||||||
@@ -481,6 +473,22 @@ impl<'a> Index<usize> for ReservedHeapSection<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the number of bytes required to pad a string of length `chunk_len`
|
||||||
|
/// with zeroes, such that `chunk_len + pstr_sentinel_length(chunk_len)` is a
|
||||||
|
/// multiple of `Heap::heap_cell_alignement()`.
|
||||||
|
fn pstr_sentinel_length(chunk_len: usize) -> usize {
|
||||||
|
const ALIGN: usize = Heap::heap_cell_alignment();
|
||||||
|
|
||||||
|
let res = chunk_len.next_multiple_of(ALIGN) - chunk_len;
|
||||||
|
|
||||||
|
// No bytes available in last chunk
|
||||||
|
if res == 0 {
|
||||||
|
ALIGN
|
||||||
|
} else {
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HeapWriter<'a> {
|
pub struct HeapWriter<'a> {
|
||||||
@@ -635,7 +643,7 @@ impl Heap {
|
|||||||
if self.free_space() >= len {
|
if self.free_space() >= len {
|
||||||
section = ReservedHeapSection {
|
section = ReservedHeapSection {
|
||||||
heap_ptr: self.inner.ptr,
|
heap_ptr: self.inner.ptr,
|
||||||
heap_cell_len: cell_index!(self.inner.byte_len),
|
heap_cell_len: self.cell_len(),
|
||||||
pstr_vec: &mut self.pstr_vec,
|
pstr_vec: &mut self.pstr_vec,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
@@ -810,6 +818,11 @@ impl Heap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SAFETY:
|
||||||
|
// - Postcondition: from `self.grow()`, `self.inner.byte_len + size_of::<HeapCellValue>()`
|
||||||
|
// is strictly less than `self.inner.byte_cap`.
|
||||||
|
// - Asserted: `self.cell_len() * size_of::<HeapCellvalue>() <= self.inner.byte_cap`.
|
||||||
|
// - Invariant: from `InnerHeap`, `self.inner.byte_cap < isize::MAX`.
|
||||||
let cell_ptr = (self.inner.ptr as *mut HeapCellValue).add(self.cell_len());
|
let cell_ptr = (self.inner.ptr as *mut HeapCellValue).add(self.cell_len());
|
||||||
cell_ptr.write(cell);
|
cell_ptr.write(cell);
|
||||||
self.pstr_vec.push(false);
|
self.pstr_vec.push(false);
|
||||||
@@ -967,17 +980,7 @@ impl Heap {
|
|||||||
|
|
||||||
const ALIGN_CELL: usize = Heap::heap_cell_alignment();
|
const ALIGN_CELL: usize = Heap::heap_cell_alignment();
|
||||||
|
|
||||||
let align_offset = unsafe {
|
let align_offset = pstr_sentinel_length(s_len);
|
||||||
self.inner.ptr
|
|
||||||
.add(self.inner.byte_len + s_len)
|
|
||||||
.align_offset(ALIGN_CELL)
|
|
||||||
};
|
|
||||||
|
|
||||||
let align_offset = if align_offset == 0 {
|
|
||||||
ALIGN_CELL
|
|
||||||
} else {
|
|
||||||
align_offset
|
|
||||||
};
|
|
||||||
|
|
||||||
let copy_size = s_len + align_offset;
|
let copy_size = s_len + align_offset;
|
||||||
|
|
||||||
@@ -1040,8 +1043,9 @@ impl Heap {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes the string will be allocated on a ALIGN_CELL-byte boundary
|
/// Returns the number of bytes needed to store `src` as a `PStr`.
|
||||||
pub(crate) const fn compute_pstr_size(src: &str) -> usize {
|
/// Assumes the string will be allocated on a ALIGN_CELL-byte boundary.
|
||||||
|
pub(crate) fn compute_pstr_size(src: &str) -> usize {
|
||||||
const ALIGN_CELL: usize = Heap::heap_cell_alignment();
|
const ALIGN_CELL: usize = Heap::heap_cell_alignment();
|
||||||
|
|
||||||
if src.is_empty() {
|
if src.is_empty() {
|
||||||
@@ -1062,7 +1066,7 @@ impl Heap {
|
|||||||
null_idx += 1;
|
null_idx += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte_size += (null_idx & !(ALIGN_CELL - 1)) + ALIGN_CELL;
|
byte_size += null_idx.next_multiple_of(ALIGN_CELL);
|
||||||
|
|
||||||
if (null_idx + 1) % ALIGN_CELL == 0 {
|
if (null_idx + 1) % ALIGN_CELL == 0 {
|
||||||
byte_size += 2 * mem::size_of::<HeapCellValue>();
|
byte_size += 2 * mem::size_of::<HeapCellValue>();
|
||||||
|
|||||||
Reference in New Issue
Block a user