@@ -607,23 +607,33 @@ impl<A: Array> SmallVec<A> {
607
607
unsafe {
608
608
let old_len = self . len ;
609
609
assert ! ( index <= old_len) ;
610
- let ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
610
+ let mut ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
611
+
612
+ // Move the trailing elements.
611
613
ptr:: copy ( ptr, ptr. offset ( lower_size_bound as isize ) , old_len - index) ;
612
- for ( off, element) in iter. enumerate ( ) {
613
- if off < lower_size_bound {
614
- ptr:: write ( ptr. offset ( off as isize ) , element) ;
615
- self . len = self . len + 1 ;
616
- } else {
617
- // Iterator provided more elements than the hint.
618
- assert ! ( index + off >= index) ; // Protect against overflow.
619
- self . insert ( index + off, element) ;
614
+
615
+ // In case the iterator panics, don't double-drop the items we just copied above.
616
+ self . set_len ( index) ;
617
+
618
+ let mut num_added = 0 ;
619
+ for element in iter {
620
+ let mut cur = ptr. offset ( num_added as isize ) ;
621
+ if num_added >= lower_size_bound {
622
+ // Iterator provided more elements than the hint. Move trailing items again.
623
+ self . reserve ( 1 ) ;
624
+ ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
625
+ cur = ptr. offset ( num_added as isize ) ;
626
+ ptr:: copy ( cur, cur. offset ( 1 ) , old_len - index) ;
620
627
}
628
+ ptr:: write ( cur, element) ;
629
+ num_added += 1 ;
621
630
}
622
- let num_added = self . len - old_len;
623
631
if num_added < lower_size_bound {
624
632
// Iterator provided fewer elements than the hint
625
633
ptr:: copy ( ptr. offset ( lower_size_bound as isize ) , ptr. offset ( num_added as isize ) , old_len - index) ;
626
634
}
635
+
636
+ self . set_len ( old_len + num_added) ;
627
637
}
628
638
}
629
639
@@ -1388,6 +1398,36 @@ pub mod tests {
1388
1398
assert_eq ! ( & v. iter( ) . map( |v| * v) . collect:: <Vec <_>>( ) , & [ 0 , 5 , 6 , 1 , 2 , 3 ] ) ;
1389
1399
}
1390
1400
1401
+ #[ test]
1402
+ // https://github.com/servo/rust-smallvec/issues/96
1403
+ fn test_insert_many_panic ( ) {
1404
+ struct PanicOnDoubleDrop {
1405
+ dropped : Box < bool >
1406
+ }
1407
+
1408
+ impl Drop for PanicOnDoubleDrop {
1409
+ fn drop ( & mut self ) {
1410
+ assert ! ( !* self . dropped, "already dropped" ) ;
1411
+ * self . dropped = true ;
1412
+ }
1413
+ }
1414
+
1415
+ struct BadIter ;
1416
+ impl Iterator for BadIter {
1417
+ type Item = PanicOnDoubleDrop ;
1418
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) { ( 1 , None ) }
1419
+ fn next ( & mut self ) -> Option < Self :: Item > { panic ! ( ) }
1420
+ }
1421
+
1422
+ let mut vec: SmallVec < [ PanicOnDoubleDrop ; 1 ] > = SmallVec :: new ( ) ;
1423
+ vec. push ( PanicOnDoubleDrop { dropped : Box :: new ( false ) } ) ;
1424
+ vec. push ( PanicOnDoubleDrop { dropped : Box :: new ( false ) } ) ;
1425
+ let result = :: std:: panic:: catch_unwind ( move || {
1426
+ vec. insert_many ( 0 , BadIter ) ;
1427
+ } ) ;
1428
+ assert ! ( result. is_err( ) ) ;
1429
+ }
1430
+
1391
1431
#[ test]
1392
1432
#[ should_panic]
1393
1433
fn test_invalid_grow ( ) {
0 commit comments