@@ -5,6 +5,9 @@ use core::ascii::EscapeDefault;
5
5
use crate :: fmt:: { self , Write } ;
6
6
use crate :: { ascii, iter, mem, ops} ;
7
7
8
+ #[ cfg( kani) ]
9
+ use crate :: kani;
10
+
8
11
#[ cfg( not( test) ) ]
9
12
impl [ u8 ] {
10
13
/// Checks if all bytes in this slice are within the ASCII range.
@@ -398,6 +401,10 @@ const fn is_ascii(s: &[u8]) -> bool {
398
401
// Read subsequent words until the last aligned word, excluding the last
399
402
// aligned word by itself to be done in tail check later, to ensure that
400
403
// 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) ) ]
401
408
while byte_pos < len - USIZE_SIZE {
402
409
// Sanity check that the read is in bounds
403
410
debug_assert ! ( byte_pos + USIZE_SIZE <= len) ;
@@ -432,3 +439,28 @@ const fn is_ascii(s: &[u8]) -> bool {
432
439
433
440
!contains_nonascii ( last_word)
434
441
}
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
+ }
0 commit comments