Skip to content

Commit 2cd6ce0

Browse files
authored
Add loop contracts and harness for Utf8Chunk::next (model-checking#158)
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent 0c70dcd commit 2cd6ce0

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

library/core/src/str/lossy.rs

+37
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use crate::fmt;
44
use crate::fmt::{Formatter, Write};
55
use crate::iter::FusedIterator;
66

7+
#[cfg(kani)]
8+
use crate::kani;
9+
710
impl [u8] {
811
/// Creates an iterator over the contiguous valid UTF-8 ranges of this
912
/// slice, and the non-UTF-8 fragments in between.
@@ -204,6 +207,12 @@ impl<'a> Iterator for Utf8Chunks<'a> {
204207

205208
let mut i = 0;
206209
let mut valid_up_to = 0;
210+
// TODO: remove `LEN` and use `self.source.len()` directly once
211+
// fix the issue that Kani loop contracts doesn't support `self`.
212+
// Tracked in https://github.com/model-checking/kani/issues/3700
213+
#[cfg(kani)]
214+
let LEN = self.source.len();
215+
#[safety::loop_invariant(i <= LEN && valid_up_to == i)]
207216
while i < self.source.len() {
208217
// SAFETY: `i < self.source.len()` per previous line.
209218
// For some reason the following are both significantly slower:
@@ -296,3 +305,31 @@ impl fmt::Debug for Utf8Chunks<'_> {
296305
f.debug_struct("Utf8Chunks").field("source", &self.debug()).finish()
297306
}
298307
}
308+
309+
#[cfg(kani)]
310+
#[unstable(feature = "kani", issue = "none")]
311+
pub mod verify {
312+
use super::*;
313+
314+
#[kani::proof]
315+
pub fn check_next() {
316+
if kani::any() {
317+
// TODO: ARR_SIZE can be `std::usize::MAX` with cbmc argument
318+
// `--arrays-uf-always`
319+
const ARR_SIZE: usize = 1000;
320+
let mut x: [u8; ARR_SIZE] = kani::any();
321+
let mut xs = kani::slice::any_slice_of_array_mut(&mut x);
322+
let mut chunks = xs.utf8_chunks();
323+
unsafe {
324+
chunks.next();
325+
}
326+
} else {
327+
let ptr = kani::any_where::<usize, _>(|val| *val != 0) as *const u8;
328+
kani::assume(ptr.is_aligned());
329+
unsafe {
330+
let mut chunks = crate::slice::from_raw_parts(ptr, 0).utf8_chunks();
331+
chunks.next();
332+
}
333+
}
334+
}
335+
}

0 commit comments

Comments
 (0)