pr_comp.h:

- new opcodes for pointers
progs.h:
	- prototype PR_Check_Opcodes
pr_edict.c:
	- move the static bounds checking to PR_Check_Opcodes in pr_opcode.c
pr_exec.c:
	- vector instruction cleanup
	- temporarily nuke bounds checking from storep.*
	- move base of address results from pr->edicts to pr->pr_globals
	- implement new pointer related instructions
	- nuke proposed global pointer instructions (not flexible enough)
pr_opcode.c:
	- add new pointer instuctions
	- re-implement static bounds/invalid opcode checking. no more multiple
	  case statements to keep track of.
This commit is contained in:
Bill Currie 2001-11-02 22:41:11 +00:00
parent 08a211385f
commit 5bf5278c2b
5 changed files with 187 additions and 281 deletions

View file

@ -172,6 +172,35 @@ typedef enum {
OP_MOD_F,
OP_MOD_I,
OP_LOADB_F,
OP_LOADB_V,
OP_LOADB_S,
OP_LOADB_ENT,
OP_LOADB_FLD,
OP_LOADB_FNC,
OP_LOADB_I,
OP_LOADB_P,
OP_STOREB_F,
OP_STOREB_V,
OP_STOREB_S,
OP_STOREB_ENT,
OP_STOREB_FLD,
OP_STOREB_FNC,
OP_STOREB_I,
OP_STOREB_P,
OP_ADDRESS_F,
OP_ADDRESS_V,
OP_ADDRESS_S,
OP_ADDRESS_ENT,
OP_ADDRESS_FLD,
OP_ADDRESS_FNC,
OP_ADDRESS_I,
OP_ADDRESS_P,
OP_LEA,
} pr_opcode_e;
typedef struct

View file

@ -75,6 +75,7 @@ void PR_LoadProgs (progs_t *pr, const char *progsname);
void PR_LoadStrings (progs_t *pr);
void PR_LoadDebug (progs_t *pr);
edict_t *PR_InitEdicts (progs_t *pr, int num_edicts);
void PR_Check_Opcodes (progs_t *pr);
void PR_Profile_f (void);

View file

