@@ -116,7 +116,21 @@ pub(crate) fn validate_aligned_to<T: AsAddress, U>(t: T) -> Result<(), Alignment
116116///
117117/// This function assumes that align is a power of two; there are no guarantees
118118/// on the answer it gives if this is not the case.
119+ #[ cfg_attr(
120+ kani,
121+ kani:: requires( len <= isize :: MAX as usize ) ,
122+ kani:: requires( align. is_power_of_two( ) ) ,
123+ kani:: ensures( |& p| ( len + p) % align. get( ) == 0 ) ,
124+ // Ensures that we add the minimum required padding.
125+ kani:: ensures( |& p| p < align. get( ) ) ,
126+ ) ]
119127pub ( crate ) const fn padding_needed_for ( len : usize , align : NonZeroUsize ) -> usize {
128+ #[ cfg( kani) ]
129+ #[ kani:: proof_for_contract( padding_needed_for) ]
130+ fn proof ( ) {
131+ padding_needed_for ( kani:: any ( ) , kani:: any ( ) ) ;
132+ }
133+
120134 // Abstractly, we want to compute:
121135 // align - (len % align).
122136 // Handling the case where len%align is 0.
@@ -178,10 +192,27 @@ pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize
178192/// May panic if `align` is not a power of two. Even if it doesn't panic in this
179193/// case, it will produce nonsense results.
180194#[ inline( always) ]
195+ #[ cfg_attr(
196+ kani,
197+ kani:: requires( align. is_power_of_two( ) ) ,
198+ kani:: ensures( |& m| m <= n && m % align. get( ) == 0 ) ,
199+ // Guarantees that `m` is the *largest* value such that `m % align == 0`.
200+ kani:: ensures( |& m| {
201+ // If this `checked_add` fails, then the next multiple would wrap
202+ // around, which trivially satisfies the "largest value" requirement.
203+ m. checked_add( align. get( ) ) . map( |next_mul| next_mul > n) . unwrap_or( true )
204+ } )
205+ ) ]
181206pub ( crate ) const fn round_down_to_next_multiple_of_alignment (
182207 n : usize ,
183208 align : NonZeroUsize ,
184209) -> usize {
210+ #[ cfg( kani) ]
211+ #[ kani:: proof_for_contract( round_down_to_next_multiple_of_alignment) ]
212+ fn proof ( ) {
213+ round_down_to_next_multiple_of_alignment ( kani:: any ( ) , kani:: any ( ) ) ;
214+ }
215+
185216 let align = align. get ( ) ;
186217 #[ cfg( zerocopy_panic_in_const_and_vec_try_reserve_1_57_0) ]
187218 debug_assert ! ( align. is_power_of_two( ) ) ;
@@ -568,53 +599,3 @@ mod tests {
568599 round_down_to_next_multiple_of_alignment ( 0 , NonZeroUsize :: new ( 3 ) . unwrap ( ) ) ;
569600 }
570601}
571-
572- #[ cfg( kani) ]
573- mod proofs {
574- use super :: * ;
575-
576- #[ kani:: proof]
577- fn prove_round_down_to_next_multiple_of_alignment ( ) {
578- fn model_impl ( n : usize , align : NonZeroUsize ) -> usize {
579- assert ! ( align. get( ) . is_power_of_two( ) ) ;
580- let mul = n / align. get ( ) ;
581- mul * align. get ( )
582- }
583-
584- let align: NonZeroUsize = kani:: any ( ) ;
585- kani:: assume ( align. get ( ) . is_power_of_two ( ) ) ;
586- let n: usize = kani:: any ( ) ;
587-
588- let expected = model_impl ( n, align) ;
589- let actual = round_down_to_next_multiple_of_alignment ( n, align) ;
590- assert_eq ! ( expected, actual, "round_down_to_next_multiple_of_alignment({}, {})" , n, align) ;
591- }
592-
593- // Restricted to nightly since we use the unstable `usize::next_multiple_of`
594- // in our model implementation.
595- #[ cfg( __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS) ]
596- #[ kani:: proof]
597- fn prove_padding_needed_for ( ) {
598- fn model_impl ( len : usize , align : NonZeroUsize ) -> usize {
599- let padded = len. next_multiple_of ( align. get ( ) ) ;
600- let padding = padded - len;
601- padding
602- }
603-
604- let align: NonZeroUsize = kani:: any ( ) ;
605- kani:: assume ( align. get ( ) . is_power_of_two ( ) ) ;
606- let len: usize = kani:: any ( ) ;
607- // Constrain `len` to valid Rust lengths, since our model implementation
608- // isn't robust to overflow.
609- kani:: assume ( len <= isize:: MAX as usize ) ;
610- kani:: assume ( align. get ( ) < 1 << 29 ) ;
611-
612- let expected = model_impl ( len, align) ;
613- let actual = padding_needed_for ( len, align) ;
614- assert_eq ! ( expected, actual, "padding_needed_for({}, {})" , len, align) ;
615-
616- let padded_len = actual + len;
617- assert_eq ! ( padded_len % align, 0 ) ;
618- assert ! ( padded_len / align >= len / align) ;
619- }
620- }
0 commit comments