@@ -4,6 +4,9 @@ use crate::fmt;
44use crate :: fmt:: { Formatter , Write } ;
55use crate :: iter:: FusedIterator ;
66
7+ #[ cfg( kani) ]
8+ use crate :: kani;
9+
710impl [ 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