@ -1180,7 +1180,6 @@ void
PR_LoadProgs (progs_t * pr, const char *progsname)
{
int i;
dstatement_t *st;
PR_LoadProgsFile (pr, progsname);
if (!pr->progs)
@ -1209,159 +1208,7 @@ PR_LoadProgs (progs_t * pr, const char *progsname)
PR_LoadDebug (pr);
// LordHavoc: bounds check anything static
for (i = 0, st = pr->pr_statements;
i < pr->progs->numstatements;
i++, st++) {
switch (st->op) {
case OP_IF:
case OP_IFNOT:
if (st->a >= pr->progs->numglobals
|| (short)st->b + i < 0
|| (short)st->b + i >= pr->progs->numstatements)
PR_Error
(pr, "PR_LoadProgs: out of bounds IF/IFNOT (statement %d)\n",
i);
break;
case OP_GOTO:
if ((short)st->a + i < 0
|| (short)st->a + i >= pr->progs->numstatements)
PR_Error
(pr, "PR_LoadProgs: out of bounds GOTO (statement %d)\n",
i);
break;
// global global global
case OP_ADD_F:
case OP_ADD_V:
case OP_SUB_F:
case OP_SUB_V:
case OP_MUL_F:
case OP_MUL_V:
case OP_MUL_FV:
case OP_MUL_VF:
case OP_DIV_F:
case OP_BITAND:
case OP_BITOR:
case OP_ADD_S:
case OP_GE_S:
case OP_LE_S:
case OP_GT_S:
case OP_LT_S:
case OP_GE:
case OP_LE:
case OP_GT:
case OP_LT:
case OP_AND:
case OP_OR:
case OP_EQ_F:
case OP_EQ_V:
case OP_EQ_S:
case OP_EQ_E:
case OP_EQ_FNC:
case OP_NE_F:
case OP_NE_V:
case OP_NE_S:
case OP_NE_E:
case OP_NE_FNC:
case OP_ADDRESS:
case OP_LOAD_F:
case OP_LOAD_FLD:
case OP_LOAD_ENT:
case OP_LOAD_S:
case OP_LOAD_FNC:
case OP_LOAD_V:
case OP_ADD_I:
case OP_SUB_I:
case OP_MUL_I:
case OP_DIV_I:
case OP_MOD_I:
case OP_MOD_F:
case OP_BITAND_I:
case OP_BITOR_I:
case OP_GE_I:
case OP_LE_I:
case OP_GT_I:
case OP_LT_I:
case OP_AND_I:
case OP_OR_I:
case OP_NOT_I:
case OP_EQ_I:
case OP_NE_I:
case OP_LOAD_I:
case OP_CONV_IF:
case OP_CONV_FI:
case OP_BITXOR_F:
case OP_BITXOR_I:
case OP_BITNOT_F:
case OP_BITNOT_I:
case OP_SHL_F:
case OP_SHR_F:
case OP_SHL_I:
case OP_SHR_I:
if (st->a >= pr->progs->numglobals
|| st->b >= pr->progs->numglobals
|| st->c >= pr->progs->numglobals)
PR_Error
(pr, "PR_LoadProgs: out of bounds global index (statement %d)\n",
i);
break;
// global none global
case OP_NOT_F:
case OP_NOT_V:
case OP_NOT_S:
case OP_NOT_FNC:
case OP_NOT_ENT:
if (st->a >= pr->progs->numglobals
|| st->c >= pr->progs->numglobals)
PR_Error
(pr, "PR_LoadProgs: out of bounds global index (statement %d)\n",
i);
break;
// 2 globals
case OP_STOREP_F:
case OP_STOREP_ENT:
case OP_STOREP_FLD:
case OP_STOREP_S:
case OP_STOREP_FNC:
case OP_STORE_F:
case OP_STORE_ENT:
case OP_STORE_FLD:
case OP_STORE_S:
case OP_STORE_FNC:
case OP_STATE:
case OP_STOREP_V:
case OP_STORE_V:
case OP_STORE_I:
case OP_STOREP_I:
if (st->a >= pr->progs->numglobals
|| st->b >= pr->progs->numglobals)
PR_Error
(pr, "PR_LoadProgs: out of bounds global index (statement %d)\n",
i);
break;
// 1 global
case OP_CALL0:
case OP_CALL1:
case OP_CALL2:
case OP_CALL3:
case OP_CALL4:
case OP_CALL5:
case OP_CALL6:
case OP_CALL7:
case OP_CALL8:
case OP_DONE:
case OP_RETURN:
if (st->a >= pr->progs->numglobals)
PR_Error
(pr, "PR_LoadProgs: out of bounds global index (statement %d)\n",
i);
break;
default:
PR_Error (pr, "PR_LoadProgs: unknown opcode %d at statement %d\n",
st->op, i);
break;
}
}
PR_Check_Opcodes (pr);
}
edict_t *

View file

