@@ -81,7 +81,7 @@ use core::hint::unreachable_unchecked;
8181use core:: iter:: { repeat, FromIterator , FusedIterator , IntoIterator } ;
8282use core:: mem;
8383use core:: mem:: MaybeUninit ;
84- use core:: ops:: { self , RangeBounds } ;
84+ use core:: ops:: { self , Range , RangeBounds } ;
8585use core:: ptr:: { self , NonNull } ;
8686use core:: slice:: { self , SliceIndex } ;
8787
@@ -865,8 +865,6 @@ impl<A: Array> SmallVec<A> {
865865
866866 /// Insert multiple elements at position `index`, shifting all following elements toward the
867867 /// back.
868- ///
869- /// Note: when the iterator panics, this can leak memory.
870868 pub fn insert_many < I : IntoIterator < Item = A :: Item > > ( & mut self , index : usize , iterable : I ) {
871869 let iter = iterable. into_iter ( ) ;
872870 if index == self . len ( ) {
@@ -887,7 +885,12 @@ impl<A: Array> SmallVec<A> {
887885 ptr:: copy ( ptr, ptr. add ( lower_size_bound) , old_len - index) ;
888886
889887 // In case the iterator panics, don't double-drop the items we just copied above.
890- self . set_len ( index) ;
888+ self . set_len ( 0 ) ;
889+ let mut guard = DropOnPanic {
890+ ptr : self . as_mut_ptr ( ) ,
891+ skip : index..lower_size_bound,
892+ len : old_len + lower_size_bound,
893+ } ;
891894
892895 let mut num_added = 0 ;
893896 for element in iter {
@@ -898,10 +901,17 @@ impl<A: Array> SmallVec<A> {
898901 ptr = self . as_mut_ptr ( ) . add ( index) ;
899902 cur = ptr. add ( num_added) ;
900903 ptr:: copy ( cur, cur. add ( 1 ) , old_len - index) ;
904+
905+ guard. ptr = self . as_mut_ptr ( ) ;
906+ guard. len += 1 ;
907+ guard. skip . end += 1 ;
901908 }
902909 ptr:: write ( cur, element) ;
910+ guard. skip . start += 1 ;
903911 num_added += 1 ;
904912 }
913+ mem:: forget ( guard) ;
914+
905915 if num_added < lower_size_bound {
906916 // Iterator provided fewer elements than the hint
907917 ptr:: copy (
@@ -913,6 +923,24 @@ impl<A: Array> SmallVec<A> {
913923
914924 self . set_len ( old_len + num_added) ;
915925 }
926+
927+ struct DropOnPanic < T > {
928+ ptr : * mut T ,
929+ len : usize ,
930+ skip : Range < usize > ,
931+ }
932+
933+ impl < T > Drop for DropOnPanic < T > {
934+ fn drop ( & mut self ) {
935+ for i in 0 ..self . len {
936+ if !self . skip . contains ( & i) {
937+ unsafe {
938+ ptr:: drop_in_place ( self . ptr . add ( i) ) ;
939+ }
940+ }
941+ }
942+ }
943+ }
916944 }
917945
918946 /// Convert a SmallVec to a Vec, without reallocating if the SmallVec has already spilled onto
@@ -2094,27 +2122,19 @@ mod tests {
20942122 }
20952123 }
20962124
2097- // These boxes are leaked on purpose by panicking `insert_many`,
2098- // so we clean them up manually to appease Miri's leak checker.
2099- let mut box1 = Box :: new ( false ) ;
2100- let mut box2 = Box :: new ( false ) ;
2101-
21022125 let mut vec: SmallVec < [ PanicOnDoubleDrop ; 0 ] > = vec ! [
21032126 PanicOnDoubleDrop {
2104- dropped: unsafe { Box :: from_raw ( & mut * box1 ) } ,
2127+ dropped: Box :: new ( false ) ,
21052128 } ,
21062129 PanicOnDoubleDrop {
2107- dropped: unsafe { Box :: from_raw ( & mut * box2 ) } ,
2130+ dropped: Box :: new ( false ) ,
21082131 } ,
21092132 ]
21102133 . into ( ) ;
21112134 let result = :: std:: panic:: catch_unwind ( move || {
21122135 vec. insert_many ( 0 , BadIter ) ;
21132136 } ) ;
21142137 assert ! ( result. is_err( ) ) ;
2115-
2116- drop ( box1) ;
2117- drop ( box2) ;
21182138 }
21192139
21202140 #[ test]
0 commit comments