Skip to content

Commit 746b5de

Browse files
committed
Add loop contracts and harness for BinaryHeap::sift_up
1 parent 3a967e3 commit 746b5de

File tree

4 files changed

+71
-1
lines changed

4 files changed

+71
-1
lines changed

library/alloc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ edition = "2021"
1010

1111
[dependencies]
1212
core = { path = "../core" }
13+
safety = { path = "../contracts/safety" }
1314
compiler_builtins = { version = "0.1.123", features = ['rustc-dep-of-std'] }
1415

1516
[dev-dependencies]

library/alloc/src/collections/binary_heap/mod.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ use crate::collections::TryReserveError;
155155
use crate::slice;
156156
use crate::vec::{self, AsVecIntoIter, Vec};
157157

158+
use safety::{ensures, requires};
159+
160+
#[cfg(kani)]
161+
#[unstable(feature="kani", issue="none")]
162+
use core::kani;
163+
158164
#[cfg(test)]
159165
mod tests;
160166

@@ -672,11 +678,13 @@ impl<T: Ord, A: Allocator> BinaryHeap<T, A> {
672678
/// # Safety
673679
///
674680
/// The caller must guarantee that `pos < self.len()`.
681+
#[requires(pos < self.len() && start <= pos)]
675682
unsafe fn sift_up(&mut self, start: usize, pos: usize) -> usize {
676683
// Take out the value at `pos` and create a hole.
677684
// SAFETY: The caller guarantees that pos < self.len()
678685
let mut hole = unsafe { Hole::new(&mut self.data, pos) };
679686

687+
#[cfg_attr(kani, kani::loop_invariant(hole.pos() <= pos))]
680688
while hole.pos() > start {
681689
let parent = (hole.pos() - 1) / 2;
682690

@@ -1897,3 +1905,61 @@ impl<'a, T: 'a + Ord + Copy, A: Allocator> Extend<&'a T> for BinaryHeap<T, A> {
18971905
self.reserve(additional);
18981906
}
18991907
}
1908+
1909+
#[cfg(kani)]
1910+
#[unstable(feature = "kani", issue = "none")]
1911+
mod verify {
1912+
use super::*;
1913+
use crate::boxed::Box;
1914+
1915+
/// Generates an arbitrary vector whose length is at most MAX_LENGTH.
1916+
pub fn any_vec<T, const MAX_LENGTH: usize>() -> Vec<T>
1917+
where
1918+
T: kani::Arbitrary,
1919+
{
1920+
let real_length: usize = kani::any_where(|sz| *sz <= MAX_LENGTH);
1921+
match real_length {
1922+
0 => vec![],
1923+
exact if exact == MAX_LENGTH => exact_vec::<T, MAX_LENGTH>(),
1924+
_ => {
1925+
let mut any_vec = exact_vec::<T, MAX_LENGTH>();
1926+
any_vec.truncate(real_length);
1927+
any_vec.shrink_to_fit();
1928+
assert!(any_vec.capacity() == any_vec.len());
1929+
any_vec
1930+
}
1931+
}
1932+
}
1933+
1934+
/// Generates an arbitrary vector that is exactly EXACT_LENGTH long.
1935+
pub fn exact_vec<T, const EXACT_LENGTH: usize>() -> Vec<T>
1936+
where
1937+
T: kani::Arbitrary,
1938+
{
1939+
let boxed_array: Box<[T; EXACT_LENGTH]> = Box::new(kani::any());
1940+
<[T]>::into_vec(boxed_array)
1941+
}
1942+
1943+
fn any_binary_heap<T: kani::Arbitrary, const MAX_SIZE: usize>() -> BinaryHeap<T> {
1944+
let data: Vec<T> = any_vec::<T, MAX_SIZE>();
1945+
BinaryHeap { data }
1946+
}
1947+
1948+
#[kani::proof]
1949+
pub fn check_any_binary_heap() {
1950+
let h: BinaryHeap<u8> = any_binary_heap::<u8, 8>();
1951+
assert!(h.len() <= 8);
1952+
}
1953+
1954+
#[kani::proof]
1955+
pub fn check_sift_up() {
1956+
let _ = Box::new(0);
1957+
const MAX_SIZE: usize = 1000;
1958+
let mut h: BinaryHeap<u8> = any_binary_heap::<u8, MAX_SIZE>();
1959+
let pos: usize = kani::any_where(|x| *x < h.len());
1960+
let start: usize = kani::any_where(|x| *x <= pos);
1961+
unsafe {
1962+
h.sift_up(start, pos);
1963+
}
1964+
}
1965+
}

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
//

scripts/check_kani.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ 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 --enable-unstable --cbmc-args --object-bits 8
48+
4849

4950
echo "Tests completed."
5051
echo

0 commit comments

Comments
 (0)