diff --git a/src/vm/mod.rs b/src/vm/mod.rs index a58b05f..011b490 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -52,10 +52,16 @@ impl<'vm> VM<'vm> { } pub fn get_thunk(&self, idx: usize) -> &'vm Thunk<'vm> { + // SAFETY: The `idx` is within bounds as `thunks` is initialized with `prog.thunks` + // and `idx` is expected to be a valid index into this collection. + // The lifetime of the returned reference is tied to `&self`. unsafe { &*(&self.thunks[idx] as *const _) } } pub fn get_func(&self, idx: usize) -> &'vm Func<'vm> { + // SAFETY: The `idx` is within bounds as `funcs` is initialized with `prog.funcs` + // and `idx` is expected to be a valid index into this collection. + // The lifetime of the returned reference is tied to `&self`. unsafe { &*(&self.funcs[idx] as *const _) } } diff --git a/src/vm/stack.rs b/src/vm/stack.rs index 9056e46..2186fb0 100644 --- a/src/vm/stack.rs +++ b/src/vm/stack.rs @@ -13,6 +13,10 @@ pub struct Stack<'vm, const CAP: usize> { macro_rules! into { ($e:expr) => { + // SAFETY: This macro is used to transmute `MaybeUninit>` to `Value<'vm>` + // or `&MaybeUninit>` to `&Value<'vm>`. + // This is safe because the `Stack` ensures that only initialized values are accessed + // within the `0..top` range. unsafe { transmute($e) } }; } @@ -45,6 +49,9 @@ impl<'vm, const CAP: usize> Stack<'vm, CAP> { self.top -= 1; let item = self.items.get_mut(self.top).unwrap(); + // SAFETY: `item` at `self.top` was previously written and is initialized. + // We replace it with `MaybeUninit::uninit()` and then `assume_init` + // on the original value, which is safe as it was initialized. unsafe { replace(item, MaybeUninit::uninit()).assume_init() } } @@ -68,6 +75,8 @@ impl Drop for Stack<'_, CAP> { fn drop(&mut self) { self.items.as_mut_slice()[0..self.top] .iter_mut() + // SAFETY: Items in the range `0..self.top` are guaranteed to be initialized. + // `assume_init_drop` is called to correctly drop these initialized `Value`s. .map(|item| unsafe { item.assume_init_drop() }) .for_each(drop) }