@@ -771,24 +771,33 @@ impl<A: Array> SmallVec<A> {
771
771
unsafe {
772
772
let old_len = self . len ( ) ;
773
773
assert ! ( index <= old_len) ;
774
- let ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
774
+ let mut ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
775
+
776
+ // Move the trailing elements.
775
777
ptr:: copy ( ptr, ptr. offset ( lower_size_bound as isize ) , old_len - index) ;
776
- for ( off, element) in iter. enumerate ( ) {
777
- if off < lower_size_bound {
778
- ptr:: write ( ptr. offset ( off as isize ) , element) ;
779
- let len = self . len ( ) + 1 ;
780
- self . set_len ( len) ;
781
- } else {
782
- // Iterator provided more elements than the hint.
783
- assert ! ( index + off >= index) ; // Protect against overflow.
784
- self . insert ( index + off, element) ;
778
+
779
+ // In case the iterator panics, don't double-drop the items we just copied above.
780
+ self . set_len ( index) ;
781
+
782
+ let mut num_added = 0 ;
783
+ for element in iter {
784
+ let mut cur = ptr. offset ( num_added as isize ) ;
785
+ if num_added >= lower_size_bound {
786
+ // Iterator provided more elements than the hint. Move trailing items again.
787
+ self . reserve ( 1 ) ;
788
+ ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
789
+ cur = ptr. offset ( num_added as isize ) ;
790
+ ptr:: copy ( cur, cur. offset ( 1 ) , old_len - index) ;
785
791
}
792
+ ptr:: write ( cur, element) ;
793
+ num_added += 1 ;
786
794
}
787
- let num_added = self . len ( ) - old_len;
788
795
if num_added < lower_size_bound {
789
796
// Iterator provided fewer elements than the hint
790
797
ptr:: copy ( ptr. offset ( lower_size_bound as isize ) , ptr. offset ( num_added as isize ) , old_len - index) ;
791
798
}
799
+
800
+ self . set_len ( old_len + num_added) ;
792
801
}
793
802
}
794
803
@@ -1645,6 +1654,37 @@ mod tests {
1645
1654
assert_eq ! ( & v. iter( ) . map( |v| * v) . collect:: <Vec <_>>( ) , & [ 0 , 5 , 6 , 1 , 2 , 3 ] ) ;
1646
1655
}
1647
1656
1657
+ #[ test]
1658
+ // https://github.com/servo/rust-smallvec/issues/96
1659
+ fn test_insert_many_panic ( ) {
1660
+ struct PanicOnDoubleDrop {
1661
+ dropped : Box < bool >
1662
+ }
1663
+
1664
+ impl Drop for PanicOnDoubleDrop {
1665
+ fn drop ( & mut self ) {
1666
+ assert ! ( !* self . dropped, "already dropped" ) ;
1667
+ * self . dropped = true ;
1668
+ }
1669
+ }
1670
+
1671
+ struct BadIter ;
1672
+ impl Iterator for BadIter {
1673
+ type Item = PanicOnDoubleDrop ;
1674
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) { ( 1 , None ) }
1675
+ fn next ( & mut self ) -> Option < Self :: Item > { panic ! ( ) }
1676
+ }
1677
+
1678
+ let mut vec: SmallVec < [ PanicOnDoubleDrop ; 0 ] > = vec ! [
1679
+ PanicOnDoubleDrop { dropped: Box :: new( false ) } ,
1680
+ PanicOnDoubleDrop { dropped: Box :: new( false ) } ,
1681
+ ] . into ( ) ;
1682
+ let result = :: std:: panic:: catch_unwind ( move || {
1683
+ vec. insert_many ( 0 , BadIter ) ;
1684
+ } ) ;
1685
+ assert ! ( result. is_err( ) ) ;
1686
+ }
1687
+
1648
1688
#[ test]
1649
1689
#[ should_panic]
1650
1690
fn test_invalid_grow ( ) {
0 commit comments