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:
Bill Currie 2001-10-18 20:05:26 +00:00
parent c2807a6da1
commit 5ca785e7e8
5 changed files with 66 additions and 3 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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;
}
}

View file

@ -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
}
}

View file

@ -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]);