@@ -14,6 +14,11 @@ use crate::num::NonZero;
1414use crate :: ptr:: { self , without_provenance, without_provenance_mut, NonNull } ;
1515use crate :: { cmp, fmt} ;
1616
17+ #[ cfg( kani) ]
18+ use crate :: kani;
19+
20+ use crate :: ub_checks:: Invariant ;
21+
1722#[ stable( feature = "boxed_slice_into_iter" , since = "1.80.0" ) ]
1823impl < T > !Iterator for [ T ] { }
1924
@@ -157,6 +162,23 @@ impl<T> AsRef<[T]> for Iter<'_, T> {
157162 }
158163}
159164
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+
160182/// Mutable slice iterator.
161183///
162184/// This struct is created by the [`iter_mut`] method on [slices].
@@ -196,6 +218,24 @@ pub struct IterMut<'a, T: 'a> {
196218 _marker : PhantomData < & ' a mut T > ,
197219}
198220
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+
199239#[ stable( feature = "core_impl_debug" , since = "1.9.0" ) ]
200240impl < T : fmt:: Debug > fmt:: Debug for IterMut < ' _ , T > {
201241 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> {
34643504 f. debug_struct ( "ChunkByMut" ) . field ( "slice" , & self . slice ) . finish ( )
34653505 }
34663506}
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