@@ -771,24 +771,33 @@ impl<A: Array> SmallVec<A> {
771771 unsafe {
772772 let old_len = self . len ( ) ;
773773 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.
775777 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) ;
785791 }
792+ ptr:: write ( cur, element) ;
793+ num_added += 1 ;
786794 }
787- let num_added = self . len ( ) - old_len;
788795 if num_added < lower_size_bound {
789796 // Iterator provided fewer elements than the hint
790797 ptr:: copy ( ptr. offset ( lower_size_bound as isize ) , ptr. offset ( num_added as isize ) , old_len - index) ;
791798 }
799+
800+ self . set_len ( old_len + num_added) ;
792801 }
793802 }
794803
@@ -1645,6 +1654,37 @@ mod tests {
16451654 assert_eq ! ( & v. iter( ) . map( |v| * v) . collect:: <Vec <_>>( ) , & [ 0 , 5 , 6 , 1 , 2 , 3 ] ) ;
16461655 }
16471656
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+
16481688 #[ test]
16491689 #[ should_panic]
16501690 fn test_invalid_grow ( ) {
0 commit comments