@@ -3,6 +3,10 @@ use crate::cmp::Ordering::{Equal, Greater, Less};
3
3
use crate :: intrinsics:: const_eval_select;
4
4
use crate :: mem:: SizedTypeProperties ;
5
5
use crate :: slice:: { self , SliceIndex } ;
6
+ use safety:: { ensures, requires} ;
7
+
8
+ #[ cfg( kani) ]
9
+ use crate :: kani;
6
10
7
11
impl < T : ?Sized > * mut T {
8
12
/// Returns `true` if the pointer is null.
@@ -400,6 +404,22 @@ impl<T: ?Sized> *mut T {
400
404
#[ rustc_const_stable( feature = "const_ptr_offset" , since = "1.61.0" ) ]
401
405
#[ inline( always) ]
402
406
#[ 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 ) ) ]
403
423
pub const unsafe fn offset ( self , count : isize ) -> * mut T
404
424
where
405
425
T : Sized ,
@@ -998,6 +1018,23 @@ impl<T: ?Sized> *mut T {
998
1018
#[ rustc_const_stable( feature = "const_ptr_offset" , since = "1.61.0" ) ]
999
1019
#[ inline( always) ]
1000
1020
#[ 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 ) ) ]
1001
1038
pub const unsafe fn add ( self , count : usize ) -> Self
1002
1039
where
1003
1040
T : Sized ,
@@ -1107,6 +1144,23 @@ impl<T: ?Sized> *mut T {
1107
1144
#[ cfg_attr( bootstrap, rustc_allow_const_fn_unstable( unchecked_neg) ) ]
1108
1145
#[ inline( always) ]
1109
1146
#[ 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 ) ) ]
1110
1164
pub const unsafe fn sub ( self , count : usize ) -> Self
1111
1165
where
1112
1166
T : Sized ,
@@ -2302,3 +2356,126 @@ impl<T: ?Sized> PartialOrd for *mut T {
2302
2356
* self >= * other
2303
2357
}
2304
2358
}
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