Skip to content

Commit 08bd977

Browse files
committed
BTreeMap: Don't leak allocators when initializing nodes
Memory was allocated via `Box::leak` and thence intended to be tracked and deallocated manually, but the allocator was also leaked, not tracked, and never dropped. Now it is dropped immediately. According to my reading of the `Allocator` trait, if a copy of the allocator remains live, then its allocations must remain live. Since the B-tree has a copy of the allocator that will only be dropped after the nodes, it's safe to not store the allocator in each node (which would be a much more intrusive change).
1 parent 1d23da6 commit 08bd977

File tree

1 file changed

+8
-2
lines changed
  • library/alloc/src/collections/btree

1 file changed

+8
-2
lines changed

library/alloc/src/collections/btree/node.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,10 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
224224
}
225225

226226
fn from_new_leaf<A: Allocator + Clone>(leaf: Box<LeafNode<K, V>, A>) -> Self {
227-
NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData }
227+
let (leaf, _alloc) = Box::into_raw_with_allocator(leaf);
228+
// SAFETY: the node was just allocated.
229+
let node = unsafe { NonNull::new_unchecked(leaf) };
230+
NodeRef { height: 0, node, _marker: PhantomData }
228231
}
229232
}
230233

@@ -242,7 +245,10 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
242245
height: usize,
243246
) -> Self {
244247
debug_assert!(height > 0);
245-
let node = NonNull::from(Box::leak(internal)).cast();
248+
let (internal, _alloc) = Box::into_raw_with_allocator(internal);
249+
// SAFETY: the node was just allocated.
250+
let internal = unsafe { NonNull::new_unchecked(internal) };
251+
let node = internal.cast();
246252
let mut this = NodeRef { height, node, _marker: PhantomData };
247253
this.borrow_mut().correct_all_childrens_parent_links();
248254
this

0 commit comments

Comments
 (0)