Build the shape before spawning a proxy from it

test_reset_and_empty called spawn() with an uninitialized stack akgl_CollisionShape
and built it on the next line. akgl_collision_proxy_initialize copies the shape,
so grid_insert read uninitialized half-extents to work out which cells to file
the proxy under -- eighteen findings inside grid_cellrect, and the test still
passed because the proxy_sync two lines later overwrote all of it.

Found by scripts/memcheck.sh, which is the only thing that could have found it:
the assertion it makes is about the query afterwards, and the query answers
correctly either way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
This commit is contained in:
2026-08-02 08:01:17 -04:00
parent 71e18184c0
commit 3a6569e384

View File

@@ -421,8 +421,12 @@ akerr_ErrorContext *test_reset_and_empty(char *name)
TEST_ASSERT(errctx, (rec.count == 0), "%s reported %d proxies in an empty world",
name, rec.count);
CATCH(errctx, spawn(&world, &shape, 0.0f, 0.0f, &proxy));
// Build the shape before spawning from it, not after. Spawning first
// initializes the proxy from an uninitialized stack struct -- the sync
// below overwrites it, so the test still passed, and valgrind still
// reported eighteen uninitialised reads inside grid_cellrect.
CATCH(errctx, akgl_collision_shape_box(&shape, &body, 0.0f));
CATCH(errctx, spawn(&world, &shape, 0.0f, 0.0f, &proxy));
CATCH(errctx, akgl_collision_proxy_sync(proxy, &shape, 0.0f, 0.0f, 0.0f));
CATCH(errctx, world.partitioner.move(&world.partitioner, proxy));