Skip to content

Commit 958e8b7

Browse files
authored
Rollup merge of rust-lang#69776 - ssomers:fix69769, r=Mark-Simulacrum
Fix & test leak of some BTreeMap nodes on panic during `into_iter` Fixes rust-lang#69769
2 parents aa8aeaa + 44c97c4 commit 958e8b7

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

src/liballoc/collections/btree/map.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,14 @@ impl<K, V> Drop for IntoIter<K, V> {
14771477
// Continue the same loop we perform below. This only runs when unwinding, so we
14781478
// don't have to care about panics this time (they'll abort).
14791479
while let Some(_) = self.0.next() {}
1480+
1481+
// No need to avoid the shared root, because the tree was definitely not empty.
1482+
unsafe {
1483+
let mut node = ptr::read(&self.0.front).into_node().forget_type();
1484+
while let Some(parent) = node.deallocate_and_ascend() {
1485+
node = parent.into_node().forget_type();
1486+
}
1487+
}
14801488
}
14811489
}
14821490

@@ -1491,7 +1499,8 @@ impl<K, V> Drop for IntoIter<K, V> {
14911499
if node.is_shared_root() {
14921500
return;
14931501
}
1494-
1502+
// Most of the nodes have been deallocated while traversing
1503+
// but one pile from a leaf up to the root is left standing.
14951504
while let Some(parent) = node.deallocate_and_ascend() {
14961505
node = parent.into_node().forget_type();
14971506
}

src/liballoc/tests/btree/map.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ fn test_split_off_large_random_sorted() {
10211021
}
10221022

10231023
#[test]
1024-
fn test_into_iter_drop_leak() {
1024+
fn test_into_iter_drop_leak_1() {
10251025
static DROPS: AtomicU32 = AtomicU32::new(0);
10261026

10271027
struct D;
@@ -1045,3 +1045,27 @@ fn test_into_iter_drop_leak() {
10451045

10461046
assert_eq!(DROPS.load(Ordering::SeqCst), 5);
10471047
}
1048+
1049+
#[test]
1050+
fn test_into_iter_drop_leak_2() {
1051+
let size = 12; // to obtain tree with 2 levels (having edges to leaf nodes)
1052+
static DROPS: AtomicU32 = AtomicU32::new(0);
1053+
static PANIC_POINT: AtomicU32 = AtomicU32::new(0);
1054+
1055+
struct D;
1056+
impl Drop for D {
1057+
fn drop(&mut self) {
1058+
if DROPS.fetch_add(1, Ordering::SeqCst) == PANIC_POINT.load(Ordering::SeqCst) {
1059+
panic!("panic in `drop`");
1060+
}
1061+
}
1062+
}
1063+
1064+
for panic_point in vec![0, 1, size - 2, size - 1] {
1065+
DROPS.store(0, Ordering::SeqCst);
1066+
PANIC_POINT.store(panic_point, Ordering::SeqCst);
1067+
let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect();
1068+
catch_unwind(move || drop(map.into_iter())).ok();
1069+
assert_eq!(DROPS.load(Ordering::SeqCst), size);
1070+
}
1071+
}

0 commit comments

Comments
 (0)