mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-22 20:41:20 +00:00
uninitialized variable detection. not perfect (lots of false negatives, but
fewer than before;) but prozac isn't giving any false positives.
This commit is contained in:
parent
c2807a6da1
commit
5ca785e7e8
5 changed files with 66 additions and 3 deletions
|
@ -302,6 +302,7 @@ typedef struct def_s {
|
|||
struct def_s *next; // general purpose linking
|
||||
struct def_s *scope_next; // to facilitate hash table removal
|
||||
struct def_s *scope; // function the var was defined in, or NULL
|
||||
struct def_s *parent; // vector/quaternion member
|
||||
} def_t;
|
||||
|
||||
//============================================================================
|
||||
|
@ -470,6 +471,7 @@ def_t *PR_GetTempDef (type_t *type, def_t *scope);
|
|||
void PR_FreeTempDefs ();
|
||||
void PR_ResetTempDefs ();
|
||||
void PR_FlushScope (def_t *scope, int force_used);
|
||||
void PR_DefInitialized (def_t *d);
|
||||
|
||||
void PR_PrintDefs (void);
|
||||
void PR_PrintFunction (def_t *def);
|
||||
|
@ -559,6 +561,7 @@ typedef struct {
|
|||
int quiet; // not so much chatter
|
||||
int debug; // produce debug info
|
||||
int undefined_function_warning; // print a warning when a function isn't defined
|
||||
int warn_uninitialized; // warn for uninitialized vars
|
||||
} options_t;
|
||||
|
||||
extern options_t options;
|
||||
|
|
|
@ -812,6 +812,24 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
|
|||
type_t *type = 0;
|
||||
expr_t *e;
|
||||
|
||||
if (options.warn_uninitialized) {
|
||||
if (op != '='
|
||||
&& e1->type == ex_def
|
||||
&& !e1->e.def->initialized) {
|
||||
warning (e1, "%s may be used uninitialized", e1->e.def->name);
|
||||
e1->e.def->initialized = 1; // only warn once
|
||||
}
|
||||
if (e2->type == ex_def
|
||||
&& !e2->e.def->initialized
|
||||
&& !(e2->e.def->type->type == ev_func && !e2->e.def->scope)) {
|
||||
warning (e2, "%s may be used uninitialized", e2->e.def->name);
|
||||
e2->e.def->initialized = 1; // only warn once
|
||||
}
|
||||
}
|
||||
|
||||
if (op == '=' && e1->type == ex_def)
|
||||
PR_DefInitialized (e1->e.def);
|
||||
|
||||
if (e1->type == ex_block && e1->e.block.is_call
|
||||
&& e2->type == ex_block && e2->e.block.is_call
|
||||
&& e1->e.block.result) {
|
||||
|
@ -936,6 +954,12 @@ asx_expr (int op, expr_t *e1, expr_t *e2)
|
|||
expr_t *
|
||||
unary_expr (int op, expr_t *e)
|
||||
{
|
||||
if (options.warn_uninitialized
|
||||
&& e->type == ex_def
|
||||
&& !e->e.def->initialized) {
|
||||
warning (e, "%s may be used uninitialized", e->e.def->name);
|
||||
e->e.def->initialized = 1; // only warn once
|
||||
}
|
||||
switch (op) {
|
||||
case '-':
|
||||
switch (e->type) {
|
||||
|
|
|
@ -98,14 +98,17 @@ PR_GetDef (type_t *type, const char *name, def_t *scope, int *allocate)
|
|||
sprintf (element, "%s_x", name);
|
||||
d = PR_GetDef (&type_float, element, scope, allocate);
|
||||
d->used = 1;
|
||||
d->parent = def;
|
||||
|
||||
sprintf (element, "%s_y", name);
|
||||
d = PR_GetDef (&type_float, element, scope, allocate);
|
||||
d->used = 1;
|
||||
d->parent = def;
|
||||
|
||||
sprintf (element, "%s_z", name);
|
||||
d = PR_GetDef (&type_float, element, scope, allocate);
|
||||
d->used = 1;
|
||||
d->parent = def;
|
||||
} else {
|
||||
*allocate += type_size[type->type];
|
||||
}
|
||||
|
@ -119,14 +122,17 @@ PR_GetDef (type_t *type, const char *name, def_t *scope, int *allocate)
|
|||
sprintf (element, "%s_x", name);
|
||||
d = PR_GetDef (&type_floatfield, element, scope, allocate);
|
||||
d->used = 1; // always `used'
|
||||
d->parent = def;
|
||||
|
||||
sprintf (element, "%s_y", name);
|
||||
d = PR_GetDef (&type_floatfield, element, scope, allocate);
|
||||
d->used = 1; // always `used'
|
||||
d->parent = def;
|
||||
|
||||
sprintf (element, "%s_z", name);
|
||||
d = PR_GetDef (&type_floatfield, element, scope, allocate);
|
||||
d->used = 1; // always `used'
|
||||
d->parent = def;
|
||||
} else {
|
||||
pr.size_fields += type_size[type->aux_type->type];
|
||||
}
|
||||
|
@ -277,3 +283,27 @@ PR_FlushScope (def_t *scope, int force_used)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PR_DefInitialized (def_t *d)
|
||||
{
|
||||
d->initialized = 1;
|
||||
if (d->type == &type_vector
|
||||
|| (d->type->type == ev_field
|
||||
&& d->type->aux_type == &type_vector)) {
|
||||
d = d->def_next;
|
||||
d->initialized = 1;
|
||||
d = d->def_next;
|
||||
d->initialized = 1;
|
||||
d = d->def_next;
|
||||
d->initialized = 1;
|
||||
}
|
||||
if (d->parent) {
|
||||
d = d->parent;
|
||||
if (d->type == &type_vector
|
||||
&& d->def_next->initialized
|
||||
&& d->def_next->def_next->initialized
|
||||
&& d->def_next->def_next->def_next->initialized)
|
||||
d->initialized = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,6 +204,8 @@ def_item
|
|||
: def_name opt_initializer
|
||||
{
|
||||
$$ = $1;
|
||||
if (!$$->scope && $$->type->type != ev_func)
|
||||
PR_DefInitialized ($$);
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -246,11 +248,13 @@ opt_initializer
|
|||
e->type = ex_def;
|
||||
e->e.def = current_def;
|
||||
append_expr (local_expr, binary_expr ('=', e, $2));
|
||||
PR_DefInitialized (current_def);
|
||||
} else {
|
||||
if ($2->type >= ex_string)
|
||||
if ($2->type >= ex_string) {
|
||||
current_def = PR_ReuseConstant ($2, current_def);
|
||||
else
|
||||
} else {
|
||||
error ($2, "non-constant expression used for initializer");
|
||||
}
|
||||
}
|
||||
}
|
||||
| '=' '#' const
|
||||
|
@ -617,7 +621,8 @@ build_scope (function_t *f, def_t *func)
|
|||
f->parm_ofs[i] = def->ofs;
|
||||
if (i > 0 && f->parm_ofs[i] < f->parm_ofs[i - 1])
|
||||
Error ("bad parm order");
|
||||
def->used = 1; // don't warn for unused params
|
||||
def->used = 1; // don't warn for unused params
|
||||
PR_DefInitialized (def); // params are assumed to be initialized
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -920,6 +920,7 @@ main (int argc, char **argv)
|
|||
myargv = argv;
|
||||
|
||||
options.version = PROG_VERSION;
|
||||
options.warn_uninitialized = 1;
|
||||
|
||||
if (CheckParm ("-h") || CheckParm ("--help")) {
|
||||
printf ("%s - A compiler for the QuakeC language\n", argv[0]);
|
||||
|
|
Loading…
Reference in a new issue