Skip to content

Commit

Permalink
Fix Machine::get_clause_p panicking from trying to read a dangling frame
Browse files Browse the repository at this point in the history
  • Loading branch information
adri326 committed Jan 12, 2025
1 parent 8aa6104 commit e74b60e
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 6 deletions.
19 changes: 19 additions & 0 deletions src/machine/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 4 additions & 2 deletions src/machine/system_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
12 changes: 8 additions & 4 deletions src/raw_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,14 @@ impl<T: RawBlockTraits> RawBlock<T> {
///
/// # 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)
}
Expand All @@ -111,10 +113,12 @@ impl<T: RawBlockTraits> RawBlock<T> {
///
/// # 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()
}
}
Expand Down

0 comments on commit e74b60e

Please sign in to comment.