@@ -14,6 +14,11 @@ use crate::num::NonZero;
14
14
use crate :: ptr:: { self , without_provenance, without_provenance_mut, NonNull } ;
15
15
use crate :: { cmp, fmt} ;
16
16
17
+ #[ cfg( kani) ]
18
+ use crate :: kani;
19
+
20
+ use crate :: ub_checks:: Invariant ;
21
+
17
22
#[ stable( feature = "boxed_slice_into_iter" , since = "1.80.0" ) ]
18
23
impl < T > !Iterator for [ T ] { }
19
24
@@ -157,6 +162,23 @@ impl<T> AsRef<[T]> for Iter<'_, T> {
157
162
}
158
163
}
159
164
165
+ #[ unstable( feature = "ub_checks" , issue = "none" ) ]
166
+ impl < T > crate :: ub_checks:: Invariant for Iter < ' _ , T > {
167
+ fn is_safe ( & self ) -> bool {
168
+ let ty_size = crate :: mem:: size_of :: < T > ( ) ;
169
+ let distance = self . ptr . addr ( ) . get ( ) . abs_diff ( self . end_or_len as usize ) ;
170
+ if ty_size == 0 || distance == 0 {
171
+ self . ptr . is_aligned ( )
172
+ } else {
173
+ let slice_ptr: * const [ T ] = crate :: ptr:: from_raw_parts ( self . ptr . as_ptr ( ) , distance / ty_size) ;
174
+ crate :: ub_checks:: same_allocation ( self . ptr . as_ptr ( ) , self . end_or_len )
175
+ && self . ptr . addr ( ) . get ( ) <= self . end_or_len as usize
176
+ && distance % ty_size == 0
177
+ && crate :: ub_checks:: can_dereference ( slice_ptr)
178
+ }
179
+ }
180
+ }
181
+
160
182
/// Mutable slice iterator.
161
183
///
162
184
/// This struct is created by the [`iter_mut`] method on [slices].
@@ -196,6 +218,24 @@ pub struct IterMut<'a, T: 'a> {
196
218
_marker : PhantomData < & ' a mut T > ,
197
219
}
198
220
221
+ #[ unstable( feature = "ub_checks" , issue = "none" ) ]
222
+ impl < T > crate :: ub_checks:: Invariant for IterMut < ' _ , T > {
223
+ fn is_safe ( & self ) -> bool {
224
+ let size = crate :: mem:: size_of :: < T > ( ) ;
225
+ if size == 0 {
226
+ self . ptr . is_aligned ( )
227
+ } else {
228
+ let distance = self . ptr . addr ( ) . get ( ) . abs_diff ( self . end_or_len as usize ) ;
229
+ let slice_ptr: * mut [ T ] = crate :: ptr:: from_raw_parts_mut ( self . ptr . as_ptr ( ) , distance / size) ;
230
+ crate :: ub_checks:: same_allocation ( self . ptr . as_ptr ( ) , self . end_or_len )
231
+ && self . ptr . addr ( ) . get ( ) <= self . end_or_len as usize
232
+ && distance % size == 0
233
+ && crate :: ub_checks:: can_dereference ( slice_ptr)
234
+ && crate :: ub_checks:: can_write ( slice_ptr)
235
+ }
236
+ }
237
+ }
238
+
199
239
#[ stable( feature = "core_impl_debug" , since = "1.9.0" ) ]
200
240
impl < T : fmt:: Debug > fmt:: Debug for IterMut < ' _ , T > {
201
241
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
@@ -3464,3 +3504,123 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkByMut<'a, T, P> {
3464
3504
f. debug_struct ( "ChunkByMut" ) . field ( "slice" , & self . slice ) . finish ( )
3465
3505
}
3466
3506
}
3507
+
3508
+ /// Verify the safety of the code implemented in this module (including generated code from macros).
3509
+ #[ unstable( feature = "kani" , issue="none" ) ]
3510
+ mod verify {
3511
+ use super :: * ;
3512
+ use crate :: kani;
3513
+
3514
+ fn any_slice < T > ( orig_slice : & [ T ] ) -> & [ T ] {
3515
+ if kani:: any ( ) {
3516
+ let first = kani:: any_where ( |idx : & usize | * idx <= orig_slice. len ( ) ) ;
3517
+ let last = kani:: any_where ( |idx : & usize | * idx >= first && * idx <= orig_slice. len ( ) ) ;
3518
+ & orig_slice[ first..last]
3519
+ } else {
3520
+ let ptr = kani:: any_where :: < usize , _ > ( |val| * val != 0 ) as * const T ;
3521
+ kani:: assume ( ptr. is_aligned ( ) ) ;
3522
+ unsafe { crate :: slice:: from_raw_parts ( ptr, 0 ) }
3523
+ }
3524
+ }
3525
+
3526
+ fn any_iter < ' a , T > ( orig_slice : & ' a [ T ] ) -> Iter < ' a , T > {
3527
+ let slice = any_slice ( orig_slice) ;
3528
+ Iter :: new ( slice)
3529
+ }
3530
+
3531
+ /// Macro that generates a harness for a given `Iter` method.
3532
+ ///
3533
+ /// Takes the name of the harness, the element type, and an expression to check.
3534
+ macro_rules! check_safe_abstraction {
3535
+ ( $harness: ident, $elem_ty: ty, $call: expr) => {
3536
+ #[ kani:: proof]
3537
+ fn $harness( ) {
3538
+ let array: [ $elem_ty; MAX_LEN ] = kani:: any( ) ;
3539
+ let mut iter = any_iter:: <$elem_ty>( & array) ;
3540
+ let target = $call;
3541
+ target( & mut iter) ;
3542
+ kani:: assert( iter. is_safe( ) , "Iter is safe" ) ;
3543
+ }
3544
+ } ;
3545
+ }
3546
+
3547
+ /// Macro that generates a harness for a given unsafe `Iter` method.
3548
+ ///
3549
+ /// Takes:
3550
+ /// 1. The name of the harness
3551
+ /// 2. the element type
3552
+ /// 3. the target function
3553
+ /// 4. the optional arguments.
3554
+ macro_rules! check_unsafe_contracts {
3555
+ ( $harness: ident, $elem_ty: ty, $func: ident( $( $args: expr) ,* ) ) => {
3556
+ #[ kani:: proof_for_contract( Iter :: $func) ]
3557
+ fn $harness( ) {
3558
+ let array: [ $elem_ty; MAX_LEN ] = kani:: any( ) ;
3559
+ let mut iter = any_iter:: <$elem_ty>( & array) ;
3560
+ let _ = unsafe { iter. $func( $( $args) ,* ) } ;
3561
+ }
3562
+ } ;
3563
+ }
3564
+
3565
+ macro_rules! check_iter_with_ty {
3566
+ ( $module: ident, $ty: ty, $max: expr) => {
3567
+ mod $module {
3568
+ use super :: * ;
3569
+ const MAX_LEN : usize = $max;
3570
+
3571
+ #[ kani:: proof]
3572
+ fn check_new_iter( ) {
3573
+ let array: [ $ty; MAX_LEN ] = kani:: any( ) ;
3574
+ let slice = any_slice:: <$ty>( & array) ;
3575
+ let mut iter = Iter :: new( slice) ;
3576
+ kani:: assert( iter. is_safe( ) , "Iter is safe" ) ;
3577
+ }
3578
+
3579
+ /// Count consumes the value, thus, invoke it directly.
3580
+ #[ kani:: proof]
3581
+ fn check_count( ) {
3582
+ let array: [ $ty; MAX_LEN ] = kani:: any( ) ;
3583
+ let mut iter = any_iter:: <$ty>( & array) ;
3584
+ iter. count( ) ;
3585
+ }
3586
+
3587
+ #[ kani:: proof]
3588
+ fn check_default( ) {
3589
+ let iter: Iter <' _, $ty> = Iter :: default ( ) ;
3590
+ kani:: assert( iter. is_safe( ) , "Iter is safe" ) ;
3591
+ }
3592
+
3593
+ check_unsafe_contracts!( check_next_back_unchecked, $ty, next_back_unchecked( ) ) ;
3594
+ //check_unsafe_contracts!(check_post_inc_start, $ty, post_inc_start(kani::any()));
3595
+ //check_unsafe_contracts!(check_pre_dec_end, $ty, pre_dec_end(kani::any()));
3596
+
3597
+ // FIXME: The functions that are commented out are currently failing verification.
3598
+ // Debugging the issue is currently blocked by:
3599
+ // https://github.com/model-checking/kani/issues/3670
3600
+ //
3601
+ // Public functions that call safe abstraction `make_slice`.
3602
+ // check_safe_abstraction!(check_as_slice, $ty, as_slice);
3603
+ // check_safe_abstraction!(check_as_ref, $ty, as_ref);
3604
+
3605
+ // check_safe_abstraction!(check_advance_back_by, $ty, advance_back_by, kani::any());
3606
+
3607
+ check_safe_abstraction!( check_is_empty, $ty, |iter: & mut Iter <' _, $ty>| { let _ = iter. is_empty( ) ; } ) ;
3608
+ check_safe_abstraction!( check_len, $ty, |iter: & mut Iter <' _, $ty>| { let _ = iter. len( ) ; } ) ;
3609
+ check_safe_abstraction!( check_size_hint, $ty, |iter: & mut Iter <' _, $ty>| { let _ = iter. size_hint( ) ; } ) ;
3610
+ //check_safe_abstraction!(check_nth, $ty, |iter: &mut Iter<'_, $ty>| { let _ = iter.nth(kani::any()); });
3611
+ //check_safe_abstraction!(check_advance_by, $ty, |iter: &mut Iter<'_, $ty>| { let _ = iter.advance_by(kani::any()); });
3612
+ //check_safe_abstraction!(check_next_back, $ty, |iter: &mut Iter<'_, $ty>| { let _ = iter.next_back(); });
3613
+ //check_safe_abstraction!(check_nth_back, $ty, |iter: &mut Iter<'_, $ty>| { let _ = iter.nth_back(kani::any()); });
3614
+ check_safe_abstraction!( check_next, $ty, |iter: & mut Iter <' _, $ty>| { let _ = iter. next( ) ; } ) ;
3615
+
3616
+ // Ensure that clone always generates a safe object.
3617
+ check_safe_abstraction!( check_clone, $ty, |iter: & mut Iter <' _, $ty>| { kani:: assert( iter. clone( ) . is_safe( ) , "Clone is safe" ) ; } ) ;
3618
+ }
3619
+ } ;
3620
+ }
3621
+
3622
+ check_iter_with_ty ! ( verify_unit, ( ) , isize :: MAX as usize ) ;
3623
+ check_iter_with_ty ! ( verify_u8, u8 , u32 :: MAX as usize ) ;
3624
+ check_iter_with_ty ! ( verify_char, char , 50 ) ;
3625
+ check_iter_with_ty ! ( verify_tup, ( char , u8 ) , 50 ) ;
3626
+ }
0 commit comments