@@ -4,6 +4,9 @@ use crate::fmt;
4
4
use crate :: fmt:: { Formatter , Write } ;
5
5
use crate :: iter:: FusedIterator ;
6
6
7
+ #[ cfg( kani) ]
8
+ use crate :: kani;
9
+
7
10
impl [ u8 ] {
8
11
/// Creates an iterator over the contiguous valid UTF-8 ranges of this
9
12
/// slice, and the non-UTF-8 fragments in between.
@@ -204,6 +207,12 @@ impl<'a> Iterator for Utf8Chunks<'a> {
204
207
205
208
let mut i = 0 ;
206
209
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) ]
207
216
while i < self . source . len ( ) {
208
217
// SAFETY: `i < self.source.len()` per previous line.
209
218
// For some reason the following are both significantly slower:
@@ -296,3 +305,31 @@ impl fmt::Debug for Utf8Chunks<'_> {
296
305
f. debug_struct ( "Utf8Chunks" ) . field ( "source" , & self . debug ( ) ) . finish ( )
297
306
}
298
307
}
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