In C-CON build, prevent leak of gamevar/gamearray labels on savegame loading.

Also, rewrite the loops in Gv_Free() and Gv_Clear() in the plain fashion so
that they are correct even if the number of gamearrays exceeds the number of
gamevars.

git-svn-id: https://svn.eduke32.com/eduke32@4839 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2014-12-26 17:29:56 +00:00
parent 7da543e4f0
commit b2e09b5a18
3 changed files with 50 additions and 36 deletions

View file

@ -36,52 +36,53 @@ LUNATIC_CB void (*A_ResetVars)(int32_t iActor);
#else #else
# include "gamestructures.c" # include "gamestructures.c"
static void Gv_Free(void) /* called from Gv_ReadSave() and Gv_ResetVars() */ // Frees the memory for the *values* of game variables and arrays. Resets their
// counts to zero. Call this function as many times as needed.
//
// Returns: old g_gameVarCount | (g_gameArrayCount<<16).
static int32_t Gv_Free(void)
{ {
// call this function as many times as needed. for (int32_t i=0; i<g_gameVarCount; i++)
int32_t i;
for (i=0; i<g_gameVarCount; i++)
{ {
if (aGameVars[i].dwFlags & GAMEVAR_USER_MASK) if (aGameVars[i].dwFlags & GAMEVAR_USER_MASK)
ALIGNED_FREE_AND_NULL(aGameVars[i].val.plValues); ALIGNED_FREE_AND_NULL(aGameVars[i].val.plValues);
aGameVars[i].dwFlags |= GAMEVAR_RESET; aGameVars[i].dwFlags |= GAMEVAR_RESET;
}
if (i >= MAXGAMEARRAYS) for (int32_t i=0; i<g_gameArrayCount; i++)
continue; {
if (aGameArrays[i].dwFlags & GAMEARRAY_NORMAL) if (aGameArrays[i].dwFlags & GAMEARRAY_NORMAL)
ALIGNED_FREE_AND_NULL(aGameArrays[i].plValues); ALIGNED_FREE_AND_NULL(aGameArrays[i].plValues);
aGameArrays[i].dwFlags |= GAMEARRAY_RESET; aGameArrays[i].dwFlags |= GAMEARRAY_RESET;
} }
EDUKE32_STATIC_ASSERT(MAXGAMEVARS < 32768);
int32_t ret = g_gameVarCount | (g_gameArrayCount<<16);
g_gameVarCount = g_gameArrayCount = 0; g_gameVarCount = g_gameArrayCount = 0;
hash_init(&h_gamevars); hash_init(&h_gamevars);
hash_init(&h_arrays); hash_init(&h_arrays);
return ret;
} }
// Calls Gv_Free() and in addition frees the labels of all game variables and
// arrays.
// Only call this function ONCE...
static void Gv_Clear(void) static void Gv_Clear(void)
{ {
// only call this function ONCE... int32_t n = Gv_Free();
int32_t i; int32_t gameVarCount = n&65535, gameArrayCount = n>>16;
Gv_Free();
// Now, only do work that Gv_Free() hasn't done. // Now, only do work that Gv_Free() hasn't done.
for (i=0; i<g_gameVarCount; i++) for (int32_t i=0; i<gameVarCount; i++)
{
DO_FREE_AND_NULL(aGameVars[i].szLabel); DO_FREE_AND_NULL(aGameVars[i].szLabel);
aGameVars[i].val.lValue=0; for (int32_t i=0; i<gameArrayCount; i++)
if (i >= MAXGAMEARRAYS)
continue;
DO_FREE_AND_NULL(aGameArrays[i].szLabel); DO_FREE_AND_NULL(aGameArrays[i].szLabel);
} }
}
int32_t Gv_ReadSave(int32_t fil, int32_t newbehav) int32_t Gv_ReadSave(int32_t fil, int32_t newbehav)
{ {
@ -107,9 +108,18 @@ int32_t Gv_ReadSave(int32_t fil, int32_t newbehav)
if (kdfread(&g_gameVarCount,sizeof(g_gameVarCount),1,fil) != 1) goto corrupt; if (kdfread(&g_gameVarCount,sizeof(g_gameVarCount),1,fil) != 1) goto corrupt;
for (i=0; i<g_gameVarCount; i++) for (i=0; i<g_gameVarCount; i++)
{ {
if (kdfread(&(aGameVars[i]),sizeof(gamevar_t),1,fil) != 1) goto corrupt; char *const olabel = aGameVars[i].szLabel;
if (kdfread(&aGameVars[i], sizeof(gamevar_t), 1, fil) != 1)
goto corrupt;
if (olabel == NULL)
aGameVars[i].szLabel = (char *)Xmalloc(MAXVARLABEL * sizeof(uint8_t)); aGameVars[i].szLabel = (char *)Xmalloc(MAXVARLABEL * sizeof(uint8_t));
if (kdfread(aGameVars[i].szLabel,sizeof(uint8_t) * MAXVARLABEL, 1, fil) != 1) goto corrupt; else
aGameVars[i].szLabel = olabel;
if (kdfread(aGameVars[i].szLabel, MAXVARLABEL, 1, fil) != 1)
goto corrupt;
hash_add(&h_gamevars, aGameVars[i].szLabel,i, 1); hash_add(&h_gamevars, aGameVars[i].szLabel,i, 1);
if (aGameVars[i].dwFlags & GAMEVAR_PERPLAYER) if (aGameVars[i].dwFlags & GAMEVAR_PERPLAYER)
@ -138,11 +148,19 @@ int32_t Gv_ReadSave(int32_t fil, int32_t newbehav)
if (aGameArrays[i].dwFlags&GAMEARRAY_READONLY) if (aGameArrays[i].dwFlags&GAMEARRAY_READONLY)
continue; continue;
// read for .size and .dwFlags (the rest are pointers): char *const olabel = aGameArrays[i].szLabel;
if (kdfread(&aGameArrays[i],sizeof(gamearray_t),1,fil) != 1) goto corrupt;
// read for .size and .dwFlags (the rest are pointers):
if (kdfread(&aGameArrays[i], sizeof(gamearray_t), 1, fil) != 1)
goto corrupt;
if (olabel == NULL)
aGameArrays[i].szLabel = (char *)Xmalloc(MAXARRAYLABEL * sizeof(uint8_t)); aGameArrays[i].szLabel = (char *)Xmalloc(MAXARRAYLABEL * sizeof(uint8_t));
if (kdfread(aGameArrays[i].szLabel,sizeof(uint8_t) * MAXARRAYLABEL, 1, fil) != 1) goto corrupt; else
aGameArrays[i].szLabel = olabel;
if (kdfread(aGameArrays[i].szLabel,sizeof(uint8_t) * MAXARRAYLABEL, 1, fil) != 1)
goto corrupt;
hash_add(&h_arrays, aGameArrays[i].szLabel, i, 1); hash_add(&h_arrays, aGameArrays[i].szLabel, i, 1);
aGameArrays[i].plValues = (intptr_t *)Xaligned_alloc(ACTOR_VAR_ALIGNMENT, aGameArrays[i].size * GAR_ELTSZ); aGameArrays[i].plValues = (intptr_t *)Xaligned_alloc(ACTOR_VAR_ALIGNMENT, aGameArrays[i].size * GAR_ELTSZ);
@ -808,7 +826,7 @@ nastyhacks:
if (EDUKE32_PREDICT_FALSE(index < 0 || index >= siz)) if (EDUKE32_PREDICT_FALSE(index < 0 || index >= siz))
{ {
negateResult = index; negateResult = index;
CON_ERRPRINTF("%s %s[%d]\n", gvxerrs[GVX_BADINDEX], aGameArrays[id].szLabel, index);; CON_ERRPRINTF("%s %s[%d]\n", gvxerrs[GVX_BADINDEX], aGameArrays[id].szLabel, index);
return -1; return -1;
} }

View file

@ -54,7 +54,7 @@ enum GamevarFlags_t {
#define PLAYER_VAR_ALIGNMENT (sizeof(intptr_t)) #define PLAYER_VAR_ALIGNMENT (sizeof(intptr_t))
#define ACTOR_VAR_ALIGNMENT 16 #define ACTOR_VAR_ALIGNMENT 16
# define MAXGAMEARRAYS (MAXGAMEVARS>>2) // must be lower than MAXGAMEVARS # define MAXGAMEARRAYS (MAXGAMEVARS>>2) // must be strictly smaller than MAXGAMEVARS
# define MAXARRAYLABEL MAXVARLABEL # define MAXARRAYLABEL MAXVARLABEL
enum GamearrayFlags_t { enum GamearrayFlags_t {

View file

@ -40,10 +40,7 @@ static void Gv_Clear(void)
for (; i>=0; i--) for (; i>=0; i--)
{ {
if (aGameVars[i].szLabel) DO_FREE_AND_NULL(aGameVars[i].szLabel);
Bfree(aGameVars[i].szLabel);
aGameVars[i].szLabel = NULL;
if ((aGameVars[i].dwFlags & GAMEVAR_USER_MASK) && aGameVars[i].val.plValues) if ((aGameVars[i].dwFlags & GAMEVAR_USER_MASK) && aGameVars[i].val.plValues)
{ {
@ -59,8 +56,7 @@ static void Gv_Clear(void)
gamearray_t *const gar = &aGameArrays[i]; gamearray_t *const gar = &aGameArrays[i];
Bfree(gar->szLabel); DO_FREE_AND_NULL(gar->szLabel);
gar->szLabel = NULL;
if ((gar->dwFlags & GAMEARRAY_NORMAL) && gar->vals) if ((gar->dwFlags & GAMEARRAY_NORMAL) && gar->vals)
{ {