@@ -7,6 +7,7 @@ use safety::{ensures, requires};
77
88#[ cfg( kani) ]
99use crate :: kani;
10+ use core:: mem;
1011
1112impl < T : ?Sized > * const T {
1213 /// Returns `true` if the pointer is null.
@@ -474,6 +475,20 @@ impl<T: ?Sized> *const T {
474475 #[ stable( feature = "pointer_byte_offsets" , since = "1.75.0" ) ]
475476 #[ rustc_const_stable( feature = "const_pointer_byte_offsets" , since = "1.75.0" ) ]
476477 #[ 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+ ) ]
477492 pub const unsafe fn byte_offset ( self , count : isize ) -> Self {
478493 // SAFETY: the caller must uphold the safety contract for `offset`.
479494 unsafe { self . cast :: < u8 > ( ) . offset ( count) . with_metadata_of ( self ) }
@@ -1012,6 +1027,20 @@ impl<T: ?Sized> *const T {
10121027 #[ stable( feature = "pointer_byte_offsets" , since = "1.75.0" ) ]
10131028 #[ rustc_const_stable( feature = "const_pointer_byte_offsets" , since = "1.75.0" ) ]
10141029 #[ 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+ ) ]
10151044 pub const unsafe fn byte_add ( self , count : usize ) -> Self {
10161045 // SAFETY: the caller must uphold the safety contract for `add`.
10171046 unsafe { self . cast :: < u8 > ( ) . add ( count) . with_metadata_of ( self ) }
@@ -1142,6 +1171,20 @@ impl<T: ?Sized> *const T {
11421171 #[ stable( feature = "pointer_byte_offsets" , since = "1.75.0" ) ]
11431172 #[ rustc_const_stable( feature = "const_pointer_byte_offsets" , since = "1.75.0" ) ]
11441173 #[ 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+ ) ]
11451188 pub const unsafe fn byte_sub ( self , count : usize ) -> Self {
11461189 // SAFETY: the caller must uphold the safety contract for `sub`.
11471190 unsafe { self . cast :: < u8 > ( ) . sub ( count) . with_metadata_of ( self ) }
@@ -2068,7 +2111,9 @@ mod verify {
20682111 check_const_offset_slice_tuple_4
20692112 ) ;
20702113
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.
20722117 const ARRAY_LEN : usize = 40 ;
20732118
20742119 macro_rules! generate_offset_from_harness {
@@ -2206,4 +2251,261 @@ mod verify {
22062251 check_const_offset_from_tuple_4,
22072252 check_const_offset_from_tuple_4_arr
22082253 ) ;
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+ ) ;
22092511}
0 commit comments