Skip to content

Commit 688b15b

Browse files
JimmycreativeOwOQinyuanWucarolynzechzhassan-aws
authored
Contracts & Harnesses for non_null::sub and non_null::sub_ptr and non_null::offset_from (#93)
Towards #53 Changes added contract and harness for non_null::sub added contract and harness for non_null::sub_ptr Revalidation To revalidate the verification results, run kani verify-std -Z unstable-options "path/to/library" -Z function-contracts -Z mem-predicates --harness ptr::non_null::verify This will run both harnesses. All default checks should pass: ``` SUMMARY: ** 0 of 1622 failed VERIFICATION:- SUCCESSFUL Verification Time: 0.3814842s SUMMARY: ** 0 of 1780 failed (1 unreachable) VERIFICATION:- SUCCESSFUL Verification Time: 0.44192737s Complete - 2 successfully verified harnesses, 0 failures, 2 total. ``` ### Clarifying Questions The proof now only handles the array with a fixed size and uses a random element in the arr for subtraction. The element is i32 type. Is this ok for the current stage? Or maybe we need to consider other types such as i64, etc and maybe change the arr to a bigger size? --------- Co-authored-by: OwO <[email protected]> Co-authored-by: Qinyuan Wu <[email protected]> Co-authored-by: Carolyn Zech <[email protected]> Co-authored-by: Zyad Hassan <[email protected]>
1 parent 82da845 commit 688b15b

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

library/core/src/ptr/non_null.rs

+87
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,12 @@ impl<T: ?Sized> NonNull<T> {
665665
#[stable(feature = "non_null_convenience", since = "1.80.0")]
666666
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
667667
#[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(unchecked_neg))]
668+
#[requires(
669+
count.checked_mul(core::mem::size_of::<T>()).is_some() &&
670+
count * core::mem::size_of::<T>() <= isize::MAX as usize &&
671+
kani::mem::same_allocation(self.as_ptr(), self.as_ptr().wrapping_sub(count))
672+
)]
673+
#[ensures(|result: &NonNull<T>| result.as_ptr() == self.as_ptr().offset(-(count as isize)))]
668674
pub const unsafe fn sub(self, count: usize) -> Self
669675
where
670676
T: Sized,
@@ -794,6 +800,11 @@ impl<T: ?Sized> NonNull<T> {
794800
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
795801
#[stable(feature = "non_null_convenience", since = "1.80.0")]
796802
#[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
803+
#[requires(
804+
(kani::mem::same_allocation(self.as_ptr(), origin.as_ptr()) &&
805+
((self.as_ptr().addr() - origin.as_ptr().addr()) % core::mem::size_of::<T>() == 0))
806+
)] // Ensure both pointers meet safety conditions for offset_from
807+
#[ensures(|result: &isize| *result == (self.as_ptr() as isize - origin.as_ptr() as isize) / core::mem::size_of::<T>() as isize)]
797808
pub const unsafe fn offset_from(self, origin: NonNull<T>) -> isize
798809
where
799810
T: Sized,
@@ -887,6 +898,13 @@ impl<T: ?Sized> NonNull<T> {
887898
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
888899
#[unstable(feature = "ptr_sub_ptr", issue = "95892")]
889900
#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
901+
#[requires(
902+
self.as_ptr().addr().checked_sub(subtracted.as_ptr().addr()).is_some() &&
903+
kani::mem::same_allocation(self.as_ptr(), subtracted.as_ptr()) &&
904+
(self.as_ptr().addr()) >= (subtracted.as_ptr().addr()) &&
905+
(self.as_ptr().addr() - subtracted.as_ptr().addr()) % core::mem::size_of::<T>() == 0
906+
)]
907+
#[ensures(|result: &usize| *result == self.as_ptr().offset_from(subtracted.as_ptr()) as usize)]
890908
pub const unsafe fn sub_ptr(self, subtracted: NonNull<T>) -> usize
891909
where
892910
T: Sized,
@@ -2386,4 +2404,73 @@ mod verify {
23862404
// Perform the alignment check
23872405
let result = non_null_ptr.is_aligned_to(align);
23882406
}
2407+
2408+
#[kani::proof_for_contract(NonNull::sub)]
2409+
pub fn non_null_check_sub() {
2410+
const SIZE: usize = 10000;
2411+
let mut generator = kani::PointerGenerator::<SIZE>::new();
2412+
// Get a raw pointer from the generator within bounds
2413+
let raw_ptr: *mut i32 = generator.any_in_bounds().ptr;
2414+
// Create a non-null pointer from the raw pointer
2415+
let ptr = unsafe { NonNull::new(raw_ptr).unwrap() };
2416+
// Create a non-deterministic count value
2417+
let count: usize = kani::any();
2418+
2419+
unsafe {
2420+
let result = ptr.sub(count);
2421+
}
2422+
}
2423+
2424+
#[kani::proof_for_contract(NonNull::sub_ptr)]
2425+
pub fn non_null_check_sub_ptr() {
2426+
const SIZE: usize = core::mem::size_of::<i32>() * 1000;
2427+
let mut generator1 = kani::PointerGenerator::<SIZE>::new();
2428+
let mut generator2 = kani::PointerGenerator::<SIZE>::new();
2429+
2430+
let ptr: *mut i32 = if kani::any() {
2431+
generator1.any_in_bounds().ptr as *mut i32
2432+
} else {
2433+
generator2.any_in_bounds().ptr as *mut i32
2434+
};
2435+
2436+
let origin: *mut i32 = if kani::any() {
2437+
generator1.any_in_bounds().ptr as *mut i32
2438+
} else {
2439+
generator2.any_in_bounds().ptr as *mut i32
2440+
};
2441+
2442+
let ptr_nonnull = unsafe { NonNull::new(ptr).unwrap() };
2443+
let origin_nonnull = unsafe { NonNull::new(origin).unwrap() };
2444+
2445+
unsafe {
2446+
let distance = ptr_nonnull.sub_ptr(origin_nonnull);
2447+
}
2448+
}
2449+
2450+
#[kani::proof_for_contract(NonNull::offset_from)]
2451+
#[kani::should_panic]
2452+
pub fn non_null_check_offset_from() {
2453+
const SIZE: usize = core::mem::size_of::<i32>() * 1000;
2454+
let mut generator1 = kani::PointerGenerator::<SIZE>::new();
2455+
let mut generator2 = kani::PointerGenerator::<SIZE>::new();
2456+
2457+
let ptr: *mut i32 = if kani::any() {
2458+
generator1.any_in_bounds().ptr as *mut i32
2459+
} else {
2460+
generator2.any_in_bounds().ptr as *mut i32
2461+
};
2462+
2463+
let origin: *mut i32 = if kani::any() {
2464+
generator1.any_in_bounds().ptr as *mut i32
2465+
} else {
2466+
generator2.any_in_bounds().ptr as *mut i32
2467+
};
2468+
2469+
let ptr_nonnull = unsafe { NonNull::new(ptr).unwrap() };
2470+
let origin_nonnull = unsafe { NonNull::new(origin).unwrap() };
2471+
2472+
unsafe {
2473+
let distance = ptr_nonnull.offset_from(origin_nonnull);
2474+
}
2475+
}
23892476
}

0 commit comments

Comments
 (0)