-
-
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] - unsafeify World::entities_mut
#4093
Conversation
db0f44b
to
52bdff0
Compare
@@ -198,7 +198,7 @@ impl Plugin for RenderPlugin { | |||
// flushing as "invalid" ensures that app world entities aren't added as "empty archetype" entities by default | |||
// these entities cannot be accessed without spawning directly onto them | |||
// this _only_ works as expected because clear_entities() is called at the end of every frame. | |||
render_app.world.entities_mut().flush_as_invalid(); | |||
unsafe { render_app.world.entities_mut() }.flush_as_invalid(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to avoid this entirely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure, I dont particularly understand what the render app is actually trying to accomplish here 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the render app "reserve" all the entities from the main app, but actually spawn something only on some of them. this marks all entities by default as invalid so that the one which won't be used aren't usable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "right" way to do this would be to expose a safe mirror of flush_as_invalid()
on World. But honestly this feature is niche enough that im fine leaving this as-is for now.
World::entities_mut
>:(World::entities_mut
>:(
68499b4
to
6b3cd61
Compare
Figuring out how to fix the |
World::entities_mut
>:(World::entities_mut
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with this change: this is very easy to create UB in safe code with, and so it's unsound if this is safe.
Entities
is not very useful in general to the average user, and mutating it is particularly rare.
I really wish we would could avoid this being pub
, but we can't, as it's needed in bevy_render.
Adding to the 0.7 milestone; this is now actually UB since #4298 is merged. |
bors r+ |
# Objective make bevy ecs a lil bit less unsound ## Solution make unsound API unsafe so that there is an unsafe block to blame: ```rust use bevy_ecs::prelude::*; #[derive(Debug, Component)] struct Foo(u8); fn main() { let mut world = World::new(); let e1 = world.spawn().id(); let e2 = world.spawn().insert(Foo(2)).id(); world.entities_mut().meta[0] = world.entities_mut().meta[1].clone(); let foo = world.entity(e1).get::<Foo>().unwrap(); // whoo i love having components i dont have dbg!(foo); } ``` This is not _strictly_ speaking UB, however: - `Query::get_multiple` cannot work if this is allowed - bevy_ecs is a pile of unsafe code whose soundness generally depends on the world being in a "correct" state with "no funny business" so it seems best to disallow this - it is trivial to get bevy to panic inside of functions with safety invariants that have been violated (the entity location is not valid) - it seems to violate what the safety invariant on `Entities::flush` is trying to ensure
World::entities_mut
World::entities_mut
# Objective make bevy ecs a lil bit less unsound ## Solution make unsound API unsafe so that there is an unsafe block to blame: ```rust use bevy_ecs::prelude::*; #[derive(Debug, Component)] struct Foo(u8); fn main() { let mut world = World::new(); let e1 = world.spawn().id(); let e2 = world.spawn().insert(Foo(2)).id(); world.entities_mut().meta[0] = world.entities_mut().meta[1].clone(); let foo = world.entity(e1).get::<Foo>().unwrap(); // whoo i love having components i dont have dbg!(foo); } ``` This is not _strictly_ speaking UB, however: - `Query::get_multiple` cannot work if this is allowed - bevy_ecs is a pile of unsafe code whose soundness generally depends on the world being in a "correct" state with "no funny business" so it seems best to disallow this - it is trivial to get bevy to panic inside of functions with safety invariants that have been violated (the entity location is not valid) - it seems to violate what the safety invariant on `Entities::flush` is trying to ensure
# Objective make bevy ecs a lil bit less unsound ## Solution make unsound API unsafe so that there is an unsafe block to blame: ```rust use bevy_ecs::prelude::*; #[derive(Debug, Component)] struct Foo(u8); fn main() { let mut world = World::new(); let e1 = world.spawn().id(); let e2 = world.spawn().insert(Foo(2)).id(); world.entities_mut().meta[0] = world.entities_mut().meta[1].clone(); let foo = world.entity(e1).get::<Foo>().unwrap(); // whoo i love having components i dont have dbg!(foo); } ``` This is not _strictly_ speaking UB, however: - `Query::get_multiple` cannot work if this is allowed - bevy_ecs is a pile of unsafe code whose soundness generally depends on the world being in a "correct" state with "no funny business" so it seems best to disallow this - it is trivial to get bevy to panic inside of functions with safety invariants that have been violated (the entity location is not valid) - it seems to violate what the safety invariant on `Entities::flush` is trying to ensure
Objective
make bevy ecs a lil bit less unsound
Solution
make unsound API unsafe so that there is an unsafe block to blame:
This is not strictly speaking UB, however:
Query::get_multiple
cannot work if this is allowedEntities::flush
is trying to ensure