Skip to content
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] - Lock down access to Entities #6740

Closed
wants to merge 16 commits into from

Conversation

james7132
Copy link
Member

@james7132 james7132 commented Nov 24, 2022

Objective

The soundness of the ECS World partially relies on the correctness of the state of Entities stored within it. We're currently allowing users to (unsafely) mutate it, as well as readily construct it without using a World. While this is not strictly unsound so long as users (including bevy_render) safely use the APIs, it's a fairly easy path to unsoundness without much of a guard rail.

Addresses #3362 for bevy_ecs::entity. Incorporates the changes from #3985.

Solution

Remove Entities's Default implementation and force access to the type to only be through a properly constructed World.

Additional cleanup for other parts of bevy_ecs::entity:

  • Entity::index and Entity::generation are no longer pub(crate), opting to force the rest of bevy_ecs to use the public interface to access these values.
  • EntityMeta is no longer pub and also not pub(crate) to attempt to cut down on updating generation without going through an Entities API. It's currently inaccessible except via the pub(crate) Vec on Entities, there was no way for an outside user to use it.
  • Added Entities::set, an unsafe pub(crate) API for setting the location of an Entity (parallel to Entities::get) that replaces the internal case where we need to set the location of an entity when it's been spawned, moved, or despawned.
  • Entities::alloc_at_without_replacement is only used in World::get_or_spawn within the first party crates, and I cannot find a public use of this API in any ecosystem crate that I've checked (via GitHub search).
  • Attempted to document the few remaining undocumented public APIs in the module.

Changelog

Removed: Entities's Default implementation.
Removed: EntityMeta
Removed: Entities::alloc_at_without_replacement and AllocAtWithoutReplacement.

Migration Guide

Entities's Default implementation has been removed. You can fetch a reference to a World's Entities via World::entities and World::entities_mut.

Entities::alloc_at_without_replacement and AllocAtWithoutReplacement has been made private due to difficulty in using it properly outside of bevy_ecs. If you still need use of this API, please file an issue.

@james7132 james7132 added C-Docs An addition or correction to our documentation 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 labels Nov 24, 2022
Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this change a lot, and the docs are good. IMO this is essential for #6733, as it restricts users to the happy path.

Co-authored-by: Alice Cecile <[email protected]>
crates/bevy_ecs/src/entity/mod.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/entity/mod.rs Outdated Show resolved Hide resolved
@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Nov 24, 2022
@james7132 james7132 added this to the 0.10 milestone Nov 24, 2022
@james7132
Copy link
Member Author

Incorporated the changes from #3985 and reworded it to address the unresolved comments from that PR.

Copy link
Contributor

@jakobhellermann jakobhellermann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thought I had is that Entity: Reflect which usually means that the fields are considered public and exposed. But we do impl_reflect_value

impl_reflect_value!(Entity(Hash, PartialEq, Serialize, Deserialize));

so it is treated as an opaque identifier.

Exists(EntityLocation),
DidNotExist,
ExistsWithWrongGeneration,
}

