@@ -488,23 +488,33 @@ impl<A: Array> SmallVec<A> {
488488 unsafe {
489489 let old_len = self . len ;
490490 assert ! ( index <= old_len) ;
491- let ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
491+ let mut ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
492+
493+ // Move the trailing elements.
492494 ptr:: copy ( ptr, ptr. offset ( lower_size_bound as isize ) , old_len - index) ;
493- for ( off, element) in iter. enumerate ( ) {
494- if off < lower_size_bound {
495- ptr:: write ( ptr. offset ( off as isize ) , element) ;
496- self . len = self . len + 1 ;
497- } else {
498- // Iterator provided more elements than the hint.
499- assert ! ( index + off >= index) ; // Protect against overflow.
500- self . insert ( index + off, element) ;
495+
496+ // In case the iterator panics, don't double-drop the items we just copied above.
497+ self . set_len ( index) ;
498+
499+ let mut num_added = 0 ;
500+ for element in iter {
501+ let mut cur = ptr. offset ( num_added as isize ) ;
502+ if num_added >= lower_size_bound {
503+ // Iterator provided more elements than the hint. Move trailing items again.
504+ self . reserve ( 1 ) ;
505+ ptr = self . as_mut_ptr ( ) . offset ( index as isize ) ;
506+ cur = ptr. offset ( num_added as isize ) ;
507+ ptr:: copy ( cur, cur. offset ( 1 ) , old_len - index) ;
501508 }
509+ ptr:: write ( cur, element) ;
510+ num_added += 1 ;
502511 }
503- let num_added = self . len - old_len;
504512 if num_added < lower_size_bound {
505513 // Iterator provided fewer elements than the hint
506514 ptr:: copy ( ptr. offset ( lower_size_bound as isize ) , ptr. offset ( num_added as isize ) , old_len - index) ;
507515 }
516+
517+ self . set_len ( old_len + num_added) ;
508518 }
509519 }
510520
@@ -1153,6 +1163,36 @@ pub mod tests {
11531163 assert_eq ! ( & v. iter( ) . map( |v| * v) . collect:: <Vec <_>>( ) , & [ 0 , 5 , 6 , 1 , 2 , 3 ] ) ;
11541164 }
11551165
1166+ #[ test]
1167+ // https://github.com/servo/rust-smallvec/issues/96
1168+ fn test_insert_many_panic ( ) {
1169+ struct PanicOnDoubleDrop {
1170+ dropped : Box < bool >
1171+ }
1172+
1173+ impl Drop for PanicOnDoubleDrop {
1174+ fn drop ( & mut self ) {
1175+ assert ! ( !* self . dropped, "already dropped" ) ;
1176+ * self . dropped = true ;
1177+ }
1178+ }
1179+
1180+ struct BadIter ;
1181+ impl Iterator for BadIter {
1182+ type Item = PanicOnDoubleDrop ;
1183+ fn size_hint ( & self ) -> ( usize , Option < usize > ) { ( 1 , None ) }
1184+ fn next ( & mut self ) -> Option < Self :: Item > { panic ! ( ) }
1185+ }
1186+
1187+ let mut vec: SmallVec < [ PanicOnDoubleDrop ; 1 ] > = SmallVec :: new ( ) ;
1188+ vec. push ( PanicOnDoubleDrop { dropped : Box :: new ( false ) } ) ;
1189+ vec. push ( PanicOnDoubleDrop { dropped : Box :: new ( false ) } ) ;
1190+ let result = :: std:: panic:: catch_unwind ( move || {
1191+ vec. insert_many ( 0 , BadIter ) ;
1192+ } ) ;
1193+ assert ! ( result. is_err( ) ) ;
1194+ }
1195+
11561196 #[ test]
11571197 #[ should_panic]
11581198 fn test_invalid_grow ( ) {
0 commit comments