Skip to content

Commit 29bc9d3

Browse files
committed
Add loop contracts and harness for Slice::repeat
1 parent a636c05 commit 29bc9d3

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

library/alloc/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@
192192
#![feature(unboxed_closures)]
193193
#![feature(unsized_fn_params)]
194194
#![feature(with_negative_coherence)]
195+
#![cfg_attr(kani, feature(proc_macro_hygiene))]
196+
#![cfg_attr(kani, feature(kani))]
195197
#![rustc_preserve_ub_checks]
196198
// tidy-alphabetical-end
197199
//

library/alloc/src/slice.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ use crate::vec::Vec;
3333
#[cfg(test)]
3434
mod tests;
3535

36+
use safety::{requires, ensures};
37+
38+
#[cfg(kani)]
39+
use core::kani;
40+
3641
#[unstable(feature = "array_chunks", issue = "74985")]
3742
pub use core::slice::ArrayChunks;
3843
#[unstable(feature = "array_chunks", issue = "74985")]
@@ -538,12 +543,16 @@ impl<T> [T] {
538543
// Using `Vec` to access `set_len()`.
539544
let capacity = self.len().checked_mul(n).expect("capacity overflow");
540545
let mut buf = Vec::with_capacity(capacity);
546+
let old_len = self.len();
541547

542548
// `2^expn` repetition is done by doubling `buf` `expn`-times.
543549
buf.extend(self);
544550
{
545551
let mut m = n >> 1;
546552
// If `m > 0`, there are remaining bits up to the leftmost '1'.
553+
#[cfg_attr(kani, kani::loop_invariant(m <= n >> 1
554+
&& (m == 0 || (old_len * (n/(m << 2)) <= buf.len() && buf.len() <= old_len * ((n/(m << 1)) ))
555+
&& (m != 0 || (old_len * ((n+1)/2) <= buf.len() && buf.len() <= old_len * n)))))]
547556
while m > 0 {
548557
// `buf.extend(buf)`:
549558
unsafe {
@@ -893,3 +902,41 @@ impl<T> sort::stable::BufGuard<T> for Vec<T> {
893902
self.spare_capacity_mut()
894903
}
895904
}
905+
906+
#[cfg(kani)]
907+
#[unstable(feature = "kani", issue = "none")]
908+
mod verify {
909+
use super::*;
910+
911+
pub fn any_slice_of_array<T, const LENGTH: usize>(arr: &[T; LENGTH]) -> &[T] {
912+
let (from, to) = any_range::<LENGTH>();
913+
&arr[from..to]
914+
}
915+
916+
/// A mutable version of the previous function
917+
pub fn any_slice_of_array_mut<T, const LENGTH: usize>(arr: &mut [T; LENGTH]) -> &mut [T] {
918+
let (from, to) = any_range::<LENGTH>();
919+
&mut arr[from..to]
920+
}
921+
922+
fn any_range<const LENGTH: usize>() -> (usize, usize) {
923+
let from: usize = kani::any();
924+
let to: usize = kani::any();
925+
kani::assume(to <= LENGTH);
926+
kani::assume(from <= to);
927+
(from, to)
928+
}
929+
930+
#[kani::proof]
931+
pub fn check_repeat() {
932+
let _ = Box::new(0);
933+
const ARR_SIZE: usize = 1000;
934+
const REPEAT_TIMES: usize = 100;
935+
let n = kani::any_where(|i| *i < REPEAT_TIMES);
936+
let mut x: [u8; ARR_SIZE] = kani::any();
937+
let xs = any_slice_of_array_mut(&mut x);
938+
unsafe {
939+
xs.repeat(n);
940+
}
941+
}
942+
}

scripts/check_kani.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ cargo build-dev --release
4444
echo "Running tests..."
4545
echo
4646
cd "$VERIFY_RUST_STD_DIR"
47-
$KANI_DIR/scripts/kani verify-std -Z unstable-options $VERIFY_RUST_STD_DIR/library --target-dir "$RUNNER_TEMP" -Z function-contracts -Z mem-predicates
47+
$KANI_DIR/scripts/kani verify-std -Z unstable-options $VERIFY_RUST_STD_DIR/library --target-dir "$RUNNER_TEMP" -Z function-contracts -Z mem-predicates -Z loop-contracts
4848

4949
echo "Tests completed."
5050
echo

0 commit comments

Comments
 (0)