-
Notifications
You must be signed in to change notification settings - Fork 60
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
Stacked Borrows: who can read frozen data #87
Comments
Thanks, good point! We will have to distinguish between "broadcast to raw ptr (read) accesses" and "frozen" to fix this. |
What if This is actually more subtle than I thought. Consider: fn test(x: &mut i32) -> i32 {
*x = 42;
let x = &*x;
unk();
return x;
} We want to argue that Oh, and if you consider interior mutability, things become even worse: |
This will be fixed by rust-lang/miri#695: Shared references get tracked with a unique ID ("tag") just like mutable references do, and the per-location borrow stack keeps track of which tags are allowed to read and maybe write to this location. That should fix all of the examples in this issue as well as the analysis concerns I raised above (which still assumed that we only have one "frozen" flag per location, instead of basically a list of shared references that are all allowed to read). |
In the current specification of stacked borrows, freezing data (e.g., reborrowing a mutable reference) makes it accessible for raw pointers until the freeze is popped.
For example, this code is legal
This has several bad consequences:
Reborrows can't be DCEed or moved forward across something that can access a potentially-invalid pointer.
If we have some code that does a reborrow, we lose the ability to assume that nobody is accessing things behind our back
For example, in this (quite notorious)
extend_from_slice
example:We would like to avoid writing to
self.len
on every loop iteration, and instead only write to it either after the for-loop finishes or when there is a panic.However, this optimization is illegal if
T::clone
can accessself.len
, and it is often hard to prove thatT::clone
does not accessself.len
without relying on aliasing assumptions (note: it might be possible to optimize this forT = u8
, because then within loop we only access locals,self
, and an immutable reference that we know is disjoint fromself
, so all accesses are accounted for, but that is too subtle an argument for LLVM in practice, and in any case does not work ifclone
can e.g. call an allocator).self
is an&mut
reference, so you would expect that nobody would be able to read fromself.len
, but if one of the reborrows that happens here (in any of the method calls) had frozen&self
, then it would have been possible to accessself.len
through a raw pointer, invalidating the optimization.This is (very) incompatible with anything resembling LLVM
noalias
on mutable reference arguments, even if some fix is done to the subtle issues in Stacked Borrows: Incompatibilities with LLVM noalias #86 (as any sane version ofnoalias
would be able to optimize theextend_from_slice
code).The text was updated successfully, but these errors were encountered: