Skip to content

Commit ea7a95f

Browse files
Dhvani-KapadiaQinyuanWucarolynzechtautschnig
authored
Contract and harness for copy_to, copy_to_nonoverlapping, copy_from, and copy_from_nonoverlapping (rust-lang#149)
Description This PR includes contracts and proof harnesses for the four APIs copy_to, copy_to_nonoverlapping, copy_from, and copy_from_nonoverlapping which are part of the NonNull library in Rust. Changes Overview: Covered APIs: NonNull::copy_to NonNull::copy_to_nonoverlapping NonNull::copy_from NonNull::opy_from_nonoverlapping Proof harness: non_null_check_copy_to non_null_check_copy_to_nonoverlapping non_null_check_copy_from non_null_check_copy_from_nonoverlapping, Revalidation To revalidate the verification results, run path_to/kani/scripts/kani verify-std -Z unstable-options "path/to/library" -Z function-contracts -Z mem-predicates --harness ptr::non_null::verify. This will run all four harnesses in the module. All default checks should pass: SUMMARY: ** 0 of 141 failed VERIFICATION:- SUCCESSFUL Verification Time: 0.62114185s Complete - 6 successfully verified harnesses, 0 failures, 6 total. Towards issue rust-lang#53 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --------- Co-authored-by: Qinyuan Wu <[email protected]> Co-authored-by: Carolyn Zech <[email protected]> Co-authored-by: Qinyuan Wu <[email protected]> Co-authored-by: Michael Tautschnig <[email protected]>
1 parent 27a9931 commit ea7a95f

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

library/core/src/ptr/non_null.rs

+84
Original file line numberDiff line numberDiff line change
@@ -1035,8 +1035,14 @@ impl<T: ?Sized> NonNull<T> {
10351035
/// [`ptr::copy`]: crate::ptr::copy()
10361036
#[inline(always)]
10371037
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1038+
#[cfg_attr(kani, kani::modifies(NonNull::slice_from_raw_parts(dest, count).as_ptr()))]
10381039
#[stable(feature = "non_null_convenience", since = "1.80.0")]
10391040
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
1041+
#[requires(count.checked_mul(core::mem::size_of::<T>()).map_or_else(|| false, |size| size <= isize::MAX as usize)
1042+
&& ub_checks::can_dereference(NonNull::slice_from_raw_parts(self, count).as_ptr())
1043+
&& ub_checks::can_write(NonNull::slice_from_raw_parts(dest, count).as_ptr()))]
1044+
#[ensures(|result: &()| ub_checks::can_dereference(self.as_ptr() as *const u8)
1045+
&& ub_checks::can_dereference(dest.as_ptr() as *const u8))]
10401046
pub const unsafe fn copy_to(self, dest: NonNull<T>, count: usize)
10411047
where
10421048
T: Sized,
@@ -1055,8 +1061,15 @@ impl<T: ?Sized> NonNull<T> {
10551061
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
10561062
#[inline(always)]
10571063
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1064+
#[cfg_attr(kani, kani::modifies(NonNull::slice_from_raw_parts(dest, count).as_ptr()))]
10581065
#[stable(feature = "non_null_convenience", since = "1.80.0")]
10591066
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
1067+
#[requires(count.checked_mul(core::mem::size_of::<T>()).map_or_else(|| false, |size| size <= isize::MAX as usize)
1068+
&& ub_checks::can_dereference(NonNull::slice_from_raw_parts(self, count).as_ptr())
1069+
&& ub_checks::can_write(NonNull::slice_from_raw_parts(dest, count).as_ptr())
1070+
&& ub_checks::maybe_is_nonoverlapping(self.as_ptr() as *const (), dest.as_ptr() as *const (), count, core::mem::size_of::<T>()))]
1071+
#[ensures(|result: &()| ub_checks::can_dereference(self.as_ptr() as *const u8)
1072+
&& ub_checks::can_dereference(dest.as_ptr() as *const u8))]
10601073
pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull<T>, count: usize)
10611074
where
10621075
T: Sized,
@@ -1075,8 +1088,14 @@ impl<T: ?Sized> NonNull<T> {
10751088
/// [`ptr::copy`]: crate::ptr::copy()
10761089
#[inline(always)]
10771090
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1091+
#[cfg_attr(kani, kani::modifies(NonNull::slice_from_raw_parts(self, count).as_ptr()))]
10781092
#[stable(feature = "non_null_convenience", since = "1.80.0")]
10791093
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
1094+
#[requires(count.checked_mul(core::mem::size_of::<T>()).map_or_else(|| false, |size| size <= isize::MAX as usize)
1095+
&& ub_checks::can_dereference(NonNull::slice_from_raw_parts(src, count).as_ptr())
1096+
&& ub_checks::can_write(NonNull::slice_from_raw_parts(self, count).as_ptr()))]
1097+
#[ensures(|result: &()| ub_checks::can_dereference(src.as_ptr() as *const u8)
1098+
&& ub_checks::can_dereference(self.as_ptr() as *const u8))]
10801099
pub const unsafe fn copy_from(self, src: NonNull<T>, count: usize)
10811100
where
10821101
T: Sized,
@@ -1095,8 +1114,15 @@ impl<T: ?Sized> NonNull<T> {
10951114
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
10961115
#[inline(always)]
10971116
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1117+
#[cfg_attr(kani, kani::modifies(NonNull::slice_from_raw_parts(self, count).as_ptr()))]
10981118
#[stable(feature = "non_null_convenience", since = "1.80.0")]
10991119
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")]
1120+
#[requires(count.checked_mul(core::mem::size_of::<T>()).map_or_else(|| false, |size| size <= isize::MAX as usize)
1121+
&& ub_checks::can_dereference(NonNull::slice_from_raw_parts(src, count).as_ptr())
1122+
&& ub_checks::can_write(NonNull::slice_from_raw_parts(self, count).as_ptr())
1123+
&& ub_checks::maybe_is_nonoverlapping(src.as_ptr() as *const (), self.as_ptr() as *const (), count, core::mem::size_of::<T>()))]
1124+
#[ensures(|result: &()| ub_checks::can_dereference(src.as_ptr() as *const u8)
1125+
&& ub_checks::can_dereference(self.as_ptr() as *const u8))]
11001126
pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull<T>, count: usize)
11011127
where
11021128
T: Sized,
@@ -2538,4 +2564,62 @@ mod verify {
25382564
let _ = ptr.byte_offset_from(origin);
25392565
}
25402566
}
2567+
2568+
#[kani::proof_for_contract(NonNull::<T>::copy_to)]
2569+
pub fn non_null_check_copy_to() {
2570+
// PointerGenerator instance
2571+
let mut generator = PointerGenerator::<16>::new();
2572+
// Generate arbitrary pointers for src and dest
2573+
let src_ptr = generator.any_in_bounds::<i32>().ptr;
2574+
let dest_ptr = generator.any_in_bounds::<i32>().ptr;
2575+
// Wrap the raw pointers in NonNull
2576+
let src = NonNull::new(src_ptr).unwrap();
2577+
let dest = NonNull::new(dest_ptr).unwrap();
2578+
// Generate an arbitrary count using kani::any
2579+
let count: usize = kani::any();
2580+
unsafe { src.copy_to(dest, count);}
2581+
}
2582+
2583+
#[kani::proof_for_contract(NonNull::<T>::copy_from)]
2584+
pub fn non_null_check_copy_from() {
2585+
// PointerGenerator instance
2586+
let mut generator = PointerGenerator::<16>::new();
2587+
// Generate arbitrary pointers for src and dest
2588+
let src_ptr = generator.any_in_bounds::<i32>().ptr;
2589+
let dest_ptr = generator.any_in_bounds::<i32>().ptr;
2590+
// Wrap the raw pointers in NonNull
2591+
let src = NonNull::new(src_ptr).unwrap();
2592+
let dest = NonNull::new(dest_ptr).unwrap();
2593+
// Generate an arbitrary count using kani::any
2594+
let count: usize = kani::any();
2595+
unsafe { src.copy_from(dest, count);}
2596+
}
2597+
#[kani::proof_for_contract(NonNull::<T>::copy_to_nonoverlapping)]
2598+
pub fn non_null_check_copy_to_nonoverlapping() {
2599+
// PointerGenerator instance
2600+
let mut generator = PointerGenerator::<16>::new();
2601+
// Generate arbitrary pointers for src and dest
2602+
let src_ptr = generator.any_in_bounds::<i32>().ptr;
2603+
let dest_ptr = generator.any_in_bounds::<i32>().ptr;
2604+
// Wrap the raw pointers in NonNull
2605+
let src = NonNull::new(src_ptr).unwrap();
2606+
let dest = NonNull::new(dest_ptr).unwrap();
2607+
// Generate an arbitrary count using kani::any
2608+
let count: usize = kani::any();
2609+
unsafe { src.copy_to_nonoverlapping(dest, count);}
2610+
}
2611+
#[kani::proof_for_contract(NonNull::<T>::copy_from_nonoverlapping)]
2612+
pub fn non_null_check_copy_from_nonoverlapping() {
2613+
// PointerGenerator instance
2614+
let mut generator = PointerGenerator::<16>::new();
2615+
// Generate arbitrary pointers for src and dest
2616+
let src_ptr = generator.any_in_bounds::<i32>().ptr;
2617+
let dest_ptr = generator.any_in_bounds::<i32>().ptr;
2618+
// Wrap the raw pointers in NonNull
2619+
let src = NonNull::new(src_ptr).unwrap();
2620+
let dest = NonNull::new(dest_ptr).unwrap();
2621+
// Generate an arbitrary count using kani::any
2622+
let count: usize = kani::any();
2623+
unsafe { src.copy_from_nonoverlapping(dest, count);}
2624+
}
25412625
}

0 commit comments

Comments
 (0)