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