Skip to content

Commit 32efecb

Browse files
committed
Add safety preconditions to alloc/src/boxed/thin.rs
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.
1 parent dc862c4 commit 32efecb

File tree

1 file changed

+31
-0
lines changed

1 file changed

+31
-0
lines changed

library/alloc/src/boxed/thin.rs

+31
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
//! <https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs>
33
//! by matthieu-m
44
5+
use safety::requires;
6+
#[cfg(kani)]
7+
use crate::kani;
8+
59
use core::error::Error;
610
use core::fmt::{self, Debug, Display, Formatter};
711
#[cfg(not(no_global_oom_handling))]
@@ -185,6 +189,7 @@ impl<T: ?Sized> ThinBox<T> {
185189
}
186190

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

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

406412
fn header(&self) -> *mut H {
413+
#[requires(self.0.as_ptr().is_aligned())]
407414
// Safety:
408415
// - At least `size_of::<H>()` bytes are allocated ahead of the pointer.
409416
// - We know that H will be aligned because the middle pointer is aligned to the greater
@@ -435,3 +442,27 @@ impl<T: ?Sized + Error> Error for ThinBox<T> {
435442
self.deref().source()
436443
}
437444
}
445+
446+
#[cfg(kani)]
447+
#[unstable(feature="kani", issue="none")]
448+
mod verify {
449+
use super::*;
450+
451+
// fn with_header(&self) -> &WithHeader<<T as Pointee>::Metadata>
452+
#[kani::proof_for_contract(impl<T::with_header)]
453+
pub fn check_with_header() {
454+
let _ = with_header(kani::any());
455+
}
456+
457+
// fn drop(&mut self)
458+
#[kani::proof_for_contract(impl<T::drop)]
459+
pub fn check_drop() {
460+
let _ = drop(kani::any());
461+
}
462+
463+
// fn header(&self) -> *mut H
464+
#[kani::proof_for_contract(::header)]
465+
pub fn check_header() {
466+
let _ = header(kani::any());
467+
}
468+
}

0 commit comments

Comments
 (0)