Report the failures libakstdlib's wrappers were already catching
Updates deps/libakstdlib to 669b2b3. That commit is a TODO entry rather than new code, so the interesting part is what libakgl was not yet calling: it links libakstdlib and uses ten of its wrappers while calling the raw libc function at a good many more sites. Four of those were carrying a real defect. akgl_game_save checked every write and threw away the close. Every write goes through aksl_fwrite, and for a record this size all of them land in stdio's buffer -- nothing reaches the device until the close flushes it, so a full disk, an exceeded quota or an NFS server going away is reported only there. The function returned success over a savegame that was never written. aksl_fclose surfaces it. tests/game.c reaches the path through /dev/full, which accepts writes and fails at the flush; against the unfixed code the test reports "expected a failure, got success" with ENOSPC. The close has to drop the FILE * before the status is examined, because fclose(3) disassociates the stream either way and CLEANUP would close it again. Written the other way round it aborted in glibc with "double free detected in tcache" the first time a close actually failed, which is how that ordering was found. akgl_game_load's end-of-file check used fgetc(3), which spells "end of file" and "the read failed" with the same EOF -- a disk error there read as a clean end and passed the check it was meant to fail. aksl_fgetc tells them apart. Extracted to require_at_eof, because inverting the sense of a call inline needs a nested ATTEMPT whose break binds to the wrong switch. Two snprintf sites were truncating under a silenced -Wformat-truncation. The compiler was right about both. The tileset one handed the shortened path to IMG_LoadTexture, so a length error was reported as a missing file, with SDL naming a path the caller never wrote. Both use aksl_snprintf now and the suppression is gone; nothing in the tree uses those macros any more. tests/tilemap.c covers the join, and against the unfixed code it gets AKGL_ERR_SDL where it wants AKERR_OUTOFBOUNDS. The two src/game.c strncpy sites the fixed-width copy sweep missed -- the savegame name field and the libversion stamp -- use aksl_strncpy and sizeof rather than a repeated 32. Also makes tests/physics_sim.c deterministic. It placed gravity_time at "now - dt" and let the real clock supply the step, so a machine busy enough to deschedule the process between that store and the SDL_GetTicksNS() inside simulate got a longer step. It went red once, under a parallel ctest. It now sets max_timestep to the step it wants and gravity_time to zero, so the bound supplies the step and the scheduler cannot reach it. TODO.md records what is deliberately not adopted: the pure-arithmetic wrappers, which can only fail on NULL and which the tree already spells two ways, and the collections, which the registries do not want because SDL owns the property-set lifetime. AGENTS.md has the rule and the fclose ordering trap. 26/26 ctest, memcheck clean, warning-clean at -Wall -Werror. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B8T5FAYXE8HEJqFLCYwNNc
This commit is contained in:
44
TODO.md
44
TODO.md
@@ -1884,6 +1884,50 @@ currently promises the opposite. `aksl_strncpy` already reports exactly that
|
||||
status when the bytes do not fit, so the change is to stop capping `n` at
|
||||
`size - 1` and let it raise.
|
||||
|
||||
## libakstdlib wrappers not yet adopted
|
||||
|
||||
`libakgl` links `libakstdlib` and uses ten of its wrappers. It calls the raw
|
||||
libc function at a good many more sites. Adopting the four that were carrying a
|
||||
real defect is done (see the 0.6.0 commit); this is what is left, and the reason
|
||||
each is left.
|
||||
|
||||
**Adopted, for the record:** `aksl_fclose` (an unchecked close in
|
||||
`akgl_game_save` lost buffered data silently), `aksl_fgetc` (`fgetc(3)` spells
|
||||
EOF and a read error the same way), `aksl_snprintf` at two sites that were
|
||||
truncating under a silenced `-Wformat-truncation`, and `aksl_strncpy` at the two
|
||||
`src/game.c` sites the fixed-width copy sweep missed.
|
||||
|
||||
### The pure-arithmetic wrappers are deliberately not adopted
|
||||
|
||||
`memset` (38 sites), `strlen` (14), `strcmp` (9), `strncmp` (9), `memcpy` (6),
|
||||
`memcmp` (2). Every one of these can only fail on a NULL argument, and at all
|
||||
but a handful of those sites the argument is a stack object whose address cannot
|
||||
be NULL. `aksl_memset` and `aksl_memcpy` are used twice each, which is the
|
||||
inconsistency worth naming: there is no rule distinguishing those two sites from
|
||||
the other 44.
|
||||
|
||||
Converting them costs an `errctx` check per line and buys a NULL check the
|
||||
compiler already knows is redundant. Not converting them leaves the file mixing
|
||||
two spellings of the same operation. **Pick one and write it down** -- the
|
||||
recommendation is to convert only where the argument is a parameter or a heap
|
||||
pointer, and say so in `AGENTS.md`, rather than either extreme.
|
||||
|
||||
### `DISABLE_GCC_WARNING_FORMAT_TRUNCATION` is now dead
|
||||
|
||||
`include/akgl/error.h` exports it and `RESTORE_GCC_WARNINGS`, and after the
|
||||
`aksl_snprintf` conversion nothing in the tree uses either. They are public
|
||||
macros, so removing them is an API change and is not done here. Both suppressed
|
||||
sites turned out to be real truncations, which is the argument for deleting
|
||||
rather than keeping them: the two times this library silenced that warning, the
|
||||
compiler was right.
|
||||
|
||||
### No wrapper is used for the collections
|
||||
|
||||
`aksl_HashMap`, `aksl_List` and `aksl_TreeNode` exist and libakgl uses SDL
|
||||
property sets for every registry instead. That is not an oversight -- the
|
||||
registries hand `SDL_PropertiesID` values to callers and SDL owns the lifetime.
|
||||
Recorded so nobody re-derives it.
|
||||
|
||||
## Arcade physics feel
|
||||
|
||||
Found by building `tests/physics_sim.c`, which runs the arcade backend as a game
|
||||
|
||||
Reference in New Issue
Block a user