-
Notifications
You must be signed in to change notification settings - Fork 59
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
What about: aliasing requirements for nested references? #532
Comments
This post is very hard to understand and quite vague about the actual problem. Lucky enough I saw rust-lang/miri#3921 (comment) before otherwise I would have been very confused...
We don't forbid optimizations on structs containing reference fields. If you have a function that takes I think what you are talking about is: SB and TB decide is to not impose any restrictions on nested references. That does mean we lose some optimizations around nested references. (Please update the issue description to explain what exactly you mean.) So far, there has been no proposal for how a memory model that enforces aliasing on nested references could work. It can't be anything like Stacked Borrows or Tree Borrows, as those models are based on "retagging" where when we want to distinguish pointers to impose different aliasing rules on them, we generate a fresh unique "tag" so that we can tell them apart. If a function takes We'd need a completely different approach. It would likely have to involve making it so that when you load from |
idiomatic usage of Rust's existing standard library API surface, in particular most of the implementation of Iterator and functions like |
though mostly, I'm somewhat perplexed why "retags" are mutation, exactly? my impression was that they are de jure creation of a new reference with the tags in question. |
Retags change the provenance of a pointer. In the Abstract Machine, provenance is real data that affects whether code has UB, so changing it must count as mutation. After all, we want to do optimizations like fn foo(x: &*const T) {
let ptr = *x;
// ...
let ptr2 = *x;
} and know that the two pointers are the same, in the sense that we can replace one by the other -- which is only the case if they are fully equal, including their provenance. |
To motivate this a bit more and expand on what I said, I will lift the example I mistakenly posted in #412. Code appears that would resemble the pattern that is, if I understand everything correctly, subject to a miscompiled like rust-lang/rust#130853 if it was written directly: let iter = vec.iter().filter(predicate);
call();
for item in iter.filter(overlapping_predicate) {
// code
} This is because the initial code that is written is actually a library exposing something like this: impl SomeType<T> {
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.inner_slice.iter().filter(valid_elements_predicate)
}
} Because |
Ref:
This is already a fact under {Stacked,Tree}Borrow, though I think it's unfortunate to forbids optimizations on structs containing reference fields. Specifically, optimizing out duplicated-read through double-reference after a function call and caching an (known to be unchanged) pointer indirection are not possible.
Here we can notice that even through
x
and*x
is both unchanged andu8: Freeze
,**x
can change via a foreign pointer with write permission. Thus caching one level of indirection*x
is not possible because it would beDisabled
by that foreign write.Could we do better on this? For this example, maybe we could leave protectors on the access trace of a
Frozen
reference argument (when without interior mutability, or course)?The text was updated successfully, but these errors were encountered: