Check memory with the suites that already exist
`cmake --build build --target memcheck` runs every registered CTest suite under valgrind. There are no new test programs, and there should not be any: tests/benchutil.h notices valgrind in LD_PRELOAD and drops the benchmark scale to 0.0005, which turns the perf suites into the broadest path coverage in the tree at a cost valgrind can survive. A benchmark walks one path a hundred thousand times; a leak check wants every path walked once. Same binaries, one flag apart, and the whole run is about thirty seconds. scripts/memcheck.sh wraps `ctest -T memcheck` because that command records defects and still exits 0, which cannot gate anything. It also forces the headless drivers, so the vendor GPU stack is never loaded -- that removes thousands of unfixable findings inside amdgpu_dri.so without suppressing anything, and it is what the suites are written for anyway. Only definite losses, invalid accesses and uninitialised reads count; "still reachable" is what SDL and FreeType keep for the process lifetime and says nothing about this library. The three suppressions in scripts/valgrind.supp are each a decision that a finding belongs to somebody else. Six defects, all filed in TODO.md under "Memory checking", the first of which is the one that matters: not one of the four json_load_file calls in src/ is ever matched by a json_decref, so every asset load abandons its parsed document -- 1.5 KB per sprite, 2.1 KB per character, 9 KB per load of the 2x2 fixture map, and on the order of a megabyte for a real one. A game that reloads a level on death leaks a level's worth of JSON every time. akgl_get_property also reads up to 4 KiB past the end of every property value it copies, and the savegame name tables read past the end of every registry key and write what they find into the file. tests/util.c zeroes three fixtures it used to leave as stack garbage. The library was never at fault there -- the tests handed it uninitialised floats and then made one real call with them -- but sixteen findings of noise in a new gate is how a gate gets ignored. The unit suites' TIMEOUT goes from 30 to 300 because CTest applies the same property to the checked run, where everything is twenty times slower. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
24
tests/util.c
24
tests/util.c
@@ -1,4 +1,5 @@
|
||||
#include <SDL3/SDL.h>
|
||||
#include <string.h>
|
||||
#include <akerror.h>
|
||||
#include <akgl/error.h>
|
||||
#include <akgl/heap.h>
|
||||
@@ -28,9 +29,14 @@ static int live_error_contexts(void)
|
||||
akerr_ErrorContext *test_akgl_rectangle_points_nullpointers(void)
|
||||
{
|
||||
RectanglePoints points;
|
||||
SDL_FRect testrect;
|
||||
// Zeroed for the same reason as the fixtures in
|
||||
// test_akgl_collide_point_rectangle_nullpointers: the last case here is a
|
||||
// real call, and feeding it stack garbage is noise under `memcheck`.
|
||||
SDL_FRect testrect = {.x = 0, .y = 0, .w = 0, .h = 0};
|
||||
PREPARE_ERROR(errctx);
|
||||
|
||||
memset((void *)&points, 0x00, sizeof(RectanglePoints));
|
||||
|
||||
ATTEMPT {
|
||||
CATCH(errctx, akgl_rectangle_points(NULL, NULL));
|
||||
FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_rectangle_points fails to FAIL with all NULL pointers");
|
||||
@@ -102,12 +108,18 @@ akerr_ErrorContext *test_akgl_rectangle_points_math(void)
|
||||
|
||||
akerr_ErrorContext *test_akgl_collide_point_rectangle_nullpointers(void)
|
||||
{
|
||||
point testpoint;
|
||||
// Zeroed rather than left as whatever the stack held. The last case in this
|
||||
// function is a real call with real arguments, and reading uninitialised
|
||||
// floats out of it is sixteen findings under `memcheck` for a test that is
|
||||
// not about coordinates at all.
|
||||
point testpoint = { .x = 0, .y = 0 };
|
||||
RectanglePoints testrectpoints;
|
||||
bool testcollide;
|
||||
bool testcollide = false;
|
||||
|
||||
PREPARE_ERROR(errctx);
|
||||
|
||||
memset(&testrectpoints, 0x00, sizeof(RectanglePoints));
|
||||
|
||||
ATTEMPT {
|
||||
CATCH(errctx, akgl_collide_point_rectangle(&testpoint, &testrectpoints, NULL));
|
||||
FAIL_BREAK(errctx, AKGL_ERR_BEHAVIOR, "akgl_collide_point_rectangle(*, *, NULL) failed");
|
||||
@@ -182,9 +194,9 @@ akerr_ErrorContext *test_akgl_collide_point_rectangle_logic(void)
|
||||
|
||||
akerr_ErrorContext *test_akgl_collide_rectangles_nullpointers(void)
|
||||
{
|
||||
SDL_FRect testrect1;
|
||||
SDL_FRect testrect2;
|
||||
bool testcollide;
|
||||
SDL_FRect testrect1 = {.x = 0, .y = 0, .w = 0, .h = 0};
|
||||
SDL_FRect testrect2 = {.x = 0, .y = 0, .w = 0, .h = 0};
|
||||
bool testcollide = false;
|
||||
|
||||
PREPARE_ERROR(errctx);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user