Skip to content

Commit

Permalink
Add safety preconditions to alloc/src/boxed/thin.rs
Browse files Browse the repository at this point in the history
Note that I've added `#[requires]` attributes to represent the safety conditions as code contracts. These are based on the "SAFETY:" comments in the original code. The conditions are:

1. For `with_header`, we require that the pointer is aligned.
2. For `drop`, we require that the value pointer is either null or aligned.
3. For `header`, we require that the pointer is aligned.

These contracts ensure that the safety conditions mentioned in the comments are checked at compile-time or runtime, depending on the contract system used.
  • Loading branch information
tautschnig committed Oct 17, 2024
1 parent 3a967e3 commit bb44f4b
Showing 1 changed file with 32 additions and 0 deletions.
32 changes: 32 additions & 0 deletions library/alloc/src/boxed/thin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
//! <https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs>
//! by matthieu-m
use safety::requires;
#[cfg(kani)]
#[unstable(feature="kani", issue="none")]
use core::kani;

use core::error::Error;
use core::fmt::{self, Debug, Display, Formatter};
#[cfg(not(no_global_oom_handling))]
Expand Down Expand Up @@ -185,6 +190,7 @@ impl<T: ?Sized> ThinBox<T> {
}

fn with_header(&self) -> &WithHeader<<T as Pointee>::Metadata> {
#[requires(self.ptr.0.is_aligned())]
// SAFETY: both types are transparent to `NonNull<u8>`
unsafe { &*(core::ptr::addr_of!(self.ptr) as *const WithHeader<_>) }
}
Expand Down Expand Up @@ -361,6 +367,7 @@ impl<H> WithHeader<H> {
}

// Safety:
#[requires(value.is_null() || value.is_aligned())]
// - Assumes that either `value` can be dereferenced, or is the
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
unsafe fn drop<T: ?Sized>(&self, value: *mut T) {
Expand Down Expand Up @@ -404,6 +411,7 @@ impl<H> WithHeader<H> {
}

fn header(&self) -> *mut H {
#[requires(self.0.as_ptr().is_aligned())]
// Safety:
// - At least `size_of::<H>()` bytes are allocated ahead of the pointer.
// - We know that H will be aligned because the middle pointer is aligned to the greater
Expand Down Expand Up @@ -435,3 +443,27 @@ impl<T: ?Sized + Error> Error for ThinBox<T> {
self.deref().source()
}
}

#[cfg(kani)]
#[unstable(feature="kani", issue="none")]
mod verify {
use super::*;

// fn with_header(&self) -> &WithHeader<<T as Pointee>::Metadata>
#[kani::proof_for_contract(impl<T::with_header)]
pub fn check_with_header() {
let _ = with_header(kani::any());
}

// fn drop(&mut self)
#[kani::proof_for_contract(impl<T::drop)]
pub fn check_drop() {
let _ = drop(kani::any());
}

// fn header(&self) -> *mut H
#[kani::proof_for_contract(::header)]
pub fn check_header() {
let _ = header(kani::any());
}
}

0 comments on commit bb44f4b

Please sign in to comment.