@@ -211,6 +211,18 @@ use core::ub_checks;
211211
212212use safety:: { ensures, requires} ;
213213
214+ /// Kani-only: documented Box raw-pointer layout besides “valid `T`”.
215+ /// `can_dereference` covers aligned/initialized; Box also forbids size > `isize::MAX`.
216+ /// Allocator provenance is a caller obligation we cannot express.
217+ #[ cfg( kani) ]
218+ fn box_ptr_fits_box_layout < T : ?Sized > ( ptr : * const T ) -> bool {
219+ ub_checks:: can_dereference ( ptr) && {
220+ // SAFETY: `can_dereference` means `ptr` is a valid `T`, so size/align exist.
221+ let layout = unsafe { Layout :: for_value_raw ( ptr) } ;
222+ layout. size ( ) <= isize:: MAX as usize
223+ }
224+ }
225+
214226#[ cfg( not( no_global_oom_handling) ) ]
215227use crate :: alloc:: handle_alloc_error;
216228use crate :: alloc:: { AllocError , Allocator , Global , Layout } ;
@@ -1157,10 +1169,10 @@ impl<T: ?Sized> Box<T> {
11571169 #[ stable( feature = "box_raw" , since = "1.4.0" ) ]
11581170 #[ inline]
11591171 #[ must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`" ]
1160- // Memory-layout contract: non-null, aligned, in-bounds, and a valid `T`
1161- // (including ZST dangling pointers). Provenance/allocator identity is a
1162- // caller obligation Kani cannot fully express.
1163- #[ requires( !raw. is_null( ) && ub_checks :: can_dereference ( raw) ) ]
1172+ // Memory-layout contract: non-null, aligned, in-bounds, valid `T`,
1173+ // size ≤ isize::MAX (including ZST dangling pointers).
1174+ // Provenance/allocator identity is a caller obligation Kani cannot fully express.
1175+ #[ requires( !raw. is_null( ) && box_ptr_fits_box_layout ( raw) ) ]
11641176 #[ ensures( |result| ( & * * result) as * const T == raw as * const T ) ]
11651177 pub unsafe fn from_raw ( raw : * mut T ) -> Self {
11661178 unsafe { Self :: from_raw_in ( raw, Global ) }
@@ -1216,7 +1228,7 @@ impl<T: ?Sized> Box<T> {
12161228 #[ unstable( feature = "box_vec_non_null" , reason = "new API" , issue = "130364" ) ]
12171229 #[ inline]
12181230 #[ must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`" ]
1219- #[ requires( ub_checks :: can_dereference ( ptr. as_ptr( ) ) ) ]
1231+ #[ requires( box_ptr_fits_box_layout ( ptr. as_ptr( ) ) ) ]
12201232 #[ ensures( |result| ( & * * result) as * const T == ptr. as_ptr( ) as * const T ) ]
12211233 pub unsafe fn from_non_null ( ptr : NonNull < T > ) -> Self {
12221234 unsafe { Self :: from_raw ( ptr. as_ptr ( ) ) }
@@ -1391,7 +1403,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
13911403 /// [memory layout]: self#memory-layout
13921404 #[ unstable( feature = "allocator_api" , issue = "32838" ) ]
13931405 #[ inline]
1394- #[ requires( !raw. is_null( ) && ub_checks :: can_dereference ( raw) ) ]
1406+ #[ requires( !raw. is_null( ) && box_ptr_fits_box_layout ( raw) ) ]
13951407 #[ ensures( |result| ( & * * result) as * const T == raw as * const T ) ]
13961408 pub unsafe fn from_raw_in ( raw : * mut T , alloc : A ) -> Self {
13971409 Box ( unsafe { Unique :: new_unchecked ( raw) } , alloc)
@@ -1446,7 +1458,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
14461458 #[ unstable( feature = "allocator_api" , issue = "32838" ) ]
14471459 // #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
14481460 #[ inline]
1449- #[ requires( ub_checks :: can_dereference ( raw. as_ptr( ) ) ) ]
1461+ #[ requires( box_ptr_fits_box_layout ( raw. as_ptr( ) ) ) ]
14501462 #[ ensures( |result| ( & * * result) as * const T == raw. as_ptr( ) as * const T ) ]
14511463 pub unsafe fn from_non_null_in ( raw : NonNull < T > , alloc : A ) -> Self {
14521464 // SAFETY: guaranteed by the caller.
@@ -2422,10 +2434,12 @@ mod verify {
24222434 #[ kani:: proof_for_contract( Box :: <[ u8 ] >:: from_raw) ]
24232435 pub fn check_from_raw_slice ( ) {
24242436 let data: [ u8 ; SLICE_CAP ] = kani:: any ( ) ;
2425- let boxed: Box < [ u8 ] > = Box :: from ( data) ;
2437+ let slice = kani:: slice:: any_slice_of_array ( & data) ;
2438+ let boxed: Box < [ u8 ] > = Box :: from ( slice) ;
2439+ let len = boxed. len ( ) ;
24262440 let ptr = Box :: into_raw ( boxed) ;
24272441 let boxed = unsafe { Box :: < [ u8 ] > :: from_raw ( ptr) } ;
2428- assert ! ( boxed. len( ) == SLICE_CAP ) ;
2442+ assert ! ( boxed. len( ) == len ) ;
24292443 }
24302444
24312445 // ---- required unsafe: from_non_null ----
@@ -2447,10 +2461,12 @@ mod verify {
24472461 #[ kani:: proof_for_contract( Box :: <[ u8 ] >:: from_non_null) ]
24482462 pub fn check_from_non_null_slice ( ) {
24492463 let data: [ u8 ; SLICE_CAP ] = kani:: any ( ) ;
2450- let boxed: Box < [ u8 ] > = Box :: from ( data) ;
2464+ let slice = kani:: slice:: any_slice_of_array ( & data) ;
2465+ let boxed: Box < [ u8 ] > = Box :: from ( slice) ;
2466+ let len = boxed. len ( ) ;
24512467 let ptr = Box :: into_non_null ( boxed) ;
24522468 let boxed = unsafe { Box :: < [ u8 ] > :: from_non_null ( ptr) } ;
2453- assert ! ( boxed. len( ) == SLICE_CAP ) ;
2469+ assert ! ( boxed. len( ) == len ) ;
24542470 }
24552471
24562472 // ---- required unsafe: from_raw_in ----
@@ -2470,6 +2486,17 @@ mod verify {
24702486 let _boxed = unsafe { Box :: from_raw_in ( ptr, Global ) } ;
24712487 }
24722488
2489+ #[ kani:: proof_for_contract( Box :: <[ u8 ] , Global >:: from_raw_in) ]
2490+ pub fn check_from_raw_in_slice ( ) {
2491+ let data: [ u8 ; SLICE_CAP ] = kani:: any ( ) ;
2492+ let slice = kani:: slice:: any_slice_of_array ( & data) ;
2493+ let boxed: Box < [ u8 ] > = Box :: from ( slice) ;
2494+ let len = boxed. len ( ) ;
2495+ let ( ptr, alloc) = Box :: into_raw_with_allocator ( boxed) ;
2496+ let boxed = unsafe { Box :: from_raw_in ( ptr, alloc) } ;
2497+ assert ! ( boxed. len( ) == len) ;
2498+ }
2499+
24732500 // ---- required unsafe: from_non_null_in ----
24742501
24752502 #[ kani:: proof_for_contract( Box :: <i32 , Global >:: from_non_null_in) ]
@@ -2486,6 +2513,17 @@ mod verify {
24862513 let _boxed = unsafe { Box :: from_non_null_in ( ptr, Global ) } ;
24872514 }
24882515
2516+ #[ kani:: proof_for_contract( Box :: <[ u8 ] , Global >:: from_non_null_in) ]
2517+ pub fn check_from_non_null_in_slice ( ) {
2518+ let data: [ u8 ; SLICE_CAP ] = kani:: any ( ) ;
2519+ let slice = kani:: slice:: any_slice_of_array ( & data) ;
2520+ let boxed: Box < [ u8 ] > = Box :: from ( slice) ;
2521+ let len = boxed. len ( ) ;
2522+ let ( ptr, alloc) = Box :: into_non_null_with_allocator ( boxed) ;
2523+ let boxed = unsafe { Box :: from_non_null_in ( ptr, alloc) } ;
2524+ assert ! ( boxed. len( ) == len) ;
2525+ }
2526+
24892527 // ---- safe functions with unsafe bodies ----
24902528
24912529 #[ kani:: proof]
@@ -2546,17 +2584,24 @@ mod verify {
25462584 }
25472585
25482586 #[ kani:: proof]
2587+ #[ kani:: unwind( 4 ) ]
25492588 pub fn check_try_new_uninit_slice ( ) {
2550- let slot = Box :: < [ i32 ] > :: try_new_uninit_slice ( 1 ) . expect ( "alloc" ) ;
2551- assert ! ( slot. len( ) == 1 ) ;
2589+ let len = kani:: any_where ( |n : & usize | * n <= SLICE_CAP ) ;
2590+ let slot = Box :: < [ i32 ] > :: try_new_uninit_slice ( len) . expect ( "alloc" ) ;
2591+ assert ! ( slot. len( ) == len) ;
25522592 assert ! ( Box :: <[ u64 ] >:: try_new_uninit_slice( usize :: MAX ) . is_err( ) ) ;
25532593 }
25542594
25552595 #[ kani:: proof]
2596+ #[ kani:: unwind( 4 ) ]
25562597 pub fn check_try_new_zeroed_slice ( ) {
2557- let slot = Box :: < [ u8 ] > :: try_new_zeroed_slice ( 1 ) . expect ( "alloc" ) ;
2598+ let len = kani:: any_where ( |n : & usize | * n <= SLICE_CAP ) ;
2599+ let slot = Box :: < [ u8 ] > :: try_new_zeroed_slice ( len) . expect ( "alloc" ) ;
25582600 let boxed = unsafe { slot. assume_init ( ) } ;
2559- assert ! ( boxed[ 0 ] == 0 ) ;
2601+ assert ! ( boxed. len( ) == len) ;
2602+ for i in 0 ..len {
2603+ assert ! ( boxed[ i] == 0 ) ;
2604+ }
25602605 assert ! ( Box :: <[ u64 ] >:: try_new_zeroed_slice( usize :: MAX ) . is_err( ) ) ;
25612606 }
25622607
@@ -2573,28 +2618,39 @@ mod verify {
25732618 }
25742619
25752620 #[ kani:: proof]
2621+ #[ kani:: unwind( 4 ) ]
25762622 pub fn check_new_uninit_slice_in ( ) {
2577- let slot: Box < [ MaybeUninit < i32 > ] , _ > = Box :: new_uninit_slice_in ( 1 , Global ) ;
2578- assert ! ( slot. len( ) == 1 ) ;
2623+ let len = kani:: any_where ( |n : & usize | * n <= SLICE_CAP ) ;
2624+ let slot: Box < [ MaybeUninit < i32 > ] , _ > = Box :: new_uninit_slice_in ( len, Global ) ;
2625+ assert ! ( slot. len( ) == len) ;
25792626 }
25802627
25812628 #[ kani:: proof]
2629+ #[ kani:: unwind( 4 ) ]
25822630 pub fn check_new_zeroed_slice_in ( ) {
2583- let slot: Box < [ MaybeUninit < u8 > ] , _ > = Box :: new_zeroed_slice_in ( 1 , Global ) ;
2631+ let len = kani:: any_where ( |n : & usize | * n <= SLICE_CAP ) ;
2632+ let slot: Box < [ MaybeUninit < u8 > ] , _ > = Box :: new_zeroed_slice_in ( len, Global ) ;
25842633 let boxed = unsafe { slot. assume_init ( ) } ;
2585- assert ! ( boxed[ 0 ] == 0 ) ;
2634+ assert ! ( boxed. len( ) == len) ;
2635+ for i in 0 ..len {
2636+ assert ! ( boxed[ i] == 0 ) ;
2637+ }
25862638 }
25872639
25882640 #[ kani:: proof]
2641+ #[ kani:: unwind( 4 ) ]
25892642 pub fn check_try_new_uninit_slice_in ( ) {
2590- let slot = Box :: < [ i32 ] > :: try_new_uninit_slice_in ( 0 , Global ) . expect ( "zst/empty" ) ;
2591- assert ! ( slot. is_empty( ) ) ;
2643+ let len = kani:: any_where ( |n : & usize | * n <= SLICE_CAP ) ;
2644+ let slot = Box :: < [ i32 ] > :: try_new_uninit_slice_in ( len, Global ) . expect ( "alloc" ) ;
2645+ assert ! ( slot. len( ) == len) ;
25922646 }
25932647
25942648 #[ kani:: proof]
2649+ #[ kani:: unwind( 4 ) ]
25952650 pub fn check_try_new_zeroed_slice_in ( ) {
2596- let slot = Box :: < [ u8 ] > :: try_new_zeroed_slice_in ( 1 , Global ) . expect ( "alloc" ) ;
2597- assert ! ( slot. len( ) == 1 ) ;
2651+ let len = kani:: any_where ( |n : & usize | * n <= SLICE_CAP ) ;
2652+ let slot = Box :: < [ u8 ] > :: try_new_zeroed_slice_in ( len, Global ) . expect ( "alloc" ) ;
2653+ assert ! ( slot. len( ) == len) ;
25982654 }
25992655
26002656 #[ kani:: proof]
0 commit comments