-
Notifications
You must be signed in to change notification settings - Fork 29
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
Contracts & Harnesses for byte_add
, byte_offset
, and byte_offset_from
#103
base: main
Are you sure you want to change the base?
Changes from all commits
bcdedb8
009c561
a8974ed
3a986c5
fff0e6a
7ce2d89
459a692
d95ad3e
670adef
505f90b
e6c6795
293d9c8
40b3833
42cb421
16bf419
8451bcb
98a196a
fbccaa2
c1b4488
48b30e5
0e11499
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 |
---|---|---|
|
@@ -532,6 +532,11 @@ impl<T: ?Sized> NonNull<T> { | |
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||
#[stable(feature = "non_null_convenience", since = "1.80.0")] | ||
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] | ||
#[requires( | ||
(self.as_ptr().addr() as isize).checked_add(count).is_some() && | ||
kani::mem::same_allocation(self.as_ptr(), self.as_ptr().wrapping_byte_offset(count)) | ||
)] | ||
#[ensures(|result: &Self| result.as_ptr() == self.as_ptr().wrapping_byte_offset(count))] | ||
pub const unsafe fn byte_offset(self, count: isize) -> Self { | ||
// SAFETY: the caller must uphold the safety contract for `offset` and `byte_offset` has | ||
// the same safety contract. | ||
|
@@ -613,6 +618,10 @@ impl<T: ?Sized> NonNull<T> { | |
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||
#[stable(feature = "non_null_convenience", since = "1.80.0")] | ||
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] | ||
#[requires( | ||
count <= (isize::MAX as usize) - self.as_ptr().addr() && // Ensure the offset doesn't overflow | ||
kani::mem::same_allocation(self.as_ptr(),self.as_ptr().wrapping_byte_add(count)) // Ensure the offset is within the same allocation | ||
danielhumanmod marked this conversation as resolved.
Show resolved
Hide resolved
|
||
)] | ||
pub const unsafe fn byte_add(self, count: usize) -> Self { | ||
// SAFETY: the caller must uphold the safety contract for `add` and `byte_add` has the same | ||
// safety contract. | ||
|
@@ -826,6 +835,11 @@ impl<T: ?Sized> NonNull<T> { | |
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||
#[stable(feature = "non_null_convenience", since = "1.80.0")] | ||
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] | ||
#[requires(kani::mem::same_allocation(self.as_ptr() as *const(), origin.as_ptr() as *const()))] | ||
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. This should also be safe if the pointers hold the same address, even if they are dangling 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.
Same as above, there is a failure: Proof harness
Error:
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. Please see my question above. |
||
#[ensures( | ||
|result: &isize| | ||
*result == (self.as_ptr() as *const u8).offset_from(origin.as_ptr() as *const u8) | ||
)] | ||
pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: NonNull<U>) -> isize { | ||
// SAFETY: the caller must uphold the safety contract for `byte_offset_from`. | ||
unsafe { self.pointer.byte_offset_from(origin.pointer) } | ||
|
@@ -1907,6 +1921,7 @@ impl<T: ?Sized> From<&T> for NonNull<T> { | |
mod verify { | ||
use super::*; | ||
use crate::ptr::null_mut; | ||
use crate::mem; | ||
use kani::PointerGenerator; | ||
|
||
trait SampleTrait { | ||
|
@@ -2473,4 +2488,54 @@ mod verify { | |
let distance = ptr_nonnull.offset_from(origin_nonnull); | ||
} | ||
} | ||
|
||
#[kani::proof_for_contract(NonNull::byte_add)] | ||
pub fn non_null_byte_add_proof() { | ||
const ARR_SIZE: usize = mem::size_of::<i32>() * 1000; | ||
let mut generator = PointerGenerator::<ARR_SIZE>::new(); | ||
|
||
let count: usize = kani::any(); | ||
let raw_ptr: *mut i32 = generator.any_in_bounds().ptr as *mut i32; | ||
|
||
unsafe { | ||
let ptr = NonNull::new(raw_ptr).unwrap(); | ||
let result = ptr.byte_add(count); | ||
} | ||
} | ||
|
||
#[kani::proof_for_contract(NonNull::byte_offset)] | ||
pub fn non_null_byte_offset_proof() { | ||
const ARR_SIZE: usize = mem::size_of::<i32>() * 1000; | ||
let mut generator = PointerGenerator::<ARR_SIZE>::new(); | ||
|
||
let count: isize = kani::any(); | ||
let raw_ptr: *mut i32 = generator.any_in_bounds().ptr as *mut i32; | ||
|
||
unsafe { | ||
let ptr = NonNull::new(raw_ptr).unwrap(); | ||
let result = ptr.byte_offset(count); | ||
} | ||
} | ||
|
||
#[kani::proof_for_contract(NonNull::byte_offset_from)] | ||
pub fn non_null_byte_offset_from_proof() { | ||
const SIZE: usize = mem::size_of::<i32>() * 1000; | ||
let mut generator1 = PointerGenerator::<SIZE>::new(); | ||
danielhumanmod marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let mut generator2 = PointerGenerator::<SIZE>::new(); | ||
|
||
let ptr: *mut i32 = generator1.any_in_bounds().ptr as *mut i32; | ||
|
||
let origin: *mut i32 = if kani::any() { | ||
generator1.any_in_bounds().ptr as *mut i32 | ||
} else { | ||
generator2.any_in_bounds().ptr as *mut i32 | ||
}; | ||
|
||
let ptr_nonnull = unsafe { NonNull::new(ptr).unwrap() }; | ||
let origin_nonnull = unsafe { NonNull::new(origin).unwrap() }; | ||
|
||
unsafe { | ||
let result = ptr_nonnull.byte_offset_from(origin_nonnull); | ||
} | ||
} | ||
} |
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.
I believe it's safe to call this function with
count == 0
even ifself.pointer
is dangling.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.
Appreciate the suggestion @celinval! But there is some failure with the my dangling proof:
Proof harness:
Error:
I am not sure whether it is because I didn't create a proper dangling scenario, could you provide some suggestion on this? Thanks!
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.
Did you extend the requires clause?
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.
Hi @celinval, do you mind being more specific about it? Based on my understanding, we need to add a proof harness where
ptr
is dangling andcount
= 0. Any additional contract need to be added into the API?