Skip to content

Commit

Permalink
OP_DIV_*: add division by zero checks.
Browse files Browse the repository at this point in the history
Now all the OP_DIV operations emit a warning and proceed on division by
zero, instead of potentially crashing the program.

This also handles the special case of -2147483648 / -1, which also traps on
x86 and thus must be handled.
  • Loading branch information
divVerent committed Jan 3, 2025
1 parent 765a1ae commit c054e21
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 3 deletions.
44 changes: 41 additions & 3 deletions prvm_execprogram.h
Original file line number Diff line number Diff line change
Expand Up @@ -884,21 +884,59 @@ 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
{
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;
}
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_DIV_I):
OPC->_int = OPA->_int / OPB->_int;
// NOTE: This also catches the second kind of division that can trap, namely, -2147483648 / -1,
// whose result is not representable as int32_t and raises the same CPU exception.
if( OPB->_int != 0 && (OPB->_int != -1 || OPA->_int != PRVM_INT_MIN) )
{
OPC->_int = OPA->_int / OPB->_int;
}
else
{
PRE_ERROR();
VM_Warning(prog, "Attempted division of %d by %d\n", (int)OPA->_int, (int)OPB->_int);
OPC->_int = 0;
}
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_DIV_IF):
OPC->_float = ((prvm_vec_t) OPA->_int) / OPB->_float;
if( OPB->_float != 0.0f )
{
OPC->_float = ((prvm_vec_t) OPA->_int) / OPB->_float;
}
else
{
PRE_ERROR();
VM_Warning(prog, "Attempted division of %d by zero\n", (int)OPA->_int);
OPC->_float = 0;
}
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_DIV_FI):
OPC->_float = OPA->_float / (prvm_vec_t) OPB->_int;
if( OPB->_int != 0 )
{
OPC->_float = OPA->_float / (prvm_vec_t) OPB->_int;
}
else
{
PRE_ERROR();
VM_Warning(prog, "Attempted division of %f by zero\n", OPA->_float);
OPC->_float = 0;
}
DISPATCH_OPCODE();
HANDLE_OPCODE(OP_CONV_ITOF):
OPC->_float = OPA->_int;
Expand Down
4 changes: 4 additions & 0 deletions qtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,16 @@ typedef int64_t prvm_int_t;
typedef uint64_t prvm_uint_t;
#define PRVM_PRIi PRIi64
#define PRVM_PRIu PRIu64
#define PRVM_INT_MIN INT64_MIN
#define PRVM_INT_MAX INT64_MAX
#else
typedef float prvm_vec_t;
typedef int32_t prvm_int_t;
typedef uint32_t prvm_uint_t;
#define PRVM_PRIi PRIi32
#define PRVM_PRIu PRIu32
#define PRVM_INT_MIN INT32_MIN
#define PRVM_INT_MAX INT32_MAX
#endif
typedef prvm_vec_t prvm_vec3_t[3];

Expand Down

0 comments on commit c054e21

Please sign in to comment.