Skip to content

Commit 0ae16b4

Browse files
Avoid leak in DrainFilter when a drop panics
1 parent 163ed23 commit 0ae16b4

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

src/liballoc/collections/linked_list.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1565,7 +1565,21 @@ where
15651565
F: FnMut(&mut T) -> bool,
15661566
{
15671567
fn drop(&mut self) {
1568-
self.for_each(drop);
1568+
struct DropGuard<'r, 'a, T, F>(&'r mut DrainFilter<'a, T, F>)
1569+
where F: FnMut(&mut T) -> bool;
1570+
1571+
impl<'r, 'a, T, F> Drop for DropGuard<'r, 'a, T, F>
1572+
where F: FnMut(&mut T) -> bool {
1573+
fn drop(&mut self) {
1574+
self.0.for_each(drop);
1575+
}
1576+
}
1577+
1578+
while let Some(item) = self.next() {
1579+
let guard = DropGuard(self);
1580+
drop(item);
1581+
mem::forget(guard);
1582+
}
15691583
}
15701584
}
15711585

src/liballoc/tests/linked_list.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::collections::LinkedList;
2-
use std::panic::catch_unwind;
2+
use std::panic::{catch_unwind, AssertUnwindSafe};
33

44
#[test]
55
fn test_basic() {
@@ -531,6 +531,40 @@ fn drain_filter_complex() {
531531
}
532532
}
533533

534+
#[test]
535+
fn drain_filter_drop_panic_leak() {
536+
static mut DROPS: i32 = 0;
537+
538+
struct D(bool);
539+
540+
impl Drop for D {
541+
fn drop(&mut self) {
542+
unsafe {
543+
DROPS += 1;
544+
}
545+
546+
if self.0 {
547+
panic!("panic in `drop`");
548+
}
549+
}
550+
}
551+
552+
let mut q = LinkedList::new();
553+
q.push_back(D(false));
554+
q.push_back(D(false));
555+
q.push_back(D(false));
556+
q.push_back(D(false));
557+
q.push_back(D(false));
558+
q.push_front(D(false));
559+
q.push_front(D(true));
560+
q.push_front(D(false));
561+
562+
catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok();
563+
564+
assert_eq!(unsafe { DROPS }, 8);
565+
assert!(q.is_empty());
566+
}
567+
534568
#[test]
535569
fn test_drop() {
536570
static mut DROPS: i32 = 0;

0 commit comments

Comments
 (0)