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 upTest whether self-referential futures are compatible with stacked borrows #532
Comments
RalfJung
added
C-enhancement
A-stacked-borrows
labels
Nov 19, 2018
RalfJung
changed the title
Test whether self-referential generators are compatible with stacked borrows
Test whether self-referential futures are compatible with stacked borrows
Nov 19, 2018
This comment has been minimized.
This comment has been minimized.
|
I'm actually working on trying to create a step-by-step example of how an
There are only two different kinds that I know of, and fundamentally they should be the same. You can have references to upvars that have been moved into the generator and references to locals created while the generator is running. Once the generator transform has run these both just become references into the generator state variable, and I don't think they're distinguishable in the MIR. |
This comment has been minimized.
This comment has been minimized.
|
Actually I might as well throw something together now, here should be a small example showing all kinds of references in an There's also the minimal framework for running an |
This comment has been minimized.
This comment has been minimized.
withoutboats
commented
Nov 19, 2018
|
@RalfJung might it be easier to focus on generators before async fn, since they have direct access to |
This comment has been minimized.
This comment has been minimized.
|
Here's a self-referential generator example: #![feature(generators, generator_trait)]
use std::ops::Generator;
fn main() {
let mut generator = || {
let mut x = Box::new(5);
let y = &mut *x;
*y = 5;
yield ();
*y = 10;
*x
};
unsafe { generator.resume() };
} |
This comment has been minimized.
This comment has been minimized.
|
@cramertj Thanks! I thought there had to be |
This comment has been minimized.
This comment has been minimized.
|
To my big surprise, this actually passes in miri :D EDIT: Even more interestingly though, it no longer passes locally... |
This comment has been minimized.
This comment has been minimized.
|
Oh. The generator MIR transform happens after we added the retag statements, leading to... strange results. However, the generator MIR stuff happens extremely late -- it happens after inlining! That seems really strange to me, shouldn't we first get the MIR "complete" before doing interesting transformations? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@withoutboats That makes sense, I wasn't aware of the layering here. This seems covered by #536 though, and it's actually working (with a small rustc fix), which is great! However, something like @Nemo157's example also seems like a nice addition. Thanks for that @Nemo157! It also seems to pass, to my ever greater surprise.^^ |
RalfJung
closed this
in
#536
Nov 26, 2018
RalfJung
reopened this
Nov 28, 2018
This comment has been minimized.
This comment has been minimized.
|
With barriers entering the picture, I now see a violation of Stacked Borrows in async functions. The error happens with the following stacktrace:
The relevant parts are: There is a call to /// Sets the thread-local task context used by async/await futures.
pub fn set_task_waker<F, R>(lw: &LocalWaker, f: F) -> R
where
F: FnOnce() -> R
{
let old_waker = TLS_WAKER.with(|tls_waker| {
tls_waker.replace(Some(NonNull::from(lw)))
});
let _reset_waker = SetOnDrop(old_waker);
f()
}Notice that pub fn get_task_waker<F, R>(f: F) -> R
where
F: FnOnce(&LocalWaker) -> R
{
let waker_ptr = TLS_WAKER.with(|tls_waker| {
// Clear the entry so that nested `get_task_waker` calls
// will fail or set their own value.
tls_waker.replace(None)
});
let _reset_waker = SetOnDrop(waker_ptr);
let mut waker_ptr = waker_ptr.expect(
"TLS LocalWaker not set. This is a rustc bug. \
Please file an issue on https://github.com/rust-lang/rust.");
unsafe { f(waker_ptr.as_mut()) }
}Notice the It also likely is just a typo, |
RalfJung
referenced this issue
Nov 28, 2018
Merged
fix futures creating aliasing mutable and shared ref #56319
This comment has been minimized.
This comment has been minimized.
|
I confirmed that rust-lang/rust#56319 fixes this. |
pietroalbini
added a commit
to pietroalbini/rust
that referenced
this issue
Nov 28, 2018
pietroalbini
added a commit
to pietroalbini/rust
that referenced
this issue
Nov 28, 2018
This comment has been minimized.
This comment has been minimized.
withoutboats
commented
Nov 28, 2018
|
This bug would have also been eliminated when the desugaring uses some sort of resume argument instead of TLS (that is, the entire context in which the mistake occurred is incidental complexity to the implementation) |
RalfJung commentedNov 19, 2018
I have no idea if an
asyncfunction that borrows across a yield point is compatible with Stacked Borrows. We should find out! I just am not sure how.@cramertj @withoutboats I could use your help. :) What is a minimal example for code that creates a self-referential future and then runs it? Ideally with no dependencies beyond libstd but that might not be possible.^^ Also, if there are different cases/"kinds" of self-referential fields in futures, we should make sure we cover all of them.
rustc must test these things somehow, right? Might be worth looking into that, too.