@@ -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
@@ -937,19 +946,17 @@ impl<A: Array> SmallVec<A> where A::Item: Clone {
937
946
if n > A :: size ( ) {
938
947
vec ! [ elem; n] . into ( )
939
948
} else {
949
+ let mut v = SmallVec :: < A > :: new ( ) ;
940
950
unsafe {
941
- let mut arr : A = :: std :: mem :: uninitialized ( ) ;
942
- let ptr = arr . ptr_mut ( ) ;
951
+ let ( ptr , len_ptr , _ ) = v . triple_mut ( ) ;
952
+ let mut local_len = SetLenOnDrop :: new ( len_ptr ) ;
943
953
944
954
for i in 0 ..n as isize {
945
955
:: std:: ptr:: write ( ptr. offset ( i) , elem. clone ( ) ) ;
946
- }
947
-
948
- SmallVec {
949
- capacity : n,
950
- data : SmallVecData :: from_inline ( arr) ,
956
+ local_len. increment_len ( 1 ) ;
951
957
}
952
958
}
959
+ v
953
960
}
954
961
}
955
962
}
@@ -1337,6 +1344,33 @@ pub unsafe trait Array {
1337
1344
fn ptr_mut ( & mut self ) -> * mut Self :: Item ;
1338
1345
}
1339
1346
1347
+ /// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
1348
+ ///
1349
+ /// Copied from https://github.com/rust-lang/rust/pull/36355
1350
+ struct SetLenOnDrop < ' a > {
1351
+ len : & ' a mut usize ,
1352
+ local_len : usize ,
1353
+ }
1354
+
1355
+ impl < ' a > SetLenOnDrop < ' a > {
1356
+ #[ inline]
1357
+ fn new ( len : & ' a mut usize ) -> Self {
1358
+ SetLenOnDrop { local_len : * len, len : len }
1359
+ }
1360
+
1361
+ #[ inline]
1362
+ fn increment_len ( & mut self , increment : usize ) {
1363
+ self . local_len += increment;
1364
+ }
1365
+ }
1366
+
1367
+ impl < ' a > Drop for SetLenOnDrop < ' a > {
1368
+ #[ inline]
1369
+ fn drop ( & mut self ) {
1370
+ * self . len = self . local_len ;
1371
+ }
1372
+ }
1373
+
1340
1374
macro_rules! impl_array(
1341
1375
( $( $size: expr) ,+) => {
1342
1376
$(
@@ -1645,6 +1679,37 @@ mod tests {
1645
1679
assert_eq ! ( & v. iter( ) . map( |v| * v) . collect:: <Vec <_>>( ) , & [ 0 , 5 , 6 , 1 , 2 , 3 ] ) ;
1646
1680
}
1647
1681
1682
+ #[ test]
1683
+ // https://github.com/servo/rust-smallvec/issues/96
1684
+ fn test_insert_many_panic ( ) {
1685
+ struct PanicOnDoubleDrop {
1686
+ dropped : Box < bool >
1687
+ }
1688
+
1689
+ impl Drop for PanicOnDoubleDrop {
1690
+ fn drop ( & mut self ) {
1691
+ assert ! ( !* self . dropped, "already dropped" ) ;
1692
+ * self . dropped = true ;
1693
+ }
1694
+ }
1695
+
1696
+ struct BadIter ;
1697
+ impl Iterator for BadIter {
1698
+ type Item = PanicOnDoubleDrop ;
1699
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) { ( 1 , None ) }
1700
+ fn next ( & mut self ) -> Option < Self :: Item > { panic ! ( ) }
1701
+ }
1702
+
1703
+ let mut vec: SmallVec < [ PanicOnDoubleDrop ; 0 ] > = vec ! [
1704
+ PanicOnDoubleDrop { dropped: Box :: new( false ) } ,
1705
+ PanicOnDoubleDrop { dropped: Box :: new( false ) } ,
1706
+ ] . into ( ) ;
1707
+ let result = :: std:: panic:: catch_unwind ( move || {
1708
+ vec. insert_many ( 0 , BadIter ) ;
1709
+ } ) ;
1710
+ assert ! ( result. is_err( ) ) ;
1711
+ }
1712
+
1648
1713
#[ test]
1649
1714
#[ should_panic]
1650
1715
fn test_invalid_grow ( ) {
0 commit comments