mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-29 23:52:22 +00:00
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 =
This commit is contained in:
parent
3177d9c7eb
commit
4c48851096
4 changed files with 116 additions and 42 deletions
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue