@@ -3,6 +3,10 @@ use crate::cmp::Ordering::{Equal, Greater, Less};
33use crate :: intrinsics:: const_eval_select;
44use crate :: mem:: SizedTypeProperties ;
55use crate :: slice:: { self , SliceIndex } ;
6+ use safety:: { ensures, requires} ;
7+
8+ #[ cfg( kani) ]
9+ use crate :: kani;
610
711impl < T : ?Sized > * mut T {
812 /// Returns `true` if the pointer is null.
@@ -400,6 +404,22 @@ impl<T: ?Sized> *mut T {
400404 #[ rustc_const_stable( feature = "const_ptr_offset" , since = "1.61.0" ) ]
401405 #[ inline( always) ]
402406 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
407+ // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned.
408+ // These conditions are not verified as part of the preconditions.
409+ #[ requires(
410+ // Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`
411+ count. checked_mul( core:: mem:: size_of:: <T >( ) as isize ) . is_some( ) &&
412+ // Precondition 2: adding the computed offset to `self` does not cause overflow
413+ ( self as isize ) . checked_add( ( count * core:: mem:: size_of:: <T >( ) as isize ) ) . is_some( ) &&
414+ // Precondition 3: If `T` is a unit type (`size_of::<T>() == 0`), this check is unnecessary as it has no allocated memory.
415+ // Otherwise, for non-unit types, `self` and `self.wrapping_offset(count)` should point to the same allocated object,
416+ // restricting `count` to prevent crossing allocation boundaries.
417+ ( ( core:: mem:: size_of:: <T >( ) == 0 ) || ( kani:: mem:: same_allocation( self , self . wrapping_offset( count) ) ) )
418+ ) ]
419+ // Postcondition: If `T` is a unit type (`size_of::<T>() == 0`), no allocation check is needed.
420+ // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object,
421+ // verifying that the result remains within the same allocation as `self`.
422+ #[ ensures( |result| ( core:: mem:: size_of:: <T >( ) == 0 ) || kani:: mem:: same_allocation( self as * const T , * result as * const T ) ) ]
403423 pub const unsafe fn offset ( self , count : isize ) -> * mut T
404424 where
405425 T : Sized ,
@@ -998,6 +1018,23 @@ impl<T: ?Sized> *mut T {
9981018 #[ rustc_const_stable( feature = "const_ptr_offset" , since = "1.61.0" ) ]
9991019 #[ inline( always) ]
10001020 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
1021+ // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned.
1022+ // These conditions are not verified as part of the preconditions.
1023+ #[ requires(
1024+ // Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`
1025+ count. checked_mul( core:: mem:: size_of:: <T >( ) ) . is_some( ) &&
1026+ count * core:: mem:: size_of:: <T >( ) <= isize :: MAX as usize &&
1027+ // Precondition 2: adding the computed offset to `self` does not cause overflow
1028+ ( self as isize ) . checked_add( ( count * core:: mem:: size_of:: <T >( ) ) as isize ) . is_some( ) &&
1029+ // Precondition 3: If `T` is a unit type (`size_of::<T>() == 0`), this check is unnecessary as it has no allocated memory.
1030+ // Otherwise, for non-unit types, `self` and `self.wrapping_add(count)` should point to the same allocated object,
1031+ // restricting `count` to prevent crossing allocation boundaries.
1032+ ( ( core:: mem:: size_of:: <T >( ) == 0 ) || ( kani:: mem:: same_allocation( self , self . wrapping_add( count) ) ) )
1033+ ) ]
1034+ // Postcondition: If `T` is a unit type (`size_of::<T>() == 0`), no allocation check is needed.
1035+ // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object,
1036+ // verifying that the result remains within the same allocation as `self`.
1037+ #[ ensures( |result| ( core:: mem:: size_of:: <T >( ) == 0 ) || kani:: mem:: same_allocation( self as * const T , * result as * const T ) ) ]
10011038 pub const unsafe fn add ( self , count : usize ) -> Self
10021039 where
10031040 T : Sized ,
@@ -1107,6 +1144,23 @@ impl<T: ?Sized> *mut T {
11071144 #[ cfg_attr( bootstrap, rustc_allow_const_fn_unstable( unchecked_neg) ) ]
11081145 #[ inline( always) ]
11091146 #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
1147+ // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned.
1148+ // These conditions are not verified as part of the preconditions.
1149+ #[ requires(
1150+ // Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`
1151+ count. checked_mul( core:: mem:: size_of:: <T >( ) ) . is_some( ) &&
1152+ count * core:: mem:: size_of:: <T >( ) <= isize :: MAX as usize &&
1153+ // Precondition 2: subtracting the computed offset from `self` does not cause overflow
1154+ ( self as isize ) . checked_sub( ( count * core:: mem:: size_of:: <T >( ) ) as isize ) . is_some( ) &&
1155+ // Precondition 3: If `T` is a unit type (`size_of::<T>() == 0`), this check is unnecessary as it has no allocated memory.
1156+ // Otherwise, for non-unit types, `self` and `self.wrapping_sub(count)` should point to the same allocated object,
1157+ // restricting `count` to prevent crossing allocation boundaries.
1158+ ( ( core:: mem:: size_of:: <T >( ) == 0 ) || ( kani:: mem:: same_allocation( self , self . wrapping_sub( count) ) ) )
1159+ ) ]
1160+ // Postcondition: If `T` is a unit type (`size_of::<T>() == 0`), no allocation check is needed.
1161+ // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object,
1162+ // verifying that the result remains within the same allocation as `self`.
1163+ #[ ensures( |result| ( core:: mem:: size_of:: <T >( ) == 0 ) || kani:: mem:: same_allocation( self as * const T , * result as * const T ) ) ]
11101164 pub const unsafe fn sub ( self , count : usize ) -> Self
11111165 where
11121166 T : Sized ,
@@ -2302,3 +2356,126 @@ impl<T: ?Sized> PartialOrd for *mut T {
23022356 * self >= * other
23032357 }
23042358}
2359+
2360+ #[ cfg( kani) ]
2361+ #[ unstable( feature = "kani" , issue = "none" ) ]
2362+ mod verify {
2363+ use crate :: kani;
2364+
2365+ /// This macro generates proofs for contracts on `add`, `sub`, and `offset`
2366+ /// operations for pointers to integer, composite, and unit types.
2367+ /// - `$type`: Specifies the pointee type.
2368+ /// - `$proof_name`: Specifies the name of the generated proof for contract.
2369+ macro_rules! generate_mut_arithmetic_harness {
2370+ ( $type: ty, $proof_name: ident, add) => {
2371+ #[ kani:: proof_for_contract( <* mut $type>:: add) ]
2372+ pub fn $proof_name( ) {
2373+ // 200 bytes are large enough to cover all pointee types used for testing
2374+ const BUF_SIZE : usize = 200 ;
2375+ let mut generator = kani:: PointerGenerator :: <BUF_SIZE >:: new( ) ;
2376+ let test_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
2377+ let count: usize = kani:: any( ) ;
2378+ unsafe {
2379+ test_ptr. add( count) ;
2380+ }
2381+ }
2382+ } ;
2383+ ( $type: ty, $proof_name: ident, sub) => {
2384+ #[ kani:: proof_for_contract( <* mut $type>:: sub) ]
2385+ pub fn $proof_name( ) {
2386+ // 200 bytes are large enough to cover all pointee types used for testing
2387+ const BUF_SIZE : usize = 200 ;
2388+ let mut generator = kani:: PointerGenerator :: <BUF_SIZE >:: new( ) ;
2389+ let test_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
2390+ let count: usize = kani:: any( ) ;
2391+ unsafe {
2392+ test_ptr. sub( count) ;
2393+ }
2394+ }
2395+ } ;
2396+ ( $type: ty, $proof_name: ident, offset) => {
2397+ #[ kani:: proof_for_contract( <* mut $type>:: offset) ]
2398+ pub fn $proof_name( ) {
2399+ // 200 bytes are large enough to cover all pointee types used for testing
2400+ const BUF_SIZE : usize = 200 ;
2401+ let mut generator = kani:: PointerGenerator :: <BUF_SIZE >:: new( ) ;
2402+ let test_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
2403+ let count: isize = kani:: any( ) ;
2404+ unsafe {
2405+ test_ptr. offset( count) ;
2406+ }
2407+ }
2408+ } ;
2409+ }
2410+
2411+ // <*mut T>:: add() integer types verification
2412+ generate_mut_arithmetic_harness ! ( i8 , check_mut_add_i8, add) ;
2413+ generate_mut_arithmetic_harness ! ( i16 , check_mut_add_i16, add) ;
2414+ generate_mut_arithmetic_harness ! ( i32 , check_mut_add_i32, add) ;
2415+ generate_mut_arithmetic_harness ! ( i64 , check_mut_add_i64, add) ;
2416+ generate_mut_arithmetic_harness ! ( i128 , check_mut_add_i128, add) ;
2417+ generate_mut_arithmetic_harness ! ( isize , check_mut_add_isize, add) ;
2418+ // Due to a bug of kani this test case is malfunctioning for now.
2419+ // Tracking issue: https://github.com/model-checking/kani/issues/3743
2420+ // generate_mut_arithmetic_harness!(u8, check_mut_add_u8, add);
2421+ generate_mut_arithmetic_harness ! ( u16 , check_mut_add_u16, add) ;
2422+ generate_mut_arithmetic_harness ! ( u32 , check_mut_add_u32, add) ;
2423+ generate_mut_arithmetic_harness ! ( u64 , check_mut_add_u64, add) ;
2424+ generate_mut_arithmetic_harness ! ( u128 , check_mut_add_u128, add) ;
2425+ generate_mut_arithmetic_harness ! ( usize , check_mut_add_usize, add) ;
2426+
2427+ // <*mut T>:: add() unit type verification
2428+ generate_mut_arithmetic_harness ! ( ( ) , check_mut_add_unit, add) ;
2429+
2430+ // <*mut T>:: add() composite types verification
2431+ generate_mut_arithmetic_harness ! ( ( i8 , i8 ) , check_mut_add_tuple_1, add) ;
2432+ generate_mut_arithmetic_harness ! ( ( f64 , bool ) , check_mut_add_tuple_2, add) ;
2433+ generate_mut_arithmetic_harness ! ( ( i32 , f64 , bool ) , check_mut_add_tuple_3, add) ;
2434+ generate_mut_arithmetic_harness ! ( ( i8 , u16 , i32 , u64 , isize ) , check_mut_add_tuple_4, add) ;
2435+
2436+ // <*mut T>:: sub() integer types verification
2437+ generate_mut_arithmetic_harness ! ( i8 , check_mut_sub_i8, sub) ;
2438+ generate_mut_arithmetic_harness ! ( i16 , check_mut_sub_i16, sub) ;
2439+ generate_mut_arithmetic_harness ! ( i32 , check_mut_sub_i32, sub) ;
2440+ generate_mut_arithmetic_harness ! ( i64 , check_mut_sub_i64, sub) ;
2441+ generate_mut_arithmetic_harness ! ( i128 , check_mut_sub_i128, sub) ;
2442+ generate_mut_arithmetic_harness ! ( isize , check_mut_sub_isize, sub) ;
2443+ generate_mut_arithmetic_harness ! ( u8 , check_mut_sub_u8, sub) ;
2444+ generate_mut_arithmetic_harness ! ( u16 , check_mut_sub_u16, sub) ;
2445+ generate_mut_arithmetic_harness ! ( u32 , check_mut_sub_u32, sub) ;
2446+ generate_mut_arithmetic_harness ! ( u64 , check_mut_sub_u64, sub) ;
2447+ generate_mut_arithmetic_harness ! ( u128 , check_mut_sub_u128, sub) ;
2448+ generate_mut_arithmetic_harness ! ( usize , check_mut_sub_usize, sub) ;
2449+
2450+ // <*mut T>:: sub() unit type verification
2451+ generate_mut_arithmetic_harness ! ( ( ) , check_mut_sub_unit, sub) ;
2452+
2453+ // <*mut T>:: sub() composite types verification
2454+ generate_mut_arithmetic_harness ! ( ( i8 , i8 ) , check_mut_sub_tuple_1, sub) ;
2455+ generate_mut_arithmetic_harness ! ( ( f64 , bool ) , check_mut_sub_tuple_2, sub) ;
2456+ generate_mut_arithmetic_harness ! ( ( i32 , f64 , bool ) , check_mut_sub_tuple_3, sub) ;
2457+ generate_mut_arithmetic_harness ! ( ( i8 , u16 , i32 , u64 , isize ) , check_mut_sub_tuple_4, sub) ;
2458+
2459+ // fn <*mut T>::offset() integer types verification
2460+ generate_mut_arithmetic_harness ! ( i8 , check_mut_offset_i8, offset) ;
2461+ generate_mut_arithmetic_harness ! ( i16 , check_mut_offset_i16, offset) ;
2462+ generate_mut_arithmetic_harness ! ( i32 , check_mut_offset_i32, offset) ;
2463+ generate_mut_arithmetic_harness ! ( i64 , check_mut_offset_i64, offset) ;
2464+ generate_mut_arithmetic_harness ! ( i128 , check_mut_offset_i128, offset) ;
2465+ generate_mut_arithmetic_harness ! ( isize , check_mut_offset_isize, offset) ;
2466+ generate_mut_arithmetic_harness ! ( u8 , check_mut_offset_u8, offset) ;
2467+ generate_mut_arithmetic_harness ! ( u16 , check_mut_offset_u16, offset) ;
2468+ generate_mut_arithmetic_harness ! ( u32 , check_mut_offset_u32, offset) ;
2469+ generate_mut_arithmetic_harness ! ( u64 , check_mut_offset_u64, offset) ;
2470+ generate_mut_arithmetic_harness ! ( u128 , check_mut_offset_u128, offset) ;
2471+ generate_mut_arithmetic_harness ! ( usize , check_mut_offset_usize, offset) ;
2472+
2473+ // fn <*mut T>::offset() unit type verification
2474+ generate_mut_arithmetic_harness ! ( ( ) , check_mut_offset_unit, offset) ;
2475+
2476+ // fn <*mut T>::offset() composite type verification
2477+ generate_mut_arithmetic_harness ! ( ( i8 , i8 ) , check_mut_offset_tuple_1, offset) ;
2478+ generate_mut_arithmetic_harness ! ( ( f64 , bool ) , check_mut_offset_tuple_2, offset) ;
2479+ generate_mut_arithmetic_harness ! ( ( i32 , f64 , bool ) , check_mut_offset_tuple_3, offset) ;
2480+ generate_mut_arithmetic_harness ! ( ( i8 , u16 , i32 , u64 , isize ) , check_mut_offset_tuple_4, offset) ;
2481+ }
0 commit comments