-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
[Merged by Bors] - System Param Lifetime Split #2605
Closed
Closed
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
alice-i-cecile
added
C-Code-Quality
A section of code that is hard to understand or change
and removed
S-Needs-Triage
This issue needs to be labelled
labels
Aug 5, 2021
@BoxyUwU you made this same change in your relations PR. What motivated that? |
cart
force-pushed
the
system-param-lifetimes
branch
from
August 6, 2021 01:46
06a7783
to
42fedfc
Compare
alice-i-cecile
added
M-Needs-Migration-Guide
A breaking change to Bevy's public API that needs to be noted in a migration guide
S-Needs-Migration-Guide
labels
Aug 8, 2021
cart
force-pushed
the
system-param-lifetimes
branch
from
August 12, 2021 00:07
4c7f66a
to
2ee8462
Compare
bors r+ |
bors bot
pushed a commit
that referenced
this pull request
Aug 15, 2021
# Objective Enable using exact World lifetimes during read-only access . This is motivated by the new renderer's need to allow read-only world-only queries to outlive the query itself (but still be constrained by the world lifetime). For example: https://github.com/bevyengine/bevy/blob/115b170d1f11a91146bb6d6e9684dceb8b21f786/pipelined/bevy_pbr2/src/render/mod.rs#L774 ## Solution Split out SystemParam state and world lifetimes and pipe those lifetimes up to read-only Query ops (and add into_inner for Res). According to every safety test I've run so far (except one), this is safe (see the temporary safety test commit). Note that changing the mutable variants to the new lifetimes would allow aliased mutable pointers (try doing that to see how it affects the temporary safety tests). The new state lifetime on SystemParam does make `#[derive(SystemParam)]` more cumbersome (the current impl requires PhantomData if you don't use both lifetimes). We can make this better by detecting whether or not a lifetime is used in the derive and adjusting accordingly, but that should probably be done in its own pr. ## Why is this a draft? The new lifetimes break QuerySet safety in one very specific case (see the query_set system in system_safety_test). We need to solve this before we can use the lifetimes given. This is due to the fact that QuerySet is just a wrapper over Query, which now relies on world lifetimes instead of `&self` lifetimes to prevent aliasing (but in systems, each Query has its own implied lifetime, not a centralized world lifetime). I believe the fix is to rewrite QuerySet to have its own World lifetime (and own the internal reference). This will complicate the impl a bit, but I think it is doable. I'm curious if anyone else has better ideas. Personally, I think these new lifetimes need to happen. We've gotta have a way to directly tie read-only World queries to the World lifetime. The new renderer is the first place this has come up, but I doubt it will be the last. Worst case scenario we can come up with a second `WorldLifetimeQuery<Q, F = ()>` parameter to enable these read-only scenarios, but I'd rather not add another type to the type zoo.
bors
bot
changed the title
System Param Lifetime Split
[Merged by Bors] - System Param Lifetime Split
Aug 15, 2021
64 tasks
geom3trik
added a commit
to geom3trik/bevy
that referenced
this pull request
Sep 30, 2021
bors bot
pushed a commit
that referenced
this pull request
Oct 15, 2021
#2605 changed the lifetime annotations on `get_component` introducing unsoundness as you could keep the returned borrow even after using the query. Example unsoundness: ```rust use bevy::prelude::*; fn main() { App::new() .add_startup_system(startup) .add_system(unsound) .run(); } #[derive(Debug, Component, PartialEq, Eq)] struct Foo(Vec<u32>); fn startup(mut c: Commands) { let e = c.spawn().insert(Foo(vec![10])).id(); c.insert_resource(e); } fn unsound(mut q: Query<&mut Foo>, res: Res<Entity>) { let foo = q.get_component::<Foo>(*res).unwrap(); let mut foo2 = q.iter_mut().next().unwrap(); let first_elem = &foo.0[0]; for _ in 0..16 { foo2.0.push(12); } dbg!(*first_elem); } ``` output: `[src/main.rs:26] *first_elem = 0`
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
A-ECS
Entities, components, systems, and events
C-Code-Quality
A section of code that is hard to understand or change
M-Needs-Migration-Guide
A breaking change to Bevy's public API that needs to be noted in a migration guide
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Objective
Enable using exact World lifetimes during read-only access . This is motivated by the new renderer's need to allow read-only world-only queries to outlive the query itself (but still be constrained by the world lifetime).
For example:
bevy/pipelined/bevy_pbr2/src/render/mod.rs
Line 774 in 115b170
Solution
Split out SystemParam state and world lifetimes and pipe those lifetimes up to read-only Query ops (and add into_inner for Res). According to every safety test I've run so far (except one), this is safe (see the temporary safety test commit). Note that changing the mutable variants to the new lifetimes would allow aliased mutable pointers (try doing that to see how it affects the temporary safety tests).
The new state lifetime on SystemParam does make
#[derive(SystemParam)]
more cumbersome (the current impl requires PhantomData if you don't use both lifetimes). We can make this better by detecting whether or not a lifetime is used in the derive and adjusting accordingly, but that should probably be done in its own pr.Why is this a draft?
The new lifetimes break QuerySet safety in one very specific case (see the query_set system in system_safety_test). We need to solve this before we can use the lifetimes given.
This is due to the fact that QuerySet is just a wrapper over Query, which now relies on world lifetimes instead of
&self
lifetimes to prevent aliasing (but in systems, each Query has its own implied lifetime, not a centralized world lifetime). I believe the fix is to rewrite QuerySet to have its own World lifetime (and own the internal reference). This will complicate the impl a bit, but I think it is doable. I'm curious if anyone else has better ideas.Personally, I think these new lifetimes need to happen. We've gotta have a way to directly tie read-only World queries to the World lifetime. The new renderer is the first place this has come up, but I doubt it will be the last. Worst case scenario we can come up with a second
WorldLifetimeQuery<Q, F = ()>
parameter to enable these read-only scenarios, but I'd rather not add another type to the type zoo.