about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-03-08 10:51:46 +0000
committerbors <bors@rust-lang.org>2020-03-08 10:51:46 +0000
commit1d5241c96208ca7d925442b1a5fa45ad18717a6f (patch)
tree3405a2f3f23004a2e1df12fdc22b589b5731b816 /src/liballoc
parentf943349eafaa75a60c05b0c84dcdb771d0eae8c9 (diff)
parent49c82d117084ad0362fee6fb9a524400c1140ce7 (diff)
downloadrust-1d5241c96208ca7d925442b1a5fa45ad18717a6f.tar.gz
rust-1d5241c96208ca7d925442b1a5fa45ad18717a6f.zip
Auto merge of #69822 - Centril:rollup-360ca2j, r=Centril
Rollup of 8 pull requests

Successful merges:

 - #69422 (Remove use of `unwrap()` from save-analysis)
 - #69548 (Turn trailing tokens in `assert!()` into hard errors)
 - #69561 (Clean up unstable book)
 - #69599 (check_binding_alt_eq_ty: improve precision wrt. `if let`)
 - #69641 (Update books)
 - #69776 (Fix & test leak of some BTreeMap nodes on panic during `into_iter`)
 - #69805 (resolve: Modernize some naming)
 - #69810 (test(bindings_after_at): add dynamic drop tests for bindings_after_at)

Failed merges:

r? @ghost
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/collections/btree/map.rs11
-rw-r--r--src/liballoc/tests/btree/map.rs26
2 files changed, 35 insertions, 2 deletions
diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs
index 8b9ffdfb49b..9da324ba2d4 100644
--- a/src/liballoc/collections/btree/map.rs
+++ b/src/liballoc/collections/btree/map.rs
@@ -1477,6 +1477,14 @@ impl<K, V> Drop for IntoIter<K, V> {
                 // Continue the same loop we perform below. This only runs when unwinding, so we
                 // don't have to care about panics this time (they'll abort).
                 while let Some(_) = self.0.next() {}
+
+                // No need to avoid the shared root, because the tree was definitely not empty.
+                unsafe {
+                    let mut node = ptr::read(&self.0.front).into_node().forget_type();
+                    while let Some(parent) = node.deallocate_and_ascend() {
+                        node = parent.into_node().forget_type();
+                    }
+                }
             }
         }
 
@@ -1491,7 +1499,8 @@ impl<K, V> Drop for IntoIter<K, V> {
             if node.is_shared_root() {
                 return;
             }
-
+            // Most of the nodes have been deallocated while traversing
+            // but one pile from a leaf up to the root is left standing.
             while let Some(parent) = node.deallocate_and_ascend() {
                 node = parent.into_node().forget_type();
             }
diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs
index fd07a4d3926..d05eec19346 100644
--- a/src/liballoc/tests/btree/map.rs
+++ b/src/liballoc/tests/btree/map.rs
@@ -1021,7 +1021,7 @@ fn test_split_off_large_random_sorted() {
 }
 
 #[test]
-fn test_into_iter_drop_leak() {
+fn test_into_iter_drop_leak_1() {
     static DROPS: AtomicU32 = AtomicU32::new(0);
 
     struct D;
@@ -1045,3 +1045,27 @@ fn test_into_iter_drop_leak() {
 
     assert_eq!(DROPS.load(Ordering::SeqCst), 5);
 }
+
+#[test]
+fn test_into_iter_drop_leak_2() {
+    let size = 12; // to obtain tree with 2 levels (having edges to leaf nodes)
+    static DROPS: AtomicU32 = AtomicU32::new(0);
+    static PANIC_POINT: AtomicU32 = AtomicU32::new(0);
+
+    struct D;
+    impl Drop for D {
+        fn drop(&mut self) {
+            if DROPS.fetch_add(1, Ordering::SeqCst) == PANIC_POINT.load(Ordering::SeqCst) {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    for panic_point in vec![0, 1, size - 2, size - 1] {
+        DROPS.store(0, Ordering::SeqCst);
+        PANIC_POINT.store(panic_point, Ordering::SeqCst);
+        let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect();
+        catch_unwind(move || drop(map.into_iter())).ok();
+        assert_eq!(DROPS.load(Ordering::SeqCst), size);
+    }
+}