@@ -735,24 +735,24 @@ impl<T, LenT: LenType, S: VecStorage<T> + ?Sized> VecInner<T, LenT, S> {
735735
736736 /// Shortens the vector, keeping the first `len` elements and dropping the rest.
737737 pub fn truncate ( & mut self , len : usize ) {
738- // This is safe because:
738+ // NOTE: It is intentional that this is `>`. Changing it to `>=` may have negative
739+ // performance implications. See rust-lang/rust#78884 for more details.
740+ if len > self . len ( ) {
741+ return ;
742+ }
743+
744+ // SAFETY: `self.buffer` contains initialized elements in the range `len..self.len()`,
745+ // so it is safe to create a mutable slice of them and drop them.
739746 //
740- // * the slice passed to `drop_in_place` is valid; the `len > self.len` case avoids creating
741- // an invalid slice, and
742- // * the `len` of the vector is shrunk before calling `drop_in_place`, such that no value
743- // will be dropped twice in case `drop_in_place` were to panic once (if it panics twice,
744- // the program aborts).
747+ // `self.len` is set before dropping the excess elements so that a panicking
748+ // `Drop` implementation does not result in inconsistent state during
749+ // unwinding that could lead to undefined behaviour.
745750 unsafe {
746- // Note: It's intentional that this is `>` and not `>=`.
747- // Changing it to `>=` has negative performance
748- // implications in some cases. See rust-lang/rust#78884 for more.
749- if len > self . len ( ) {
750- return ;
751- }
752751 let remaining_len = self . len ( ) - len;
753- let s = ptr:: slice_from_raw_parts_mut ( self . as_mut_ptr ( ) . add ( len) , remaining_len) ;
752+ let remaining =
753+ ptr:: slice_from_raw_parts_mut ( self . as_mut_ptr ( ) . add ( len) , remaining_len) ;
754754 self . len = LenT :: from_usize ( len) ;
755- ptr:: drop_in_place ( s ) ;
755+ ptr:: drop_in_place ( remaining ) ;
756756 }
757757 }
758758
@@ -1572,13 +1572,21 @@ where
15721572impl < T , LenT : LenType , const N : usize > Drop for IntoIter < T , N , LenT > {
15731573 fn drop ( & mut self ) {
15741574 let len = self . vec . len ;
1575- self . vec . len = LenT :: ZERO ;
1575+
1576+ // SAFETY: `self.vec` contains initialized elements in the range `self.next..len`,
1577+ // so it is safe to create a mutable slice of them and drop them.
1578+ //
1579+ // `self.vec.len` is set to `0` before dropping the elements so that
1580+ // a panicking `Drop` implementation does not result in inconsistent
1581+ // state during unwinding that could lead to undefined behaviour.
15761582 unsafe {
1577- // Drop all the elements that have not been moved out of vec
1583+ // Drop all elements that have not been consumed yet.
1584+ let remaining_len = len - self . next ;
15781585 let remaining = slice:: from_raw_parts_mut (
15791586 self . vec . as_mut_ptr ( ) . add ( self . next . into_usize ( ) ) ,
1580- ( len - self . next ) . into_usize ( ) ,
1587+ remaining_len . into_usize ( ) ,
15811588 ) ;
1589+ self . vec . len = LenT :: ZERO ;
15821590 ptr:: drop_in_place ( remaining) ;
15831591 }
15841592 }
@@ -1810,7 +1818,7 @@ where
18101818mod tests {
18111819 use core:: fmt:: Write ;
18121820 use std:: {
1813- panic:: catch_unwind,
1821+ panic:: { catch_unwind, AssertUnwindSafe } ,
18141822 sync:: atomic:: { AtomicI32 , Ordering :: Relaxed } ,
18151823 } ;
18161824
@@ -2393,40 +2401,57 @@ mod tests {
23932401 }
23942402 }
23952403
2404+ #[ derive( Debug ) ]
2405+ struct Dropper < ' a > ( & ' a AtomicI32 ) ;
2406+
2407+ impl < ' a > Dropper < ' a > {
2408+ fn new ( count : & ' a AtomicI32 ) -> Self {
2409+ count. fetch_add ( 1 , Relaxed ) ;
2410+ Self ( count)
2411+ }
2412+ }
2413+ impl Drop for Dropper < ' _ > {
2414+ fn drop ( & mut self ) {
2415+ self . 0 . fetch_sub ( 1 , Relaxed ) ;
2416+ panic ! ( "Testing panicking" ) ;
2417+ }
2418+ }
2419+
2420+ // This tests that a panic in a downstream drop implementation does not lead to an
2421+ // inconsistent state during unwinding that could lead to undefined behaviour.
2422+ // For more info see https://github.com/rust-embedded/heapless/issues/659.
23962423 #[ test]
2397- fn test_use_after_free_intoiter_drop ( ) {
2398- // This tests that a panic in a downstream drop implementation does not lead to an
2399- // inconsistent state during unwinding that could lead to undefined behaviour.
2400- // For more info see https://github.com/rust-embedded/heapless/issues/659
2424+ fn test_use_after_free_clear ( ) {
2425+ let count = AtomicI32 :: new ( 0 ) ;
24012426
2402- static COUNT : AtomicI32 = AtomicI32 :: new ( 0 ) ;
2427+ let mut vec = Vec :: < Dropper , 5 > :: new ( ) ;
2428+ vec. push ( Dropper :: new ( & count) ) . unwrap ( ) ;
24032429
2404- #[ derive( Debug ) ]
2405- #[ allow( unused) ]
2406- struct Dropper ( ) ;
2430+ catch_unwind ( AssertUnwindSafe ( || {
2431+ vec. clear ( ) ;
2432+ } ) )
2433+ . unwrap_err ( ) ;
24072434
2408- impl Dropper {
2409- fn new ( ) -> Self {
2410- COUNT . fetch_add ( 1 , Relaxed ) ;
2411- Self ( )
2412- }
2413- fn count ( ) -> i32 {
2414- COUNT . load ( Relaxed )
2415- }
2416- }
2417- impl Drop for Dropper {
2418- fn drop ( & mut self ) {
2419- COUNT . fetch_sub ( 1 , Relaxed ) ;
2420- panic ! ( "Testing panicking" ) ;
2421- }
2422- }
2435+ assert_eq ! ( count. load( Relaxed ) , 0 ) ;
2436+ assert_eq ! ( vec. len( ) , 0 ) ;
2437+ }
2438+
2439+ // This tests that a panic in a downstream drop implementation does not lead to an
2440+ // inconsistent state during unwinding that could lead to undefined behaviour.
2441+ // For more info see https://github.com/rust-embedded/heapless/issues/659.
2442+ #[ test]
2443+ fn test_use_after_free_intoiter_drop ( ) {
2444+ let count = AtomicI32 :: new ( 0 ) ;
24232445
24242446 let mut vec = Vec :: < Dropper , 5 > :: new ( ) ;
2425- vec. push ( Dropper :: new ( ) ) . unwrap ( ) ;
2426- let iterator = vec. into_iter ( ) ;
2447+ vec. push ( Dropper :: new ( & count) ) . unwrap ( ) ;
2448+
2449+ catch_unwind ( move || {
2450+ drop ( vec. into_iter ( ) ) ;
2451+ } )
2452+ . unwrap_err ( ) ;
24272453
2428- catch_unwind ( move || drop ( iterator) ) . unwrap_err ( ) ;
2429- assert_eq ! ( Dropper :: count( ) , 0 ) ;
2454+ assert_eq ! ( count. load( Relaxed ) , 0 ) ;
24302455 }
24312456
24322457 fn _test_variance < ' a : ' b , ' b > ( x : Vec < & ' a ( ) , 42 > ) -> Vec < & ' b ( ) , 42 > {
0 commit comments