Consume libakstdlib 0.2.0
Some checks failed
libakgl CI Build / cmake_build (push) Failing after 19s
libakgl CI Build / mutation_test (push) Failing after 17s

Pass fixed buffer sizes to the bounded formatting and realpath wrappers. Route save-game records through exact-transfer helpers so the required fread/fwrite count parameter stays local to the complete-record contract.

Co-Authored-By: Codex GPT-5 <noreply@openai.com>
This commit is contained in:
2026-07-31 08:27:15 -04:00
parent 42b60f725d
commit 996cacb10c
4 changed files with 47 additions and 26 deletions

View File

@@ -43,6 +43,20 @@ MIX_Mixer *akgl_mixer = NULL;
MIX_Track *akgl_tracks[AKGL_GAME_AUDIO_MAX_TRACKS]; MIX_Track *akgl_tracks[AKGL_GAME_AUDIO_MAX_TRACKS];
akgl_Game game; akgl_Game game;
static akerr_ErrorContext *write_exact(const void *ptr, size_t size, size_t nmemb, FILE *fp)
{
size_t transferred;
return aksl_fwrite(ptr, size, nmemb, fp, &transferred);
}
static akerr_ErrorContext *read_exact(void *ptr, size_t size, size_t nmemb, FILE *fp)
{
size_t transferred;
return aksl_fread(ptr, size, nmemb, fp, &transferred);
}
void akgl_game_lowfps(void) void akgl_game_lowfps(void)
{ {
SDL_Log("Low FPS! %d", game.fps); SDL_Log("Low FPS! %d", game.fps);
@@ -188,9 +202,9 @@ void akgl_game_save_actorname_iterator(void *userdata, SDL_PropertiesID props, c
PREPARE_ERROR(e); PREPARE_ERROR(e);
ATTEMPT { ATTEMPT {
FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer"); FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
CATCH(e, aksl_fwrite((char *)name, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp)); CATCH(e, write_exact((char *)name, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp));
actor = SDL_GetPointerProperty(props, name, NULL); actor = SDL_GetPointerProperty(props, name, NULL);
CATCH(e, aksl_fwrite(&actor, 1, sizeof(akgl_Actor *), fp)); CATCH(e, write_exact(&actor, 1, sizeof(akgl_Actor *), fp));
} CLEANUP { } CLEANUP {
} PROCESS(e) { } PROCESS(e) {
} FINISH_NORETURN(e); } FINISH_NORETURN(e);
@@ -210,8 +224,8 @@ void akgl_game_save_spritename_iterator(void *userdata, SDL_PropertiesID props,
ATTEMPT { ATTEMPT {
FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer"); FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
sprite = SDL_GetPointerProperty(props, name, NULL); sprite = SDL_GetPointerProperty(props, name, NULL);
CATCH(e, aksl_fwrite((char *)name, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp)); CATCH(e, write_exact((char *)name, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite(&sprite, 1, sizeof(akgl_Sprite *), fp)); CATCH(e, write_exact(&sprite, 1, sizeof(akgl_Sprite *), fp));
} CLEANUP { } CLEANUP {
} PROCESS(e) { } PROCESS(e) {
} FINISH_NORETURN(e); } FINISH_NORETURN(e);
@@ -231,8 +245,8 @@ void akgl_game_save_spritesheetname_iterator(void *userdata, SDL_PropertiesID pr
ATTEMPT { ATTEMPT {
FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer"); FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
spritesheet = SDL_GetPointerProperty(props, name, NULL); spritesheet = SDL_GetPointerProperty(props, name, NULL);
CATCH(e, aksl_fwrite((char *)name, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp)); CATCH(e, write_exact((char *)name, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp));
CATCH(e, aksl_fwrite(&spritesheet, 1, sizeof(akgl_SpriteSheet *), fp)); CATCH(e, write_exact(&spritesheet, 1, sizeof(akgl_SpriteSheet *), fp));
} CLEANUP { } CLEANUP {
} PROCESS(e) { } PROCESS(e) {
} FINISH_NORETURN(e); } FINISH_NORETURN(e);
@@ -252,8 +266,8 @@ void akgl_game_save_charactername_iterator(void *userdata, SDL_PropertiesID prop
ATTEMPT { ATTEMPT {
FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer"); FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
character = SDL_GetPointerProperty(props, name, NULL); character = SDL_GetPointerProperty(props, name, NULL);
CATCH(e, aksl_fwrite((char *)name, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp)); CATCH(e, write_exact((char *)name, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite(&character, 1, sizeof(akgl_Character *), fp)); CATCH(e, write_exact(&character, 1, sizeof(akgl_Character *), fp));
} CLEANUP { } CLEANUP {
} PROCESS(e) { } PROCESS(e) {
} FINISH_NORETURN(e); } FINISH_NORETURN(e);
@@ -286,29 +300,29 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save_actors(FILE *fp)
AKGL_REGISTRY_ACTOR, AKGL_REGISTRY_ACTOR,
&akgl_game_save_actorname_iterator, &akgl_game_save_actorname_iterator,
(void *)fp); (void *)fp);
CATCH(e, aksl_fwrite((void *)&nullbuf, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp)); CATCH(e, write_exact((void *)&nullbuf, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite((void *)&nullbuf, 1, sizeof(akgl_Actor *), fp)); CATCH(e, write_exact((void *)&nullbuf, 1, sizeof(akgl_Actor *), fp));
// write the sprite name pointer table // write the sprite name pointer table
SDL_EnumerateProperties( SDL_EnumerateProperties(
AKGL_REGISTRY_SPRITE, AKGL_REGISTRY_SPRITE,
&akgl_game_save_spritename_iterator, &akgl_game_save_spritename_iterator,
(void *)fp); (void *)fp);
CATCH(e, aksl_fwrite((void *)&nullbuf, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp)); CATCH(e, write_exact((void *)&nullbuf, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite((void *)&nullbuf, 1, sizeof(akgl_Sprite *), fp)); CATCH(e, write_exact((void *)&nullbuf, 1, sizeof(akgl_Sprite *), fp));
// write the spritesheet name pointer table // write the spritesheet name pointer table
SDL_EnumerateProperties( SDL_EnumerateProperties(
AKGL_REGISTRY_SPRITESHEET, AKGL_REGISTRY_SPRITESHEET,
&akgl_game_save_spritesheetname_iterator, &akgl_game_save_spritesheetname_iterator,
(void *)fp); (void *)fp);
CATCH(e, aksl_fwrite((void *)&nullbuf, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp)); CATCH(e, write_exact((void *)&nullbuf, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp));
CATCH(e, aksl_fwrite((void *)&nullbuf, 1, sizeof(akgl_SpriteSheet *), fp)); CATCH(e, write_exact((void *)&nullbuf, 1, sizeof(akgl_SpriteSheet *), fp));
// write the character name pointer table // write the character name pointer table
SDL_EnumerateProperties( SDL_EnumerateProperties(
AKGL_REGISTRY_CHARACTER, AKGL_REGISTRY_CHARACTER,
&akgl_game_save_charactername_iterator, &akgl_game_save_charactername_iterator,
(void *)fp); (void *)fp);
CATCH(e, aksl_fwrite((void *)&nullbuf, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp)); CATCH(e, write_exact((void *)&nullbuf, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite((void *)&nullbuf, 1, sizeof(akgl_Character *), fp)); CATCH(e, write_exact((void *)&nullbuf, 1, sizeof(akgl_Character *), fp));
} CLEANUP { } CLEANUP {
} PROCESS(e) { } PROCESS(e) {
} FINISH(e, true); } FINISH(e, true);
@@ -323,7 +337,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save(char *fpath)
ATTEMPT { ATTEMPT {
FAIL_ZERO_BREAK(e, fpath, AKERR_NULLPOINTER, "NULL file path"); FAIL_ZERO_BREAK(e, fpath, AKERR_NULLPOINTER, "NULL file path");
CATCH(e, aksl_fopen(fpath, "wb", &fp)); CATCH(e, aksl_fopen(fpath, "wb", &fp));
CATCH(e, aksl_fwrite(&game, 1, sizeof(akgl_Game), fp)); CATCH(e, write_exact(&game, 1, sizeof(akgl_Game), fp));
CATCH(e, akgl_game_save_actors(fp)); CATCH(e, akgl_game_save_actors(fp));
} CLEANUP { } CLEANUP {
// CLEANUP must precede PROCESS: with the two transposed, the fclose // CLEANUP must precede PROCESS: with the two transposed, the fclose
@@ -363,8 +377,8 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_objectnamemap(FILE *fp, SDL_Pr
// corrupt name table as a successful load. // corrupt name table as a successful load.
while ( done == false ) { while ( done == false ) {
ATTEMPT { ATTEMPT {
CATCH(e, aksl_fread((void *)&objname, 1, namelength, fp)); CATCH(e, read_exact((void *)&objname, 1, namelength, fp));
CATCH(e, aksl_fread((void *)&ptr, 1, ptrlength, fp)); CATCH(e, read_exact((void *)&ptr, 1, ptrlength, fp));
// End of the map // End of the map
if ( ptr == 0x00 && objname[0] == 0x00 ) { if ( ptr == 0x00 && objname[0] == 0x00 ) {
done = true; done = true;
@@ -456,7 +470,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath)
ATTEMPT { ATTEMPT {
CATCH(e, aksl_fopen(fpath, "rb", &fp)); CATCH(e, aksl_fopen(fpath, "rb", &fp));
CATCH(e, aksl_fread((void *)&savegame, 1, sizeof(akgl_Game), fp)); CATCH(e, read_exact((void *)&savegame, 1, sizeof(akgl_Game), fp));
CATCH(e, akgl_game_load_versioncmp("library", (char *)&savegame.libversion, (char *)AKGL_VERSION)); CATCH(e, akgl_game_load_versioncmp("library", (char *)&savegame.libversion, (char *)AKGL_VERSION));
CATCH(e, akgl_game_load_versioncmp("game", (char *)&savegame.version, (char *)&game.version)); CATCH(e, akgl_game_load_versioncmp("game", (char *)&savegame.version, (char *)&game.version));
FAIL_NONZERO_RETURN( FAIL_NONZERO_RETURN(

View File

@@ -596,7 +596,7 @@ akerr_ErrorContext *akgl_tilemap_load(char *fname, akgl_Tilemap *dest)
//CATCH(errctx, akgl_heap_next_string(&tmpstr)); //CATCH(errctx, akgl_heap_next_string(&tmpstr));
//CATCH(errctx, akgl_string_initialize(tmpstr, NULL)); //CATCH(errctx, akgl_string_initialize(tmpstr, NULL));
//SDL_snprintf(tmpstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), fname); //SDL_snprintf(tmpstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), fname);
CATCH(errctx, aksl_realpath(fname, (char *)&dirnamestr->data)); CATCH(errctx, aksl_realpath(fname, (char *)&dirnamestr->data, sizeof(dirnamestr->data)));
dirname((char *)&dirnamestr->data); dirname((char *)&dirnamestr->data);
json = json_load_file(fname, 0, &error); json = json_load_file(fname, 0, &error);

View File

@@ -54,9 +54,16 @@ akerr_ErrorContext *akgl_path_relative_root(char *root, char *path, akgl_String
FAIL_RETURN(e, AKERR_OUTOFBOUNDS, "Total path length (%d) is greater than maximum akgl_String length (%d)", (rootlen + pathlen), AKGL_MAX_STRING_LENGTH); FAIL_RETURN(e, AKERR_OUTOFBOUNDS, "Total path length (%d) is greater than maximum akgl_String length (%d)", (rootlen + pathlen), AKGL_MAX_STRING_LENGTH);
} }
DISABLE_GCC_WARNING_FORMAT_TRUNCATION DISABLE_GCC_WARNING_FORMAT_TRUNCATION
CATCH(e, aksl_sprintf(&count, (char *)&pathbuf->data, "%s/%s", root, path)); CATCH(e, aksl_snprintf(
&count,
(char *)&pathbuf->data,
sizeof(pathbuf->data),
"%s/%s",
root,
path
));
RESTORE_GCC_WARNINGS RESTORE_GCC_WARNINGS
CATCH(e, aksl_realpath((char *)&pathbuf->data, (char *)&strbuf->data)); CATCH(e, aksl_realpath((char *)&pathbuf->data, (char *)&strbuf->data, sizeof(strbuf->data)));
CATCH(e, akgl_string_copy(strbuf, dst, 0)); CATCH(e, akgl_string_copy(strbuf, dst, 0));
} CLEANUP { } CLEANUP {
IGNORE(akgl_heap_release_string(strbuf)); IGNORE(akgl_heap_release_string(strbuf));
@@ -80,7 +87,7 @@ akerr_ErrorContext *akgl_path_relative(char *root, char *path, akgl_String *dst)
ATTEMPT { ATTEMPT {
// Is path relative to our current working directory? // Is path relative to our current working directory?
CATCH(e, aksl_realpath(path, (char *)&strbuf->data)); CATCH(e, aksl_realpath(path, (char *)&strbuf->data, sizeof(strbuf->data)));
// Yes it is. strbuf->data contains the absolute path. // Yes it is. strbuf->data contains the absolute path.
CATCH(e, akgl_string_copy(strbuf, dst, 0)); CATCH(e, akgl_string_copy(strbuf, dst, 0));
} CLEANUP { } CLEANUP {
@@ -109,7 +116,7 @@ akerr_ErrorContext *akgl_path_relative_from(char *path, char *from, akgl_String
FAIL_ZERO_RETURN(e, path, AKERR_NULLPOINTER, "path"); FAIL_ZERO_RETURN(e, path, AKERR_NULLPOINTER, "path");
FAIL_ZERO_RETURN(e, from, AKERR_NULLPOINTER, "from"); FAIL_ZERO_RETURN(e, from, AKERR_NULLPOINTER, "from");
PASS(e, akgl_heap_next_string(&dirnamestr)); PASS(e, akgl_heap_next_string(&dirnamestr));
PASS(e, aksl_realpath(from, (char *)&dirnamestr->data)); PASS(e, aksl_realpath(from, (char *)&dirnamestr->data, sizeof(dirnamestr->data)));
dirname((char *)&dirnamestr->data); dirname((char *)&dirnamestr->data);
SUCCEED_RETURN(e); SUCCEED_RETURN(e);