Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PRVM: Return NaN/inf values for divisions by zero. #246

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions prvm_edict.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ cvar_t prvm_garbagecollection_scan_limit = {CF_CLIENT | CF_SERVER, "prvm_garbage
cvar_t prvm_garbagecollection_strings = {CF_CLIENT | CF_SERVER, "prvm_garbagecollection_strings", "1", "automatically call strunzone() on strings that are not referenced"};
cvar_t prvm_stringdebug = {CF_CLIENT | CF_SERVER, "prvm_stringdebug", "0", "Print debug and warning messages related to strings"};
cvar_t sv_entfields_noescapes = {CF_SERVER, "sv_entfields_noescapes", "wad", "Space-separated list of fields in which backslashes won't be parsed as escapes when loading entities from .bsp or .ent files. This is a workaround for buggy maps with unescaped backslashes used as path separators (only forward slashes are allowed in Quake VFS paths)."};
cvar_t prvm_gameplayfix_div0is0 = {CF_SERVER, "prvm_gameplayfix_div0is0", "0", "When set to 1, floating point division by 0 will return zero instead of returning the IEEE standardized result (likely nan or inf). Other ways of getting non-finite values are not affected, and the warning will still print."};

static double prvm_reuseedicts_always_allow = 0;
qbool prvm_runawaycheck = true;
Expand Down Expand Up @@ -3238,6 +3239,7 @@ void PRVM_Init (void)
Cvar_RegisterVariable (&prvm_garbagecollection_strings);
Cvar_RegisterVariable (&prvm_stringdebug);
Cvar_RegisterVariable (&sv_entfields_noescapes);
Cvar_RegisterVariable (&prvm_gameplayfix_div0is0);

// COMMANDLINEOPTION: PRVM: -norunaway disables the runaway loop check (it might be impossible to exit DarkPlaces if used!)
prvm_runawaycheck = !Sys_CheckParm("-norunaway");
Expand Down
1 change: 1 addition & 0 deletions prvm_exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,7 @@ static void PRVM_StatementCoverageEvent(prvm_prog_t *prog, mfunction_t *func, in
extern cvar_t prvm_traceqc;
extern cvar_t prvm_statementprofiling;
extern qbool prvm_runawaycheck;
extern cvar_t prvm_gameplayfix_div0is0;

#define PRVM_GLOBALSBASE 0x80000000

Expand Down
62 changes: 33 additions & 29 deletions prvm_execprogram.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,16 +394,17 @@ prvm_eval_t *src;
OPC->vector[2] = tempfloat * OPA->vector[2];
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_DIV_F):
if( OPB->_float != 0.0f )
{
OPC->_float = OPA->_float / OPB->_float;
}
else
if( OPB->_float == 0.0f )
{
PRE_ERROR();
VM_Warning(prog, "Attempted division of %f by zero\n", OPA->_float);
OPC->_float = 0.0f;
if (prvm_gameplayfix_div0is0.integer)
{
OPC->_float = 0;
DISPATCH_OPCODE();
}
}
OPC->_float = OPA->_float / OPB->_float;
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_BITAND_F):
OPC->_float = (prvm_int_t)OPA->_float & (prvm_int_t)OPB->_float;
Expand Down Expand Up @@ -884,21 +885,22 @@ prvm_eval_t *src;
OPC->vector[2] = (prvm_vec_t) OPB->_int * OPA->vector[2];
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_DIV_VF):
if( OPB->_float != 0.0f )
{
float temp = 1.0f / OPB->_float;
OPC->vector[0] = temp * OPA->vector[0];
OPC->vector[1] = temp * OPA->vector[1];
OPC->vector[2] = temp * OPA->vector[2];
}
else
if( OPB->_float == 0.0f )
{
PRE_ERROR();
VM_Warning(prog, "Attempted division of '%f %f %f' by zero\n", OPA->vector[0], OPA->vector[1], OPA->vector[2]);
OPC->vector[0] = 0.0f;
OPC->vector[1] = 0.0f;
OPC->vector[2] = 0.0f;
if (prvm_gameplayfix_div0is0.integer)
{
OPC->vector[0] = 0;
OPC->vector[1] = 0;
OPC->vector[2] = 0;
DISPATCH_OPCODE();
}
}
tempfloat = OPB->_float;
OPC->vector[0] = OPA->vector[0] / tempfloat;
OPC->vector[1] = OPA->vector[1] / tempfloat;
OPC->vector[2] = OPA->vector[2] / tempfloat;
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_DIV_I):
// NOTE: This also catches the second kind of division that can trap, namely, -2147483648 / -1,
Expand All @@ -915,28 +917,30 @@ prvm_eval_t *src;
}
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_DIV_IF):
if( OPB->_float != 0.0f )
{
OPC->_float = ((prvm_vec_t) OPA->_int) / OPB->_float;
}
else
if( OPB->_float == 0.0f )
{
PRE_ERROR();
VM_Warning(prog, "Attempted division of %"PRVM_PRIi" by zero\n", OPA->_int);
OPC->_float = 0;
if (prvm_gameplayfix_div0is0.integer)
{
OPC->_float = 0;
DISPATCH_OPCODE();
}
}
OPC->_float = ((prvm_vec_t) OPA->_int) / OPB->_float;
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_DIV_FI):
if( OPB->_int != 0 )
{
OPC->_float = OPA->_float / (prvm_vec_t) OPB->_int;
}
else
if( OPB->_int == 0 )
{
PRE_ERROR();
VM_Warning(prog, "Attempted division of %f by zero\n", OPA->_float);
OPC->_float = 0;
if (prvm_gameplayfix_div0is0.integer)
{
OPC->_float = 0;
DISPATCH_OPCODE();
}
}
OPC->_float = OPA->_float / (prvm_vec_t) OPB->_int;
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_CONV_ITOF):
OPC->_float = OPA->_int;
Expand Down
Loading