Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upVecDeque: fix for stacked borrows #56161
Conversation
rust-highfive
assigned
KodrAus
Nov 22, 2018
This comment has been minimized.
This comment has been minimized.
|
r? @KodrAus (rust_highfive has picked a reviewer for you, use r? to override) |
rust-highfive
added
the
S-waiting-on-review
label
Nov 22, 2018
gnzlbg
reviewed
Nov 22, 2018
This comment has been minimized.
This comment has been minimized.
|
Turns out just not using a mutable buffer, as suggested by @gnzlbg, is enough :) |
This comment has been minimized.
This comment has been minimized.
|
Since this is super tricky stuff, it would be awesome if the PR description was updated to correspond to the final state of the PR . |
This comment has been minimized.
This comment has been minimized.
|
@bluss Good point, done. |
bluss
reviewed
Nov 24, 2018
| @@ -2808,14 +2808,14 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> { | |||
| #[unstable(feature = "ptr_internals", issue = "0")] | |||
| impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> { | |||
| fn from(reference: &'a mut T) -> Self { | |||
| Unique { pointer: NonZero(reference as _), _marker: PhantomData } | |||
| Unique { pointer: NonZero(reference as *mut T as *const T), _marker: PhantomData } | |||
This comment has been minimized.
This comment has been minimized.
bluss
Nov 24, 2018
•
Contributor
If I understand you correctly, the _ here was filled in with &'a T, and that's no good?
This comment has been minimized.
This comment has been minimized.
RalfJung
Nov 24, 2018
Author
Member
Yes.
Ideally we could make it infer *mut T for the _, that would be the safer choice.
RalfJung
force-pushed the
RalfJung:vecdeque-stacked-borrows
branch
from
3a3502d
to
8223fc1
Dec 1, 2018
This comment has been minimized.
This comment has been minimized.
|
Rebased (because I want to test this together with #56165) |
This was referenced Dec 2, 2018
This comment was marked as resolved.
This comment was marked as resolved.
|
|
RalfJung
added some commits
Nov 22, 2018
RalfJung
force-pushed the
RalfJung:vecdeque-stacked-borrows
branch
from
8223fc1
to
feb775c
Dec 7, 2018
This comment has been minimized.
This comment has been minimized.
|
This PR is now awaiting review for 12 days. Ping @KodrAus |
This comment has been minimized.
This comment has been minimized.
|
r? me |
This comment has been minimized.
This comment has been minimized.
|
r? @gnzlbg |
This comment has been minimized.
This comment has been minimized.
|
These are really subtle rules, and I’m worried about what this means for This combination feels very dangerous:
|
This comment has been minimized.
This comment has been minimized.
|
I think I feel strongly enough about this that I’m opposed to landing this PR as-is. Making soundness rely on the non-existence of a shared reference is not acceptable IMO as long as such a shared reference can be created "invisibly" like this. |
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin I am not sure that I understand your argument correctly. Are you arguing that it is easy to assert immutability accidentally and therefore introduce undefined behavior ? If so, I agree. But this code was doing so explicitly with There are a couple of ideas being floated around about how to prevent "asserting immutability by accident" (e.g. making |
This comment has been minimized.
This comment has been minimized.
|
Yes, this is what I’m arguing. We have here a combination of three things:
It’s only with all three combined that there’s a problem. So we can fix the problem in any of three ways: A. Not accepting this proposed model I am opposed to doing only C. because that doen’t help with other potential instances of the same problem. This is made worse by 2. being, in my opinion, very unexpected. I claim to be fairly proficient at Rust, and I had no idea this was happening. So I think we should fix |
This comment has been minimized.
This comment has been minimized.
From my understanding, this was an explicit design goal from the start. Cc @eddyb @Gankro @nikomatsakis Not doing this kills a lot of useful optimizations, because it means that creating a shared reference gives license to anyone to mutate data (until a barrier is added). In particular, the change I am making here is a necessary requirement to ever solve #16515 for shared references.
This was one of the first rules I ever learned about mutability in Rust: Though shall not mutate through shared references. Of course this has to include raw pointers created from shared references, otherwise the rule is useless (the compiler syntactically prevents direct assignment to a shared reference). This rule is the reason we have
That, I think, is a problem. We should change the coercion logic to only coerce to The reason I would like to land this PR is that it is needed to move forward with experimenting with this model in miri. I do not see this as acknowledgement that these will ultimately be the rules. But as long as a core data structure like When I previously talked about this with @nikomatsakis, he was open to changing the coercion rules in principle, but also said that coercion is a mess and in its current state maybe should not be touched, but rewritten. This PR is a way forward for experimentation with miri that is not blocked on fixing coercion. But I absolutely agree that we should block accepting this model and exploiting it in the compiler on fixing coercions. I am not sure what would be the best place to track this. |
This comment has been minimized.
This comment has been minimized.
|
So is the problem here that
I hope/suspect "rewritten" here doesn't mean just rewriting the |
This comment has been minimized.
This comment has been minimized.
The problem is that coercion chains are not atomic. I have no idea what |
This comment has been minimized.
This comment has been minimized.
|
FWIW, I'm fine to changing this to |
This comment has been minimized.
This comment has been minimized.
|
Are |
This comment has been minimized.
This comment has been minimized.
Same here, except I didn't even know that it used to be a single type. Alas, too late. @eddyb I think the relevant code is rust/src/librustc_typeck/check/coercion.rs Lines 734 to 752 in f504d3f any hint what I'd have to change there to make it not create a shared reference, but instead two casts? Or do we just want to allow direct cast from |
This comment has been minimized.
This comment has been minimized.
That's what we want, yes. |
This comment has been minimized.
This comment has been minimized.
|
I opened #56604 for the coercion problem, let's continue the discussion there. |
RalfJung
referenced this pull request
Dec 7, 2018
Open
Coercing &mut to *const should not create a shared reference #56604
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin Beyond the issue above, I have added a not-yet-working test with a FIXME to miri and recorded this in the "missing validation tracking issue" at rust-lang/miri#551. Is that enough to remedy your concerns about this change?
I could change miri to be less strict about the "writing through raw pointers obtained from shared references" rule, but it seems strange to accept code that we definitely know we do not want to accept. |
This comment has been minimized.
This comment has been minimized.
Turns out that Still, seems likely that other code (besides |
RalfJung
referenced this pull request
Dec 9, 2018
Open
RFC for an operator to take a raw reference #2582
This comment has been minimized.
This comment has been minimized.
Ok, landing this PR to unblock other work sounds acceptable, with the understanding that it is not "the" way to fix this kind of unsoundess (#56604 is) and that unsafe code outside of std does not need to be audited for this pattern. |
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin As a process note (not an opinion on #56604 or rust-lang/rfcs#2582), such an understanding depends on consensus within T-lang; Since this is a soundness fix, we should just land it with a |
This comment has been minimized.
This comment has been minimized.
|
It’s not actually a soundness fix since nothing in codegen relies on the model this code violates |
This comment has been minimized.
This comment has been minimized.
Agreed. Okay so can I get someone to r+ this? :D |
This comment has been minimized.
This comment has been minimized.
|
@bors r+ |
This comment has been minimized.
This comment has been minimized.
|
|
bors
added
S-waiting-on-bors
and removed
S-waiting-on-review
labels
Dec 12, 2018
kennytm
added a commit
to kennytm/rust
that referenced
this pull request
Dec 12, 2018
This comment has been minimized.
This comment has been minimized.
bors
added a commit
that referenced
this pull request
Dec 13, 2018
This comment has been minimized.
This comment has been minimized.
|
|
bors
merged commit feb775c
into
rust-lang:master
Dec 13, 2018
This comment has been minimized.
This comment has been minimized.
rust-highfive
added a commit
to rust-lang-nursery/rust-toolstate
that referenced
this pull request
Dec 13, 2018
Xanewok
referenced this pull request
Dec 13, 2018
Open
thread '<unnamed>' panicked at 'Forcing query with already existing DepNode. #999
This comment has been minimized.
This comment has been minimized.
|
@alexcrichton @kennytm this is intermittent - any possibility to retrigger the (On a similar note, why do newest nightlies don't contain RLS or rustfmt? The toolstate was ok and the manifest tool was fixed from what I've seen - anything else blocking these from distribution?) |
This comment has been minimized.
This comment has been minimized.
That would be #56667. There simply wasn't a new nightly since the tools were fixed. |
RalfJung
deleted the
RalfJung:vecdeque-stacked-borrows
branch
Dec 13, 2018
This comment has been minimized.
This comment has been minimized.
|
Ah, so it's not because the nightlies are blocked on broken tools but there's a problem with distributing nightlies itself! Makes sense, thanks for the heads up. EDIT: Or maybe not (it seems clippy managed to break just before the distribution). In any case, hopefully the next nightlies are okay. |
RalfJung commentedNov 22, 2018
•
edited
VecDequeviolates a version of stacked borrows where creating a shared reference is not enough to make a location mutably accessible from raw pointers (and I think that is the version we want). There are two problems:NonNull<T>from&mut Tgoes through&T(inferred for a_), then*const T, thenNonNull<T>. That means in this stricter version of Stacked Borrows, we cannot actually write to such aNonNullbecause it was created from a shared reference! This PR fixes that by going from&mut Tto*mut Tto*const T.VecDeque::draincreates theDrainstruct by first creating aNonNullfromself(which is an&mut VecDeque), and then callingself.buffer_as_mut_slice(). The latter reborrowsself, asserting thatselfis currently the unique pointer to access thisVecDeque, and hence invalidating theNonNullthat was created earlier. This PR fixes that by instead usingself.buffer_as_slice(), which only performs read accesses and creates only shared references, meaning the raw pointer (NonNull) remains valid.It is possible that other methods on
VecDequedo something similar, miri's test coverage ofVecDequeis sparse to say the least.Cc @nikomatsakis @Gankro