diff --git a/tools/qfcc/include/def.h b/tools/qfcc/include/def.h index 5ff4b7afd..51da57204 100644 --- a/tools/qfcc/include/def.h +++ b/tools/qfcc/include/def.h @@ -119,13 +119,18 @@ def_t *new_def (const char *name, struct type_s *type, Aliasing a def to the same type is useless, but not checked. Aliasing a def to a type larger than the def's type will generate an internal error. + If the offset is negative, or the offset plus the size of the aliasing type + is greater than the size of the def's type, then an internal error will + be generated. + \param def The def to be aliased. \param type The type of the alias. + \param offset Offset of the alias relative to the def. \return The def aliasing \a def. \todo Make aliasing to the same type a no-op? */ -def_t *alias_def (def_t *def, struct type_s *type); +def_t *alias_def (def_t *def, struct type_s *type, int offset); /** Free a def. diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 87d7a0388..864dc89fe 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -145,7 +145,7 @@ new_def (const char *name, type_t *type, defspace_t *space, } def_t * -alias_def (def_t *def, type_t *type) +alias_def (def_t *def, type_t *type, int offset) { def_t *alias; @@ -157,9 +157,12 @@ alias_def (def_t *def, type_t *type) } if (type_size (type) > type_size (def->type)) internal_error (0, "aliasing a def to a larger type"); + if (offset < 0 || offset + type_size (type) > type_size (def->type)) + internal_error (0, "invalid alias offset"); ALLOC (16384, def_t, defs, alias); alias->return_addr = __builtin_return_address (0); - alias->offset = def->offset; + alias->offset = offset; + alias->offset_reloc = 1; alias->type = type; alias->alias = def; alias->line = pr.source_line; diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index e0c9f074f..b0cf19de9 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -72,7 +72,7 @@ get_value_def (ex_value_t *value, etype_t type) } def = emit_value (value, 0); if (type != def->type->type) - return alias_def (def, ev_types[type]); + return alias_def (def, ev_types[type], 0); return def; } @@ -89,7 +89,7 @@ get_operand_def (expr_t *expr, operand_t *op) case sy_var: if (op->type != op->o.symbol->type->type) return alias_def (op->o.symbol->s.def, - ev_types[op->type]); + ev_types[op->type], 0); return op->o.symbol->s.def; case sy_func: return op->o.symbol->s.func->def; @@ -114,16 +114,15 @@ get_operand_def (expr_t *expr, operand_t *op) case op_pointer: def = op->o.value->v.pointer.def; if (op->o.value->v.pointer.val || op->type != def->type->type) { - def = alias_def (def, ev_types[op->type]); - def->offset = op->o.value->v.pointer.val; - def->offset_reloc = 1; + def = alias_def (def, ev_types[op->type], + op->o.value->v.pointer.val); } return def; case op_alias: def = get_operand_def (expr, op->o.alias); if (def->alias) def = def->alias; - def = alias_def (def, ev_types[op->type]); + def = alias_def (def, ev_types[op->type], 0); return def; } return 0;