@@ -81,7 +81,7 @@ use core::hint::unreachable_unchecked;
81
81
use core:: iter:: { repeat, FromIterator , FusedIterator , IntoIterator } ;
82
82
use core:: mem;
83
83
use core:: mem:: MaybeUninit ;
84
- use core:: ops:: { self , RangeBounds } ;
84
+ use core:: ops:: { self , Range , RangeBounds } ;
85
85
use core:: ptr:: { self , NonNull } ;
86
86
use core:: slice:: { self , SliceIndex } ;
87
87
@@ -865,8 +865,6 @@ impl<A: Array> SmallVec<A> {
865
865
866
866
/// Insert multiple elements at position `index`, shifting all following elements toward the
867
867
/// back.
868
- ///
869
- /// Note: when the iterator panics, this can leak memory.
870
868
pub fn insert_many < I : IntoIterator < Item = A :: Item > > ( & mut self , index : usize , iterable : I ) {
871
869
let iter = iterable. into_iter ( ) ;
872
870
if index == self . len ( ) {
@@ -887,7 +885,12 @@ impl<A: Array> SmallVec<A> {
887
885
ptr:: copy ( ptr, ptr. add ( lower_size_bound) , old_len - index) ;
888
886
889
887
// 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
+ } ;
891
894
892
895
let mut num_added = 0 ;
893
896
for element in iter {
@@ -898,10 +901,17 @@ impl<A: Array> SmallVec<A> {
898
901
ptr = self . as_mut_ptr ( ) . add ( index) ;
899
902
cur = ptr. add ( num_added) ;
900
903
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 ;
901
908
}
902
909
ptr:: write ( cur, element) ;
910
+ guard. skip . start += 1 ;
903
911
num_added += 1 ;
904
912
}
913
+ mem:: forget ( guard) ;
914
+
905
915
if num_added < lower_size_bound {
906
916
// Iterator provided fewer elements than the hint
907
917
ptr:: copy (
@@ -913,6 +923,24 @@ impl<A: Array> SmallVec<A> {
913
923
914
924
self . set_len ( old_len + num_added) ;
915
925
}
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
+ }
916
944
}
917
945
918
946
/// Convert a SmallVec to a Vec, without reallocating if the SmallVec has already spilled onto
@@ -2094,27 +2122,19 @@ mod tests {
2094
2122
}
2095
2123
}
2096
2124
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
-
2102
2125
let mut vec: SmallVec < [ PanicOnDoubleDrop ; 0 ] > = vec ! [
2103
2126
PanicOnDoubleDrop {
2104
- dropped: unsafe { Box :: from_raw ( & mut * box1 ) } ,
2127
+ dropped: Box :: new ( false ) ,
2105
2128
} ,
2106
2129
PanicOnDoubleDrop {
2107
- dropped: unsafe { Box :: from_raw ( & mut * box2 ) } ,
2130
+ dropped: Box :: new ( false ) ,
2108
2131
} ,
2109
2132
]
2110
2133
. into ( ) ;
2111
2134
let result = :: std:: panic:: catch_unwind ( move || {
2112
2135
vec. insert_many ( 0 , BadIter ) ;
2113
2136
} ) ;
2114
2137
assert ! ( result. is_err( ) ) ;
2115
-
2116
- drop ( box1) ;
2117
- drop ( box2) ;
2118
2138
}
2119
2139
2120
2140
#[ test]
0 commit comments