impl Entity {
#[cfg(test)]
pub(crate) const fn new(index: u32, generation: u32) -> Entity {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at the other methods on Entity.

After this PR we still have

  • Entity::from_bits(Entity::to_bits(entity)) is still a perfect roundtrip
  • Entity::from_raw(index) still exists and gives an entity with index and generation 0
  • Entity::index() and Entity::generation()

The use case from the docs of from_raw could be replace with Entity::INVALID. Do we know of other use cases, otherwise maybe replace it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually isn't a departure from the current status quo. Both fields were pub(crate) before this so you couldn't create a raw entity outside of Entity::from_raw before this PR.

The only time I can think of needing to construct a raw entity that isn't covered by serialization or reflection is for testing, for which there is no real need to round-trip it.

@alice-i-cecile
Copy link
Member

That last thread may be nice to address elsewhere, but shouldn't block this work :)

bors r+

bors bot pushed a commit that referenced this pull request Nov 28, 2022
# Objective
The soundness of the ECS `World` partially relies on the correctness of the state of `Entities` stored within it. We're currently allowing users to (unsafely) mutate it, as well as readily construct it without using a `World`. While this is not strictly unsound so long as users (including `bevy_render`) safely use the APIs, it's a fairly easy path to unsoundness without much of a guard rail.

Addresses #3362 for `bevy_ecs::entity`. Incorporates the changes from #3985.

## Solution
Remove `Entities`'s  `Default` implementation and force access to the type to only be through a properly constructed `World`.

Additional cleanup for other parts of `bevy_ecs::entity`:

 - `Entity::index` and `Entity::generation` are no longer `pub(crate)`, opting to force the rest of bevy_ecs to use the public interface to access these values.
 - `EntityMeta` is no longer `pub` and also not `pub(crate)` to attempt to cut down on updating `generation` without going through an `Entities` API. It's currently inaccessible except via the `pub(crate)` Vec on `Entities`, there was no way for an outside user to use it.
 - Added `Entities::set`, an unsafe `pub(crate)` API for setting the location of an Entity (parallel to `Entities::get`) that replaces the internal case where we need to set the location of an entity when it's been spawned, moved, or despawned.
 - `Entities::alloc_at_without_replacement` is only used in `World::get_or_spawn` within the first party crates, and I cannot find a public use of this API in any ecosystem crate that I've checked (via GitHub search).
 - Attempted to document the few remaining undocumented public APIs in the module.

---

## Changelog
Removed: `Entities`'s `Default` implementation.
Removed: `EntityMeta`
Removed: `Entities::alloc_at_without_replacement` and `AllocAtWithoutReplacement`.

Co-authored-by: james7132 <[email protected]>
Co-authored-by: James Liu <[email protected]>
@bors
Copy link
Contributor

bors bot commented Nov 28, 2022

Build failed (retrying...):

@bors
Copy link
Contributor

bors bot commented Nov 28, 2022

Merge conflict.

@james7132
Copy link
Member Author

bors retry

bors bot pushed a commit that referenced this pull request Nov 28, 2022
# Objective
The soundness of the ECS `World` partially relies on the correctness of the state of `Entities` stored within it. We're currently allowing users to (unsafely) mutate it, as well as readily construct it without using a `World`. While this is not strictly unsound so long as users (including `bevy_render`) safely use the APIs, it's a fairly easy path to unsoundness without much of a guard rail.

Addresses #3362 for `bevy_ecs::entity`. Incorporates the changes from #3985.

## Solution
Remove `Entities`'s  `Default` implementation and force access to the type to only be through a properly constructed `World`.

Additional cleanup for other parts of `bevy_ecs::entity`:

 - `Entity::index` and `Entity::generation` are no longer `pub(crate)`, opting to force the rest of bevy_ecs to use the public interface to access these values.
 - `EntityMeta` is no longer `pub` and also not `pub(crate)` to attempt to cut down on updating `generation` without going through an `Entities` API. It's currently inaccessible except via the `pub(crate)` Vec on `Entities`, there was no way for an outside user to use it.
 - Added `Entities::set`, an unsafe `pub(crate)` API for setting the location of an Entity (parallel to `Entities::get`) that replaces the internal case where we need to set the location of an entity when it's been spawned, moved, or despawned.
 - `Entities::alloc_at_without_replacement` is only used in `World::get_or_spawn` within the first party crates, and I cannot find a public use of this API in any ecosystem crate that I've checked (via GitHub search).
 - Attempted to document the few remaining undocumented public APIs in the module.

---

## Changelog
Removed: `Entities`'s `Default` implementation.
Removed: `EntityMeta`
Removed: `Entities::alloc_at_without_replacement` and `AllocAtWithoutReplacement`.

Co-authored-by: james7132 <[email protected]>
Co-authored-by: James Liu <[email protected]>
@bors bors bot changed the title Lock down access to Entities [Merged by Bors] - Lock down access to Entities Nov 28, 2022
@bors bors bot closed this Nov 28, 2022
@james7132 james7132 deleted the document-ecs-entity branch December 12, 2022 04:02
taiyoungjang pushed a commit to taiyoungjang/bevy that referenced this pull request Dec 15, 2022
# Objective
The soundness of the ECS `World` partially relies on the correctness of the state of `Entities` stored within it. We're currently allowing users to (unsafely) mutate it, as well as readily construct it without using a `World`. While this is not strictly unsound so long as users (including `bevy_render`) safely use the APIs, it's a fairly easy path to unsoundness without much of a guard rail.

Addresses bevyengine#3362 for `bevy_ecs::entity`. Incorporates the changes from bevyengine#3985.

## Solution
Remove `Entities`'s  `Default` implementation and force access to the type to only be through a properly constructed `World`.

Additional cleanup for other parts of `bevy_ecs::entity`:

 - `Entity::index` and `Entity::generation` are no longer `pub(crate)`, opting to force the rest of bevy_ecs to use the public interface to access these values.
 - `EntityMeta` is no longer `pub` and also not `pub(crate)` to attempt to cut down on updating `generation` without going through an `Entities` API. It's currently inaccessible except via the `pub(crate)` Vec on `Entities`, there was no way for an outside user to use it.
 - Added `Entities::set`, an unsafe `pub(crate)` API for setting the location of an Entity (parallel to `Entities::get`) that replaces the internal case where we need to set the location of an entity when it's been spawned, moved, or despawned.
 - `Entities::alloc_at_without_replacement` is only used in `World::get_or_spawn` within the first party crates, and I cannot find a public use of this API in any ecosystem crate that I've checked (via GitHub search).
 - Attempted to document the few remaining undocumented public APIs in the module.

---

## Changelog
Removed: `Entities`'s `Default` implementation.
Removed: `EntityMeta`
Removed: `Entities::alloc_at_without_replacement` and `AllocAtWithoutReplacement`.

Co-authored-by: james7132 <[email protected]>
Co-authored-by: James Liu <[email protected]>
alradish pushed a commit to alradish/bevy that referenced this pull request Jan 22, 2023
# Objective
The soundness of the ECS `World` partially relies on the correctness of the state of `Entities` stored within it. We're currently allowing users to (unsafely) mutate it, as well as readily construct it without using a `World`. While this is not strictly unsound so long as users (including `bevy_render`) safely use the APIs, it's a fairly easy path to unsoundness without much of a guard rail.

Addresses bevyengine#3362 for `bevy_ecs::entity`. Incorporates the changes from bevyengine#3985.

## Solution
Remove `Entities`'s  `Default` implementation and force access to the type to only be through a properly constructed `World`.

Additional cleanup for other parts of `bevy_ecs::entity`:

 - `Entity::index` and `Entity::generation` are no longer `pub(crate)`, opting to force the rest of bevy_ecs to use the public interface to access these values.
 - `EntityMeta` is no longer `pub` and also not `pub(crate)` to attempt to cut down on updating `generation` without going through an `Entities` API. It's currently inaccessible except via the `pub(crate)` Vec on `Entities`, there was no way for an outside user to use it.
 - Added `Entities::set`, an unsafe `pub(crate)` API for setting the location of an Entity (parallel to `Entities::get`) that replaces the internal case where we need to set the location of an entity when it's been spawned, moved, or despawned.
 - `Entities::alloc_at_without_replacement` is only used in `World::get_or_spawn` within the first party crates, and I cannot find a public use of this API in any ecosystem crate that I've checked (via GitHub search).
 - Attempted to document the few remaining undocumented public APIs in the module.

---

## Changelog
Removed: `Entities`'s `Default` implementation.
Removed: `EntityMeta`
Removed: `Entities::alloc_at_without_replacement` and `AllocAtWithoutReplacement`.

Co-authored-by: james7132 <[email protected]>
Co-authored-by: James Liu <[email protected]>
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
# Objective
The soundness of the ECS `World` partially relies on the correctness of the state of `Entities` stored within it. We're currently allowing users to (unsafely) mutate it, as well as readily construct it without using a `World`. While this is not strictly unsound so long as users (including `bevy_render`) safely use the APIs, it's a fairly easy path to unsoundness without much of a guard rail.

Addresses bevyengine#3362 for `bevy_ecs::entity`. Incorporates the changes from bevyengine#3985.

## Solution
Remove `Entities`'s  `Default` implementation and force access to the type to only be through a properly constructed `World`.

Additional cleanup for other parts of `bevy_ecs::entity`:

 - `Entity::index` and `Entity::generation` are no longer `pub(crate)`, opting to force the rest of bevy_ecs to use the public interface to access these values.
 - `EntityMeta` is no longer `pub` and also not `pub(crate)` to attempt to cut down on updating `generation` without going through an `Entities` API. It's currently inaccessible except via the `pub(crate)` Vec on `Entities`, there was no way for an outside user to use it.
 - Added `Entities::set`, an unsafe `pub(crate)` API for setting the location of an Entity (parallel to `Entities::get`) that replaces the internal case where we need to set the location of an entity when it's been spawned, moved, or despawned.
 - `Entities::alloc_at_without_replacement` is only used in `World::get_or_spawn` within the first party crates, and I cannot find a public use of this API in any ecosystem crate that I've checked (via GitHub search).
 - Attempted to document the few remaining undocumented public APIs in the module.

---

## Changelog
Removed: `Entities`'s `Default` implementation.
Removed: `EntityMeta`
Removed: `Entities::alloc_at_without_replacement` and `AllocAtWithoutReplacement`.

Co-authored-by: james7132 <[email protected]>
Co-authored-by: James Liu <[email protected]>
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 C-Docs An addition or correction to our documentation M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants