@@ -1210,6 +1210,8 @@ impl<T: ?Sized> NonNull<T> {
1210
1210
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
1211
1211
#[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
1212
1212
#[ rustc_const_stable( feature = "const_ptr_write" , since = "1.83.0" ) ]
1213
+ #[ cfg_attr( kani, kani:: modifies( self . as_ptr( ) ) ) ]
1214
+ #[ requires( ub_checks:: can_write( self . as_ptr( ) ) ) ]
1213
1215
pub const unsafe fn write ( self , val : T )
1214
1216
where
1215
1217
T : Sized ,
@@ -1229,6 +1231,13 @@ impl<T: ?Sized> NonNull<T> {
1229
1231
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
1230
1232
#[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
1231
1233
#[ rustc_const_stable( feature = "const_ptr_write" , since = "1.83.0" ) ]
1234
+ #[ cfg_attr( kani, kani:: modifies( crate :: ptr:: slice_from_raw_parts( self . as_ptr( ) , count) ) ) ]
1235
+ #[ requires(
1236
+ count. checked_mul( core:: mem:: size_of:: <T >( ) as usize ) . is_some_and( |byte_count| byte_count. wrapping_add( self . as_ptr( ) as usize ) <= isize :: MAX as usize ) &&
1237
+ ub_checks:: can_write( core:: ptr:: slice_from_raw_parts_mut( self . as_ptr( ) , count) )
1238
+ ) ]
1239
+ #[ ensures( |_|
1240
+ ub_checks:: can_dereference( crate :: ptr:: slice_from_raw_parts( self . as_ptr( ) as * const u8 , count * size_of:: <T >( ) ) ) ) ]
1232
1241
pub const unsafe fn write_bytes ( self , val : u8 , count : usize )
1233
1242
where
1234
1243
T : Sized ,
@@ -1272,6 +1281,8 @@ impl<T: ?Sized> NonNull<T> {
1272
1281
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
1273
1282
#[ stable( feature = "non_null_convenience" , since = "1.80.0" ) ]
1274
1283
#[ rustc_const_stable( feature = "const_ptr_write" , since = "1.83.0" ) ]
1284
+ #[ cfg_attr( kani, kani:: modifies( self . as_ptr( ) ) ) ]
1285
+ #[ requires( ub_checks:: can_write_unaligned( self . as_ptr( ) ) ) ]
1275
1286
pub const unsafe fn write_unaligned ( self , val : T )
1276
1287
where
1277
1288
T : Sized ,
@@ -2531,12 +2542,143 @@ mod verify {
2531
2542
}
2532
2543
}
2533
2544
2545
+ macro_rules! generate_write_harness {
2546
+ ( $type: ty, $harness_name: ident) => {
2547
+ #[ kani:: proof_for_contract( NonNull :: write) ]
2548
+ pub fn $harness_name( ) {
2549
+ // Create a pointer generator for the given type with appropriate byte size
2550
+ const ARR_SIZE : usize = mem:: size_of:: <$type>( ) * 100 ;
2551
+ let mut generator = kani:: PointerGenerator :: <ARR_SIZE >:: new( ) ;
2552
+
2553
+ // Get a raw pointer from the generator
2554
+ let raw_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
2555
+
2556
+ // Create a non-null pointer from the raw pointer
2557
+ let ptr = NonNull :: new( raw_ptr) . unwrap( ) ;
2558
+
2559
+ // Create a non-deterministic value to write
2560
+ let new_value: $type = kani:: any( ) ;
2561
+
2562
+ unsafe {
2563
+ // Perform the volatile write operation
2564
+ ptr. write( new_value) ;
2565
+
2566
+ // Read back the value and assert it's correct
2567
+ assert_eq!( ptr. as_ptr( ) . read( ) , new_value) ;
2568
+ }
2569
+ }
2570
+ } ;
2571
+ }
2572
+
2573
+ #[ kani:: proof_for_contract( NonNull :: write) ]
2574
+ pub fn non_null_check_write_unit ( ) {
2575
+ // Create a pointer generator for the given type with appropriate byte size
2576
+ let mut generator = kani:: PointerGenerator :: < 1 > :: new ( ) ;
2577
+
2578
+ // Get a raw pointer from the generator
2579
+ let raw_ptr: * mut ( ) = generator. any_in_bounds ( ) . ptr ;
2580
+
2581
+ // Create a non-null pointer from the raw pointer
2582
+ let ptr = NonNull :: new ( raw_ptr) . unwrap ( ) ;
2583
+
2584
+ // Create a non-deterministic value to write
2585
+ let new_value: ( ) = kani:: any ( ) ;
2586
+
2587
+ unsafe {
2588
+ // Perform the volatile write operation
2589
+ ptr. write ( new_value) ;
2590
+
2591
+ // Read back the value and assert it's correct
2592
+ assert_eq ! ( ptr. as_ptr( ) . read( ) , new_value) ;
2593
+ }
2594
+ }
2595
+
2596
+ // Generate proof harnesses for multiple types with appropriate byte sizes
2597
+ generate_write_harness ! ( i8 , non_null_check_write_i8) ;
2598
+ generate_write_harness ! ( i16 , non_null_check_write_i16) ;
2599
+ generate_write_harness ! ( i32 , non_null_check_write_i32) ;
2600
+ generate_write_harness ! ( i64 , non_null_check_write_i64) ;
2601
+ generate_write_harness ! ( i128 , non_null_check_write_i128) ;
2602
+ generate_write_harness ! ( isize , non_null_check_write_isize) ;
2603
+ generate_write_harness ! ( u8 , non_null_check_write_u8) ;
2604
+ generate_write_harness ! ( u16 , non_null_check_write_u16) ;
2605
+ generate_write_harness ! ( u32 , non_null_check_write_u32) ;
2606
+ generate_write_harness ! ( u64 , non_null_check_write_u64) ;
2607
+ generate_write_harness ! ( u128 , non_null_check_write_u128) ;
2608
+ generate_write_harness ! ( usize , non_null_check_write_usize) ;
2609
+
2610
+ macro_rules! generate_write_unaligned_harness {
2611
+ ( $type: ty, $harness_name: ident) => {
2612
+ #[ kani:: proof_for_contract( NonNull :: write_unaligned) ]
2613
+ pub fn $harness_name( ) {
2614
+ // Create a pointer generator for the given type with appropriate byte size
2615
+ const ARR_SIZE : usize = mem:: size_of:: <$type>( ) * 100 ;
2616
+ let mut generator = kani:: PointerGenerator :: <ARR_SIZE >:: new( ) ;
2617
+
2618
+ // Get a raw pointer from the generator
2619
+ let raw_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
2620
+
2621
+ // Create a non-null pointer from the raw pointer
2622
+ let ptr = NonNull :: new( raw_ptr) . unwrap( ) ;
2623
+
2624
+ // Create a non-deterministic value to write
2625
+ let new_value: $type = kani:: any( ) ;
2626
+
2627
+ unsafe {
2628
+ // Perform the volatile write operation
2629
+ ptr. write_unaligned( new_value) ;
2630
+
2631
+ // Read back the value and assert it's correct
2632
+ assert_eq!( ptr. as_ptr( ) . read_unaligned( ) , new_value) ;
2633
+ }
2634
+ }
2635
+ } ;
2636
+ }
2637
+
2638
+ #[ kani:: proof_for_contract( NonNull :: write_unaligned) ]
2639
+ pub fn non_null_check_write_unaligned_unit ( ) {
2640
+ // Create a pointer generator for the given type with appropriate byte size
2641
+ let mut generator = kani:: PointerGenerator :: < 1 > :: new ( ) ;
2642
+
2643
+ // Get a raw pointer from the generator
2644
+ let raw_ptr: * mut ( ) = generator. any_in_bounds ( ) . ptr ;
2645
+
2646
+ // Create a non-null pointer from the raw pointer
2647
+ let ptr = NonNull :: new ( raw_ptr) . unwrap ( ) ;
2648
+
2649
+ // Create a non-deterministic value to write
2650
+ let new_value: ( ) = kani:: any ( ) ;
2651
+
2652
+ unsafe {
2653
+ // Perform the volatile write operation
2654
+ ptr. write_unaligned ( new_value) ;
2655
+
2656
+ // Read back the value and assert it's correct
2657
+ assert_eq ! ( ptr. as_ptr( ) . read_unaligned( ) , new_value) ;
2658
+ }
2659
+ }
2660
+
2661
+ // Generate proof harnesses for multiple types with appropriate byte sizes
2662
+ generate_write_unaligned_harness ! ( i8 , non_null_check_write_unaligned_i8) ;
2663
+ generate_write_unaligned_harness ! ( i16 , non_null_check_write_unaligned_i16) ;
2664
+ generate_write_unaligned_harness ! ( i32 , non_null_check_write_unaligned_i32) ;
2665
+ generate_write_unaligned_harness ! ( i64 , non_null_check_write_unaligned_i64) ;
2666
+ generate_write_unaligned_harness ! ( i128 , non_null_check_write_unaligned_i128) ;
2667
+ generate_write_unaligned_harness ! ( isize , non_null_check_write_unaligned_isize) ;
2668
+ generate_write_unaligned_harness ! ( u8 , non_null_check_write_unaligned_u8) ;
2669
+ generate_write_unaligned_harness ! ( u16 , non_null_check_write_unaligned_u16) ;
2670
+ generate_write_unaligned_harness ! ( u32 , non_null_check_write_unaligned_u32) ;
2671
+ generate_write_unaligned_harness ! ( u64 , non_null_check_write_unaligned_u64) ;
2672
+ generate_write_unaligned_harness ! ( u128 , non_null_check_write_unaligned_u128) ;
2673
+ generate_write_unaligned_harness ! ( usize , non_null_check_write_unaligned_usize) ;
2674
+
2534
2675
macro_rules! generate_write_volatile_harness {
2535
- ( $type: ty, $byte_size : expr , $ harness_name: ident) => {
2676
+ ( $type: ty, $harness_name: ident) => {
2536
2677
#[ kani:: proof_for_contract( NonNull :: write_volatile) ]
2537
2678
pub fn $harness_name( ) {
2538
2679
// Create a pointer generator for the given type with appropriate byte size
2539
- let mut generator = kani:: PointerGenerator :: <$byte_size>:: new( ) ;
2680
+ const ARR_SIZE : usize = mem:: size_of:: <$type>( ) * 100 ;
2681
+ let mut generator = kani:: PointerGenerator :: <ARR_SIZE >:: new( ) ;
2540
2682
2541
2683
// Get a raw pointer from the generator
2542
2684
let raw_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
@@ -2558,28 +2700,114 @@ mod verify {
2558
2700
} ;
2559
2701
}
2560
2702
2703
+ #[ kani:: proof_for_contract( NonNull :: write_volatile) ]
2704
+ pub fn non_null_check_write_volatile_unit ( ) {
2705
+ // Create a pointer generator for the given type with appropriate byte size
2706
+ let mut generator = kani:: PointerGenerator :: < 1 > :: new ( ) ;
2707
+
2708
+ // Get a raw pointer from the generator
2709
+ let raw_ptr: * mut ( ) = generator. any_in_bounds ( ) . ptr ;
2710
+
2711
+ // Create a non-null pointer from the raw pointer
2712
+ let ptr = NonNull :: new ( raw_ptr) . unwrap ( ) ;
2713
+
2714
+ // Create a non-deterministic value to write
2715
+ let new_value: ( ) = kani:: any ( ) ;
2716
+
2717
+ unsafe {
2718
+ // Perform the volatile write operation
2719
+ ptr. write_volatile ( new_value) ;
2720
+
2721
+ // Read back the value and assert it's correct
2722
+ assert_eq ! ( ptr. as_ptr( ) . read_volatile( ) , new_value) ;
2723
+ }
2724
+ }
2725
+
2726
+ // Generate proof harnesses for multiple types with appropriate byte sizes
2727
+ generate_write_volatile_harness ! ( i8 , non_null_check_write_volatile_i8) ;
2728
+ generate_write_volatile_harness ! ( i16 , non_null_check_write_volatile_i16) ;
2729
+ generate_write_volatile_harness ! ( i32 , non_null_check_write_volatile_i32) ;
2730
+ generate_write_volatile_harness ! ( i64 , non_null_check_write_volatile_i64) ;
2731
+ generate_write_volatile_harness ! ( i128 , non_null_check_write_volatile_i128) ;
2732
+ generate_write_volatile_harness ! ( isize , non_null_check_write_volatile_isize) ;
2733
+ generate_write_volatile_harness ! ( u8 , non_null_check_write_volatile_u8) ;
2734
+ generate_write_volatile_harness ! ( u16 , non_null_check_write_volatile_u16) ;
2735
+ generate_write_volatile_harness ! ( u32 , non_null_check_write_volatile_u32) ;
2736
+ generate_write_volatile_harness ! ( u64 , non_null_check_write_volatile_u64) ;
2737
+ generate_write_volatile_harness ! ( u128 , non_null_check_write_volatile_u128) ;
2738
+ generate_write_volatile_harness ! ( usize , non_null_check_write_volatile_usize) ;
2739
+
2740
+ macro_rules! generate_write_bytes_harness {
2741
+ ( $type: ty, $harness_name: ident) => {
2742
+ #[ kani:: proof_for_contract( NonNull :: write_bytes) ]
2743
+ pub fn $harness_name( ) {
2744
+ // Create a pointer generator for the given type with appropriate byte size
2745
+ const ARR_SIZE : usize = mem:: size_of:: <$type>( ) * 10 ;
2746
+ let mut generator = kani:: PointerGenerator :: <ARR_SIZE >:: new( ) ;
2747
+
2748
+ // Get a raw pointer from the generator
2749
+ let raw_ptr: * mut $type = generator. any_in_bounds( ) . ptr;
2750
+
2751
+ // Create a non-null pointer from the raw pointer
2752
+ let ptr = NonNull :: new( raw_ptr) . unwrap( ) ;
2753
+
2754
+ // Create a non-deterministic value to write
2755
+ let val: u8 = kani:: any( ) ;
2756
+
2757
+ // Create a non-deterministic count
2758
+ let count: usize = kani:: any( ) ;
2759
+
2760
+ unsafe {
2761
+ // Perform the volatile write operation
2762
+ ptr. write_bytes( val, count) ;
2763
+
2764
+ // Create a non-deterministic count
2765
+ let i: usize = kani:: any_where( |& x| x < count * mem:: size_of:: <$type>( ) ) ;
2766
+ let ptr_byte = ptr. as_ptr( ) as * const u8 ;
2767
+
2768
+ // Read back the value and assert it's correct
2769
+ assert_eq!( * ptr_byte. add( i) , val) ;
2770
+ }
2771
+ }
2772
+ } ;
2773
+ }
2774
+
2775
+ #[ kani:: proof_for_contract( NonNull :: write_bytes) ]
2776
+ pub fn non_null_check_write_bytes_unit ( ) {
2777
+ // Create a pointer generator for the given type with appropriate byte size
2778
+ let mut generator = kani:: PointerGenerator :: < 1 > :: new ( ) ;
2779
+
2780
+ // Get a raw pointer from the generator
2781
+ let raw_ptr: * mut ( ) = generator. any_in_bounds ( ) . ptr ;
2782
+
2783
+ // Create a non-null pointer from the raw pointer
2784
+ let ptr = NonNull :: new ( raw_ptr) . unwrap ( ) ;
2785
+
2786
+ // Create a non-deterministic value to write
2787
+ let val: u8 = kani:: any ( ) ;
2788
+
2789
+ // Create a non-deterministic count
2790
+ let count: usize = kani:: any ( ) ;
2791
+
2792
+ unsafe {
2793
+ // Perform the volatile write operation
2794
+ ptr. write_bytes ( val, count) ;
2795
+ }
2796
+ }
2797
+
2561
2798
// Generate proof harnesses for multiple types with appropriate byte sizes
2562
- generate_write_volatile_harness ! ( i8 , 1 , non_null_check_write_volatile_i8) ;
2563
- generate_write_volatile_harness ! ( i16 , 2 , non_null_check_write_volatile_i16) ;
2564
- generate_write_volatile_harness ! ( i32 , 4 , non_null_check_write_volatile_i32) ;
2565
- generate_write_volatile_harness ! ( i64 , 8 , non_null_check_write_volatile_i64) ;
2566
- generate_write_volatile_harness ! ( i128 , 16 , non_null_check_write_volatile_i128) ;
2567
- generate_write_volatile_harness ! (
2568
- isize ,
2569
- { core:: mem:: size_of:: <isize >( ) } ,
2570
- non_null_check_write_volatile_isize
2571
- ) ;
2572
- generate_write_volatile_harness ! ( u8 , 1 , non_null_check_write_volatile_u8) ;
2573
- generate_write_volatile_harness ! ( u16 , 2 , non_null_check_write_volatile_u16) ;
2574
- generate_write_volatile_harness ! ( u32 , 4 , non_null_check_write_volatile_u32) ;
2575
- generate_write_volatile_harness ! ( u64 , 8 , non_null_check_write_volatile_u64) ;
2576
- generate_write_volatile_harness ! ( u128 , 16 , non_null_check_write_volatile_u128) ;
2577
- generate_write_volatile_harness ! (
2578
- usize ,
2579
- { core:: mem:: size_of:: <usize >( ) } ,
2580
- non_null_check_write_volatile_usize
2581
- ) ;
2582
- generate_write_volatile_harness ! ( ( ) , 1 , non_null_check_write_volatile_unit) ;
2799
+ generate_write_bytes_harness ! ( i8 , non_null_check_write_bytes_i8) ;
2800
+ generate_write_bytes_harness ! ( i16 , non_null_check_write_bytes_i16) ;
2801
+ generate_write_bytes_harness ! ( i32 , non_null_check_write_bytes_i32) ;
2802
+ generate_write_bytes_harness ! ( i64 , non_null_check_write_bytes_i64) ;
2803
+ generate_write_bytes_harness ! ( i128 , non_null_check_write_bytes_i128) ;
2804
+ generate_write_bytes_harness ! ( isize , non_null_check_write_bytes_isize) ;
2805
+ generate_write_bytes_harness ! ( u8 , non_null_check_write_bytes_u8) ;
2806
+ generate_write_bytes_harness ! ( u16 , non_null_check_write_bytes_u16) ;
2807
+ generate_write_bytes_harness ! ( u32 , non_null_check_write_bytes_u32) ;
2808
+ generate_write_bytes_harness ! ( u64 , non_null_check_write_bytes_u64) ;
2809
+ generate_write_bytes_harness ! ( u128 , non_null_check_write_bytes_u128) ;
2810
+ generate_write_bytes_harness ! ( usize , non_null_check_write_bytes_usize) ;
2583
2811
2584
2812
#[ kani:: proof_for_contract( NonNull :: byte_add) ]
2585
2813
pub fn non_null_byte_add_proof ( ) {
0 commit comments