]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
OP_DIV_*: add division by zero checks. divVerent/div_u
authorRudolf Polzer <divVerent@gmail.com>
Fri, 3 Jan 2025 23:28:23 +0000 (18:28 -0500)
committerRudolf Polzer <divVerent@gmail.com>
Fri, 3 Jan 2025 23:40:44 +0000 (18:40 -0500)
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.

prvm_execprogram.h
qtypes.h

index 173677fab70f467791e3aef5a5bd83671f45ec81..1988dac011ce852667e82ba0df4104f74a8201c5 100644 (file)
@@ -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;
index 7e10a4fa4310e5d7acd49ca3ea4243aa8b3f9847..653364b9f10019f98dc8d1284e65a5eca9f76fe9 100644 (file)
--- a/qtypes.h
+++ b/qtypes.h
@@ -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];