Skip to content

Commit fd34606

Browse files
committed
Auto merge of rust-lang#80391 - ssomers:btree_cleanup_slices_3, r=Mark-Simulacrum
BTreeMap: tougher checking on most uses of copy_nonoverlapping Miri checks pointer provenance and destination, but we can check it in debug builds already. Also, we can let Miri confirm we don't mistake imprints of moved keys and values as genuine. r? `@Mark-Simulacrum`
2 parents 34628e5 + 26b9462 commit fd34606

File tree

1 file changed

+32
-26
lines changed
  • library/alloc/src/collections/btree

1 file changed

+32
-26
lines changed

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

+32-26
Original file line numberDiff line numberDiff line change
@@ -1124,21 +1124,20 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>
11241124
/// by taking care of leaf data.
11251125
fn split_leaf_data(&mut self, new_node: &mut LeafNode<K, V>) -> (K, V) {
11261126
debug_assert!(self.idx < self.node.len());
1127-
let new_len = self.node.len() - self.idx - 1;
1127+
let old_len = self.node.len();
1128+
let new_len = old_len - self.idx - 1;
11281129
new_node.len = new_len as u16;
11291130
unsafe {
11301131
let k = self.node.key_area_mut(self.idx).assume_init_read();
11311132
let v = self.node.val_area_mut(self.idx).assume_init_read();
11321133

1133-
ptr::copy_nonoverlapping(
1134-
self.node.key_area_mut(self.idx + 1..).as_ptr(),
1135-
new_node.keys.as_mut_ptr(),
1136-
new_len,
1134+
move_to_slice(
1135+
self.node.key_area_mut(self.idx + 1..old_len),
1136+
&mut new_node.keys[..new_len],
11371137
);
1138-
ptr::copy_nonoverlapping(
1139-
self.node.val_area_mut(self.idx + 1..).as_ptr(),
1140-
new_node.vals.as_mut_ptr(),
1141-
new_len,
1138+
move_to_slice(
1139+
self.node.val_area_mut(self.idx + 1..old_len),
1140+
&mut new_node.vals[..new_len],
11421141
);
11431142

11441143
*self.node.len_mut() = self.idx as u16;
@@ -1190,20 +1189,20 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
11901189
/// - All the edges and key-value pairs to the right of this handle are put into
11911190
/// a newly allocated node.
11921191
pub fn split(mut self) -> SplitResult<'a, K, V, marker::Internal> {
1192+
let old_len = self.node.len();
11931193
unsafe {
11941194
let mut new_node = Box::new(InternalNode::new());
11951195
let kv = self.split_leaf_data(&mut new_node.data);
11961196
let new_len = usize::from(new_node.data.len);
1197-
ptr::copy_nonoverlapping(
1198-
self.node.edge_area_mut(self.idx + 1..).as_ptr(),
1199-
new_node.edges.as_mut_ptr(),
1200-
new_len + 1,
1197+
move_to_slice(
1198+
self.node.edge_area_mut(self.idx + 1..old_len + 1),
1199+
&mut new_node.edges[..new_len + 1],
12011200
);
12021201

12031202
let height = self.node.height;
12041203
let mut right = NodeRef::from_new_internal(new_node, height);
12051204

1206-
right.borrow_mut().correct_childrens_parent_links(0..=new_len);
1205+
right.borrow_mut().correct_childrens_parent_links(0..new_len + 1);
12071206

12081207
SplitResult { left: self.node, kv, right }
12091208
}
@@ -1323,18 +1322,16 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
13231322

13241323
let parent_key = slice_remove(parent_node.key_area_mut(..old_parent_len), parent_idx);
13251324
left_node.key_area_mut(old_left_len).write(parent_key);
1326-
ptr::copy_nonoverlapping(
1327-
right_node.key_area_mut(..).as_ptr(),
1328-
left_node.key_area_mut(old_left_len + 1..).as_mut_ptr(),
1329-
right_len,
1325+
move_to_slice(
1326+
right_node.key_area_mut(..right_len),
1327+
left_node.key_area_mut(old_left_len + 1..new_left_len),
13301328
);
13311329

13321330
let parent_val = slice_remove(parent_node.val_area_mut(..old_parent_len), parent_idx);
13331331
left_node.val_area_mut(old_left_len).write(parent_val);
1334-
ptr::copy_nonoverlapping(
1335-
right_node.val_area_mut(..).as_ptr(),
1336-
left_node.val_area_mut(old_left_len + 1..).as_mut_ptr(),
1337-
right_len,
1332+
move_to_slice(
1333+
right_node.val_area_mut(..right_len),
1334+
left_node.val_area_mut(old_left_len + 1..new_left_len),
13381335
);
13391336

13401337
slice_remove(&mut parent_node.edge_area_mut(..old_parent_len + 1), parent_idx + 1);
@@ -1346,10 +1343,9 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> {
13461343
// of the node of this edge, thus above zero, so they are internal.
13471344
let mut left_node = left_node.reborrow_mut().cast_to_internal_unchecked();
13481345
let mut right_node = right_node.cast_to_internal_unchecked();
1349-
ptr::copy_nonoverlapping(
1350-
right_node.edge_area_mut(..).as_ptr(),
1351-
left_node.edge_area_mut(old_left_len + 1..).as_mut_ptr(),
1352-
right_len + 1,
1346+
move_to_slice(
1347+
right_node.edge_area_mut(..right_len + 1),
1348+
left_node.edge_area_mut(old_left_len + 1..new_left_len + 1),
13531349
);
13541350

13551351
left_node.correct_childrens_parent_links(old_left_len + 1..new_left_len + 1);
@@ -1741,5 +1737,15 @@ unsafe fn slice_remove<T>(slice: &mut [MaybeUninit<T>], idx: usize) -> T {
17411737
}
17421738
}
17431739

1740+
/// Moves all values from a slice of initialized elements to a slice
1741+
/// of uninitialized elements, leaving behind `src` as all uninitialized.
1742+
/// Works like `dst.copy_from_slice(src)` but does not require `T` to be `Copy`.
1743+
fn move_to_slice<T>(src: &mut [MaybeUninit<T>], dst: &mut [MaybeUninit<T>]) {
1744+
assert!(src.len() == dst.len());
1745+
unsafe {
1746+
ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len());
1747+
}
1748+
}
1749+
17441750
#[cfg(test)]
17451751
mod tests;

0 commit comments

Comments
 (0)