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] - Fix unsoundnes in insert remove and despawn #7805

Closed
wants to merge 4 commits into from

Conversation

BoxyUwU
Copy link
Member

@BoxyUwU BoxyUwU commented Feb 24, 2023

EntityMut::move_entity_from_remove had two soundness bugs:

  • When removing the entity from the archetype, the swapped entity had its table row updated to the same as the removed entity's
  • When removing the entity from the table, the swapped entity did not have its table row updated

BundleInsert::insert had two/three soundness bugs

  • When moving an entity to a new archetype from an insert, the swapped entity had its table row set to a different entities
  • When moving an entity to a new table from an insert, the swapped entity did not have its table row updated
    See added tests for examples that trigger those bugs

EntityMut::despawn had two soundness bugs

  • When despawning an entity, the swapped entity had its table row set to a different entities even if the table didnt change
  • When despawning an entity, the swapped entity did not have its table row updated

@BoxyUwU BoxyUwU added A-ECS Entities, components, systems, and events P-Critical This must be fixed immediately or contributors or users will be severely impacted P-Unsound A bug that results in undefined compiler behavior labels Feb 24, 2023
@BoxyUwU BoxyUwU added this to the 0.10 milestone Feb 24, 2023
crates/bevy_ecs/src/world/entity_ref.rs Show resolved Hide resolved
crates/bevy_ecs/src/world/entity_ref.rs Show resolved Hide resolved
Comment on lines +379 to +382
archetype_id: swapped_location.archetype_id,
archetype_row: old_location.archetype_row,
table_id: swapped_location.table_id,
table_row: swapped_location.table_row,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
archetype_id: swapped_location.archetype_id,
archetype_row: old_location.archetype_row,
table_id: swapped_location.table_id,
table_row: swapped_location.table_row,
archetype_row: old_location.archetype_row,
..swapped_location

Alternatively, we should consider exposing a pub(crate) get_mut from Entities or just mutate swapped_location with the archetype row.

Copy link
Member Author

Choose a reason for hiding this comment

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

I specifically chose to construct a whole new struct here so that if we change the fields we'll get a compile error rather than it continuing to compile

Copy link
Member

Choose a reason for hiding this comment

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

That makes sense to me. Not sure if the compiler will optimize that down though. Probably worth investigating separately.

Not sure if this is worth leaving a comment so others don't try to make that change.

Comment on lines +414 to +417
archetype_id: swapped_location.archetype_id,
archetype_row: swapped_location.archetype_row,
table_id: swapped_location.table_id,
table_row: old_location.table_row,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
archetype_id: swapped_location.archetype_id,
archetype_row: swapped_location.archetype_row,
table_id: swapped_location.table_id,
table_row: old_location.table_row,
table_row: old_location.table_row,
..swapped_location

Alternatively just mutate the table_row on swapped_location.

@maniwani
Copy link
Contributor

maniwani commented Feb 24, 2023

Insertion has the same UB, I think.

Overwrites table row.

let result = self.archetype.swap_remove(location.archetype_row);
if let Some(swapped_entity) = result.swapped_entity {
self.entities.set(swapped_entity.index(), location);
}

let result = self.archetype.swap_remove(location.archetype_row);
if let Some(swapped_entity) = result.swapped_entity {
self.entities.set(swapped_entity.index(), location);
}

Does not update table row on EntityLocation.

if let Some(swapped_entity) = move_result.swapped_entity {
let swapped_location = self.entities.get(swapped_entity).unwrap();
let swapped_archetype = if self.archetype.id() == swapped_location.archetype_id
{
&mut *self.archetype
} else if new_archetype.id() == swapped_location.archetype_id {
new_archetype
} else {
// SAFETY: the only two borrowed archetypes are above and we just did collision checks
&mut *self
.archetypes_ptr
.add(swapped_location.archetype_id.index())
};
swapped_archetype
.set_entity_table_row(swapped_location.archetype_row, result.table_row);
}

@BoxyUwU BoxyUwU changed the title Fix unsoundnes in EntityMut::move_entity_from_remove Fix unsoundnes in insert remove and despawn Feb 24, 2023
@james7132 james7132 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 Feb 24, 2023
@james7132
Copy link
Member

bors r+

bors bot pushed a commit that referenced this pull request Feb 27, 2023
`EntityMut::move_entity_from_remove` had two soundness bugs:

- When removing the entity from the archetype, the swapped entity had its table row updated to the same as the removed entity's
- When removing the entity from the table, the swapped entity did not have its table row updated

`BundleInsert::insert` had two/three soundness bugs
- When moving an entity to a new archetype from an `insert`, the swapped entity had its table row set to a different entities 
- When moving an entity to a new table from an `insert`, the swapped entity did not have its table row updated 
See added tests for examples that trigger those bugs

`EntityMut::despawn` had two soundness bugs
- When despawning an entity, the swapped entity had its table row set to a different entities even if the table didnt change
- When despawning an entity, the swapped entity did not have its table row updated
@bors bors bot changed the title Fix unsoundnes in insert remove and despawn [Merged by Bors] - Fix unsoundnes in insert remove and despawn Feb 27, 2023
@bors bors bot closed this Feb 27, 2023
Shfty pushed a commit to shfty-rust/bevy that referenced this pull request Mar 19, 2023
`EntityMut::move_entity_from_remove` had two soundness bugs:

- When removing the entity from the archetype, the swapped entity had its table row updated to the same as the removed entity's
- When removing the entity from the table, the swapped entity did not have its table row updated

`BundleInsert::insert` had two/three soundness bugs
- When moving an entity to a new archetype from an `insert`, the swapped entity had its table row set to a different entities 
- When moving an entity to a new table from an `insert`, the swapped entity did not have its table row updated 
See added tests for examples that trigger those bugs

`EntityMut::despawn` had two soundness bugs
- When despawning an entity, the swapped entity had its table row set to a different entities even if the table didnt change
- When despawning an entity, the swapped entity did not have its table row updated
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 P-Critical This must be fixed immediately or contributors or users will be severely impacted P-Unsound A bug that results in undefined compiler behavior 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.

3 participants