From 05b0df052d6723284e92b0c9df9485186dac2095 Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreplay.github.com> Date: Mon, 11 Jul 2022 14:38:43 +1000 Subject: [PATCH] ecs: fix pointer invalidation in get/setComponent The reference to the old archetype is invalidated by getOrPut() calls of std.ArrayHashMap. The implementation of std.ArrayHashMap means that pointers can be invalidated on getOrPut() calls even if the key exists in the map. This means that the reference to the old archetype needs to be refreshed unconditionally (i.e. not only if the new archetype didn't exist previously). --- ecs/src/entities.zig | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ecs/src/entities.zig b/ecs/src/entities.zig index 42b1c5e5..8ec09bea 100644 --- a/ecs/src/entities.zig +++ b/ecs/src/entities.zig @@ -523,11 +523,12 @@ pub fn Entities(all_components: anytype) type { // new component was added), or the same archetype storage table (if just updating the // value of a component.) var archetype_entry = try entities.archetypes.getOrPut(entities.allocator, new_hash); - if (!archetype_entry.found_existing) { - // getOrPut allocated, so the archetype we retrieved earlier may no longer be a valid - // pointer. Refresh it now: - archetype = entities.archetypeByID(entity); + // getOrPut allocated, so the archetype we retrieved earlier may no longer be a valid + // pointer. Refresh it now: + archetype = entities.archetypeByID(entity); + + if (!archetype_entry.found_existing) { const columns = entities.allocator.alloc(Column, archetype.columns.len + 1) catch |err| { assert(entities.archetypes.swapRemove(new_hash)); return err; @@ -653,11 +654,12 @@ pub fn Entities(all_components: anytype) type { // guarantee that archetype (A, C) exists - and so removing a component sometimes does // require creating a new archetype table! var archetype_entry = try entities.archetypes.getOrPut(entities.allocator, new_hash); - if (!archetype_entry.found_existing) { - // getOrPut allocated, so the archetype we retrieved earlier may no longer be a valid - // pointer. Refresh it now: - archetype = entities.archetypeByID(entity); + // getOrPut allocated, so the archetype we retrieved earlier may no longer be a valid + // pointer. Refresh it now: + archetype = entities.archetypeByID(entity); + + if (!archetype_entry.found_existing) { const columns = entities.allocator.alloc(Column, archetype.columns.len - 1) catch |err| { assert(entities.archetypes.swapRemove(new_hash)); return err;