Skip to content

Commit e10a8f6

Browse files
add loop-invariants and harnesses
1 parent 4c08921 commit e10a8f6

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

library/core/src/slice/memchr.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
3636
let mut i = 0;
3737

3838
// FIXME(const-hack): Replace with `text.iter().pos(|c| *c == x)`.
39+
#[safety::loop_invariant(true)]
3940
while i < text.len() {
4041
if text[i] == x {
4142
return Some(i);
@@ -78,6 +79,7 @@ const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
7879

7980
// search the body of the text
8081
let repeated_x = usize::repeat_u8(x);
82+
#[safety::loop_invariant(true)]
8183
while offset <= len - 2 * USIZE_BYTES {
8284
// SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes
8385
// between the offset and the end of the slice.
@@ -139,6 +141,7 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
139141
let repeated_x = usize::repeat_u8(x);
140142
let chunk_bytes = size_of::<Chunk>();
141143

144+
#[safety::loop_invariant(true)]
142145
while offset > min_aligned_offset {
143146
// SAFETY: offset starts at len - suffix.len(), as long as it is greater than
144147
// min_aligned_offset (prefix.len()) the remaining distance is at least 2 * chunk_bytes.
@@ -159,3 +162,30 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
159162
// Find the byte before the point the body loop stopped.
160163
text[..offset].iter().rposition(|elt| *elt == x)
161164
}
165+
166+
#[cfg(kani)]
167+
#[unstable(feature = "kani", issue = "none")]
168+
pub mod verify {
169+
use super::*;
170+
171+
#[kani::proof]
172+
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
173+
pub fn check_memchr_naive() {
174+
const ARR_SIZE: usize = 1000;
175+
let x: u8 = kani::any();
176+
let a: [u8; ARR_SIZE] = kani::any();
177+
let text = kani::slice::any_slice_of_array(&a);
178+
let _result = memchr_naive(x, text);
179+
}
180+
181+
#[kani::proof]
182+
#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))]
183+
pub fn check_memchr_naive() {
184+
const ARR_SIZE: usize = 1000;
185+
let x: u8 = kani::any();
186+
let a: [u8; ARR_SIZE] = kani::any();
187+
let text = kani::slice::any_slice_of_array(&a);
188+
let _result = memrchr(x, text);
189+
}
190+
191+
}

0 commit comments

Comments
 (0)