Fix several memory leaks in level_parser.y that occur when parsing errors occur:

* In case of a semantic error (i.e. we detect something is wrong in a parsing rule) deallocate the resources of our current tokens __before__ calling YYABORT
 * Only add a LEVEL_DATASET* to the psLevels list when we've fully and succesfully finished parsing of the corresponding level_entry
 * Add a bison "destructor" that handles destruction of tokens on the parsing stack when a syntax error occurs (i.e. the current tokens cannot be matched to any parsing rule)


git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@4888 4a71c877-e1ca-e34f-864e-861f7616d084
master
Giel van Schijndel 2008-05-02 20:37:23 +00:00
parent efd188a632
commit 0071531040
1 changed files with 36 additions and 3 deletions

View File

@ -43,6 +43,21 @@ void yyerror(const char* msg)
debug(LOG_ERROR, "Level File parse error: `%s` at line `%d` text `%s`", msg, levGetErrorLine(), levGetErrorText());
}
static void freeDataSet(LEVEL_DATASET * const d)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(d->apDataFiles); ++i)
{
if (d->apDataFiles[i] != NULL)
{
free(d->apDataFiles[i]);
}
}
free(d->pName);
free(d);
}
#define YYPARSE_PARAM yyparse_param
#define yycontext ((parser_context*)yyparse_param)
@ -63,7 +78,18 @@ void yyerror(const char* msg)
%token <sval> QTEXT
%token <ival> INTEGER
%destructor { free($$); } IDENTIFIER QTEXT
%destructor {
// Force type checking by the compiler
char * const s = $$;
if (s != NULL)
free(s);
} IDENTIFIER QTEXT
%destructor {
if ($$ != NULL)
freeDataSet($$);
} level_line level_rule
/* keywords */
%token LEVEL
@ -83,7 +109,7 @@ void yyerror(const char* msg)
%token MISS_CLEAR
/* rule types */
%type <dataset> level_rule
%type <dataset> level_line level_rule
%type <ltype> level_type
%start lev_file
@ -99,6 +125,9 @@ lev_file: /* Empty to allow empty files */
;
level_entry: level_line level_directives_1st dataload_directives
{
LIST_ADDEND(psLevels, $1, LEVEL_DATASET);
}
;
level_line: level_rule IDENTIFIER
@ -111,12 +140,16 @@ level_line: level_rule IDENTIFIER
if (psFoundData == NULL)
{
yyerror("Cannot find full data set for `camchange'");
freeDataSet($1);
free($2);
YYABORT;
}
if (psFoundData->type != LDS_CAMSTART)
{
yyerror("Invalid data set name for `camchange'");
freeDataSet($1);
free($2);
YYABORT;
}
psFoundData->psChange = $1;
@ -127,6 +160,7 @@ level_line: level_rule IDENTIFIER
// Make this dataset current to our parsing context
yycontext->dataset = $1;
$$ = $1;
}
;
@ -145,7 +179,6 @@ level_rule: level_type
$$->game = -1;
$$->dataDir = yycontext->datadir;
LIST_ADDEND(psLevels, $$, LEVEL_DATASET);
yycontext->currData = 0;
yycontext->dataLoaded = false;