Skip to content

Commit 9041ec1

Browse files
authored
Prove correctness of layout len utilities with kani (#402)
Proves that `round_down_to_next_multiple_of_alignment` and `padding_needed_for` are equivalent to model implementations.
1 parent c9968e4 commit 9041ec1

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

src/third_party/rust/layout.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use core::num::NonZeroUsize;
1414
/// # Panics
1515
///
1616
/// May panic if `align` is not a power of two.
17+
//
18+
// TODO(#419): Replace `len` with a witness type for region size.
1719
#[inline(always)]
1820
pub(crate) const fn _padding_needed_for(len: usize, align: NonZeroUsize) -> usize {
1921
// Rounded up value is:

src/util.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,53 @@ mod tests {
149149
}
150150
}
151151
}
152+
153+
#[cfg(kani)]
154+
mod proofs {
155+
use super::*;
156+
157+
#[kani::proof]
158+
fn prove_round_down_to_next_multiple_of_alignment() {
159+
fn model_impl(n: usize, align: NonZeroUsize) -> usize {
160+
assert!(align.get().is_power_of_two());
161+
let mul = n / align.get();
162+
mul * align.get()
163+
}
164+
165+
let align: NonZeroUsize = kani::any();
166+
kani::assume(align.get().is_power_of_two());
167+
let n: usize = kani::any();
168+
169+
let expected = model_impl(n, align);
170+
let actual = _round_down_to_next_multiple_of_alignment(n, align);
171+
assert_eq!(expected, actual, "round_down_to_next_multiple_of_alignment({n}, {align})");
172+
}
173+
174+
// Restricted to nightly since we use the unstable `usize::next_multiple_of`
175+
// in our model implementation.
176+
#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
177+
#[kani::proof]
178+
fn prove_padding_needed_for() {
179+
fn model_impl(len: usize, align: NonZeroUsize) -> usize {
180+
let padded = len.next_multiple_of(align.get());
181+
let padding = padded - len;
182+
padding
183+
}
184+
185+
let align: NonZeroUsize = kani::any();
186+
kani::assume(align.get().is_power_of_two());
187+
let len: usize = kani::any();
188+
// Constrain `len` to valid Rust lengths, since our model implementation
189+
// isn't robust to overflow.
190+
kani::assume(len <= isize::MAX as usize);
191+
kani::assume(align.get() < 1 << 29);
192+
193+
let expected = model_impl(len, align);
194+
let actual = core_layout::_padding_needed_for(len, align);
195+
assert_eq!(expected, actual, "padding_needed_for({len}, {align})");
196+
197+
let padded_len = actual + len;
198+
assert_eq!(padded_len % align, 0);
199+
assert!(padded_len / align >= len / align);
200+
}
201+
}

0 commit comments

Comments
 (0)