@@ -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 ( ) {
@@ -881,27 +879,41 @@ impl<A: Array> SmallVec<A> {
881
879
unsafe {
882
880
let old_len = self . len ( ) ;
883
881
assert ! ( index <= old_len) ;
884
- let mut ptr = self . as_mut_ptr ( ) . add ( index) ;
882
+ let start = self . as_mut_ptr ( ) ;
883
+ let mut ptr = start. add ( index) ;
885
884
886
885
// Move the trailing elements.
887
886
ptr:: copy ( ptr, ptr. add ( lower_size_bound) , old_len - index) ;
888
887
889
888
// In case the iterator panics, don't double-drop the items we just copied above.
890
- self . set_len ( index) ;
889
+ self . set_len ( 0 ) ;
890
+ let mut guard = DropOnPanic {
891
+ start,
892
+ skip : index..lower_size_bound,
893
+ len : old_len + lower_size_bound,
894
+ } ;
891
895
892
896
let mut num_added = 0 ;
893
897
for element in iter {
894
898
let mut cur = ptr. add ( num_added) ;
895
899
if num_added >= lower_size_bound {
896
900
// Iterator provided more elements than the hint. Move trailing items again.
897
901
self . reserve ( 1 ) ;
898
- ptr = self . as_mut_ptr ( ) . add ( index) ;
902
+ let start = self . as_mut_ptr ( ) ;
903
+ ptr = start. add ( index) ;
899
904
cur = ptr. add ( num_added) ;
900
905
ptr:: copy ( cur, cur. add ( 1 ) , old_len - index) ;
906
+
907
+ guard. start = start;
908
+ guard. len += 1 ;
909
+ guard. skip . end += 1 ;
901
910
}
902
911
ptr:: write ( cur, element) ;
912
+ guard. skip . start += 1 ;
903
913
num_added += 1 ;
904
914
}
915
+ mem:: forget ( guard) ;
916
+
905
917
if num_added < lower_size_bound {
906
918
// Iterator provided fewer elements than the hint
907
919
ptr:: copy (
@@ -913,6 +925,24 @@ impl<A: Array> SmallVec<A> {
913
925
914
926
self . set_len ( old_len + num_added) ;
915
927
}
928
+
929
+ struct DropOnPanic < T > {
930
+ start : * mut T ,
931
+ skip : Range < usize > ,
932
+ len : usize ,
933
+ }
934
+
935
+ impl < T > Drop for DropOnPanic < T > {
936
+ fn drop ( & mut self ) {
937
+ for i in 0 ..self . len {
938
+ if !self . skip . contains ( & i) {
939
+ unsafe {
940
+ ptr:: drop_in_place ( self . start . add ( i) ) ;
941
+ }
942
+ }
943
+ }
944
+ }
945
+ }
916
946
}
917
947
918
948
/// Convert a SmallVec to a Vec, without reallocating if the SmallVec has already spilled onto
@@ -1097,6 +1127,22 @@ impl<A: Array> SmallVec<A> {
1097
1127
data : SmallVecData :: from_heap ( ptr, length) ,
1098
1128
}
1099
1129
}
1130
+
1131
+ /// Returns a raw pointer to the vector's buffer.
1132
+ pub fn as_ptr ( & self ) -> * const A :: Item {
1133
+ // We shadow the slice method of the same name to avoid going through
1134
+ // `deref`, which creates an intermediate reference that may place
1135
+ // additional safety constraints on the contents of the slice.
1136
+ self . triple ( ) . 0
1137
+ }
1138
+
1139
+ /// Returns a raw mutable pointer to the vector's buffer.
1140
+ pub fn as_mut_ptr ( & mut self ) -> * mut A :: Item {
1141
+ // We shadow the slice method of the same name to avoid going through
1142
+ // `deref_mut`, which creates an intermediate reference that may place
1143
+ // additional safety constraints on the contents of the slice.
1144
+ self . triple_mut ( ) . 0
1145
+ }
1100
1146
}
1101
1147
1102
1148
impl < A : Array > SmallVec < A >
@@ -2094,27 +2140,19 @@ mod tests {
2094
2140
}
2095
2141
}
2096
2142
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
2143
let mut vec: SmallVec < [ PanicOnDoubleDrop ; 0 ] > = vec ! [
2103
2144
PanicOnDoubleDrop {
2104
- dropped: unsafe { Box :: from_raw ( & mut * box1 ) } ,
2145
+ dropped: Box :: new ( false ) ,
2105
2146
} ,
2106
2147
PanicOnDoubleDrop {
2107
- dropped: unsafe { Box :: from_raw ( & mut * box2 ) } ,
2148
+ dropped: Box :: new ( false ) ,
2108
2149
} ,
2109
2150
]
2110
2151
. into ( ) ;
2111
2152
let result = :: std:: panic:: catch_unwind ( move || {
2112
2153
vec. insert_many ( 0 , BadIter ) ;
2113
2154
} ) ;
2114
2155
assert ! ( result. is_err( ) ) ;
2115
-
2116
- drop ( box1) ;
2117
- drop ( box2) ;
2118
2156
}
2119
2157
2120
2158
#[ test]
0 commit comments