@@ -116,7 +116,21 @@ pub(crate) fn validate_aligned_to<T: AsAddress, U>(t: T) -> Result<(), Alignment
116
116
///
117
117
/// This function assumes that align is a power of two; there are no guarantees
118
118
/// 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
+ ) ]
119
127
pub ( 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
+
120
134
// Abstractly, we want to compute:
121
135
// align - (len % align).
122
136
// Handling the case where len%align is 0.
@@ -178,10 +192,27 @@ pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize
178
192
/// May panic if `align` is not a power of two. Even if it doesn't panic in this
179
193
/// case, it will produce nonsense results.
180
194
#[ 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
+ ) ]
181
206
pub ( crate ) const fn round_down_to_next_multiple_of_alignment (
182
207
n : usize ,
183
208
align : NonZeroUsize ,
184
209
) -> 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
+
185
216
let align = align. get ( ) ;
186
217
#[ cfg( zerocopy_panic_in_const_and_vec_try_reserve_1_57_0) ]
187
218
debug_assert ! ( align. is_power_of_two( ) ) ;
@@ -568,53 +599,3 @@ mod tests {
568
599
round_down_to_next_multiple_of_alignment ( 0 , NonZeroUsize :: new ( 3 ) . unwrap ( ) ) ;
569
600
}
570
601
}
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