diff --git a/src/machine/stack.rs b/src/machine/stack.rs index 73094c3fb..6e85f9489 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -301,6 +301,25 @@ impl Stack { } } + /// Reads an [`OrFrame`] placed immediately after [`self.top()`](Self::top). + /// + /// # Safety + /// + /// The stack must contain a valid [`OrFrame`] at offset [`self.top()`](Self::top). + /// + /// No other allocations must have been done since the last call to [`truncate()`](Self::truncate). + #[inline(always)] + pub(crate) unsafe fn read_dangling_or_frame(&self) -> &OrFrame { + unsafe { + // SAFETY: + // - Assumed: the stack contains a valid `OrFrame` at this offset + // - Assumed: no other allocations have been done since the last call to `self.truncate()` + // - Postcondition: from `self.buf.truncate`, the pointer `ptr` is not yet invalidated. + let ptr = self.buf.get_unchecked(self.top()); + &*(ptr as *const OrFrame) + } + } + #[inline(always)] pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame { unsafe { diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 2378dfe2a..dbdf401be 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1235,8 +1235,10 @@ impl Machine { // the last clause of the retract // helper to delay deallocation of its // environment frame. - let clause_b = self.machine_st.stack.top(); - self.machine_st.stack.index_or_frame(clause_b).prelude.biip as usize + unsafe { + // TODO: verify that the assumption above always holds + self.machine_st.stack.read_dangling_or_frame().prelude.biip as usize + } }; return ( diff --git a/src/raw_block.rs b/src/raw_block.rs index 43f06f082..cc7f9cfe9 100644 --- a/src/raw_block.rs +++ b/src/raw_block.rs @@ -85,12 +85,14 @@ impl RawBlock { /// /// # Safety /// - /// The caller must ensure that `offset < self.len()` + /// The caller must ensure that `offset` is within a region allocated with [`Self::alloc`]. + /// + /// It must notably ensure that `offset < self.capacity()`. pub unsafe fn get_unchecked(&self, offset: usize) -> *const u8 { // SAFETY: // - Invariant: `self.base + self.size() == self.top` is the top bound of // the allocated region. - // - Assumed: `offset < self.len()` + // - Assumed: `offset < self.capacity()` // Thus `self.base + offset` is within the allocated region. self.base.add(offset) } @@ -111,10 +113,12 @@ impl RawBlock { /// /// # Safety /// - /// The caller must ensure that `offset < self.len()` + /// The caller must ensure that `offset` is within a region allocated with [`Self::alloc`]. + /// + /// It must notably ensure that `offset < self.capacity()`. pub unsafe fn get_mut_unchecked(&mut self, offset: usize) -> *mut u8 { unsafe { - // SAFETY: Assumed: `offset < self.len()` + // SAFETY: Assumed. self.get_unchecked(offset).cast_mut() } }