Skip to content

Commit d87df69

Browse files
committed
fix overlapping mutable and shared references in BTreeMap's into_slices_mut
1 parent e544947 commit d87df69

File tree

1 file changed

+22
-3
lines changed
  • src/liballoc/collections/btree

1 file changed

+22
-3
lines changed

src/liballoc/collections/btree/node.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,8 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
645645
}
646646

647647
fn into_key_slice_mut(mut self) -> &'a mut [K] {
648+
// Same as for `into_key_slice` above, we try to avoid a run-time check
649+
// (the alignment comparison will usually be performed at compile-time).
648650
if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
649651
&mut []
650652
} else {
@@ -667,9 +669,26 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
667669
}
668670
}
669671

670-
fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) {
671-
let k = unsafe { ptr::read(&self) };
672-
(k.into_key_slice_mut(), self.into_val_slice_mut())
672+
fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) {
673+
debug_assert!(!self.is_shared_root());
674+
// We cannot use the getters here, because calling the second one
675+
// invalidates the reference returned by the first.
676+
// More precisely, it is the call to `len` that is the culprit,
677+
// because that creates a shared reference to the header, which *can*
678+
// overlap with the keys.
679+
unsafe {
680+
let len = self.len();
681+
let leaf = self.as_leaf_mut();
682+
let keys = slice::from_raw_parts_mut(
683+
MaybeUninit::first_ptr_mut(&mut (*leaf).keys),
684+
len
685+
);
686+
let vals = slice::from_raw_parts_mut(
687+
MaybeUninit::first_ptr_mut(&mut (*leaf).vals),
688+
len
689+
);
690+
(keys, vals)
691+
}
673692
}
674693
}
675694

0 commit comments

Comments
 (0)