-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
BTreeMap: respect pointer provenance rules in split_off #79347
Conversation
I'm pretty sure |
188008d
to
81f72ac
Compare
Let's call the previous pointer-provenance-proofed part of the node.rs API X and the support for X uses completely generic functions like
Y uses a separate set of functions based around
The problem described here is really about the X and Y worlds interfering, so barring there's a way for them to live in harmony, I've committed another fix, that keeps them separate to reduce (future) confusion. |
716e6c3
to
b0f3584
Compare
b0f3584
to
2f39bf3
Compare
Everything uses slices, and they no longer implicitly use node length. Includes #79363. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't yet have time to review all of the changed code -- I think it's mostly trivial changes but wide-spread so will need to just sit down and review. I am a bit worried about the extent of these changes; they don't look quite like a revert of previous provenance PRs but are certainly changing similar code. I am not sure that I feel completely certain of the framework to a sufficient extent to be able to review the code with an eye towards ensuring provenance is respected in these operations, and I'm not sure if miri is currently checking sufficiently that relying on it makes sense.
I am thinking that the extent of the mangling we seem to require based on this (and previous) patches to support the provenance may point to needing a simpler model of provenance or some way to bypass the requirement.
In any case, that is all mostly not relevant for this PR -- just some musings. cc @RalfJung
I will try to review this later today or tomorrow.
@@ -1796,5 +1694,42 @@ unsafe fn slice_remove<T>(slice: &mut [MaybeUninit<T>], idx: usize) -> T { | |||
} | |||
} | |||
|
|||
/// Shifts the slice such that the element at `mid` becomes the first. | |||
/// Is similar to `rotate_left`, but assumes the leading elements are | |||
/// uninitialized and leaves the trailing elements uninitialized. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the comparison to rotate_left is confusing. This does not perform any sort of rotation, it just shifts elements to the left. slice_shift_left might be a more appropriate name, and mid
could be distance
in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I meant it could be implemented using rotate_left
.
/// | ||
/// # Safety | ||
/// The `dest` slice is at least as long as the `source` slice. | ||
unsafe fn slice_move<T>(source: &[MaybeUninit<T>], dest: &mut [MaybeUninit<T>]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we note in the comment here that this is equivalent to copy_from_slice aside from avoiding bounds checking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and aside from not requiring T to be Copy
and not requiring the destination to be the same length.
Well, they do pretty much redo those, more thoroughly.
The extent here is purely because I wanted to get rid of the node length sneaking in left and right, when it only mattered considering pointer provenance. Now the slice length is explicit, used prominently in release code, and
I'll chip off a few layers as separate PRs. That's how I started them anyway, but I had to adjust each layer and threw it all in one bowl. |
2f39bf3
to
6080b0b
Compare
That's not entirely true. The node length snuck in a bit deeper because of the initial attempt at pointer provenance proofing. The issue pointer provenance stumbled over, here and in previous PRs, is that the destination of ptr::copy_nonoverlapping didn't seem big enough. Initially that was because that destination didn't bother to figure out a size and just got a single pointer. Later, as in this PR, pointer provenance complained because it got the wrong size. In hindsight, I think the latter (i.e. what's currently is master) is worse, because it confuses human readers of the code too. With this PR, a debug_assert checks the destination size much earlier, before Miri comes along or before you need to debug a buffer write overrun. Also, using the same slice API for source and destination, I think it's actually quite easy to supply an accurate size, it helps readers, and I doubt it costs a penny in release builds. So, I think we end up with more readable and more maintainable code.
I do agree that I doubt everyone sees it that way, or is prepared to invest in more defensive code. It might help adoption if there's a separate option that doesn't sound the alarm if it sees something like |
Yeah, I am worried about what this entire experience of making BTree compatible with Stacked Borrows says about Stacked Borrows. Once the next aliasing model proposal is on the table, we should evaluate it against some older versions of BTree to check if that model would have declared less UB here, and thus required fewer changes. FWIW, there is a way to bypass provenance -- just use raw pointers everywhere. But there cannot be a way to bypass provenance when references are being used, as that would subvert the entire point of the aliasing model: if we cannot rely on all aliases of a reference following the rules, then we might a swell have no rules since at that point they are just pointless. To be fair, I also think that part of the problem is that this code here was written without giving much thought to conforming with a potential aliasing model of Rust. Sure, no concrete model existed, but it is curious that BTree seems to have way more issues than any other code in the standard library. |
Miri with |
☔ The latest upstream changes (presumably #79988) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
f0ed9ac
to
f8d47fa
Compare
f8d47fa
to
8824efd
Compare
@bors r+ rollup=never |
📌 Commit 8824efd has been approved by |
☀️ Test successful - checks-actions |
The test cases for
split_off
reported a few more violations (now that they support -Zmiri-track-raw-pointers). The functionsshift_kv
andshift_edges
do not fix anything, I think, but ifmove_kv
andmove_edges
exist, they deserve to live too.r? @Mark-Simulacrum