Skip to content

Commit 04136f6

Browse files
authored
Unrolled build for #146859
Rollup merge of #146859 - cammeresi:btree-alloc-20250920, r=joboet 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). Fixes: #106203
2 parents eabf390 + 137d4ea commit 04136f6

File tree

2 files changed

+13
-2
lines changed

2 files changed

+13
-2
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ pub struct BTreeMap<
194194
root: Option<Root<K, V>>,
195195
length: usize,
196196
/// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes).
197+
// Although some of the accessory types store a copy of the allocator, the nodes do not.
198+
// Because allocations will remain live as long as any copy (like this one) of the allocator
199+
// is live, it's unnecessary to store the allocator in each node.
197200
pub(super) alloc: ManuallyDrop<A>,
198201
// For dropck; the `Box` avoids making the `Unpin` impl more strict than before
199202
_marker: PhantomData<crate::boxed::Box<(K, V), A>>,

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

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

227227
fn from_new_leaf<A: Allocator + Clone>(leaf: Box<LeafNode<K, V>, A>) -> Self {
228-
NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData }
228+
// The allocator must be dropped, not leaked. See also `BTreeMap::alloc`.
229+
let (leaf, _alloc) = Box::into_raw_with_allocator(leaf);
230+
// SAFETY: the node was just allocated.
231+
let node = unsafe { NonNull::new_unchecked(leaf) };
232+
NodeRef { height: 0, node, _marker: PhantomData }
229233
}
230234
}
231235

@@ -243,7 +247,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
243247
height: usize,
244248
) -> Self {
245249
debug_assert!(height > 0);
246-
let node = NonNull::from(Box::leak(internal)).cast();
250+
// The allocator must be dropped, not leaked. See also `BTreeMap::alloc`.
251+
let (internal, _alloc) = Box::into_raw_with_allocator(internal);
252+
// SAFETY: the node was just allocated.
253+
let internal = unsafe { NonNull::new_unchecked(internal) };
254+
let node = internal.cast();
247255
let mut this = NodeRef { height, node, _marker: PhantomData };
248256
this.borrow_mut().correct_all_childrens_parent_links();
249257
this

0 commit comments

Comments
 (0)