@@ -176,7 +176,10 @@ impl<T, S: Storage> QueueInner<T, S> {
176176
177177 #[ inline]
178178 fn increment ( & self , val : usize ) -> usize {
179- let val = val + 1 ;
179+ // We know that self.n() <= usize::MAX
180+ // So this can only overflow if N == usize::MAX
181+ // and in this case the overflow will be equivalent to the modulo N operation
182+ let val = val. wrapping_add ( 1 ) ;
180183 if val >= self . n ( ) {
181184 val - self . n ( )
182185 } else {
@@ -628,8 +631,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
628631 if self . index < self . len {
629632 let head = self . rb . head . load ( Ordering :: Relaxed ) ;
630633
631- let i = head + self . index ;
632- let i = if i >= self . rb . n ( ) { i - self . rb . n ( ) } else { i } ;
634+ let i = match head. checked_add ( self . index ) {
635+ Some ( i) if i >= self . rb . n ( ) => i - self . rb . n ( ) ,
636+ Some ( i) => i,
637+ None => head. wrapping_add ( self . index ) . wrapping_sub ( self . rb . n ( ) ) ,
638+ } ;
633639 self . index += 1 ;
634640
635641 Some ( unsafe { & * ( self . rb . buffer . borrow ( ) . get_unchecked ( i) . get ( ) as * const T ) } )
@@ -646,8 +652,11 @@ impl<'a, T> Iterator for IterMut<'a, T> {
646652 if self . index < self . len {
647653 let head = self . rb . head . load ( Ordering :: Relaxed ) ;
648654
649- let i = head + self . index ;
650- let i = if i >= self . rb . n ( ) { i - self . rb . n ( ) } else { i } ;
655+ let i = match head. checked_add ( self . index ) {
656+ Some ( i) if i >= self . rb . n ( ) => i - self . rb . n ( ) ,
657+ Some ( i) => i,
658+ None => head. wrapping_add ( self . index ) . wrapping_sub ( self . rb . n ( ) ) ,
659+ } ;
651660 self . index += 1 ;
652661
653662 Some ( unsafe { & mut * self . rb . buffer . borrow ( ) . get_unchecked ( i) . get ( ) . cast :: < T > ( ) } )
@@ -663,8 +672,11 @@ impl<T> DoubleEndedIterator for Iter<'_, T> {
663672 let head = self . rb . head . load ( Ordering :: Relaxed ) ;
664673
665674 // self.len > 0, since it's larger than self.index > 0
666- let i = head + self . len - 1 ;
667- let i = if i >= self . rb . n ( ) { i - self . rb . n ( ) } else { i } ;
675+ let i = match head. checked_add ( self . len - 1 ) {
676+ Some ( i) if i >= self . rb . n ( ) => i - self . rb . n ( ) ,
677+ Some ( i) => i,
678+ None => head. wrapping_add ( self . len - 1 ) . wrapping_sub ( self . rb . n ( ) ) ,
679+ } ;
668680 self . len -= 1 ;
669681 Some ( unsafe { & * ( self . rb . buffer . borrow ( ) . get_unchecked ( i) . get ( ) as * const T ) } )
670682 } else {
@@ -678,6 +690,7 @@ impl<T> DoubleEndedIterator for IterMut<'_, T> {
678690 if self . index < self . len {
679691 let head = self . rb . head . load ( Ordering :: Relaxed ) ;
680692
693+ // TODO: fix usize overflow
681694 // self.len > 0, since it's larger than self.index > 0
682695 let i = head + self . len - 1 ;
683696 let i = if i >= self . rb . n ( ) { i - self . rb . n ( ) } else { i } ;
@@ -888,9 +901,19 @@ impl<T> Producer<'_, T> {
888901
889902#[ cfg( test) ]
890903mod tests {
891- use std:: hash:: { Hash , Hasher } ;
904+ use std:: {
905+ cell:: UnsafeCell ,
906+ hash:: { Hash , Hasher } ,
907+ mem:: MaybeUninit ,
908+ } ;
892909
893910 use super :: { Consumer , Producer , Queue } ;
911+ #[ cfg( not( feature = "portable-atomic" ) ) ]
912+ use core:: sync:: atomic;
913+ #[ cfg( feature = "portable-atomic" ) ]
914+ use portable_atomic as atomic;
915+
916+ use atomic:: AtomicUsize ;
894917
895918 use static_assertions:: assert_not_impl_any;
896919
@@ -1310,4 +1333,65 @@ mod tests {
13101333 } ;
13111334 assert_eq ! ( hash1, hash2) ;
13121335 }
1336+
1337+ // Test for some integer overflow bugs. See
1338+ // https://github.com/rust-embedded/heapless/pull/652#discussion_r3046630717
1339+ // for more info
1340+ #[ test]
1341+ fn test_len_overflow ( ) {
1342+ let mut queue = Queue :: < ( ) , { usize:: MAX } > {
1343+ head : AtomicUsize :: new ( usize:: MAX ) ,
1344+ tail : AtomicUsize :: new ( 2 ) ,
1345+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX ] ,
1346+ } ;
1347+ queue. enqueue ( ( ) ) . unwrap ( ) ;
1348+ queue. enqueue ( ( ) ) . unwrap ( ) ;
1349+
1350+ let collected: Vec < _ > = queue. iter ( ) . collect ( ) ;
1351+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
1352+ }
1353+ #[ test]
1354+ fn test_usize_overflow_iter ( ) {
1355+ let queue = Queue :: < ( ) , { usize:: MAX - 1 } > {
1356+ head : AtomicUsize :: new ( usize:: MAX - 3 ) ,
1357+ tail : AtomicUsize :: new ( 2 ) ,
1358+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX - 1 ] ,
1359+ } ;
1360+
1361+ let collected: Vec < _ > = queue. iter ( ) . collect ( ) ;
1362+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
1363+ }
1364+ #[ test]
1365+ fn test_usize_overflow_iter_mut ( ) {
1366+ let mut queue = Queue :: < ( ) , { usize:: MAX - 1 } > {
1367+ head : AtomicUsize :: new ( usize:: MAX - 3 ) ,
1368+ tail : AtomicUsize :: new ( 2 ) ,
1369+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX - 1 ] ,
1370+ } ;
1371+
1372+ let collected: Vec < _ > = queue. iter_mut ( ) . collect ( ) ;
1373+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
1374+ }
1375+ #[ test]
1376+ fn test_usize_overflow_iter_rev ( ) {
1377+ let queue = Queue :: < ( ) , { usize:: MAX - 1 } > {
1378+ head : AtomicUsize :: new ( usize:: MAX - 3 ) ,
1379+ tail : AtomicUsize :: new ( 2 ) ,
1380+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX - 1 ] ,
1381+ } ;
1382+
1383+ let collected: Vec < _ > = queue. iter ( ) . rev ( ) . collect ( ) ;
1384+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
1385+ }
1386+ #[ test]
1387+ fn test_usize_overflow_iter_mut_rev ( ) {
1388+ let mut queue = Queue :: < ( ) , { usize:: MAX - 1 } > {
1389+ head : AtomicUsize :: new ( usize:: MAX - 3 ) ,
1390+ tail : AtomicUsize :: new ( 2 ) ,
1391+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX - 1 ] ,
1392+ } ;
1393+
1394+ let collected: Vec < _ > = queue. iter_mut ( ) . rev ( ) . collect ( ) ;
1395+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
1396+ }
13131397}
0 commit comments