@@ -2762,26 +2762,17 @@ impl<T, F> Iterator for DrainFilter<'_, T, F>
27622762 type Item = T ;
27632763
27642764 fn next ( & mut self ) -> Option < T > {
2765- struct SetIdxOnDrop < ' a > {
2766- idx : & ' a mut usize ,
2767- new_idx : usize ,
2768- }
2769-
2770- impl < ' a > Drop for SetIdxOnDrop < ' a > {
2771- fn drop ( & mut self ) {
2772- * self . idx = self . new_idx ;
2773- }
2774- }
2775-
27762765 unsafe {
27772766 while self . idx < self . old_len {
27782767 let i = self . idx ;
27792768 let v = slice:: from_raw_parts_mut ( self . vec . as_mut_ptr ( ) , self . old_len ) ;
2780- let mut set_idx = SetIdxOnDrop { new_idx : self . idx , idx : & mut self . idx } ;
27812769 self . panic_flag = true ;
27822770 let drained = ( self . pred ) ( & mut v[ i] ) ;
27832771 self . panic_flag = false ;
2784- set_idx. new_idx += 1 ;
2772+ // Update the index *after* the predicate is called. If the index
2773+ // is updated prior and the predicate panics, the element at this
2774+ // index would be leaked.
2775+ self . idx += 1 ;
27852776 if drained {
27862777 self . del += 1 ;
27872778 return Some ( ptr:: read ( & v[ i] ) ) ;
@@ -2806,9 +2797,6 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
28062797 where F : FnMut ( & mut T ) -> bool ,
28072798{
28082799 fn drop ( & mut self ) {
2809- // If the predicate panics, we still need to backshift everything
2810- // down after the last successfully drained element, but no additional
2811- // elements are drained or checked.
28122800 struct BackshiftOnDrop < ' a , ' b , T , F >
28132801 where
28142802 F : FnMut ( & mut T ) -> bool ,
@@ -2822,6 +2810,12 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
28222810 {
28232811 fn drop ( & mut self ) {
28242812 unsafe {
2813+ // Backshift any unprocessed elements, preventing double-drop
2814+ // of any element that *should* have been previously overwritten
2815+ // but was not due to a panic in the filter predicate. This is
2816+ // implemented via drop so that it's guaranteed to run even in
2817+ // the event of a panic while consuming the remainder of the
2818+ // DrainFilter.
28252819 while self . drain . idx < self . drain . old_len {
28262820 let i = self . drain . idx ;
28272821 self . drain . idx += 1 ;
@@ -2845,6 +2839,9 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
28452839 drain : self
28462840 } ;
28472841
2842+ // Attempt to consume any remaining elements if the filter predicate
2843+ // has not yet panicked. We'll backshift any remaining elements
2844+ // whether we've already panicked or if the consumption here panics.
28482845 if !backshift. drain . panic_flag {
28492846 backshift. drain . for_each ( drop) ;
28502847 }
0 commit comments