Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit dc49245

Browse files
Fix leak in btree_map::IntoIter when drop panics
1 parent 5d04790 commit dc49245

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

src/liballoc/collections/btree/map.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1381,7 +1381,22 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
13811381
#[stable(feature = "btree_drop", since = "1.7.0")]
13821382
impl<K, V> Drop for IntoIter<K, V> {
13831383
fn drop(&mut self) {
1384-
self.for_each(drop);
1384+
struct DropGuard<'a, K, V>(&'a mut IntoIter<K, V>);
1385+
1386+
impl<'a, K, V> Drop for DropGuard<'a, K, V> {
1387+
fn drop(&mut self) {
1388+
// Continue the same loop we perform below. This only runs when unwinding, so we
1389+
// don't have to care about panics this time (they'll abort).
1390+
while let Some(_) = self.0.next() {}
1391+
}
1392+
}
1393+
1394+
while let Some(pair) = self.next() {
1395+
let guard = DropGuard(self);
1396+
drop(pair);
1397+
mem::forget(guard);
1398+
}
1399+
13851400
unsafe {
13861401
let leaf_node = ptr::read(&self.front).into_node();
13871402
if leaf_node.is_shared_root() {

src/liballoc/tests/btree/map.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use std::fmt::Debug;
55
use std::iter::FromIterator;
66
use std::ops::Bound::{self, Excluded, Included, Unbounded};
77
use std::ops::RangeBounds;
8+
use std::panic::catch_unwind;
89
use std::rc::Rc;
10+
use std::sync::atomic::{AtomicU32, Ordering};
911

1012
use super::DeterministicRng;
1113

@@ -980,3 +982,29 @@ fn test_split_off_large_random_sorted() {
980982
assert!(map.into_iter().eq(data.clone().into_iter().filter(|x| x.0 < key)));
981983
assert!(right.into_iter().eq(data.into_iter().filter(|x| x.0 >= key)));
982984
}
985+
986+
#[test]
987+
fn test_into_iter_drop_leak() {
988+
static DROPS: AtomicU32 = AtomicU32::new(0);
989+
990+
struct D;
991+
992+
impl Drop for D {
993+
fn drop(&mut self) {
994+
if DROPS.fetch_add(1, Ordering::SeqCst) == 3 {
995+
panic!("panic in `drop`");
996+
}
997+
}
998+
}
999+
1000+
let mut map = BTreeMap::new();
1001+
map.insert("a", D);
1002+
map.insert("b", D);
1003+
map.insert("c", D);
1004+
map.insert("d", D);
1005+
map.insert("e", D);
1006+
1007+
catch_unwind(move || drop(map.into_iter())).ok();
1008+
1009+
assert_eq!(DROPS.load(Ordering::SeqCst), 5);
1010+
}

0 commit comments

Comments
 (0)