Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix overlapping references in BTree #58431

Merged
merged 2 commits into from
Feb 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 20 additions & 12 deletions src/liballoc/collections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1634,9 +1634,11 @@ impl<'a, K, V> RangeMut<'a, K, V> {

let mut cur_handle = match handle.right_kv() {
Ok(kv) => {
let (k, v) = ptr::read(&kv).into_kv_mut();
self.front = kv.right_edge();
return (k, v);
self.front = ptr::read(&kv).right_edge();
// Doing the descend invalidates the references returned by `into_kv_mut`,
// so we have to do this last.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I struggle with this comment because there's no descend here, right? Maybe the right_edge also invalidates references, or the change is just here to match the code below where a descend happens.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, there's still a call to right_edge so I wanted to be sure that wouldn't cause any problems, without actually checking in detail what that function does. The comment is probably a copy-paste mistake though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've taken the plunge and collapsed the two copies in each iterator in my #66747 PR

let (k, v) = kv.into_kv_mut();
return (k, v); // coerce k from `&mut K` to `&K`
}
Err(last_edge) => {
let next_level = last_edge.into_node().ascend().ok();
Expand All @@ -1647,9 +1649,11 @@ impl<'a, K, V> RangeMut<'a, K, V> {
loop {
match cur_handle.right_kv() {
Ok(kv) => {
let (k, v) = ptr::read(&kv).into_kv_mut();
self.front = first_leaf_edge(kv.right_edge().descend());
return (k, v);
self.front = first_leaf_edge(ptr::read(&kv).right_edge().descend());
// Doing the descend invalidates the references returned by `into_kv_mut`,
// so we have to do this last.
let (k, v) = kv.into_kv_mut();
return (k, v); // coerce k from `&mut K` to `&K`
}
Err(last_edge) => {
let next_level = last_edge.into_node().ascend().ok();
Expand Down Expand Up @@ -1680,9 +1684,11 @@ impl<'a, K, V> RangeMut<'a, K, V> {

let mut cur_handle = match handle.left_kv() {
Ok(kv) => {
let (k, v) = ptr::read(&kv).into_kv_mut();
self.back = kv.left_edge();
return (k, v);
self.back = ptr::read(&kv).left_edge();
// Doing the descend invalidates the references returned by `into_kv_mut`,
// so we have to do this last.
let (k, v) = kv.into_kv_mut();
return (k, v); // coerce k from `&mut K` to `&K`
}
Err(last_edge) => {
let next_level = last_edge.into_node().ascend().ok();
Expand All @@ -1693,9 +1699,11 @@ impl<'a, K, V> RangeMut<'a, K, V> {
loop {
match cur_handle.left_kv() {
Ok(kv) => {
let (k, v) = ptr::read(&kv).into_kv_mut();
self.back = last_leaf_edge(kv.left_edge().descend());
return (k, v);
self.back = last_leaf_edge(ptr::read(&kv).left_edge().descend());
// Doing the descend invalidates the references returned by `into_kv_mut`,
// so we have to do this last.
let (k, v) = kv.into_kv_mut();
return (k, v); // coerce k from `&mut K` to `&K`
}
Err(last_edge) => {
let next_level = last_edge.into_node().ascend().ok();
Expand Down
25 changes: 22 additions & 3 deletions src/liballoc/collections/btree/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,8 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
}

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

fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) {
let k = unsafe { ptr::read(&self) };
(k.into_key_slice_mut(), self.into_val_slice_mut())
fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) {
debug_assert!(!self.is_shared_root());
// We cannot use the getters here, because calling the second one
// invalidates the reference returned by the first.
// More precisely, it is the call to `len` that is the culprit,
// because that creates a shared reference to the header, which *can*
// overlap with the keys (and even the values, for ZST keys).
unsafe {
let len = self.len();
let leaf = self.as_leaf_mut();
let keys = slice::from_raw_parts_mut(
MaybeUninit::first_ptr_mut(&mut (*leaf).keys),
len
);
let vals = slice::from_raw_parts_mut(
MaybeUninit::first_ptr_mut(&mut (*leaf).vals),
len
);
(keys, vals)
}
}
}

Expand Down