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
|
@ -290,6 +290,9 @@ typedef struct def_s {
|
||||||
int initialized;// 1 when a declaration included "= immediate"
|
int initialized;// 1 when a declaration included "= immediate"
|
||||||
statref_t *refs; // for relocations
|
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 *def_next; // for writing out the global defs list
|
||||||
struct def_s *next; // general purpose linking
|
struct def_s *next; // general purpose linking
|
||||||
struct def_s *scope_next; // to facilitate hash table removal
|
struct def_s *scope_next; // to facilitate hash table removal
|
||||||
|
@ -425,6 +428,7 @@ type_t *PR_ParseType (void);
|
||||||
char *PR_ParseName (void);
|
char *PR_ParseName (void);
|
||||||
def_t *PR_ParseImmediate (def_t *def);
|
def_t *PR_ParseImmediate (def_t *def);
|
||||||
def_t *PR_ReuseConstant (expr_t *expr, 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);
|
qboolean PR_Check (token_type_t type, const char *string);
|
||||||
void PR_Expect (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 "scope.h"
|
||||||
#include "qc-parse.h"
|
#include "qc-parse.h"
|
||||||
|
|
||||||
|
def_t *emit_sub_expr (expr_t *e, def_t *dest);
|
||||||
|
|
||||||
def_t *
|
def_t *
|
||||||
emit_statement (int sline, opcode_t *op, def_t *var_a, def_t *var_b, def_t *var_c)
|
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;
|
statement->c = 0;
|
||||||
ret = var_a;
|
ret = var_a;
|
||||||
} else { // allocate result space
|
} else { // allocate result space
|
||||||
if (!var_c)
|
if (!var_c) {
|
||||||
var_c = PR_GetTempDef (types[op->type_c], pr_scope);
|
var_c = PR_GetTempDef (types[op->type_c], pr_scope);
|
||||||
|
var_c->users += 2;
|
||||||
|
}
|
||||||
statement->c = var_c->ofs;
|
statement->c = var_c->ofs;
|
||||||
ret = var_c;
|
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_a, statement, 0);
|
||||||
PR_AddStatementRef (var_b, statement, 1);
|
PR_AddStatementRef (var_b, statement, 1);
|
||||||
PR_AddStatementRef (var_c, statement, 2);
|
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;
|
return var_c;
|
||||||
}
|
}
|
||||||
|
|
||||||
def_t *emit_sub_expr (expr_t *e, def_t *dest);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
emit_branch (int line, opcode_t *op, expr_t *e, expr_t *l)
|
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;
|
expr_t *e2 = e->e.expr.e2;
|
||||||
|
|
||||||
def_a = emit_sub_expr (e1, 0);
|
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);
|
def_b = emit_sub_expr (e2, 0);
|
||||||
op = PR_Opcode_Find ("=", 5, def_b, def_a, &def_void);
|
op = PR_Opcode_Find ("=", 5, def_b, def_a, &def_void);
|
||||||
emit_statement (e->line, op, def_b, def_a, 0);
|
emit_statement (e->line, op, def_b, def_a, 0);
|
||||||
|
@ -156,25 +164,29 @@ emit_sub_expr (expr_t *e, def_t *dest)
|
||||||
{
|
{
|
||||||
opcode_t *op;
|
opcode_t *op;
|
||||||
char *operator;
|
char *operator;
|
||||||
def_t *def_a, *def_b;
|
def_t *def_a, *def_b, *d = 0;
|
||||||
int priority;
|
int priority;
|
||||||
|
|
||||||
switch (e->type) {
|
switch (e->type) {
|
||||||
case ex_block:
|
case ex_block:
|
||||||
if (e->e.block.result) {
|
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)
|
for (e = e->e.block.head; e; e = e->next)
|
||||||
emit_expr (e);
|
emit_expr (e);
|
||||||
return res;
|
break;
|
||||||
}
|
}
|
||||||
case ex_label:
|
case ex_label:
|
||||||
error (e, "internal error");
|
error (e, "internal error");
|
||||||
abort ();
|
abort ();
|
||||||
case ex_expr:
|
case ex_expr:
|
||||||
if (e->e.expr.op == 'c')
|
if (e->e.expr.op == 'c') {
|
||||||
return emit_function_call (e, dest);
|
d = emit_function_call (e, dest);
|
||||||
if (e->e.expr.op == '=')
|
break;
|
||||||
return emit_assign_expr (e);
|
}
|
||||||
|
if (e->e.expr.op == '=') {
|
||||||
|
d = emit_assign_expr (e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
||||||
def_b = emit_sub_expr (e->e.expr.e2, 0);
|
def_b = emit_sub_expr (e->e.expr.e2, 0);
|
||||||
switch (e->e.expr.op) {
|
switch (e->e.expr.op) {
|
||||||
|
@ -257,10 +269,13 @@ emit_sub_expr (expr_t *e, def_t *dest)
|
||||||
default:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
if (!dest)
|
if (!dest) {
|
||||||
dest = PR_GetTempDef (e->e.expr.type, pr_scope);
|
dest = PR_GetTempDef (e->e.expr.type, pr_scope);
|
||||||
|
dest->users += 2;
|
||||||
|
}
|
||||||
op = PR_Opcode_Find (operator, priority, def_a, def_b, dest);
|
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:
|
case ex_uexpr:
|
||||||
if (e->e.expr.op == '!') {
|
if (e->e.expr.op == '!') {
|
||||||
operator = "!";
|
operator = "!";
|
||||||
|
@ -281,23 +296,30 @@ emit_sub_expr (expr_t *e, def_t *dest)
|
||||||
priority = 3;
|
priority = 3;
|
||||||
def_a = PR_ReuseConstant (&zero, 0);
|
def_a = PR_ReuseConstant (&zero, 0);
|
||||||
def_b = emit_sub_expr (e->e.expr.e1, 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 = PR_GetTempDef (e->e.expr.type, pr_scope);
|
||||||
|
dest->users += 2;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
op = PR_Opcode_Find (operator, priority, def_a, def_b, dest);
|
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:
|
case ex_def:
|
||||||
return e->e.def;
|
d = e->e.def;
|
||||||
|
break;
|
||||||
case ex_temp:
|
case ex_temp:
|
||||||
if (!e->e.temp.def) {
|
if (!e->e.temp.def) {
|
||||||
if (dest)
|
if (dest)
|
||||||
e->e.temp.def = dest;
|
e->e.temp.def = dest;
|
||||||
else
|
else
|
||||||
e->e.temp.def = PR_GetTempDef (e->e.temp.type, pr_scope);
|
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_string:
|
||||||
case ex_float:
|
case ex_float:
|
||||||
case ex_vector:
|
case ex_vector:
|
||||||
|
@ -307,9 +329,11 @@ emit_sub_expr (expr_t *e, def_t *dest)
|
||||||
case ex_pointer:
|
case ex_pointer:
|
||||||
case ex_quaternion:
|
case ex_quaternion:
|
||||||
case ex_integer:
|
case ex_integer:
|
||||||
return PR_ReuseConstant (e, 0);
|
d = PR_ReuseConstant (e, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
PR_FreeTempDefs ();
|
||||||
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -320,10 +344,6 @@ emit_expr (expr_t *e)
|
||||||
def_t *def_b;
|
def_t *def_b;
|
||||||
statref_t *ref;
|
statref_t *ref;
|
||||||
elabel_t *label;
|
elabel_t *label;
|
||||||
//opcode_t *op;
|
|
||||||
static int level = 0;
|
|
||||||
|
|
||||||
level++;
|
|
||||||
|
|
||||||
switch (e->type) {
|
switch (e->type) {
|
||||||
case ex_label:
|
case ex_label:
|
||||||
|
@ -404,6 +424,5 @@ emit_expr (expr_t *e)
|
||||||
warning (e, "Ignoring useless expression");
|
warning (e, "Ignoring useless expression");
|
||||||
break;
|
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]);
|
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 *
|
expr_t *
|
||||||
new_expr (void)
|
new_expr (void)
|
||||||
{
|
{
|
||||||
|
@ -214,10 +223,11 @@ new_label_expr (void)
|
||||||
static int label = 0;
|
static int label = 0;
|
||||||
int lnum = ++label;
|
int lnum = ++label;
|
||||||
const char *fname = current_func->def->name;
|
const char *fname = current_func->def->name;
|
||||||
|
int len = 1 + strlen (fname) + 1 + ceil (log10 (lnum) + 1) + 1;
|
||||||
|
|
||||||
expr_t *l = new_expr ();
|
expr_t *l = new_expr ();
|
||||||
l->type = ex_label;
|
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);
|
sprintf (l->e.label.name, "$%s_%d", fname, lnum);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
@ -238,6 +248,9 @@ new_binary_expr (int op, expr_t *e1, expr_t *e2)
|
||||||
{
|
{
|
||||||
expr_t *e = new_expr ();
|
expr_t *e = new_expr ();
|
||||||
|
|
||||||
|
inc_users (e1);
|
||||||
|
inc_users (e2);
|
||||||
|
|
||||||
e->type = ex_expr;
|
e->type = ex_expr;
|
||||||
e->e.expr.op = op;
|
e->e.expr.op = op;
|
||||||
e->e.expr.e1 = e1;
|
e->e.expr.e1 = e1;
|
||||||
|
@ -250,6 +263,8 @@ new_unary_expr (int op, expr_t *e1)
|
||||||
{
|
{
|
||||||
expr_t *e = new_expr ();
|
expr_t *e = new_expr ();
|
||||||
|
|
||||||
|
inc_users (e1);
|
||||||
|
|
||||||
e->type = ex_uexpr;
|
e->type = ex_uexpr;
|
||||||
e->e.expr.op = op;
|
e->e.expr.op = op;
|
||||||
e->e.expr.e1 = e1;
|
e->e.expr.e1 = e1;
|
||||||
|
@ -327,11 +342,28 @@ print_expr (expr_t *e)
|
||||||
printf (" u%s", get_op_string (e->e.expr.op));
|
printf (" u%s", get_op_string (e->e.expr.op));
|
||||||
break;
|
break;
|
||||||
case ex_def:
|
case ex_def:
|
||||||
|
if (e->e.def->name)
|
||||||
printf ("%s", 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;
|
break;
|
||||||
case ex_temp:
|
case ex_temp:
|
||||||
|
printf ("(");
|
||||||
print_expr (e->e.temp.expr);
|
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;
|
break;
|
||||||
case ex_string:
|
case ex_string:
|
||||||
printf ("\"%s\"", e->e.string_val);
|
printf ("\"%s\"", e->e.string_val);
|
||||||
|
@ -797,7 +829,12 @@ type_mismatch:
|
||||||
type = &type_float;
|
type = &type_float;
|
||||||
}
|
}
|
||||||
if (op == '=' && e1->type == ex_expr && e1->e.expr.op == '.') {
|
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)
|
if (!type)
|
||||||
error (e1, "internal error");
|
error (e1, "internal error");
|
||||||
|
|
|
@ -204,6 +204,7 @@ PR_GetTempDef (type_t *type, def_t *scope)
|
||||||
def->ofs = scope->num_locals;
|
def->ofs = scope->num_locals;
|
||||||
scope->num_locals += type_size[size];
|
scope->num_locals += type_size[size];
|
||||||
}
|
}
|
||||||
|
def->users = 0;
|
||||||
def->next = temp_scope.next;
|
def->next = temp_scope.next;
|
||||||
temp_scope.next = def;
|
temp_scope.next = def;
|
||||||
return def;
|
return def;
|
||||||
|
@ -212,27 +213,40 @@ PR_GetTempDef (type_t *type, def_t *scope)
|
||||||
void
|
void
|
||||||
PR_FreeTempDefs (void)
|
PR_FreeTempDefs (void)
|
||||||
{
|
{
|
||||||
def_t *def, *d;
|
def_t **def, *d;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
for (def = temp_scope.next; def; def = d) {
|
def = &temp_scope.next;
|
||||||
size = type_size[def->type->type];
|
while (*def) {
|
||||||
d = def->next;
|
if ((*def)->users <= 0) {
|
||||||
def->next = free_temps[size];
|
d = *def;
|
||||||
free_temps[size] = 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
|
void
|
||||||
PR_ResetTempDefs (void)
|
PR_ResetTempDefs (void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
//def_t *d;
|
def_t *d;
|
||||||
|
|
||||||
for (i = 0; i < sizeof (free_temps) / sizeof (free_temps[0]); i++) {
|
for (i = 0; i < sizeof (free_temps) / sizeof (free_temps[0]); i++) {
|
||||||
free_temps[i] = 0;
|
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
|
void
|
||||||
|
|
Loading…
Reference in New Issue