Brought over pr_exec.c and pals from darkplaces.

Improvements include bounds checking, 40% less instructions per
opcode, support for 65535 globals. Might even break something.
This commit is contained in:
Dabb 2000-12-06 13:23:44 +00:00
parent 0dd34a3e20
commit a7b6d2df88
3 changed files with 1014 additions and 343 deletions

View file

@ -75,6 +75,7 @@ extern globalvars_t *pr_global_struct;
extern float *pr_globals; // same as pr_global_struct extern float *pr_globals; // same as pr_global_struct
extern int pr_edict_size; // in bytes extern int pr_edict_size; // in bytes
extern int pr_edictareasize; // LordHavoc: for bounds checking
//============================================================================ //============================================================================

View file

@ -49,6 +49,7 @@
#endif #endif
cvar_t *r_skyname; cvar_t *r_skyname;
cvar_t *pr_boundscheck;
void SV_Error (char *error, ...); void SV_Error (char *error, ...);
void FindEdictFieldOffsets(); void FindEdictFieldOffsets();
@ -62,6 +63,7 @@ dstatement_t *pr_statements;
globalvars_t *pr_global_struct; globalvars_t *pr_global_struct;
float *pr_globals; // same as pr_global_struct float *pr_globals; // same as pr_global_struct
int pr_edict_size; // in bytes int pr_edict_size; // in bytes
int pr_edictareasize; // LordHavoc: in bytes
int type_size[8] = {1,sizeof(void *)/4,1,3,1,1,sizeof(void *)/4,sizeof(void *)/4}; int type_size[8] = {1,sizeof(void *)/4,1,3,1,1,sizeof(void *)/4,sizeof(void *)/4};
@ -995,7 +997,6 @@ void ED_LoadFromFile (char *data)
Con_DPrintf ("%i entities inhibited\n", inhibit); Con_DPrintf ("%i entities inhibited\n", inhibit);
} }
/* /*
=============== ===============
PR_LoadProgs PR_LoadProgs
@ -1005,6 +1006,7 @@ void PR_LoadProgs (void)
{ {
int i; int i;
char num[32]; char num[32];
dstatement_t *st;
dfunction_t *f; dfunction_t *f;
// flush the non-C variable lookup cache // flush the non-C variable lookup cache
@ -1012,14 +1014,15 @@ void PR_LoadProgs (void)
gefvCache[i].field[0] = 0; gefvCache[i].field[0] = 0;
progs = (dprograms_t *)COM_LoadHunkFile ("qwprogs.dat"); progs = (dprograms_t *)COM_LoadHunkFile ("qwprogs.dat");
if (!progs) if (!progs) {
progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat"); progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat");
if (!progs)
SV_Error ("PR_LoadProgs: couldn't load progs.dat"); SV_Error ("PR_LoadProgs: couldn't load progs.dat");
}
Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024); Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024);
// add prog crc to the serverinfo // add prog crc to the serverinfo
snprintf (num, sizeof(num), "%i", CRC_Block ((byte *)progs, com_filesize)); snprintf (num, sizeof(num), "%i", CRC_Block((byte *)progs, com_filesize));
Info_SetValueForStarKey (svs.info, "*progs", num, MAX_SERVERINFO_STRING); Info_SetValueForStarKey (svs.info, "*progs", num, MAX_SERVERINFO_STRING);
// byte swap the header // byte swap the header
@ -1029,7 +1032,7 @@ void PR_LoadProgs (void)
if (progs->version != PROG_VERSION) if (progs->version != PROG_VERSION)
SV_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); SV_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION);
if (progs->crc != PROGHEADER_CRC) if (progs->crc != PROGHEADER_CRC)
SV_Error ("You must have the progs.dat from QuakeWorld installed"); SV_Error ("You must have the qwprogs.dat from QuakeWorld installed");
pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
pr_strings = (char *)progs + progs->ofs_strings; pr_strings = (char *)progs + progs->ofs_strings;
@ -1044,6 +1047,8 @@ void PR_LoadProgs (void)
pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);
pr_edictareasize = pr_edict_size * MAX_EDICTS;
// byte swap the lumps // byte swap the lumps
for (i=0 ; i<progs->numstatements ; i++) for (i=0 ; i<progs->numstatements ; i++)
{ {
@ -1101,8 +1106,108 @@ void PR_LoadProgs (void)
// LordHavoc: Ender added this // LordHavoc: Ender added this
FindEdictFieldOffsets(); FindEdictFieldOffsets();
}
// LordHavoc: bounds check anything static
for (i = 0,st = pr_statements;i < progs->numstatements;i++,st++)
{
switch (st->op)
{
case OP_IF:
case OP_IFNOT:
if ((unsigned short) st->a >= progs->numglobals || st->b + i < 0 || st->b + i >= progs->numstatements)
SV_Error("PR_LoadProgs: out of bounds IF/IFNOT (statement %d)\n", i);
break;
case OP_GOTO:
if (st->a + i < 0 || st->a + i >= progs->numstatements)
SV_Error("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_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:
if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
SV_Error("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 ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->c >= progs->numglobals)
SV_Error("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:
if ((unsigned short) st->a >= progs->numglobals || (unsigned short) st->b >= progs->numglobals)
SV_Error("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 ((unsigned short) st->a >= progs->numglobals)
SV_Error("PR_LoadProgs: out of bounds global index (statement %d)\n", i);
break;
default:
SV_Error("PR_LoadProgs: unknown opcode %d at statement %d\n", st->op, i);
break;
}
}
FindEdictFieldOffsets(); // LordHavoc: update field offset list
}
/* /*
=============== ===============
@ -1120,6 +1225,7 @@ void PR_Init (void)
void PR_Init_Cvars (void) void PR_Init_Cvars (void)
{ {
r_skyname = Cvar_Get ("r_skyname", com_token, CVAR_SERVERINFO, "name of skybox"); r_skyname = Cvar_Get ("r_skyname", com_token, CVAR_SERVERINFO, "name of skybox");
pr_boundscheck = Cvar_Get("pr_boundscheck", "1", CVAR_NONE, "Server progs bounds checking");
} }

File diff suppressed because it is too large Load diff