@@ -110,7 +110,10 @@ impl<T, const N: usize> Queue<T, N> {
110110
111111 #[ inline]
112112 fn increment ( val : usize ) -> usize {
113- ( val + 1 ) % N
113+ // We know that N <= usize::MAX
114+ // So this can only overflow if N == usize::MAX
115+ // and in this case the overflow will be equivalent to the modulo N operation
116+ val. wrapping_add ( 1 ) % N
114117 }
115118
116119 /// Creates an empty queue with a fixed capacity of `N - 1`
@@ -363,7 +366,11 @@ impl<'a, T, const N: usize> Iterator for Iter<'a, T, N> {
363366 if self . index < self . len {
364367 let head = self . rb . head . load ( Ordering :: Relaxed ) ;
365368
366- let i = ( head + self . index ) % N ;
369+ let i = match head. checked_add ( self . index ) {
370+ Some ( i) if i >= N => i - N ,
371+ Some ( i) => i,
372+ None => head. wrapping_add ( self . index ) . wrapping_sub ( N ) ,
373+ } ;
367374 self . index += 1 ;
368375
369376 Some ( unsafe { & * ( self . rb . buffer . get_unchecked ( i) . get ( ) as * const T ) } )
@@ -380,7 +387,11 @@ impl<'a, T, const N: usize> Iterator for IterMut<'a, T, N> {
380387 if self . index < self . len {
381388 let head = self . rb . head . load ( Ordering :: Relaxed ) ;
382389
383- let i = ( head + self . index ) % N ;
390+ let i = match head. checked_add ( self . index ) {
391+ Some ( i) if i >= N => i - N ,
392+ Some ( i) => i,
393+ None => head. wrapping_add ( self . index ) . wrapping_sub ( N ) ,
394+ } ;
384395 self . index += 1 ;
385396
386397 Some ( unsafe { & mut * ( self . rb . buffer . get_unchecked ( i) . get ( ) as * mut T ) } )
@@ -396,7 +407,11 @@ impl<'a, T, const N: usize> DoubleEndedIterator for Iter<'a, T, N> {
396407 let head = self . rb . head . load ( Ordering :: Relaxed ) ;
397408
398409 // self.len > 0, since it's larger than self.index > 0
399- let i = ( head + self . len - 1 ) % N ;
410+ let i = match head. checked_add ( self . len - 1 ) {
411+ Some ( i) if i >= N => i - N ,
412+ Some ( i) => i,
413+ None => head. wrapping_add ( self . len - 1 ) . wrapping_sub ( N ) ,
414+ } ;
400415 self . len -= 1 ;
401416 Some ( unsafe { & * ( self . rb . buffer . get_unchecked ( i) . get ( ) as * const T ) } )
402417 } else {
@@ -411,7 +426,11 @@ impl<'a, T, const N: usize> DoubleEndedIterator for IterMut<'a, T, N> {
411426 let head = self . rb . head . load ( Ordering :: Relaxed ) ;
412427
413428 // self.len > 0, since it's larger than self.index > 0
414- let i = ( head + self . len - 1 ) % N ;
429+ let i = match head. checked_add ( self . len - 1 ) {
430+ Some ( i) if i >= N => i - N ,
431+ Some ( i) => i,
432+ None => head. wrapping_add ( self . len - 1 ) . wrapping_sub ( N ) ,
433+ } ;
415434 self . len -= 1 ;
416435 Some ( unsafe { & mut * ( self . rb . buffer . get_unchecked ( i) . get ( ) as * mut T ) } )
417436 } else {
@@ -590,7 +609,10 @@ impl<'a, T, const N: usize> Producer<'a, T, N> {
590609
591610#[ cfg( test) ]
592611mod tests {
612+ use super :: AtomicUsize ;
593613 use crate :: spsc:: Queue ;
614+ use core:: cell:: UnsafeCell ;
615+ use core:: mem:: MaybeUninit ;
594616 use hash32:: Hasher ;
595617
596618 #[ test]
@@ -904,4 +926,74 @@ mod tests {
904926 } ;
905927 assert_eq ! ( hash1, hash2) ;
906928 }
929+
930+ // Test for some integer overflow bugs. See
931+ // https://github.com/rust-embedded/heapless/pull/652#discussion_r3046630717
932+ // for more info
933+ #[ test]
934+ #[ cfg_attr( miri, ignore) ] // too slow
935+ fn test_len_overflow ( ) {
936+ let mut queue = Queue :: < ( ) , { usize:: MAX } > {
937+ head : AtomicUsize :: new ( usize:: MAX ) ,
938+ tail : AtomicUsize :: new ( 2 ) ,
939+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX ] ,
940+ } ;
941+ queue. enqueue ( ( ) ) . unwrap ( ) ;
942+ queue. enqueue ( ( ) ) . unwrap ( ) ;
943+
944+ let collected: Vec < _ > = queue. iter ( ) . collect ( ) ;
945+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
946+ }
947+
948+ #[ test]
949+ #[ cfg_attr( miri, ignore) ] // too slow
950+ fn test_usize_overflow_iter ( ) {
951+ let queue = Queue :: < ( ) , { usize:: MAX - 1 } > {
952+ head : AtomicUsize :: new ( usize:: MAX - 3 ) ,
953+ tail : AtomicUsize :: new ( 2 ) ,
954+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX - 1 ] ,
955+ } ;
956+
957+ let collected: Vec < _ > = queue. iter ( ) . collect ( ) ;
958+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
959+ }
960+
961+ #[ test]
962+ #[ cfg_attr( miri, ignore) ] // too slow
963+ fn test_usize_overflow_iter_mut ( ) {
964+ let mut queue = Queue :: < ( ) , { usize:: MAX - 1 } > {
965+ head : AtomicUsize :: new ( usize:: MAX - 3 ) ,
966+ tail : AtomicUsize :: new ( 2 ) ,
967+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX - 1 ] ,
968+ } ;
969+
970+ let collected: Vec < _ > = queue. iter_mut ( ) . collect ( ) ;
971+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
972+ }
973+
974+ #[ test]
975+ #[ cfg_attr( miri, ignore) ] // too slow
976+ fn test_usize_overflow_iter_rev ( ) {
977+ let queue = Queue :: < ( ) , { usize:: MAX - 1 } > {
978+ head : AtomicUsize :: new ( usize:: MAX - 3 ) ,
979+ tail : AtomicUsize :: new ( 2 ) ,
980+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX - 1 ] ,
981+ } ;
982+
983+ let collected: Vec < _ > = queue. iter ( ) . rev ( ) . collect ( ) ;
984+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
985+ }
986+
987+ #[ test]
988+ #[ cfg_attr( miri, ignore) ] // too slow
989+ fn test_usize_overflow_iter_mut_rev ( ) {
990+ let mut queue = Queue :: < ( ) , { usize:: MAX - 1 } > {
991+ head : AtomicUsize :: new ( usize:: MAX - 3 ) ,
992+ tail : AtomicUsize :: new ( 2 ) ,
993+ buffer : [ const { UnsafeCell :: new ( MaybeUninit :: new ( ( ) ) ) } ; usize:: MAX - 1 ] ,
994+ } ;
995+
996+ let collected: Vec < _ > = queue. iter_mut ( ) . rev ( ) . collect ( ) ;
997+ assert_eq ! ( & collected, & [ & ( ) ; 4 ] ) ;
998+ }
907999}
0 commit comments