Ralith / hecs

A handy ECS
Apache License 2.0
924 stars 81 forks source link

Panic in `Archetype::assert_type_info` is reachable #310

Closed aweinstock314 closed 1 year ago

aweinstock314 commented 1 year ago

I don't have a deterministic reproducer for it yet, but I managed to hit the assertion at https://github.com/Ralith/hecs/blob/ba76555316dad04d5d5ffa95981f44d30ab3f38b/src/archetype.rs#L48-L51 a couple of times, using CommandBuffer::run_on to insert clones of components from one copy of a World into a freshly deserialized world (where the deserializer can produce one of the component types that the CommandBuffer contains).

Stack trace is attached. hecs_archetype_panic_20230328.txt

aweinstock314 commented 1 year ago

I've managed to make a deterministic reproducer for it. The world originally contains {Position, Size, Rotation, Renderable, SpawnPoint, LevelData, RBPosition, RBSize, RBRotation} components, (where RBRotation is a typedef for RollbackBuffer<Rotation, { ROLLBACK_SIZE }> and so on), then a CommandBuffer is made to save only the RBRotation components, and a fresh world containing no RollbackBuffers is deserialized, and that CommandBuffer is run on it, which results in the crash.

Repository containing data for the reproduction: https://github.com/aweinstock314/hecs_issue310_reproducer Stack trace: stacktrace_20230403.txt

aweinstock314 commented 1 year ago

As of https://github.com/aweinstock314/hecs_issue310_reproducer/commit/2200827b30cc12a066e912a6e1b88cd95e0acd06, I've pruned the components in both serialized worlds: the "pre" world now only contains RBRotations and the "post" world now only contains entity ids, no components.

aweinstock314 commented 1 year ago

I've gotten it to crash with no deserialization (a handcrafted world with 2 entities with a single ZST component) and the same stack trace:

#[test]
fn attempt2() {
    let mut world = hecs::World::new();
    #[derive(Clone)]
    struct A;
    let _a = world.spawn((A,));
    let _b = world.spawn((A,));
    let mut cmd = hecs::CommandBuffer::new();
    for (entity, (data,)) in world.query_mut::<(&A,)>() {
        cmd.insert(entity, (data.clone(),));
    }
    let mut world = hecs::World::new();
    let _a = world.spawn(());
    cmd.run_on(&mut world);
}
Ralith commented 1 year ago

Fix published in 0.10.2.