Skip to content

Commit 8b4f971

Browse files
committed
Add loop contracts and harness for Slice::is_ascii
1 parent 25ad12b commit 8b4f971

File tree

4 files changed

+35
-2
lines changed

4 files changed

+35
-2
lines changed

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@
230230
#![feature(unboxed_closures)]
231231
#![feature(unsized_fn_params)]
232232
#![feature(with_negative_coherence)]
233+
#![feature(proc_macro_hygiene)]
233234
// tidy-alphabetical-end
234235
//
235236
// Target features:

library/core/src/slice/ascii.rs

+32
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ use core::ascii::EscapeDefault;
55
use crate::fmt::{self, Write};
66
use crate::{ascii, iter, mem, ops};
77

8+
#[cfg(kani)]
9+
use crate::kani;
10+
811
#[cfg(not(test))]
912
impl [u8] {
1013
/// Checks if all bytes in this slice are within the ASCII range.
@@ -398,6 +401,10 @@ const fn is_ascii(s: &[u8]) -> bool {
398401
// Read subsequent words until the last aligned word, excluding the last
399402
// aligned word by itself to be done in tail check later, to ensure that
400403
// tail is always one `usize` at most to extra branch `byte_pos == len`.
404+
#[safety::loop_invariant(byte_pos <= len
405+
&& byte_pos >= offset_to_aligned
406+
&& word_ptr as usize >= start as usize + offset_to_aligned
407+
&& (byte_pos - offset_to_aligned) == (word_ptr as usize - start as usize - offset_to_aligned))]
401408
while byte_pos < len - USIZE_SIZE {
402409
// Sanity check that the read is in bounds
403410
debug_assert!(byte_pos + USIZE_SIZE <= len);
@@ -432,3 +439,28 @@ const fn is_ascii(s: &[u8]) -> bool {
432439

433440
!contains_nonascii(last_word)
434441
}
442+
443+
#[cfg(kani)]
444+
#[unstable(feature = "kani", issue = "none")]
445+
pub mod verify {
446+
use super::*;
447+
448+
#[kani::proof]
449+
#[kani::unwind(8)]
450+
pub fn check_is_ascii() {
451+
if kani::any() {
452+
// TODO: ARR_SIZE can be `std::usize::MAX` with cbmc argument
453+
// `--arrays-uf-always`
454+
const ARR_SIZE: usize = 1000;
455+
let mut x: [u8; ARR_SIZE] = kani::any();
456+
let mut xs = kani::slice::any_slice_of_array_mut(&mut x);
457+
is_ascii(xs);
458+
} else {
459+
let ptr = kani::any_where::<usize, _>(|val| *val != 0) as *const u8;
460+
kani::assume(ptr.is_aligned());
461+
unsafe{
462+
assert_eq!(is_ascii(crate::slice::from_raw_parts(ptr, 0)), true);
463+
}
464+
}
465+
}
466+
}

scripts/run-kani.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ main() {
183183

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

186-
"$kani_path" verify-std -Z unstable-options ./library --target-dir "$temp_dir_target" -Z function-contracts -Z mem-predicates --output-format=terse $command_args
186+
"$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
187187
}
188188

189189
main

tool_config/kani-version.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# incompatible with the verify-std repo.
33

44
[kani]
5-
commit = "2565ef65767a696f1d519b42621b4e502e8970d0"
5+
commit = "8400296f5280be4f99820129bc66447e8dff63f4"

0 commit comments

Comments
 (0)