@@ -7,6 +7,7 @@ use safety::{ensures, requires};
7
7
8
8
#[ cfg( kani) ]
9
9
use crate :: kani;
10
+ use core:: mem;
10
11
11
12
impl < T : ?Sized > * const T {
12
13
/// Returns `true` if the pointer is null.
@@ -474,6 +475,20 @@ impl<T: ?Sized> *const T {
474
475
#[ stable( feature = "pointer_byte_offsets" , since = "1.75.0" ) ]
475
476
#[ rustc_const_stable( feature = "const_pointer_byte_offsets" , since = "1.75.0" ) ]
476
477
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
478
+ #[ requires(
479
+ // If count is zero, any pointer is valid including null pointer.
480
+ ( count == 0 ) ||
481
+ // Else if count is not zero, then ensure that adding `count` doesn't cause
482
+ // overflow and that both pointers `self` and the result are in the same
483
+ // allocation
484
+ ( ( self . addr( ) as isize ) . checked_add( count) . is_some( ) &&
485
+ core:: ub_checks:: same_allocation( self , self . wrapping_byte_offset( count) ) )
486
+ ) ]
487
+ #[ ensures( |& result|
488
+ // The resulting pointer should either be unchanged or still point to the same allocation
489
+ ( self . addr( ) == result. addr( ) ) ||
490
+ ( core:: ub_checks:: same_allocation( self , result) )
491
+ ) ]
477
492
pub const unsafe fn byte_offset ( self , count : isize ) -> Self {
478
493
// SAFETY: the caller must uphold the safety contract for `offset`.
479
494
unsafe { self . cast :: < u8 > ( ) . offset ( count) . with_metadata_of ( self ) }
@@ -1012,6 +1027,20 @@ impl<T: ?Sized> *const T {
1012
1027
#[ stable( feature = "pointer_byte_offsets" , since = "1.75.0" ) ]
1013
1028
#[ rustc_const_stable( feature = "const_pointer_byte_offsets" , since = "1.75.0" ) ]
1014
1029
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
1030
+ #[ requires(
1031
+ // If count is zero, any pointer is valid including null pointer.
1032
+ ( count == 0 ) ||
1033
+ // Else if count is not zero, then ensure that adding `count` doesn't cause
1034
+ // overflow and that both pointers `self` and the result are in the same
1035
+ // allocation
1036
+ ( ( self . addr( ) as isize ) . checked_add( count as isize ) . is_some( ) &&
1037
+ core:: ub_checks:: same_allocation( self , self . wrapping_byte_add( count) ) )
1038
+ ) ]
1039
+ #[ ensures( |& result|
1040
+ // The resulting pointer should either be unchanged or still point to the same allocation
1041
+ ( self . addr( ) == result. addr( ) ) ||
1042
+ ( core:: ub_checks:: same_allocation( self , result) )
1043
+ ) ]
1015
1044
pub const unsafe fn byte_add ( self , count : usize ) -> Self {
1016
1045
// SAFETY: the caller must uphold the safety contract for `add`.
1017
1046
unsafe { self . cast :: < u8 > ( ) . add ( count) . with_metadata_of ( self ) }
@@ -1142,6 +1171,20 @@ impl<T: ?Sized> *const T {
1142
1171
#[ stable( feature = "pointer_byte_offsets" , since = "1.75.0" ) ]
1143
1172
#[ rustc_const_stable( feature = "const_pointer_byte_offsets" , since = "1.75.0" ) ]
1144
1173
#[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
1174
+ #[ requires(
1175
+ // If count is zero, any pointer is valid including null pointer.
1176
+ ( count == 0 ) ||
1177
+ // Else if count is not zero, then ensure that subtracting `count` doesn't
1178
+ // cause overflow and that both pointers `self` and the result are in the
1179
+ // same allocation
1180
+ ( ( self . addr( ) as isize ) . checked_sub( count as isize ) . is_some( ) &&
1181
+ core:: ub_checks:: same_allocation( self , self . wrapping_byte_sub( count) ) )
1182
+ ) ]
1183
+ #[ ensures( |& result|
1184
+ // The resulting pointer should either be unchanged or still point to the same allocation
1185
+ ( self . addr( ) == result. addr( ) ) ||
1186
+ ( core:: ub_checks:: same_allocation( self , result) )
1187
+ ) ]
1145
1188
pub const unsafe fn byte_sub ( self , count : usize ) -> Self {
1146
1189
// SAFETY: the caller must uphold the safety contract for `sub`.
1147
1190
unsafe { self . cast :: < u8 > ( ) . sub ( count) . with_metadata_of ( self ) }
@@ -2068,7 +2111,9 @@ mod verify {
2068
2111
check_const_offset_slice_tuple_4
2069
2112
) ;
2070
2113
2071
- // Array size bound for kani::any_array for `offset_from` verification
2114
+ // The array's length is set to an arbitrary value, which defines its size.
2115
+ // In this case, implementing a dynamic array is not possible, because
2116
+ // PointerGenerator does not support dynamic sized arrays.
2072
2117
const ARRAY_LEN : usize = 40 ;
2073
2118
2074
2119
macro_rules! generate_offset_from_harness {
@@ -2206,4 +2251,261 @@ mod verify {
2206
2251
check_const_offset_from_tuple_4,
2207
2252
check_const_offset_from_tuple_4_arr
2208
2253
) ;
2254
+
2255
+ #[ kani:: proof_for_contract( <* const ( ) >:: byte_offset) ]
2256
+ #[ kani:: should_panic]
2257
+ pub fn check_const_byte_offset_unit_invalid_count ( ) {
2258
+ let val = ( ) ;
2259
+ let ptr: * const ( ) = & val;
2260
+ let count: isize = kani:: any_where ( |& x| x != ( mem:: size_of :: < ( ) > ( ) as isize ) ) ;
2261
+ unsafe {
2262
+ ptr. byte_offset ( count) ;
2263
+ }
2264
+ }
2265
+
2266
+ #[ kani:: proof_for_contract( <* const ( ) >:: byte_offset) ]
2267
+ pub fn check_const_byte_offset_cast_unit ( ) {
2268
+ let mut generator = PointerGenerator :: < ARRAY_LEN > :: new ( ) ;
2269
+ let ptr: * const u8 = generator. any_in_bounds ( ) . ptr ;
2270
+ let ptr1: * const ( ) = ptr as * const ( ) ;
2271
+ let count: isize = kani:: any ( ) ;
2272
+ unsafe {
2273
+ ptr1. byte_offset ( count) ;
2274
+ }
2275
+ }
2276
+
2277
+ // generate proof for contracts of byte_add, byte_sub and byte_offset to verify
2278
+ // unit pointee type
2279
+ // - `$fn_name`: function for which the contract must be verified
2280
+ // - `$proof_name`: name of the harness generated
2281
+ macro_rules! gen_const_byte_arith_harness_for_unit {
2282
+ ( byte_offset, $proof_name: ident) => {
2283
+ #[ kani:: proof_for_contract( <* const ( ) >:: byte_offset) ]
2284
+ pub fn $proof_name( ) {
2285
+ let val = ( ) ;
2286
+ let ptr: * const ( ) = & val;
2287
+ let count: isize = mem:: size_of:: <( ) >( ) as isize ;
2288
+ unsafe {
2289
+ ptr. byte_offset( count) ;
2290
+ }
2291
+ }
2292
+ } ;
2293
+
2294
+ ( $fn_name: ident, $proof_name: ident) => {
2295
+ #[ kani:: proof_for_contract( <* const ( ) >:: $fn_name) ]
2296
+ pub fn $proof_name( ) {
2297
+ let val = ( ) ;
2298
+ let ptr: * const ( ) = & val;
2299
+ //byte_add and byte_sub need count to be usize unlike byte_offset
2300
+ let count: usize = mem:: size_of:: <( ) >( ) ;
2301
+ unsafe {
2302
+ ptr. $fn_name( count) ;
2303
+ }
2304
+ }
2305
+ } ;
2306
+ }
2307
+
2308
+ gen_const_byte_arith_harness_for_unit ! ( byte_add, check_const_byte_add_unit) ;
2309
+ gen_const_byte_arith_harness_for_unit ! ( byte_sub, check_const_byte_sub_unit) ;
2310
+ gen_const_byte_arith_harness_for_unit ! ( byte_offset, check_const_byte_offset_unit) ;
2311
+
2312
+ // generate proof for contracts for byte_add, byte_sub and byte_offset
2313
+ // - `$type`: pointee type
2314
+ // - `$fn_name`: function for which the contract must be verified
2315
+ // - `$proof_name`: name of the harness generated
2316
+ macro_rules! gen_const_byte_arith_harness {
2317
+ ( $type: ty, byte_offset, $proof_name: ident) => {
2318
+ #[ kani:: proof_for_contract( <* const $type>:: byte_offset) ]
2319
+ pub fn $proof_name( ) {
2320
+ // generator with space for single element
2321
+ let mut generator1 = PointerGenerator :: <{ mem:: size_of:: <$type>( ) } >:: new( ) ;
2322
+ // generator with space for multiple elements
2323
+ let mut generator2 =
2324
+ PointerGenerator :: <{ mem:: size_of:: <$type>( ) * ARRAY_LEN } >:: new( ) ;
2325
+
2326
+ let ptr: * const $type = if kani:: any( ) {
2327
+ generator1. any_in_bounds( ) . ptr
2328
+ } else {
2329
+ generator2. any_in_bounds( ) . ptr
2330
+ } ;
2331
+
2332
+ let count: isize = kani:: any( ) ;
2333
+
2334
+ unsafe {
2335
+ ptr. byte_offset( count) ;
2336
+ }
2337
+ }
2338
+ } ;
2339
+
2340
+ ( $type: ty, $fn_name: ident, $proof_name: ident) => {
2341
+ #[ kani:: proof_for_contract( <* const $type>:: $fn_name) ]
2342
+ pub fn $proof_name( ) {
2343
+ // generator with space for single element
2344
+ let mut generator1 = PointerGenerator :: <{ mem:: size_of:: <$type>( ) } >:: new( ) ;
2345
+ // generator with space for multiple elements
2346
+ let mut generator2 =
2347
+ PointerGenerator :: <{ mem:: size_of:: <$type>( ) * ARRAY_LEN } >:: new( ) ;
2348
+
2349
+ let ptr: * const $type = if kani:: any( ) {
2350
+ generator1. any_in_bounds( ) . ptr
2351
+ } else {
2352
+ generator2. any_in_bounds( ) . ptr
2353
+ } ;
2354
+
2355
+ //byte_add and byte_sub need count to be usize unlike byte_offset
2356
+ let count: usize = kani:: any( ) ;
2357
+
2358
+ unsafe {
2359
+ ptr. $fn_name( count) ;
2360
+ }
2361
+ }
2362
+ } ;
2363
+ }
2364
+
2365
+ gen_const_byte_arith_harness ! ( i8 , byte_add, check_const_byte_add_i8) ;
2366
+ gen_const_byte_arith_harness ! ( i16 , byte_add, check_const_byte_add_i16) ;
2367
+ gen_const_byte_arith_harness ! ( i32 , byte_add, check_const_byte_add_i32) ;
2368
+ gen_const_byte_arith_harness ! ( i64 , byte_add, check_const_byte_add_i64) ;
2369
+ gen_const_byte_arith_harness ! ( i128 , byte_add, check_const_byte_add_i128) ;
2370
+ gen_const_byte_arith_harness ! ( isize , byte_add, check_const_byte_add_isize) ;
2371
+ gen_const_byte_arith_harness ! ( u8 , byte_add, check_const_byte_add_u8) ;
2372
+ gen_const_byte_arith_harness ! ( u16 , byte_add, check_const_byte_add_u16) ;
2373
+ gen_const_byte_arith_harness ! ( u32 , byte_add, check_const_byte_add_u32) ;
2374
+ gen_const_byte_arith_harness ! ( u64 , byte_add, check_const_byte_add_u64) ;
2375
+ gen_const_byte_arith_harness ! ( u128 , byte_add, check_const_byte_add_u128) ;
2376
+ gen_const_byte_arith_harness ! ( usize , byte_add, check_const_byte_add_usize) ;
2377
+ gen_const_byte_arith_harness ! ( ( i8 , i8 ) , byte_add, check_const_byte_add_tuple_1) ;
2378
+ gen_const_byte_arith_harness ! ( ( f64 , bool ) , byte_add, check_const_byte_add_tuple_2) ;
2379
+ gen_const_byte_arith_harness ! ( ( i32 , f64 , bool ) , byte_add, check_const_byte_add_tuple_3) ;
2380
+ gen_const_byte_arith_harness ! (
2381
+ ( i8 , u16 , i32 , u64 , isize ) ,
2382
+ byte_add,
2383
+ check_const_byte_add_tuple_4
2384
+ ) ;
2385
+
2386
+ gen_const_byte_arith_harness ! ( i8 , byte_sub, check_const_byte_sub_i8) ;
2387
+ gen_const_byte_arith_harness ! ( i16 , byte_sub, check_const_byte_sub_i16) ;
2388
+ gen_const_byte_arith_harness ! ( i32 , byte_sub, check_const_byte_sub_i32) ;
2389
+ gen_const_byte_arith_harness ! ( i64 , byte_sub, check_const_byte_sub_i64) ;
2390
+ gen_const_byte_arith_harness ! ( i128 , byte_sub, check_const_byte_sub_i128) ;
2391
+ gen_const_byte_arith_harness ! ( isize , byte_sub, check_const_byte_sub_isize) ;
2392
+ gen_const_byte_arith_harness ! ( u8 , byte_sub, check_const_byte_sub_u8) ;
2393
+ gen_const_byte_arith_harness ! ( u16 , byte_sub, check_const_byte_sub_u16) ;
2394
+ gen_const_byte_arith_harness ! ( u32 , byte_sub, check_const_byte_sub_u32) ;
2395
+ gen_const_byte_arith_harness ! ( u64 , byte_sub, check_const_byte_sub_u64) ;
2396
+ gen_const_byte_arith_harness ! ( u128 , byte_sub, check_const_byte_sub_u128) ;
2397
+ gen_const_byte_arith_harness ! ( usize , byte_sub, check_const_byte_sub_usize) ;
2398
+ gen_const_byte_arith_harness ! ( ( i8 , i8 ) , byte_sub, check_const_byte_sub_tuple_1) ;
2399
+ gen_const_byte_arith_harness ! ( ( f64 , bool ) , byte_sub, check_const_byte_sub_tuple_2) ;
2400
+ gen_const_byte_arith_harness ! ( ( i32 , f64 , bool ) , byte_sub, check_const_byte_sub_tuple_3) ;
2401
+ gen_const_byte_arith_harness ! (
2402
+ ( i8 , u16 , i32 , u64 , isize ) ,
2403
+ byte_sub,
2404
+ check_const_byte_sub_tuple_4
2405
+ ) ;
2406
+
2407
+ gen_const_byte_arith_harness ! ( i8 , byte_offset, check_const_byte_offset_i8) ;
2408
+ gen_const_byte_arith_harness ! ( i16 , byte_offset, check_const_byte_offset_i16) ;
2409
+ gen_const_byte_arith_harness ! ( i32 , byte_offset, check_const_byte_offset_i32) ;
2410
+ gen_const_byte_arith_harness ! ( i64 , byte_offset, check_const_byte_offset_i64) ;
2411
+ gen_const_byte_arith_harness ! ( i128 , byte_offset, check_const_byte_offset_i128) ;
2412
+ gen_const_byte_arith_harness ! ( isize , byte_offset, check_const_byte_offset_isize) ;
2413
+ gen_const_byte_arith_harness ! ( u8 , byte_offset, check_const_byte_offset_u8) ;
2414
+ gen_const_byte_arith_harness ! ( u16 , byte_offset, check_const_byte_offset_u16) ;
2415
+ gen_const_byte_arith_harness ! ( u32 , byte_offset, check_const_byte_offset_u32) ;
2416
+ gen_const_byte_arith_harness ! ( u64 , byte_offset, check_const_byte_offset_u64) ;
2417
+ gen_const_byte_arith_harness ! ( u128 , byte_offset, check_const_byte_offset_u128) ;
2418
+ gen_const_byte_arith_harness ! ( usize , byte_offset, check_const_byte_offset_usize) ;
2419
+ gen_const_byte_arith_harness ! ( ( i8 , i8 ) , byte_offset, check_const_byte_offset_tuple_1) ;
2420
+ gen_const_byte_arith_harness ! ( ( f64 , bool ) , byte_offset, check_const_byte_offset_tuple_2) ;
2421
+ gen_const_byte_arith_harness ! (
2422
+ ( i32 , f64 , bool ) ,
2423
+ byte_offset,
2424
+ check_const_byte_offset_tuple_3
2425
+ ) ;
2426
+ gen_const_byte_arith_harness ! (
2427
+ ( i8 , u16 , i32 , u64 , isize ) ,
2428
+ byte_offset,
2429
+ check_const_byte_offset_tuple_4
2430
+ ) ;
2431
+
2432
+ macro_rules! gen_const_byte_arith_harness_for_slice {
2433
+ ( $type: ty, byte_offset, $proof_name: ident) => {
2434
+ #[ kani:: proof_for_contract( <* const [ $type] >:: byte_offset) ]
2435
+ pub fn $proof_name( ) {
2436
+ let arr: [ $type; ARRAY_LEN ] = kani:: Arbitrary :: any_array( ) ;
2437
+ let slice: & [ $type] = kani:: slice:: any_slice_of_array( & arr) ;
2438
+ let ptr: * const [ $type] = slice;
2439
+
2440
+ let count: isize = kani:: any( ) ;
2441
+
2442
+ unsafe {
2443
+ ptr. byte_offset( count) ;
2444
+ }
2445
+ }
2446
+ } ;
2447
+
2448
+ ( $type: ty, $fn_name: ident, $proof_name: ident) => {
2449
+ #[ kani:: proof_for_contract( <* const [ $type] >:: $fn_name) ]
2450
+ pub fn $proof_name( ) {
2451
+ let arr: [ $type; ARRAY_LEN ] = kani:: Arbitrary :: any_array( ) ;
2452
+ let slice: & [ $type] = kani:: slice:: any_slice_of_array( & arr) ;
2453
+ let ptr: * const [ $type] = slice;
2454
+
2455
+ //byte_add and byte_sub need count to be usize unlike byte_offset
2456
+ let count: usize = kani:: any( ) ;
2457
+
2458
+ unsafe {
2459
+ ptr. $fn_name( count) ;
2460
+ }
2461
+ }
2462
+ } ;
2463
+ }
2464
+
2465
+ gen_const_byte_arith_harness_for_slice ! ( i8 , byte_add, check_const_byte_add_i8_slice) ;
2466
+ gen_const_byte_arith_harness_for_slice ! ( i16 , byte_add, check_const_byte_add_i16_slice) ;
2467
+ gen_const_byte_arith_harness_for_slice ! ( i32 , byte_add, check_const_byte_add_i32_slice) ;
2468
+ gen_const_byte_arith_harness_for_slice ! ( i64 , byte_add, check_const_byte_add_i64_slice) ;
2469
+ gen_const_byte_arith_harness_for_slice ! ( i128 , byte_add, check_const_byte_add_i128_slice) ;
2470
+ gen_const_byte_arith_harness_for_slice ! ( isize , byte_add, check_const_byte_add_isize_slice) ;
2471
+ gen_const_byte_arith_harness_for_slice ! ( u8 , byte_add, check_const_byte_add_u8_slice) ;
2472
+ gen_const_byte_arith_harness_for_slice ! ( u16 , byte_add, check_const_byte_add_u16_slice) ;
2473
+ gen_const_byte_arith_harness_for_slice ! ( u32 , byte_add, check_const_byte_add_u32_slice) ;
2474
+ gen_const_byte_arith_harness_for_slice ! ( u64 , byte_add, check_const_byte_add_u64_slice) ;
2475
+ gen_const_byte_arith_harness_for_slice ! ( u128 , byte_add, check_const_byte_add_u128_slice) ;
2476
+ gen_const_byte_arith_harness_for_slice ! ( usize , byte_add, check_const_byte_add_usize_slice) ;
2477
+
2478
+ gen_const_byte_arith_harness_for_slice ! ( i8 , byte_sub, check_const_byte_sub_i8_slice) ;
2479
+ gen_const_byte_arith_harness_for_slice ! ( i16 , byte_sub, check_const_byte_sub_i16_slice) ;
2480
+ gen_const_byte_arith_harness_for_slice ! ( i32 , byte_sub, check_const_byte_sub_i32_slice) ;
2481
+ gen_const_byte_arith_harness_for_slice ! ( i64 , byte_sub, check_const_byte_sub_i64_slice) ;
2482
+ gen_const_byte_arith_harness_for_slice ! ( i128 , byte_sub, check_const_byte_sub_i128_slice) ;
2483
+ gen_const_byte_arith_harness_for_slice ! ( isize , byte_sub, check_const_byte_sub_isize_slice) ;
2484
+ gen_const_byte_arith_harness_for_slice ! ( u8 , byte_sub, check_const_byte_sub_u8_slice) ;
2485
+ gen_const_byte_arith_harness_for_slice ! ( u16 , byte_sub, check_const_byte_sub_u16_slice) ;
2486
+ gen_const_byte_arith_harness_for_slice ! ( u32 , byte_sub, check_const_byte_sub_u32_slice) ;
2487
+ gen_const_byte_arith_harness_for_slice ! ( u64 , byte_sub, check_const_byte_sub_u64_slice) ;
2488
+ gen_const_byte_arith_harness_for_slice ! ( u128 , byte_sub, check_const_byte_sub_u128_slice) ;
2489
+ gen_const_byte_arith_harness_for_slice ! ( usize , byte_sub, check_const_byte_sub_usize_slice) ;
2490
+
2491
+ gen_const_byte_arith_harness_for_slice ! ( i8 , byte_offset, check_const_byte_offset_i8_slice) ;
2492
+ gen_const_byte_arith_harness_for_slice ! ( i16 , byte_offset, check_const_byte_offset_i16_slice) ;
2493
+ gen_const_byte_arith_harness_for_slice ! ( i32 , byte_offset, check_const_byte_offset_i32_slice) ;
2494
+ gen_const_byte_arith_harness_for_slice ! ( i64 , byte_offset, check_const_byte_offset_i64_slice) ;
2495
+ gen_const_byte_arith_harness_for_slice ! ( i128 , byte_offset, check_const_byte_offset_i128_slice) ;
2496
+ gen_const_byte_arith_harness_for_slice ! (
2497
+ isize ,
2498
+ byte_offset,
2499
+ check_const_byte_offset_isize_slice
2500
+ ) ;
2501
+ gen_const_byte_arith_harness_for_slice ! ( u8 , byte_offset, check_const_byte_offset_u8_slice) ;
2502
+ gen_const_byte_arith_harness_for_slice ! ( u16 , byte_offset, check_const_byte_offset_u16_slice) ;
2503
+ gen_const_byte_arith_harness_for_slice ! ( u32 , byte_offset, check_const_byte_offset_u32_slice) ;
2504
+ gen_const_byte_arith_harness_for_slice ! ( u64 , byte_offset, check_const_byte_offset_u64_slice) ;
2505
+ gen_const_byte_arith_harness_for_slice ! ( u128 , byte_offset, check_const_byte_offset_u128_slice) ;
2506
+ gen_const_byte_arith_harness_for_slice ! (
2507
+ usize ,
2508
+ byte_offset,
2509
+ check_const_byte_offset_usize_slice
2510
+ ) ;
2209
2511
}
0 commit comments