-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add safety preconditions to alloc/src/alloc.rs #118
base: main
Are you sure you want to change the base?
Changes from all commits
9822a02
80a8886
f685389
f529e5d
71061d3
247d3be
90fbc0e
f17509e
cb4b650
b1bad7a
d28ca19
d640ef6
7560486
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -10,6 +10,11 @@ use core::hint; | |||||
#[cfg(not(test))] | ||||||
use core::ptr::{self, NonNull}; | ||||||
|
||||||
use safety::{ensures,requires}; | ||||||
#[cfg(kani)] | ||||||
#[unstable(feature="kani", issue="none")] | ||||||
use core::kani; | ||||||
|
||||||
#[cfg(test)] | ||||||
mod tests; | ||||||
|
||||||
|
@@ -187,6 +192,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { | |||||
impl Global { | ||||||
#[inline] | ||||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||||||
#[ensures(|ret| layout.size() != 0 || ret.is_ok())] | ||||||
fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> { | ||||||
match layout.size() { | ||||||
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), | ||||||
|
@@ -200,6 +206,10 @@ impl Global { | |||||
} | ||||||
|
||||||
// SAFETY: Same as `Allocator::grow` | ||||||
#[requires(new_layout.size() >= old_layout.size())] | ||||||
#[requires(old_layout.size() == 0 || old_layout.align() != 0)] | ||||||
#[requires(new_layout.size() == 0 || new_layout.align() != 0)] | ||||||
#[requires(ptr.as_ptr() as usize % old_layout.align() == 0)] | ||||||
#[inline] | ||||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||||||
unsafe fn grow_impl( | ||||||
|
@@ -265,6 +275,8 @@ unsafe impl Allocator for Global { | |||||
|
||||||
#[inline] | ||||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||||||
#[requires(layout.size() == 0 || layout.align() != 0)] | ||||||
#[requires(ptr.as_ptr() as usize % layout.align() == 0)] | ||||||
Comment on lines
+278
to
+279
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't we need to require that the pointer is actually allocated? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We actually need an even stronger precondition (and Kani correctly detects this via the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We would need ghost state. 😄 |
||||||
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { | ||||||
if layout.size() != 0 { | ||||||
// SAFETY: `layout` is non-zero in size, | ||||||
|
@@ -275,6 +287,10 @@ unsafe impl Allocator for Global { | |||||
|
||||||
#[inline] | ||||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||||||
#[requires(new_layout.size() >= old_layout.size())] | ||||||
#[requires(old_layout.size() == 0 || old_layout.align() != 0)] | ||||||
#[requires(new_layout.size() == 0 || new_layout.align() != 0)] | ||||||
#[requires(ptr.as_ptr() as usize % old_layout.align() == 0)] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
unsafe fn grow( | ||||||
&self, | ||||||
ptr: NonNull<u8>, | ||||||
|
@@ -287,6 +303,10 @@ unsafe impl Allocator for Global { | |||||
|
||||||
#[inline] | ||||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||||||
#[requires(new_layout.size() >= old_layout.size())] | ||||||
#[requires(old_layout.size() == 0 || old_layout.align() != 0)] | ||||||
#[requires(new_layout.size() == 0 || new_layout.align() != 0)] | ||||||
#[requires(ptr.as_ptr() as usize % old_layout.align() == 0)] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
unsafe fn grow_zeroed( | ||||||
&self, | ||||||
ptr: NonNull<u8>, | ||||||
|
@@ -299,6 +319,10 @@ unsafe impl Allocator for Global { | |||||
|
||||||
#[inline] | ||||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||||||
#[requires(new_layout.size() <= old_layout.size())] | ||||||
#[requires(old_layout.size() == 0 || old_layout.align() != 0)] | ||||||
#[requires(new_layout.size() == 0 || new_layout.align() != 0)] | ||||||
#[requires(ptr.as_ptr() as usize % old_layout.align() == 0)] | ||||||
unsafe fn shrink( | ||||||
&self, | ||||||
ptr: NonNull<u8>, | ||||||
|
@@ -445,3 +469,79 @@ pub mod __alloc_error_handler { | |||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
#[cfg(kani)] | ||||||
#[unstable(feature="kani", issue="none")] | ||||||
mod verify { | ||||||
use super::*; | ||||||
|
||||||
// fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> | ||||||
#[kani::proof_for_contract(Global::alloc_impl)] | ||||||
pub fn check_alloc_impl() { | ||||||
let _ = Global.alloc_impl(kani::any(), kani::any()); | ||||||
} | ||||||
|
||||||
// TODO: Kani correctly detects that the precondition is too weak. We'd need a way to express | ||||||
// that ptr either points to a ZST (we can do this), or else is heap-allocated (we cannot). | ||||||
// // unsafe fn grow_impl(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> | ||||||
// #[kani::proof_for_contract(Global::grow_impl)] | ||||||
// pub fn check_grow_impl() { | ||||||
// let raw_ptr = kani::any::<usize>() as *mut u8; | ||||||
// unsafe { | ||||||
// let n = NonNull::new_unchecked(raw_ptr); | ||||||
// let _ = Global.grow_impl(n, kani::any(), kani::any(), kani::any()); | ||||||
// } | ||||||
// } | ||||||
|
||||||
// TODO: disabled as Kani does not currently support contracts on traits. See | ||||||
// https://github.com/model-checking/kani/issues/1997 | ||||||
// // unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) | ||||||
// #[kani::proof_for_contract(Allocator::deallocate)] | ||||||
// pub fn check_deallocate() { | ||||||
// let obj : &dyn Allocator = &Global; | ||||||
// let raw_ptr = kani::any::<usize>() as *mut u8; | ||||||
// unsafe { | ||||||
// let n = NonNull::new_unchecked(raw_ptr); | ||||||
// let _ = obj.deallocate(n, kani::any()); | ||||||
// } | ||||||
// } | ||||||
|
||||||
// TODO: disabled as Kani does not currently support contracts on traits. See | ||||||
// https://github.com/model-checking/kani/issues/1997 | ||||||
// // unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> | ||||||
// #[kani::proof_for_contract(Allocator::grow)] | ||||||
// pub fn check_grow() { | ||||||
// let obj : &dyn Allocator = &Global; | ||||||
// let raw_ptr = kani::any::<usize>() as *mut u8; | ||||||
// unsafe { | ||||||
// let n = NonNull::new_unchecked(raw_ptr); | ||||||
// let _ = obj.grow(n, kani::any(), kani::any()); | ||||||
// } | ||||||
// } | ||||||
|
||||||
// TODO: disabled as Kani does not currently support contracts on traits. See | ||||||
// https://github.com/model-checking/kani/issues/1997 | ||||||
// // unsafe fn grow_zeroed(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> | ||||||
// #[kani::proof_for_contract(Allocator::grow_zeroed)] | ||||||
// pub fn check_grow_zeroed() { | ||||||
// let obj : &dyn Allocator = &Global; | ||||||
// let raw_ptr = kani::any::<usize>() as *mut u8; | ||||||
// unsafe { | ||||||
// let n = NonNull::new_unchecked(raw_ptr); | ||||||
// let _ = obj.grow_zeroed(n, kani::any(), kani::any()); | ||||||
// } | ||||||
// } | ||||||
|
||||||
// TODO: disabled as Kani does not currently support contracts on traits. See | ||||||
// https://github.com/model-checking/kani/issues/1997 | ||||||
// // unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> | ||||||
// #[kani::proof_for_contract(Allocator::shrink)] | ||||||
// pub fn check_shrink() { | ||||||
// let obj : &dyn Allocator = &Global; | ||||||
// let raw_ptr = kani::any::<usize>() as *mut u8; | ||||||
// unsafe { | ||||||
// let n = NonNull::new_unchecked(raw_ptr); | ||||||
// let _ = obj.shrink(n, kani::any(), kani::any()); | ||||||
// } | ||||||
// } | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.