@ -251,6 +251,7 @@ void
PR_ExecuteProgram (progs_t * pr, func_t fnum)
{
int exitdepth, profile, startprofile;
int pointer;
dfunction_t *f, *newf;
dstatement_t *st;
edict_t *ed;
@ -289,9 +290,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
OPC.float_var = OPA.float_var + OPB.float_var;
break;
case OP_ADD_V:
OPC.vector_var[0] = OPA.vector_var[0] + OPB.vector_var[0];
OPC.vector_var[1] = OPA.vector_var[1] + OPB.vector_var[1];
OPC.vector_var[2] = OPA.vector_var[2] + OPB.vector_var[2];
VectorAdd (OPA.vector_var, OPB.vector_var, OPC.vector_var);
break;
case OP_ADD_S:
{
@ -309,28 +308,19 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
OPC.float_var = OPA.float_var - OPB.float_var;
break;
case OP_SUB_V:
OPC.vector_var[0] = OPA.vector_var[0] - OPB.vector_var[0];
OPC.vector_var[1] = OPA.vector_var[1] - OPB.vector_var[1];
OPC.vector_var[2] = OPA.vector_var[2] - OPB.vector_var[2];
VectorSubtract (OPA.vector_var, OPB.vector_var, OPC.vector_var);
break;
case OP_MUL_F:
OPC.float_var = OPA.float_var * OPB.float_var;
break;
case OP_MUL_V:
OPC.float_var =
OPA.vector_var[0] * OPB.vector_var[0] +
OPA.vector_var[1] * OPB.vector_var[1] +
OPA.vector_var[2] * OPB.vector_var[2];
OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var);
break;
case OP_MUL_FV:
OPC.vector_var[0] = OPA.float_var * OPB.vector_var[0];
OPC.vector_var[1] = OPA.float_var * OPB.vector_var[1];
OPC.vector_var[2] = OPA.float_var * OPB.vector_var[2];
VectorScale (OPB.vector_var, OPA.float_var, OPC.vector_var);
break;
case OP_MUL_VF:
OPC.vector_var[0] = OPB.float_var * OPA.vector_var[0];
OPC.vector_var[1] = OPB.float_var * OPA.vector_var[1];
OPC.vector_var[2] = OPB.float_var * OPA.vector_var[2];
VectorScale (OPA.vector_var, OPB.float_var, OPC.vector_var);
break;
case OP_DIV_F:
OPC.float_var = OPA.float_var / OPB.float_var;
@ -452,9 +442,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
OPB.integer_var = OPA.integer_var;
break;
case OP_STORE_V:
OPB.vector_var[0] = OPA.vector_var[0];
OPB.vector_var[1] = OPA.vector_var[1];
OPB.vector_var[2] = OPA.vector_var[2];
VectorCopy (OPA.vector_var, OPB.vector_var);
break;
case OP_STOREP_F:
@ -463,40 +451,16 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
case OP_STOREP_S:
case OP_STOREP_FNC: // pointers
case OP_STOREP_I:
if (pr_boundscheck->int_val
&& (OPB.integer_var < 0 || OPB.integer_var + 4 >
pr->pr_edictareasize)) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Progs attempted to write to an out of "
"bounds edict\n");
return;
}
if (pr_boundscheck->int_val && (OPB.integer_var %
pr->pr_edict_size <
((byte *) & (*pr->edicts)->v -
(byte *) * pr->edicts))) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Progs attempted to write to an engine "
"edict field\n");
return;
}
ptr = (pr_type_t*)((int)*pr->edicts + OPB.integer_var);
//FIXME put bounds checking back
ptr = pr->pr_globals + OPB.integer_var;
ptr->integer_var = OPA.integer_var;
break;
case OP_STOREP_V:
if (pr_boundscheck->int_val
&& (OPB.integer_var < 0 || OPB.integer_var + 12 >
pr->pr_edictareasize)) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Progs attempted to write to an out of "
"bounds edict\n");
return;
}
ptr = (pr_type_t*)((int)*pr->edicts + OPB.integer_var);
ptr->vector_var[0] = OPA.vector_var[0];
ptr->vector_var[1] = OPA.vector_var[1];
ptr->vector_var[2] = OPA.vector_var[2];
//FIXME put bounds checking back
ptr = pr->pr_globals + OPB.integer_var;
VectorCopy (OPA.vector_var, ptr->vector_var);
break;
case OP_ADDRESS:
if (pr_boundscheck->int_val
&& (OPA.entity_var < 0 || OPA.entity_var >=
@ -521,9 +485,19 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
return;
}
ed = PROG_TO_EDICT (pr, OPA.entity_var);
OPC.integer_var = (int) &ed->v[OPB.integer_var] -
(int) *pr->edicts;
OPC.integer_var = &ed->v[OPB.integer_var] - pr->pr_globals;
break;
case OP_ADDRESS_F:
case OP_ADDRESS_V:
case OP_ADDRESS_S:
case OP_ADDRESS_ENT:
case OP_ADDRESS_FLD:
case OP_ADDRESS_FNC:
case OP_ADDRESS_I:
case OP_ADDRESS_P:
OPC.integer_var = st->a;
break;
case OP_LOAD_F:
case OP_LOAD_FLD:
case OP_LOAD_ENT:
@ -569,6 +543,50 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
ed = PROG_TO_EDICT (pr, OPA.entity_var);
memcpy (&OPC, &ed->v[OPB.integer_var], 3 * sizeof (OPC));
break;
case OP_LOADB_F:
case OP_LOADB_S:
case OP_LOADB_ENT:
case OP_LOADB_FLD:
case OP_LOADB_FNC:
case OP_LOADB_I:
case OP_LOADB_P:
//FIXME put bounds checking in
pointer = OPA.integer_var + OPB.integer_var;
ptr = pr->pr_globals + pointer;
OPC.integer_var = ptr->integer_var;
break;
case OP_LOADB_V:
//FIXME put bounds checking in
pointer = OPA.integer_var + OPB.integer_var;
ptr = pr->pr_globals + pointer;
VectorCopy (ptr->vector_var, OPC.vector_var);
break;
case OP_LEA:
pointer = OPA.integer_var + OPB.integer_var;
OPC.integer_var = pointer;
break;
case OP_STOREB_F:
case OP_STOREB_S:
case OP_STOREB_ENT:
case OP_STOREB_FLD:
case OP_STOREB_FNC:
case OP_STOREB_I:
case OP_STOREB_P:
//FIXME put bounds checking in
pointer = OPB.integer_var + OPC.integer_var;
ptr = pr->pr_globals + pointer;
ptr->integer_var = OPA.integer_var;
break;
case OP_STOREB_V:
//FIXME put bounds checking in
pointer = OPB.integer_var + OPC.integer_var;
ptr = pr->pr_globals + pointer;
VectorCopy (OPA.vector_var, ptr->vector_var);
break;
// ==================
case OP_IFNOT:
if (!OPA.integer_var)
@ -643,10 +661,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
case OP_DIV_VF:
{
float temp = 1.0f / OPB.float_var;
OPC.vector_var[0] = temp * OPA.vector_var[0];
OPC.vector_var[1] = temp * OPA.vector_var[1];
OPC.vector_var[2] = temp * OPA.vector_var[2];
VectorScale (OPA.vector_var, temp, OPC.vector_var);
}
break;
*/
@ -707,78 +722,6 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum)
// LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
/*
case OP_GSTOREP_I:
case OP_GSTOREP_F:
case OP_GSTOREP_ENT:
case OP_GSTOREP_FLD: // integers
case OP_GSTOREP_S:
case OP_GSTOREP_FNC: // pointers
if (pr_boundscheck->int_val && (OPB.integer_var < 0 ||
OPB.integer_var >= pr->pr_globaldefs)) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Progs attempted to write to an invalid "
"indexed global\n");
return;
}
pr->pr_globals[OPB.integer_var] = OPA.float_var;
break;
case OP_GSTOREP_V:
if (pr_boundscheck->int_val
&& (OPB.integer_var < 0 || OPB.integer_var + 2 >=
pr->pr_globaldefs)) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Progs attempted to write to an invalid "
"indexed global\n");
return;
}
pr->pr_globals[OPB.integer_var] = OPA.vector_var[0];
pr->pr_globals[OPB.integer_var + 1] = OPA.vector_var[1];
pr->pr_globals[OPB.integer_var + 2] = OPA.vector_var[2];
break;
case OP_GADDRESS:
i = OPA.integer_var + (int) OPB.float_var;
if (pr_boundscheck->int_val
&& (i < 0 || i >= pr->pr_globaldefs)) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Progs attempted to address an out of "
"bounds global\n");
return;
}
OPC.float_var = pr->pr_globals[i];
break;
case OP_GLOAD_I:
case OP_GLOAD_F:
case OP_GLOAD_FLD:
case OP_GLOAD_ENT:
case OP_GLOAD_S:
case OP_GLOAD_FNC:
if (pr_boundscheck->int_val
&& (OPA.integer_var < 0 || OPA.integer_var >=
pr->pr_globaldefs)) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Progs attempted to read an invalid "
"indexed global\n");
return;
}
OPC.float_var = pr->pr_globals[OPA.integer_var];
break;
case OP_GLOAD_V:
if (pr_boundscheck->int_val
&& (OPA.integer_var < 0 || OPA.integer_var + 2 >=
pr->pr_globaldefs)) {
pr->pr_xstatement = st - pr->pr_statements;
PR_RunError (pr, "Progs attempted to read an invalid "
"indexed global\n");
return;
}
OPC.vector_var[0] = pr->pr_globals[OPA.integer_var];
OPC.vector_var[1] = pr->pr_globals[OPA.integer_var + 1];
OPC.vector_var[2] = pr->pr_globals[OPA.integer_var + 2];
break;
case OP_BOUNDCHECK:
if (OPA.integer_var < 0 || OPA.integer_var >= st->b) {
pr->pr_xstatement = st - pr->pr_statements;

View file

@ -42,6 +42,7 @@ static const char rcsid[] =
#include "QF/hash.h"
#include "QF/pr_comp.h"
#include "QF/progs.h"
hashtab_t *opcode_table;
@ -90,8 +91,28 @@ opcode_t pr_opcodes[] = {
{".", "load.fld", OP_LOAD_FLD, false, ev_entity, ev_field, ev_field, PROG_ID_VERSION},
{".", "load.fnc", OP_LOAD_FNC, false, ev_entity, ev_field, ev_func, PROG_ID_VERSION},
{".", "loadb.f", OP_LOADB_F, false, ev_pointer, ev_integer, ev_float, PROG_VERSION},
{".", "loadb.v", OP_LOADB_V, false, ev_pointer, ev_integer, ev_vector, PROG_VERSION},
{".", "loadb.s", OP_LOADB_S, false, ev_pointer, ev_integer, ev_string, PROG_VERSION},
{".", "loadb.ent", OP_LOADB_ENT, false, ev_pointer, ev_integer, ev_entity, PROG_VERSION},
{".", "loadb.fld", OP_LOADB_FLD, false, ev_pointer, ev_integer, ev_field, PROG_VERSION},
{".", "loadb.fnc", OP_LOADB_FNC, false, ev_pointer, ev_integer, ev_func, PROG_VERSION},
{".", "loadb.i", OP_LOADB_I, false, ev_pointer, ev_integer, ev_integer, PROG_VERSION},
{".", "loadb.p", OP_LOADB_P, false, ev_pointer, ev_integer, ev_pointer, PROG_VERSION},
{".", "address", OP_ADDRESS, false, ev_entity, ev_field, ev_pointer, PROG_ID_VERSION},
{"&", "address.f", OP_ADDRESS_F, false, ev_float, ev_void, ev_pointer, PROG_VERSION},
{"&", "address.v", OP_ADDRESS_V, false, ev_vector, ev_void, ev_pointer, PROG_VERSION},
{"&", "address.s", OP_ADDRESS_S, false, ev_string, ev_void, ev_pointer, PROG_VERSION},
{"&", "address.ent", OP_ADDRESS_ENT, false, ev_entity, ev_void, ev_pointer, PROG_VERSION},
{"&", "address.fld", OP_ADDRESS_FLD, false, ev_field, ev_void, ev_pointer, PROG_VERSION},
{"&", "address.fnc", OP_ADDRESS_FNC, false, ev_func, ev_void, ev_pointer, PROG_VERSION},
{"&", "address.i", OP_ADDRESS_I, false, ev_integer, ev_void, ev_pointer, PROG_VERSION},
{"&", "address.p", OP_ADDRESS_P, false, ev_pointer, ev_void, ev_pointer, PROG_VERSION},
{"&", "lea", OP_LEA, false, ev_pointer, ev_integer, ev_pointer, PROG_VERSION},
{"=", "store.f", OP_STORE_F, true, ev_float, ev_float, ev_void, PROG_ID_VERSION},
{"=", "store.v", OP_STORE_V, true, ev_vector, ev_vector, ev_void, PROG_ID_VERSION},
{"=", "store.s", OP_STORE_S, true, ev_string, ev_string, ev_void, PROG_ID_VERSION},
@ -106,6 +127,15 @@ opcode_t pr_opcodes[] = {
{"=", "storep.fld", OP_STOREP_FLD, true, ev_field, ev_pointer, ev_void, PROG_ID_VERSION},
{"=", "storep.fnc", OP_STOREP_FNC, true, ev_func, ev_pointer, ev_void, PROG_ID_VERSION},
{"=", "storeb.f", OP_STOREB_F, true, ev_float, ev_pointer, ev_integer, PROG_VERSION},
{"=", "storeb.v", OP_STOREB_V, true, ev_vector, ev_pointer, ev_integer, PROG_VERSION},
{"=", "storeb.s", OP_STOREB_S, true, ev_string, ev_pointer, ev_integer, PROG_VERSION},
{"=", "storeb.ent", OP_STOREB_ENT, true, ev_entity, ev_pointer, ev_integer, PROG_VERSION},
{"=", "storeb.fld", OP_STOREB_FLD, true, ev_field, ev_pointer, ev_integer, PROG_VERSION},
{"=", "storeb.fnc", OP_STOREB_FNC, true, ev_func, ev_pointer, ev_integer, PROG_VERSION},
{"=", "storeb.i", OP_STOREB_I, true, ev_integer, ev_pointer, ev_integer, PROG_VERSION},
{"=", "storeb.p", OP_STOREB_P, true, ev_pointer, ev_pointer, ev_integer, PROG_VERSION},
{"<RETURN>", "return", OP_RETURN, false, ev_void, ev_void, ev_void, PROG_ID_VERSION},
{"!", "not.f", OP_NOT_F, false, ev_float, ev_void, ev_integer, PROG_ID_VERSION},
@ -208,3 +238,59 @@ PR_Opcode_Init (void)
Hash_Add (opcode_table, op);
}
}
static inline void
check_branch (progs_t *pr, dstatement_t *st, opcode_t *op, short offset)
{
int address = st - pr->pr_statements;
address += offset - 1;
if (address < 0 || address >= pr->progs->numstatements)
PR_Error (pr, "PR_Check_Opcodes: invalid branch (statement %d: %s)\n",
st - pr->pr_statements, op->opname);
}
static inline void
check_global (progs_t *pr, dstatement_t *st, opcode_t *op, etype_t type,
unsigned short operand)
{
if (type == ev_void && operand) {
if (st->op != OP_RETURN && st->op != OP_DONE) //FIXME need better "not used flags"
PR_Error (pr, "PR_Check_Opcodes: non-zero global index in void operand (statement %d: %s)\n", st - pr->pr_statements, op->opname);
} else if (operand >= pr->progs->numglobals) {
PR_Error (pr, "PR_Check_Opcodes: out of bounds global index (statement %d: %s)\n", st - pr->pr_statements, op->opname);
}
}
void
PR_Check_Opcodes (progs_t *pr)
{
opcode_t *op;
dstatement_t *st;
for (st = pr->pr_statements;
st - pr->pr_statements < pr->progs->numstatements;
st++) {
op = PR_Opcode (st->op);
if (!op) {
PR_Error (pr,
"PR_Check_Opcodes: unknown opcode %d at statement %d\n",
st->op, st - pr->pr_statements);
}
switch (st->op) {
case OP_IF:
case OP_IFNOT:
check_global (pr, st, op, op->type_a, st->a);
check_branch (pr, st, op, st->b);
break;
case OP_GOTO:
check_branch (pr, st, op, st->a);
break;
default:
check_global (pr, st, op, op->type_a, st->a);
check_global (pr, st, op, op->type_b, st->b);
check_global (pr, st, op, op->type_c, st->c);
break;
}
}
}