@@ -488,23 +488,33 @@ impl<A: Array> SmallVec<A> {
488
488
unsafe {
489
489
let old_len = self . len ;
490
490
assert ! ( index <= old_len) ;
491
- let ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
491
+ let mut ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
492
+
493
+ // Move the trailing elements.
492
494
ptr:: copy ( ptr, ptr. offset ( lower_size_bound as isize ) , old_len - index) ;
493
- for ( off, element) in iter. enumerate ( ) {
494
- if off < lower_size_bound {
495
- ptr:: write ( ptr. offset ( off as isize ) , element) ;
496
- self . len = self . len + 1 ;
497
- } else {
498
- // Iterator provided more elements than the hint.
499
- assert ! ( index + off >= index) ; // Protect against overflow.
500
- self . insert ( index + off, element) ;
495
+
496
+ // In case the iterator panics, don't double-drop the items we just copied above.
497
+ self . set_len ( index) ;
498
+
499
+ let mut num_added = 0 ;
500
+ for element in iter {
501
+ let mut cur = ptr. offset ( num_added as isize ) ;
502
+ if num_added >= lower_size_bound {
503
+ // Iterator provided more elements than the hint. Move trailing items again.
504
+ self . reserve ( 1 ) ;
505
+ ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
506
+ cur = ptr. offset ( num_added as isize ) ;
507
+ ptr:: copy ( cur, cur. offset ( 1 ) , old_len - index) ;
501
508
}
509
+ ptr:: write ( cur, element) ;
510
+ num_added += 1 ;
502
511
}
503
- let num_added = self . len - old_len;
504
512
if num_added < lower_size_bound {
505
513
// Iterator provided fewer elements than the hint
506
514
ptr:: copy ( ptr. offset ( lower_size_bound as isize ) , ptr. offset ( num_added as isize ) , old_len - index) ;
507
515
}
516
+
517
+ self . set_len ( old_len + num_added) ;
508
518
}
509
519
}
510
520
@@ -1153,6 +1163,36 @@ pub mod tests {
1153
1163
assert_eq ! ( & v. iter( ) . map( |v| * v) . collect:: <Vec <_>>( ) , & [ 0 , 5 , 6 , 1 , 2 , 3 ] ) ;
1154
1164
}
1155
1165
1166
+ #[ test]
1167
+ // https://github.com/servo/rust-smallvec/issues/96
1168
+ fn test_insert_many_panic ( ) {
1169
+ struct PanicOnDoubleDrop {
1170
+ dropped : Box < bool >
1171
+ }
1172
+
1173
+ impl Drop for PanicOnDoubleDrop {
1174
+ fn drop ( & mut self ) {
1175
+ assert ! ( !* self . dropped, "already dropped" ) ;
1176
+ * self . dropped = true ;
1177
+ }
1178
+ }
1179
+
1180
+ struct BadIter ;
1181
+ impl Iterator for BadIter {
1182
+ type Item = PanicOnDoubleDrop ;
1183
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) { ( 1 , None ) }
1184
+ fn next ( & mut self ) -> Option < Self :: Item > { panic ! ( ) }
1185
+ }
1186
+
1187
+ let mut vec: SmallVec < [ PanicOnDoubleDrop ; 1 ] > = SmallVec :: new ( ) ;
1188
+ vec. push ( PanicOnDoubleDrop { dropped : Box :: new ( false ) } ) ;
1189
+ vec. push ( PanicOnDoubleDrop { dropped : Box :: new ( false ) } ) ;
1190
+ let result = :: std:: panic:: catch_unwind ( move || {
1191
+ vec. insert_many ( 0 , BadIter ) ;
1192
+ } ) ;
1193
+ assert ! ( result. is_err( ) ) ;
1194
+ }
1195
+
1156
1196
#[ test]
1157
1197
#[ should_panic]
1158
1198
fn test_invalid_grow ( ) {
0 commit comments