From 4c4885109677a937215ad842a8b8ad737a469478 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 22 Aug 2001 21:55:01 +0000 Subject: [PATCH] fix a buffer overflow in new_label_expr use reference counting for temp defs and call PR_FreeTempDefs at the end of emit_sub_expr as well as emit_expr. fix a (relatively harmless) bug in type processesing of foo.bar = --- tools/qfcc/include/qfcc.h | 4 ++ tools/qfcc/source/emit.c | 75 ++++++++++++++++++++++++-------------- tools/qfcc/source/expr.c | 49 ++++++++++++++++++++++--- tools/qfcc/source/pr_def.c | 30 +++++++++++---- 4 files changed, 116 insertions(+), 42 deletions(-) diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index 909437c8b..14a212654 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -290,6 +290,9 @@ typedef struct def_s { int initialized;// 1 when a declaration included "= immediate" statref_t *refs; // for relocations + int users; // ref counted temps + struct expr_s *expr; // temp expr using this def + struct def_s *def_next; // for writing out the global defs list struct def_s *next; // general purpose linking struct def_s *scope_next; // to facilitate hash table removal @@ -425,6 +428,7 @@ type_t *PR_ParseType (void); char *PR_ParseName (void); def_t *PR_ParseImmediate (def_t *def); def_t *PR_ReuseConstant (expr_t *expr, def_t *def); +type_t *PR_FindType (type_t *new); qboolean PR_Check (token_type_t type, const char *string); void PR_Expect (token_type_t type, const char *string); diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 5fed68ef2..8ee581a51 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -7,6 +7,8 @@ #include "scope.h" #include "qc-parse.h" +def_t *emit_sub_expr (expr_t *e, def_t *dest); + def_t * emit_statement (int sline, opcode_t *op, def_t *var_a, def_t *var_b, def_t *var_c) { @@ -41,11 +43,19 @@ emit_statement (int sline, opcode_t *op, def_t *var_a, def_t *var_b, def_t *var_ statement->c = 0; ret = var_a; } else { // allocate result space - if (!var_c) + if (!var_c) { var_c = PR_GetTempDef (types[op->type_c], pr_scope); + var_c->users += 2; + } statement->c = var_c->ofs; ret = var_c; } + if (var_a) + var_a->users--; + if (var_b) + var_b->users--; + if (var_c) + var_c->users--; PR_AddStatementRef (var_a, statement, 0); PR_AddStatementRef (var_b, statement, 1); PR_AddStatementRef (var_c, statement, 2); @@ -55,8 +65,6 @@ emit_statement (int sline, opcode_t *op, def_t *var_a, def_t *var_b, def_t *var_ return var_c; } -def_t *emit_sub_expr (expr_t *e, def_t *dest); - void emit_branch (int line, opcode_t *op, expr_t *e, expr_t *l) { @@ -125,7 +133,7 @@ emit_assign_expr (expr_t *e) expr_t *e2 = e->e.expr.e2; def_a = emit_sub_expr (e1, 0); - if (def_a->type == &type_pointer) { + if (def_a->type->type == ev_pointer) { def_b = emit_sub_expr (e2, 0); op = PR_Opcode_Find ("=", 5, def_b, def_a, &def_void); emit_statement (e->line, op, def_b, def_a, 0); @@ -154,27 +162,31 @@ emit_assign_expr (expr_t *e) def_t * emit_sub_expr (expr_t *e, def_t *dest) { - opcode_t *op; - char *operator; - def_t *def_a, *def_b; - int priority; + opcode_t *op; + char *operator; + def_t *def_a, *def_b, *d = 0; + int priority; switch (e->type) { case ex_block: if (e->e.block.result) { - def_t *res = emit_sub_expr (e->e.block.result, dest); + d = emit_sub_expr (e->e.block.result, dest); for (e = e->e.block.head; e; e = e->next) emit_expr (e); - return res; + break; } case ex_label: error (e, "internal error"); abort (); case ex_expr: - if (e->e.expr.op == 'c') - return emit_function_call (e, dest); - if (e->e.expr.op == '=') - return emit_assign_expr (e); + if (e->e.expr.op == 'c') { + d = emit_function_call (e, dest); + break; + } + if (e->e.expr.op == '=') { + d = emit_assign_expr (e); + break; + } def_a = emit_sub_expr (e->e.expr.e1, 0); def_b = emit_sub_expr (e->e.expr.e2, 0); switch (e->e.expr.op) { @@ -257,10 +269,13 @@ emit_sub_expr (expr_t *e, def_t *dest) default: abort (); } - if (!dest) + if (!dest) { dest = PR_GetTempDef (e->e.expr.type, pr_scope); + dest->users += 2; + } op = PR_Opcode_Find (operator, priority, def_a, def_b, dest); - return emit_statement (e->line, op, def_a, def_b, dest); + d = emit_statement (e->line, op, def_a, def_b, dest); + break; case ex_uexpr: if (e->e.expr.op == '!') { operator = "!"; @@ -281,23 +296,30 @@ emit_sub_expr (expr_t *e, def_t *dest) priority = 3; def_a = PR_ReuseConstant (&zero, 0); def_b = emit_sub_expr (e->e.expr.e1, 0); - if (!dest) + if (!dest) { dest = PR_GetTempDef (e->e.expr.type, pr_scope); + dest->users += 2; + } } else { abort (); } op = PR_Opcode_Find (operator, priority, def_a, def_b, dest); - return emit_statement (e->line, op, def_a, def_b, dest); + d = emit_statement (e->line, op, def_a, def_b, dest); + break; case ex_def: - return e->e.def; + d = e->e.def; + break; case ex_temp: if (!e->e.temp.def) { if (dest) e->e.temp.def = dest; else e->e.temp.def = PR_GetTempDef (e->e.temp.type, pr_scope); + e->e.temp.def->users = e->e.temp.users; + e->e.temp.def->expr = e; } - return e->e.temp.def; + d = e->e.temp.def; + break; case ex_string: case ex_float: case ex_vector: @@ -307,9 +329,11 @@ emit_sub_expr (expr_t *e, def_t *dest) case ex_pointer: case ex_quaternion: case ex_integer: - return PR_ReuseConstant (e, 0); + d = PR_ReuseConstant (e, 0); + break; } - return 0; + PR_FreeTempDefs (); + return d; } void @@ -320,10 +344,6 @@ emit_expr (expr_t *e) def_t *def_b; statref_t *ref; elabel_t *label; - //opcode_t *op; - static int level = 0; - - level++; switch (e->type) { case ex_label: @@ -404,6 +424,5 @@ emit_expr (expr_t *e) warning (e, "Ignoring useless expression"); break; } - if (--level == 0) - PR_FreeTempDefs (); + PR_FreeTempDefs (); } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index e648919d2..e04018a46 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -199,6 +199,15 @@ type_mismatch (expr_t *e1, expr_t *e2, int op) type_names[t1], get_op_string (op), type_names[t2]); } +void +inc_users (expr_t *e) +{ + if (e && e->type == ex_temp) + e->e.temp.users++; + else if (e && e->type == ex_block) + inc_users (e->e.block.result); +} + expr_t * new_expr (void) { @@ -211,13 +220,14 @@ new_expr (void) expr_t * new_label_expr (void) { - static int label = 0; - int lnum = ++label; + static int label = 0; + int lnum = ++label; const char *fname = current_func->def->name; + int len = 1 + strlen (fname) + 1 + ceil (log10 (lnum) + 1) + 1; expr_t *l = new_expr (); l->type = ex_label; - l->e.label.name = malloc (1 + strlen (fname) + 1 + ceil (log10 (lnum)) + 1); + l->e.label.name = malloc (len); sprintf (l->e.label.name, "$%s_%d", fname, lnum); return l; } @@ -238,6 +248,9 @@ new_binary_expr (int op, expr_t *e1, expr_t *e2) { expr_t *e = new_expr (); + inc_users (e1); + inc_users (e2); + e->type = ex_expr; e->e.expr.op = op; e->e.expr.e1 = e1; @@ -250,6 +263,8 @@ new_unary_expr (int op, expr_t *e1) { expr_t *e = new_expr (); + inc_users (e1); + e->type = ex_uexpr; e->e.expr.op = op; e->e.expr.e1 = e1; @@ -327,11 +342,28 @@ print_expr (expr_t *e) printf (" u%s", get_op_string (e->e.expr.op)); break; case ex_def: - printf ("%s", e->e.def->name); + if (e->e.def->name) + printf ("%s", e->e.def->name); + if (e->e.def->scope) { + printf ("<%d>", e->e.def->ofs); + } else { + printf ("[%d]", e->e.def->ofs); + } break; case ex_temp: + printf ("("); print_expr (e->e.temp.expr); - printf ("@"); + printf (":"); + if (e->e.temp.def) { + if (e->e.temp.def->name) { + printf("%s", e->e.temp.def->name); + } else { + printf("<%d>", e->e.temp.def->ofs); + } + } else { + printf("<>"); + } + printf (":%s)@", type_names [e->e.temp.type->type]); break; case ex_string: printf ("\"%s\"", e->e.string_val); @@ -797,7 +829,12 @@ type_mismatch: type = &type_float; } if (op == '=' && e1->type == ex_expr && e1->e.expr.op == '.') { - e1->e.expr.type = &type_pointer; + type_t new; + + memset (&new, 0, sizeof (new)); + new.type = ev_pointer; + type = new.aux_type = e1->e.expr.type; + e1->e.expr.type = PR_FindType (&new); } if (!type) error (e1, "internal error"); diff --git a/tools/qfcc/source/pr_def.c b/tools/qfcc/source/pr_def.c index 1f0098b64..f36d5da4f 100644 --- a/tools/qfcc/source/pr_def.c +++ b/tools/qfcc/source/pr_def.c @@ -204,6 +204,7 @@ PR_GetTempDef (type_t *type, def_t *scope) def->ofs = scope->num_locals; scope->num_locals += type_size[size]; } + def->users = 0; def->next = temp_scope.next; temp_scope.next = def; return def; @@ -212,27 +213,40 @@ PR_GetTempDef (type_t *type, def_t *scope) void PR_FreeTempDefs (void) { - def_t *def, *d; + def_t **def, *d; int size; - for (def = temp_scope.next; def; def = d) { - size = type_size[def->type->type]; - d = def->next; - def->next = free_temps[size]; - free_temps[size] = def; + def = &temp_scope.next; + while (*def) { + if ((*def)->users <= 0) { + d = *def; + *def = d->next; + + size = type_size[d->type->type]; + if (d->expr) + d->expr->e.temp.def = 0; + + d->next = free_temps[size]; + free_temps[size] = d; + } else { + def = &(*def)->next; + } } - temp_scope.next = 0; } void PR_ResetTempDefs (void) { int i; - //def_t *d; + def_t *d; for (i = 0; i < sizeof (free_temps) / sizeof (free_temps[0]); i++) { free_temps[i] = 0; } + + for (d = temp_scope.next; d; d = d->next) + printf ("%3d %3d\n", d->ofs, d->users); + temp_scope.next = 0; } void