Skip to content
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

Add loop contracts and harness for small_slice_eq #122

Merged
2 changes: 2 additions & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
#![feature(with_negative_coherence)]
// Required for Kani loop contracts, which are annotated as custom stmt attributes.
#![feature(proc_macro_hygiene)]
// tidy-alphabetical-end
//
// Target features:
Expand Down
61 changes: 60 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.as_ptr().addr()
&& py.addr() >= y.as_ptr().addr()
&& px.addr() - x.as_ptr().addr() == py.addr() - y.as_ptr().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,50 @@ 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);
}
}

/* This harness check `small_slice_eq` with dangling pointer to slice
with zero size. Kani finds safety issue of `small_slice_eq` in this
harness and hence the proof will fail.

#[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());
assert_eq!(
unsafe {
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