Skip to content

Hooks and observers that run on spawn and immediately despawn their entity are unsound #19828

@grind086

Description

@grind086

Bevy version

0.16.1 and main branch

What you did

Attempted to despawn an entity from an insert hook, which triggered a debug panic in EntityWorldMut::new. For example:

use bevy::ecs::{
    component::{Component, HookContext},
    world::{DeferredWorld, World},
};

#[derive(Component)]
#[component(on_insert = on_insert_a)]
struct A;

fn on_insert_a(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
    // This causes a panic in debug builds, but not in release builds.
    world.commands().entity(entity).despawn();
}

fn main() {
    let mut world = World::new();
    world.spawn(A);
}

What went wrong

When an entity is immediately despawned by a hook or observer, this flush in World::spawn_with_caller:

if !unsafe { self.command_queue.is_empty() } {
self.flush();
entity_location = self.entities().get(entity);
}

Invalidates this safety guarantee a few lines later:

// SAFETY: entity and location are valid, as they were just created above
let mut entity = unsafe { EntityWorldMut::new(self, entity, entity_location) };

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-BugAn unexpected or incorrect behaviorP-UnsoundA bug that results in undefined compiler behavior

    Type

    No type

    Projects

    Status

    Observer overhaul

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions