Skip to content

Add loop contracts and harness for small_slice_eq #122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
#![feature(with_negative_coherence)]
#![feature(proc_macro_hygiene)]
// tidy-alphabetical-end
//
// Target features:
Expand Down
56 changes: 55 additions & 1 deletion library/core/src/str/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ use crate::convert::TryInto as _;
use crate::slice::memchr;
use crate::{cmp, fmt};

#[cfg(all(target_arch = "x86_64", any(kani, target_feature = "sse2")))]
use safety::{loop_invariant, requires};

#[cfg(kani)]
use crate::kani;

// Pattern

/// A string pattern.
Expand Down Expand Up @@ -1905,8 +1911,9 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
/// # Safety
///
/// Both slices must have the same length.
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] // only called on x86
#[cfg(all(target_arch = "x86_64", any(kani, target_feature = "sse2")))] // only called on x86
#[inline]
#[requires(x.len() == y.len())]
unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
debug_assert_eq!(x.len(), y.len());
// This function is adapted from
Expand Down Expand Up @@ -1951,6 +1958,11 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
unsafe {
let (mut px, mut py) = (x.as_ptr(), y.as_ptr());
let (pxend, pyend) = (px.add(x.len() - 4), py.add(y.len() - 4));
#[loop_invariant(crate::ub_checks::same_allocation(x.as_ptr(), px)
&& crate::ub_checks::same_allocation(y.as_ptr(), py)
&& px.addr() >= x.addr()
&& py.addr() >= y.addr()
&& px.addr() - x.addr() == py.addr() - y.addr())]
while px < pxend {
let vx = (px as *const u32).read_unaligned();
let vy = (py as *const u32).read_unaligned();
Expand All @@ -1965,3 +1977,45 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool {
vx == vy
}
}

#[cfg(kani)]
#[unstable(feature = "kani", issue = "none")]
pub mod verify {
use super::*;

#[cfg(all(kani, target_arch = "x86_64"))] // only called on x86
#[kani::proof]
#[kani::unwind(4)]
pub fn check_small_slice_eq() {
// TODO: ARR_SIZE can be `std::usize::MAX` with cbmc argument
// `--arrays-uf-always`
const ARR_SIZE: usize = 1000;
let x: [u8; ARR_SIZE] = kani::any();
let y: [u8; ARR_SIZE] = kani::any();
let xs = kani::slice::any_slice_of_array(&x);
let ys = kani::slice::any_slice_of_array(&y);
kani::assume(xs.len() == ys.len());
unsafe {
small_slice_eq(xs, ys);
}
}

#[cfg(all(kani, target_arch = "x86_64"))] // only called on x86
#[kani::proof]
#[kani::unwind(4)]
pub fn check_small_slice_eq_empty() {
let ptr_x = kani::any_where::<usize, _>(|val| *val != 0) as *const u8;
let ptr_y = kani::any_where::<usize, _>(|val| *val != 0) as *const u8;
kani::assume(ptr_x.is_aligned());
kani::assume(ptr_y.is_aligned());
unsafe {
assert_eq!(
small_slice_eq(
crate::slice::from_raw_parts(ptr_x, 0),
crate::slice::from_raw_parts(ptr_y, 0),
),
true
);
}
}
}
2 changes: 1 addition & 1 deletion scripts/run-kani.sh
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ main() {

echo "Running Kani verify-std command..."

"$kani_path" verify-std -Z unstable-options ./library --target-dir "$temp_dir_target" -Z function-contracts -Z mem-predicates --output-format=terse $command_args
"$kani_path" verify-std -Z unstable-options ./library --target-dir "$temp_dir_target" -Z function-contracts -Z mem-predicates -Z loop-contracts --output-format=terse $command_args --enable-unstable --cbmc-args --object-bits 12
}

main
Expand Down
2 changes: 1 addition & 1 deletion tool_config/kani-version.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
# incompatible with the verify-std repo.

[kani]
commit = "2565ef65767a696f1d519b42621b4e502e8970d0"
commit = "8400296f5280be4f99820129bc66447e8dff63f4"
Loading