@@ -2762,26 +2762,17 @@ impl<T, F> Iterator for DrainFilter<'_, T, F>
2762
2762
type Item = T ;
2763
2763
2764
2764
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
-
2776
2765
unsafe {
2777
2766
while self . idx < self . old_len {
2778
2767
let i = self . idx ;
2779
2768
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 } ;
2781
2769
self . panic_flag = true ;
2782
2770
let drained = ( self . pred ) ( & mut v[ i] ) ;
2783
2771
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 ;
2785
2776
if drained {
2786
2777
self . del += 1 ;
2787
2778
return Some ( ptr:: read ( & v[ i] ) ) ;
@@ -2806,9 +2797,6 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
2806
2797
where F : FnMut ( & mut T ) -> bool ,
2807
2798
{
2808
2799
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.
2812
2800
struct BackshiftOnDrop < ' a , ' b , T , F >
2813
2801
where
2814
2802
F : FnMut ( & mut T ) -> bool ,
@@ -2822,6 +2810,12 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
2822
2810
{
2823
2811
fn drop ( & mut self ) {
2824
2812
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.
2825
2819
while self . drain . idx < self . drain . old_len {
2826
2820
let i = self . drain . idx ;
2827
2821
self . drain . idx += 1 ;
@@ -2845,6 +2839,9 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
2845
2839
drain : self
2846
2840
} ;
2847
2841
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.
2848
2845
if !backshift. drain . panic_flag {
2849
2846
backshift. drain . for_each ( drop) ;
2850
2847
}
0 commit comments