@@ -405,6 +405,22 @@ impl<T: ?Sized> *mut T {
405
405
#[ rustc_const_stable( feature = "const_ptr_offset" , since = "1.61.0" ) ]
406
406
#[ inline( always) ]
407
407
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
408
+ // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned.
409
+ // These conditions are not verified as part of the preconditions.
410
+ #[ requires(
411
+ // Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`
412
+ count. checked_mul( core:: mem:: size_of:: <T >( ) as isize ) . is_some( ) &&
413
+ // Precondition 2: adding the computed offset to `self` does not cause overflow
414
+ ( self as isize ) . checked_add( ( count * core:: mem:: size_of:: <T >( ) as isize ) ) . is_some( ) &&
415
+ // Precondition 3: If `T` is a unit type (`size_of::<T>() == 0`), this check is unnecessary as it has no allocated memory.
416
+ // Otherwise, for non-unit types, `self` and `self.wrapping_offset(count)` should point to the same allocated object,
417
+ // restricting `count` to prevent crossing allocation boundaries.
418
+ ( ( core:: mem:: size_of:: <T >( ) == 0 ) || ( kani:: mem:: same_allocation( self , self . wrapping_offset( count) ) ) )
419
+ ) ]
420
+ // Postcondition: If `T` is a unit type (`size_of::<T>() == 0`), no allocation check is needed.
421
+ // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object,
422
+ // verifying that the result remains within the same allocation as `self`.
423
+ #[ ensures( |result| ( core:: mem:: size_of:: <T >( ) == 0 ) || kani:: mem:: same_allocation( self as * const T , * result as * const T ) ) ]
408
424
pub const unsafe fn offset ( self , count : isize ) -> * mut T
409
425
where
410
426
T : Sized ,
@@ -1013,6 +1029,23 @@ impl<T: ?Sized> *mut T {
1013
1029
#[ rustc_const_stable( feature = "const_ptr_offset" , since = "1.61.0" ) ]
1014
1030
#[ inline( always) ]
1015
1031
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
1032
+ // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned.
1033
+ // These conditions are not verified as part of the preconditions.
1034
+ #[ requires(
1035
+ // Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`
1036
+ count. checked_mul( core:: mem:: size_of:: <T >( ) ) . is_some( ) &&
1037
+ count * core:: mem:: size_of:: <T >( ) <= isize :: MAX as usize &&
1038
+ // Precondition 2: adding the computed offset to `self` does not cause overflow
1039
+ ( self as isize ) . checked_add( ( count * core:: mem:: size_of:: <T >( ) ) as isize ) . is_some( ) &&
1040
+ // Precondition 3: If `T` is a unit type (`size_of::<T>() == 0`), this check is unnecessary as it has no allocated memory.
1041
+ // Otherwise, for non-unit types, `self` and `self.wrapping_add(count)` should point to the same allocated object,
1042
+ // restricting `count` to prevent crossing allocation boundaries.
1043
+ ( ( core:: mem:: size_of:: <T >( ) == 0 ) || ( kani:: mem:: same_allocation( self , self . wrapping_add( count) ) ) )
1044
+ ) ]
1045
+ // Postcondition: If `T` is a unit type (`size_of::<T>() == 0`), no allocation check is needed.
1046
+ // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object,
1047
+ // verifying that the result remains within the same allocation as `self`.
1048
+ #[ ensures( |result| ( core:: mem:: size_of:: <T >( ) == 0 ) || kani:: mem:: same_allocation( self as * const T , * result as * const T ) ) ]
1016
1049
pub const unsafe fn add ( self , count : usize ) -> Self
1017
1050
where
1018
1051
T : Sized ,
@@ -1122,6 +1155,23 @@ impl<T: ?Sized> *mut T {
1122
1155
#[ cfg_attr( bootstrap, rustc_allow_const_fn_unstable( unchecked_neg) ) ]
1123
1156
#[ inline( always) ]
1124
1157
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
1158
+ // Note: It is the caller's responsibility to ensure that `self` is non-null and properly aligned.
1159
+ // These conditions are not verified as part of the preconditions.
1160
+ #[ requires(
1161
+ // Precondition 1: the computed offset `count * size_of::<T>()` does not overflow `isize`
1162
+ count. checked_mul( core:: mem:: size_of:: <T >( ) ) . is_some( ) &&
1163
+ count * core:: mem:: size_of:: <T >( ) <= isize :: MAX as usize &&
1164
+ // Precondition 2: subtracting the computed offset from `self` does not cause overflow
1165
+ ( self as isize ) . checked_sub( ( count * core:: mem:: size_of:: <T >( ) ) as isize ) . is_some( ) &&
1166
+ // Precondition 3: If `T` is a unit type (`size_of::<T>() == 0`), this check is unnecessary as it has no allocated memory.
1167
+ // Otherwise, for non-unit types, `self` and `self.wrapping_sub(count)` should point to the same allocated object,
1168
+ // restricting `count` to prevent crossing allocation boundaries.
1169
+ ( ( core:: mem:: size_of:: <T >( ) == 0 ) || ( kani:: mem:: same_allocation( self , self . wrapping_sub( count) ) ) )
1170
+ ) ]
1171
+ // Postcondition: If `T` is a unit type (`size_of::<T>() == 0`), no allocation check is needed.
1172
+ // Otherwise, for non-unit types, ensure that `self` and `result` point to the same allocated object,
1173
+ // verifying that the result remains within the same allocation as `self`.
1174
+ #[ ensures( |result| ( core:: mem:: size_of:: <T >( ) == 0 ) || kani:: mem:: same_allocation( self as * const T , * result as * const T ) ) ]
1125
1175
pub const unsafe fn sub ( self , count : usize ) -> Self
1126
1176
where
1127
1177
T : Sized ,
@@ -2506,5 +2556,121 @@ pub mod verify {
2506
2556
generate_mut_byte_offset_from_slice_harness ! ( i64 , check_mut_byte_offset_from_i64_slice) ;
2507
2557
generate_mut_byte_offset_from_slice_harness ! ( i128 , check_mut_byte_offset_from_i128_slice) ;
2508
2558
generate_mut_byte_offset_from_slice_harness ! ( isize , check_mut_byte_offset_from_isize_slice) ;
2509
-
2559
+
2560
+ /// This macro generates proofs for contracts on `add`, `sub`, and `offset`
2561
+ /// operations for pointers to integer, composite, and unit types.
2562
+ /// - `$type`: Specifies the pointee type.
2563
+ /// - `$proof_name`: Specifies the name of the generated proof for contract.
2564
+ macro_rules! generate_mut_arithmetic_harness {
2565
+ ( $type: ty, $proof_name: ident, add) => {
2566
+ #[ kani:: proof_for_contract( <* mut $type>:: add) ]
2567
+ pub fn $proof_name( ) {
2568
+ // 200 bytes are large enough to cover all pointee types used for testing
2569
+ const BUF_SIZE : usize = 200 ;
2570
+ let mut generator = kani:: PointerGenerator :: <BUF_SIZE >:: new( ) ;
2571
+ let test_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
2572
+ let count: usize = kani:: any( ) ;
2573
+ unsafe {
2574
+ test_ptr. add( count) ;
2575
+ }
2576
+ }
2577
+ } ;
2578
+ ( $type: ty, $proof_name: ident, sub) => {
2579
+ #[ kani:: proof_for_contract( <* mut $type>:: sub) ]
2580
+ pub fn $proof_name( ) {
2581
+ // 200 bytes are large enough to cover all pointee types used for testing
2582
+ const BUF_SIZE : usize = 200 ;
2583
+ let mut generator = kani:: PointerGenerator :: <BUF_SIZE >:: new( ) ;
2584
+ let test_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
2585
+ let count: usize = kani:: any( ) ;
2586
+ unsafe {
2587
+ test_ptr. sub( count) ;
2588
+ }
2589
+ }
2590
+ } ;
2591
+ ( $type: ty, $proof_name: ident, offset) => {
2592
+ #[ kani:: proof_for_contract( <* mut $type>:: offset) ]
2593
+ pub fn $proof_name( ) {
2594
+ // 200 bytes are large enough to cover all pointee types used for testing
2595
+ const BUF_SIZE : usize = 200 ;
2596
+ let mut generator = kani:: PointerGenerator :: <BUF_SIZE >:: new( ) ;
2597
+ let test_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
2598
+ let count: isize = kani:: any( ) ;
2599
+ unsafe {
2600
+ test_ptr. offset( count) ;
2601
+ }
2602
+ }
2603
+ } ;
2604
+ }
2605
+
2606
+ // <*mut T>:: add() integer types verification
2607
+ generate_mut_arithmetic_harness ! ( i8 , check_mut_add_i8, add) ;
2608
+ generate_mut_arithmetic_harness ! ( i16 , check_mut_add_i16, add) ;
2609
+ generate_mut_arithmetic_harness ! ( i32 , check_mut_add_i32, add) ;
2610
+ generate_mut_arithmetic_harness ! ( i64 , check_mut_add_i64, add) ;
2611
+ generate_mut_arithmetic_harness ! ( i128 , check_mut_add_i128, add) ;
2612
+ generate_mut_arithmetic_harness ! ( isize , check_mut_add_isize, add) ;
2613
+ // Due to a bug of kani this test case is malfunctioning for now.
2614
+ // Tracking issue: https://github.com/model-checking/kani/issues/3743
2615
+ // generate_mut_arithmetic_harness!(u8, check_mut_add_u8, add);
2616
+ generate_mut_arithmetic_harness ! ( u16 , check_mut_add_u16, add) ;
2617
+ generate_mut_arithmetic_harness ! ( u32 , check_mut_add_u32, add) ;
2618
+ generate_mut_arithmetic_harness ! ( u64 , check_mut_add_u64, add) ;
2619
+ generate_mut_arithmetic_harness ! ( u128 , check_mut_add_u128, add) ;
2620
+ generate_mut_arithmetic_harness ! ( usize , check_mut_add_usize, add) ;
2621
+
2622
+ // <*mut T>:: add() unit type verification
2623
+ generate_mut_arithmetic_harness ! ( ( ) , check_mut_add_unit, add) ;
2624
+
2625
+ // <*mut T>:: add() composite types verification
2626
+ generate_mut_arithmetic_harness ! ( ( i8 , i8 ) , check_mut_add_tuple_1, add) ;
2627
+ generate_mut_arithmetic_harness ! ( ( f64 , bool ) , check_mut_add_tuple_2, add) ;
2628
+ generate_mut_arithmetic_harness ! ( ( i32 , f64 , bool ) , check_mut_add_tuple_3, add) ;
2629
+ generate_mut_arithmetic_harness ! ( ( i8 , u16 , i32 , u64 , isize ) , check_mut_add_tuple_4, add) ;
2630
+
2631
+ // <*mut T>:: sub() integer types verification
2632
+ generate_mut_arithmetic_harness ! ( i8 , check_mut_sub_i8, sub) ;
2633
+ generate_mut_arithmetic_harness ! ( i16 , check_mut_sub_i16, sub) ;
2634
+ generate_mut_arithmetic_harness ! ( i32 , check_mut_sub_i32, sub) ;
2635
+ generate_mut_arithmetic_harness ! ( i64 , check_mut_sub_i64, sub) ;
2636
+ generate_mut_arithmetic_harness ! ( i128 , check_mut_sub_i128, sub) ;
2637
+ generate_mut_arithmetic_harness ! ( isize , check_mut_sub_isize, sub) ;
2638
+ generate_mut_arithmetic_harness ! ( u8 , check_mut_sub_u8, sub) ;
2639
+ generate_mut_arithmetic_harness ! ( u16 , check_mut_sub_u16, sub) ;
2640
+ generate_mut_arithmetic_harness ! ( u32 , check_mut_sub_u32, sub) ;
2641
+ generate_mut_arithmetic_harness ! ( u64 , check_mut_sub_u64, sub) ;
2642
+ generate_mut_arithmetic_harness ! ( u128 , check_mut_sub_u128, sub) ;
2643
+ generate_mut_arithmetic_harness ! ( usize , check_mut_sub_usize, sub) ;
2644
+
2645
+ // <*mut T>:: sub() unit type verification
2646
+ generate_mut_arithmetic_harness ! ( ( ) , check_mut_sub_unit, sub) ;
2647
+
2648
+ // <*mut T>:: sub() composite types verification
2649
+ generate_mut_arithmetic_harness ! ( ( i8 , i8 ) , check_mut_sub_tuple_1, sub) ;
2650
+ generate_mut_arithmetic_harness ! ( ( f64 , bool ) , check_mut_sub_tuple_2, sub) ;
2651
+ generate_mut_arithmetic_harness ! ( ( i32 , f64 , bool ) , check_mut_sub_tuple_3, sub) ;
2652
+ generate_mut_arithmetic_harness ! ( ( i8 , u16 , i32 , u64 , isize ) , check_mut_sub_tuple_4, sub) ;
2653
+
2654
+ // fn <*mut T>::offset() integer types verification
2655
+ generate_mut_arithmetic_harness ! ( i8 , check_mut_offset_i8, offset) ;
2656
+ generate_mut_arithmetic_harness ! ( i16 , check_mut_offset_i16, offset) ;
2657
+ generate_mut_arithmetic_harness ! ( i32 , check_mut_offset_i32, offset) ;
2658
+ generate_mut_arithmetic_harness ! ( i64 , check_mut_offset_i64, offset) ;
2659
+ generate_mut_arithmetic_harness ! ( i128 , check_mut_offset_i128, offset) ;
2660
+ generate_mut_arithmetic_harness ! ( isize , check_mut_offset_isize, offset) ;
2661
+ generate_mut_arithmetic_harness ! ( u8 , check_mut_offset_u8, offset) ;
2662
+ generate_mut_arithmetic_harness ! ( u16 , check_mut_offset_u16, offset) ;
2663
+ generate_mut_arithmetic_harness ! ( u32 , check_mut_offset_u32, offset) ;
2664
+ generate_mut_arithmetic_harness ! ( u64 , check_mut_offset_u64, offset) ;
2665
+ generate_mut_arithmetic_harness ! ( u128 , check_mut_offset_u128, offset) ;
2666
+ generate_mut_arithmetic_harness ! ( usize , check_mut_offset_usize, offset) ;
2667
+
2668
+ // fn <*mut T>::offset() unit type verification
2669
+ generate_mut_arithmetic_harness ! ( ( ) , check_mut_offset_unit, offset) ;
2670
+
2671
+ // fn <*mut T>::offset() composite type verification
2672
+ generate_mut_arithmetic_harness ! ( ( i8 , i8 ) , check_mut_offset_tuple_1, offset) ;
2673
+ generate_mut_arithmetic_harness ! ( ( f64 , bool ) , check_mut_offset_tuple_2, offset) ;
2674
+ generate_mut_arithmetic_harness ! ( ( i32 , f64 , bool ) , check_mut_offset_tuple_3, offset) ;
2675
+ generate_mut_arithmetic_harness ! ( ( i8 , u16 , i32 , u64 , isize ) , check_mut_offset_tuple_4, offset) ;
2510
2676
}
0 commit comments