Skip to content

Commit d92155b

Browse files
committed
Auto merge of #73971 - ssomers:slice_slasher, r=Mark-Simulacrum
BTreeMap mutable iterators should not take any reference to visited nodes during iteration Fixes #73915, overlapping mutable references during BTreeMap iteration r? `@RalfJung`
2 parents b4bdc07 + 8158d56 commit d92155b

File tree

6 files changed

+206
-164
lines changed

6 files changed

+206
-164
lines changed

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -2796,8 +2796,8 @@ enum UnderflowResult<'a, K, V> {
27962796
Stole(bool),
27972797
}
27982798

2799-
fn handle_underfull_node<K, V>(
2800-
node: NodeRef<marker::Mut<'_>, K, V, marker::LeafOrInternal>,
2799+
fn handle_underfull_node<'a, K: 'a, V: 'a>(
2800+
node: NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>,
28012801
) -> UnderflowResult<'_, K, V> {
28022802
let parent = match node.ascend() {
28032803
Ok(parent) => parent,

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

+9-6
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
7777
let min_len = if is_root { 0 } else { node::MIN_LEN };
7878
assert!(node.len() >= min_len, "{} < {}", node.len(), min_len);
7979

80-
for &key in node.keys() {
80+
for idx in 0..node.len() {
81+
let key = *unsafe { node.key_at(idx) };
8182
checker.is_ascending(key);
8283
}
8384
leaf_length += node.len();
@@ -120,7 +121,13 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
120121
Position::Leaf(leaf) => {
121122
let depth = root_node.height();
122123
let indent = " ".repeat(depth);
123-
result += &format!("\n{}{:?}", indent, leaf.keys())
124+
result += &format!("\n{}", indent);
125+
for idx in 0..leaf.len() {
126+
if idx > 0 {
127+
result += ", ";
128+
}
129+
result += &format!("{:?}", unsafe { leaf.key_at(idx) });
130+
}
124131
}
125132
Position::Internal(_) => {}
126133
Position::InternalKV(kv) => {
@@ -432,7 +439,6 @@ fn test_iter_mut_mutation() {
432439
}
433440

434441
#[test]
435-
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
436442
fn test_values_mut() {
437443
let mut a: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)).collect();
438444
test_all_refs(&mut 13, a.values_mut());
@@ -455,7 +461,6 @@ fn test_values_mut_mutation() {
455461
}
456462

457463
#[test]
458-
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
459464
fn test_iter_entering_root_twice() {
460465
let mut map: BTreeMap<_, _> = (0..2).map(|i| (i, i)).collect();
461466
let mut it = map.iter_mut();
@@ -471,7 +476,6 @@ fn test_iter_entering_root_twice() {
471476
}
472477

473478
#[test]
474-
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
475479
fn test_iter_descending_to_same_node_twice() {
476480
let mut map: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)).collect();
477481
let mut it = map.iter_mut();
@@ -515,7 +519,6 @@ fn test_iter_mixed() {
515519
}
516520

517521
#[test]
518-
#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
519522
fn test_iter_min_max() {
520523
let mut a = BTreeMap::new();
521524
assert_eq!(a.iter().min(), None);

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

+2-6
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,6 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed
366366
impl<'a, K, V> Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge> {
367367
/// Moves the leaf edge handle to the next leaf edge and returns references to the
368368
/// key and value in between.
369-
/// The returned references might be invalidated when the updated handle is used again.
370369
///
371370
/// # Safety
372371
/// There must be another KV in the direction travelled.
@@ -376,14 +375,12 @@ impl<'a, K, V> Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::E
376375
let kv = unsafe { unwrap_unchecked(kv.ok()) };
377376
(unsafe { ptr::read(&kv) }.next_leaf_edge(), kv)
378377
});
379-
// Doing the descend (and perhaps another move) invalidates the references
380-
// returned by `into_kv_valmut`, so we have to do this last.
378+
// Doing this last is faster, according to benchmarks.
381379
kv.into_kv_valmut()
382380
}
383381

384382
/// Moves the leaf edge handle to the previous leaf and returns references to the
385383
/// key and value in between.
386-
/// The returned references might be invalidated when the updated handle is used again.
387384
///
388385
/// # Safety
389386
/// There must be another KV in the direction travelled.
@@ -393,8 +390,7 @@ impl<'a, K, V> Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::E
393390
let kv = unsafe { unwrap_unchecked(kv.ok()) };
394391
(unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv)
395392
});
396-
// Doing the descend (and perhaps another move) invalidates the references
397-
// returned by `into_kv_valmut`, so we have to do this last.
393+
// Doing this last is faster, according to benchmarks.
398394
kv.into_kv_valmut()
399395
}
400396
}

0 commit comments

Comments
 (0)