Skip to content

Commit 5e32da1

Browse files
LinkedList: drop remaining items when drop panics
1 parent 27d6f55 commit 5e32da1

File tree

2 files changed

+122
-1
lines changed

2 files changed

+122
-1
lines changed

src/liballoc/collections/linked_list.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,21 @@ impl<T> LinkedList<T> {
808808
#[stable(feature = "rust1", since = "1.0.0")]
809809
unsafe impl<#[may_dangle] T> Drop for LinkedList<T> {
810810
fn drop(&mut self) {
811-
while let Some(_) = self.pop_front_node() {}
811+
struct DropGuard<'a, T>(&'a mut LinkedList<T>);
812+
813+
impl<'a, T> Drop for DropGuard<'a, T> {
814+
fn drop(&mut self) {
815+
// Continue the same loop we do below. This only runs when a destructor has
816+
// panicked. If another one panics this will abort.
817+
while let Some(_) = self.0.pop_front_node() {}
818+
}
819+
}
820+
821+
while let Some(node) = self.pop_front_node() {
822+
let guard = DropGuard(self);
823+
drop(node);
824+
mem::forget(guard);
825+
}
812826
}
813827
}
814828

src/liballoc/tests/linked_list.rs

+107
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::LinkedList;
2+
use std::panic::catch_unwind;
23

34
#[test]
45
fn test_basic() {
@@ -529,3 +530,109 @@ fn drain_filter_complex() {
529530
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
530531
}
531532
}
533+
534+
535+
#[test]
536+
fn test_drop() {
537+
static mut DROPS: i32 = 0;
538+
struct Elem;
539+
impl Drop for Elem {
540+
fn drop(&mut self) {
541+
unsafe {
542+
DROPS += 1;
543+
}
544+
}
545+
}
546+
547+
let mut ring = LinkedList::new();
548+
ring.push_back(Elem);
549+
ring.push_front(Elem);
550+
ring.push_back(Elem);
551+
ring.push_front(Elem);
552+
drop(ring);
553+
554+
assert_eq!(unsafe { DROPS }, 4);
555+
}
556+
557+
#[test]
558+
fn test_drop_with_pop() {
559+
static mut DROPS: i32 = 0;
560+
struct Elem;
561+
impl Drop for Elem {
562+
fn drop(&mut self) {
563+
unsafe {
564+
DROPS += 1;
565+
}
566+
}
567+
}
568+
569+
let mut ring = LinkedList::new();
570+
ring.push_back(Elem);
571+
ring.push_front(Elem);
572+
ring.push_back(Elem);
573+
ring.push_front(Elem);
574+
575+
drop(ring.pop_back());
576+
drop(ring.pop_front());
577+
assert_eq!(unsafe { DROPS }, 2);
578+
579+
drop(ring);
580+
assert_eq!(unsafe { DROPS }, 4);
581+
}
582+
583+
#[test]
584+
fn test_drop_clear() {
585+
static mut DROPS: i32 = 0;
586+
struct Elem;
587+
impl Drop for Elem {
588+
fn drop(&mut self) {
589+
unsafe {
590+
DROPS += 1;
591+
}
592+
}
593+
}
594+
595+
let mut ring = LinkedList::new();
596+
ring.push_back(Elem);
597+
ring.push_front(Elem);
598+
ring.push_back(Elem);
599+
ring.push_front(Elem);
600+
ring.clear();
601+
assert_eq!(unsafe { DROPS }, 4);
602+
603+
drop(ring);
604+
assert_eq!(unsafe { DROPS }, 4);
605+
}
606+
607+
#[test]
608+
fn test_drop_panic() {
609+
static mut DROPS: i32 = 0;
610+
611+
struct D(bool);
612+
613+
impl Drop for D {
614+
fn drop(&mut self) {
615+
unsafe {
616+
DROPS += 1;
617+
}
618+
619+
if self.0 {
620+
panic!("panic in `drop`");
621+
}
622+
}
623+
}
624+
625+
let mut q = LinkedList::new();
626+
q.push_back(D(false));
627+
q.push_back(D(false));
628+
q.push_back(D(false));
629+
q.push_back(D(false));
630+
q.push_back(D(false));
631+
q.push_front(D(false));
632+
q.push_front(D(false));
633+
q.push_front(D(true));
634+
635+
catch_unwind(move || drop(q)).ok();
636+
637+
assert_eq!(unsafe { DROPS }, 8);
638+
}

0 commit comments

Comments
 (0)