Avoid leak in DrainFilter when a drop panics
This commit is contained in:
parent
163ed23f00
commit
0ae16b47ff
@ -1565,7 +1565,21 @@ impl<T, F> Drop for DrainFilter<'_, T, F>
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.for_each(drop);
|
||||
struct DropGuard<'r, 'a, T, F>(&'r mut DrainFilter<'a, T, F>)
|
||||
where F: FnMut(&mut T) -> bool;
|
||||
|
||||
impl<'r, 'a, T, F> Drop for DropGuard<'r, 'a, T, F>
|
||||
where F: FnMut(&mut T) -> bool {
|
||||
fn drop(&mut self) {
|
||||
self.0.for_each(drop);
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(item) = self.next() {
|
||||
let guard = DropGuard(self);
|
||||
drop(item);
|
||||
mem::forget(guard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::collections::LinkedList;
|
||||
use std::panic::catch_unwind;
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
@ -531,6 +531,40 @@ fn drain_filter_complex() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_filter_drop_panic_leak() {
|
||||
static mut DROPS: i32 = 0;
|
||||
|
||||
struct D(bool);
|
||||
|
||||
impl Drop for D {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROPS += 1;
|
||||
}
|
||||
|
||||
if self.0 {
|
||||
panic!("panic in `drop`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut q = LinkedList::new();
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_front(D(false));
|
||||
q.push_front(D(true));
|
||||
q.push_front(D(false));
|
||||
|
||||
catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok();
|
||||
|
||||
assert_eq!(unsafe { DROPS }, 8);
|
||||
assert!(q.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drop() {
|
||||
static mut DROPS: i32 = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user