Skip to content

observe on WorldEntityMut may cause the reference to be invalidated #16212

@nakedible

Description

@nakedible

Bevy version

0.15.0-rc.2 (present in 0.14.0) as well

What you did

    #[derive(Event)]
    struct Boom;

    #[derive(Event)]
    struct BoomTomorrow;

    fn boom(trigger: Trigger<Boom>, mut commands: Commands) {
        println!("boom, despawning entity: {:?}", trigger.entity());
        commands.entity(trigger.entity()).despawn();
    }

    fn boom_tomorrow(trigger: Trigger<Boom>, mut commands: Commands) {
        // boom tomorrow
    }

    #[test]
    fn test_boom() {
        let mut app = App::new();

        let mut id = app.world_mut().spawn(Name::new("a")).observe(boom).id();
        let mut id2 = app.world_mut().spawn(Name::new("b")).id();
        
        app.world_mut().flush();
        println!("flushed");
        
        let mut a = app.world_mut().entity_mut(id);
        a.trigger(Boom);
        a.observe(boom_tomorrow);
        let name = a.get::<Name>().unwrap();
        assert_eq!(name.as_str(), "b");
    }

Result

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s

What went wrong

  • WorldEntityMut depends on the fact that the EntityLocation it caches does not change while it is alive, or changes when it itself expects it to.
  • This means that there must be no way to flush the command queue while WorldEntityMut lives, as this might cause queued despawns to be run.
  • observe internally calls world.spawn().
  • world.spawn() implicitly has a flush() in it, as evidenced in bug report Commands apply at unexpected times with exclusive World access #14621.
  • Hence, entity gets despawned while WorldEntityMut exists, which means any accesses will use outdated EntityLocation

Additional information

Also related as context #16034.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-BugAn unexpected or incorrect behaviorD-ModestA "normal" level of difficulty; suitable for simple features or challenging fixesS-Needs-DesignThis issue requires design work to think about how it would best be accomplished

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions