Skip to content

Commit 4a98087

Browse files
add loop invariants and harnesses for some ascii functions
1 parent 4c08921 commit 4a98087

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

library/core/src/slice/ascii.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ impl [u8] {
6868
let mut a = self;
6969
let mut b = other;
7070

71+
#[safety::loop_invariant(
72+
a.len() <= self.len() && b.len() <= other.len() &&
73+
(a.len() == 0 || self.as_ptr().wrapping_add(self.len()-a.len()) == a.as_ptr()) &&
74+
(b.len() == 0 || other.as_ptr().wrapping_add(other.len()-b.len()) == b.as_ptr())
75+
)]
7176
while let ([first_a, rest_a @ ..], [first_b, rest_b @ ..]) = (a, b) {
7277
if first_a.eq_ignore_ascii_case(&first_b) {
7378
a = rest_a;
@@ -160,6 +165,10 @@ impl [u8] {
160165
let mut bytes = self;
161166
// Note: A pattern matching based approach (instead of indexing) allows
162167
// making the function const.
168+
#[safety::loop_invariant(
169+
bytes.len() <= self.len() &&
170+
(bytes.len() == 0 || self.as_ptr().wrapping_add(self.len()-bytes.len()) == bytes.as_ptr())
171+
)]
163172
while let [first, rest @ ..] = bytes {
164173
if first.is_ascii_whitespace() {
165174
bytes = rest;
@@ -189,6 +198,10 @@ impl [u8] {
189198
let mut bytes = self;
190199
// Note: A pattern matching based approach (instead of indexing) allows
191200
// making the function const.
201+
#[safety::loop_invariant(
202+
bytes.len() <= self.len() &&
203+
(bytes.len() == 0 || self.as_ptr() == bytes.as_ptr())
204+
)]
192205
while let [rest @ .., last] = bytes {
193206
if last.is_ascii_whitespace() {
194207
bytes = rest;
@@ -338,6 +351,12 @@ impl<'a> fmt::Debug for EscapeAscii<'a> {
338351
#[doc(hidden)]
339352
#[inline]
340353
pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool {
354+
#[cfg(kani)]
355+
let on_entry_bytes = bytes;
356+
#[safety::loop_invariant(
357+
bytes.len() <= on_entry_bytes.len() &&
358+
(bytes.len() == 0 || bytes.as_ptr() == on_entry_bytes.as_ptr())
359+
)]
341360
while let [rest @ .., last] = bytes {
342361
if !last.is_ascii() {
343362
break;
@@ -536,4 +555,29 @@ pub mod verify {
536555
}
537556
}
538557
}
558+
559+
#[kani::proof]
560+
pub fn check_trim_ascii_start() {
561+
let a: [u8; 100] = kani::any();
562+
let _ret = a.trim_ascii_start();
563+
}
564+
565+
#[kani::proof]
566+
pub fn check_eq_ignore_ascii_case() {
567+
let a: [u8; 100] = kani::any();
568+
let b: [u8; 100] = kani::any();
569+
let _ret = a.eq_ignore_ascii_case(b.as_slice());
570+
}
571+
572+
#[kani::proof]
573+
fn check_is_ascii_simple() {
574+
let mut bytes: [u8; 100] = kani::any();
575+
let _ret = bytes.is_ascii_simple();
576+
}
577+
578+
#[kani::proof]
579+
fn check_trim_ascii_end() {
580+
let mut a: [u8; 100] = kani::any();
581+
let _ret = a.trim_ascii_end();
582+
}
539583
}

0 commit comments

Comments
 (0)