From 0a203c0ab5da922cbc04de8e482dbe52c26e61d4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 13 Jan 2010 06:36:54 +0000 Subject: [PATCH] qccx (etc) "integer" autodetection. Check for usage of denormal floats and if found, either bail with a descriptive error message or give a mild warning that things will probably break. This avoids the possibility of things like RuneQuake getting "lucky" and doing real harm, and certainly avoids the segfaults. --- include/QF/progs.h | 1 + libs/gamecode/engine/pr_load.c | 2 ++ libs/gamecode/engine/pr_opcode.c | 24 +++++++++++++++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 308c37b05..61506e637 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1372,6 +1372,7 @@ struct progs_s { dprograms_t *progs; int progs_size; unsigned short crc; + int denorm_found; struct memzone_s *zone; int zone_size; diff --git a/libs/gamecode/engine/pr_load.c b/libs/gamecode/engine/pr_load.c index 01205dcdf..d7b2d76ae 100644 --- a/libs/gamecode/engine/pr_load.c +++ b/libs/gamecode/engine/pr_load.c @@ -127,6 +127,8 @@ PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone) // store prog crc pr->crc = CRC_Block ((byte*)&progs, sizeof (progs)); + pr->denorm_found = 0; + // byte swap the header for (i = 0; i < sizeof (progs) / 4; i++) ((int *) &progs)[i] = LittleLong (((int *) &progs)[i]); diff --git a/libs/gamecode/engine/pr_opcode.c b/libs/gamecode/engine/pr_opcode.c index f57ea7685..f98a3300c 100644 --- a/libs/gamecode/engine/pr_opcode.c +++ b/libs/gamecode/engine/pr_opcode.c @@ -45,6 +45,7 @@ static __attribute__ ((used)) const char rcsid[] = #include "QF/hash.h" #include "QF/pr_comp.h" #include "QF/progs.h" +#include "QF/sys.h" hashtab_t *opcode_table; @@ -1197,6 +1198,8 @@ check_branch (progs_t *pr, dstatement_t *st, opcode_t *op, short offset) (long)(st - pr->pr_statements), op->opname); } +#define ISDENORM(x) ((x) && !((x) & 0x7f800000)) + static inline void check_global (progs_t *pr, dstatement_t *st, opcode_t *op, etype_t type, unsigned short operand) @@ -1218,6 +1221,22 @@ check_global (progs_t *pr, dstatement_t *st, opcode_t *op, etype_t type, msg = "out of bounds global index"; goto error; } + if (type == ev_float) + if (ISDENORM (G_INT (pr, operand)) + && !pr->denorm_found) { + pr->denorm_found = 1; + if (pr_boundscheck-> int_val) { + Sys_Printf ("DENORMAL floats detected, these progs might " + "not work. Good luck.\n"); + return; + } + msg = "DENORMAL float detected. These progs are probably " + "using qccx arrays and integers. If just simple arrays " + "are being used, then they should work, but if " + "internal.qc is used, they most definitely will NOT. To" + "allow these progs to be used, set pr_boundscheck to 1."; + goto error; + } break; } return; @@ -1255,7 +1274,10 @@ PR_Check_Opcodes (progs_t *pr) && pr->fields.think != -1 && pr->fields.frame != -1) state_ok = 1; - if (!pr_boundscheck->int_val) { + //FIXME need to decide if I really want to always do static bounds checking + // the only problem is that it slows progs load a little, but it's the only + // way to check for qccx' evil + if (0 && !pr_boundscheck->int_val) { for (i = 0, st = pr->pr_statements; i < pr->progs->numstatements; st++, i++) { op = PR_Opcode (st->op);