sys.[ch]:

handle SIGFPE and allow the registered signal handler to do recovery
	rather than bail
progs.h, pr_exec.c, pr_load.c:
	if pr_faultchecks is 1 (0 is default), handle division by 0 gracefully
	by loading the maximum representable number into the answer
	Closes: #58
the rest:
	kill the SIGFPE stuff
This commit is contained in:
Bill Currie 2002-11-13 19:26:44 +00:00
parent 8cf5c9a430
commit 836c469737
10 changed files with 70 additions and 44 deletions

View file

@ -249,6 +249,7 @@ extern struct cvar_s *pr_debug;
extern struct cvar_s *pr_deadbeef_ents;
extern struct cvar_s *pr_deadbeef_locals;
extern struct cvar_s *pr_boundscheck;
extern struct cvar_s *pr_faultchecks;
extern const char *pr_gametype;

View file

@ -71,7 +71,7 @@ int Sys_TimeID (void);
// not to hog cpu when paused or debugging
void Sys_MaskFPUExceptions (void);
void Sys_PushSignalHook (void (*hook)(int, void*), void *data);
void Sys_PushSignalHook (int (*hook)(int, void*), void *data);
void Sys_PopSignalHook (void);
// send text to the console

View file

@ -36,7 +36,7 @@ static const char rcsid[] =
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <signal.h>
#include <stdarg.h>
#include "QF/cvar.h"
@ -168,13 +168,6 @@ PR_LeaveFunction (progs_t * pr)
pr->pr_xstatement = pr->pr_stack[pr->pr_depth].s;
}
static void
signal_hook (int sig, void *data)
{
progs_t *pr = (progs_t *) data;
PR_DumpState (pr);
}
#define OPA (*op_a)
#define OPB (*op_b)
#define OPC (*op_c)
@ -186,6 +179,42 @@ signal_hook (int sig, void *data)
#define FNZ(x) ((x).integer_var && (x).integer_var != 0x80000000)
static int
signal_hook (int sig, void *data)
{
progs_t *pr = (progs_t *) data;
if (sig == SIGFPE && pr_faultchecks->int_val) {
dstatement_t *st;
pr_type_t *op_a, *op_b, *op_c;
st = pr->pr_statements + pr->pr_xstatement;
op_a = pr->pr_globals + st->a;
op_b = pr->pr_globals + st->b;
op_c = pr->pr_globals + st->c;
switch (st->op) {
case OP_DIV_F:
if ((OPA.integer_var & 0x80000000)
^ (OPB.integer_var & 0x80000000))
OPC.integer_var = 0xff7fffff;
else
OPC.integer_var = 0x7f7fffff;
return 1;
case OP_DIV_I:
if (OPA.integer_var & 0x80000000)
OPC.integer_var = -0x80000000;
else
OPC.integer_var = 0x7fffffff;
return 1;
default:
break;
}
}
PR_DumpState (pr);
return 0;
}
/*
PR_ExecuteProgram

View file

@ -53,6 +53,8 @@ static const char rcsid[] =
#include "compat.h"
cvar_t *pr_faultchecks;
static const char *
function_get_key (void *f, void *_pr)
{
@ -294,6 +296,8 @@ PR_Init_Cvars (void)
pr_deadbeef_locals = Cvar_Get ("pr_deadbeef_locals", "0", CVAR_NONE, NULL,
"set to clear uninitialized local vars to "
"0xdeadbeef");
pr_faultchecks = Cvar_Get ("pr_faultchecks", "0", CVAR_NONE, NULL,
"capture and handle division by 0 in progs");
PR_Debug_Init_Cvars ();
}

View file

@ -583,17 +583,17 @@ static jmp_buf aiee_abort;
typedef struct sh_stack_s {
struct sh_stack_s *next;
void (*signal_hook)(int,void*);
int (*signal_hook)(int,void*);
void *data;
} sh_stack_t;
static sh_stack_t *sh_stack;
static sh_stack_t *free_sh;
static void (*signal_hook)(int,void*);
static int (*signal_hook)(int,void*);
static void *signal_hook_data;
void
Sys_PushSignalHook (void (*hook)(int, void *), void *data)
Sys_PushSignalHook (int (*hook)(int, void *), void *data)
{
sh_stack_t *s;
@ -639,6 +639,8 @@ aiee (int sig)
static void
signal_handler (int sig)
{
int recover = 0;
printf ("Received signal %d, exiting...\n", sig);
switch (sig) {
@ -660,21 +662,35 @@ signal_handler (int sig)
#endif
signal (SIGILL, aiee);
signal (SIGSEGV, aiee);
signal (SIGFPE, aiee);
if (!setjmp (aiee_abort)) {
if (signal_hook)
signal_hook (sig, signal_hook_data);
recover = signal_hook (sig, signal_hook_data);
Sys_Shutdown ();
}
if (recover) {
#ifndef _WIN32
signal (SIGQUIT, SIG_DFL);
signal (SIGTRAP, SIG_DFL);
signal (SIGIOT, SIG_DFL);
signal (SIGBUS, SIG_DFL);
signal (SIGQUIT, signal_handler);
signal (SIGTRAP, signal_handler);
signal (SIGIOT, signal_handler);
signal (SIGBUS, signal_handler);
#endif
signal (SIGILL, SIG_DFL);
signal (SIGSEGV, SIG_DFL);
signal (SIGILL, signal_handler);
signal (SIGSEGV, signal_handler);
signal (SIGFPE, signal_handler);
} else {
#ifndef _WIN32
signal (SIGQUIT, SIG_DFL);
signal (SIGTRAP, SIG_DFL);
signal (SIGIOT, SIG_DFL);
signal (SIGBUS, SIG_DFL);
#endif
signal (SIGILL, SIG_DFL);
signal (SIGSEGV, SIG_DFL);
signal (SIGFPE, SIG_DFL);
}
}
}
@ -693,5 +709,5 @@ Sys_Init (void)
signal (SIGILL, signal_handler);
signal (SIGSEGV, signal_handler);
signal (SIGTERM, signal_handler);
// signal (SIGFPE, signal_handler);
signal (SIGFPE, signal_handler);
}

View file

@ -95,8 +95,6 @@ startup (void)
Sys_Error ("This version of " PROGRAM
" requires at least Win95 or NT 4.0");
}
#else
signal (SIGFPE, SIG_IGN);
#endif
}

View file

@ -69,21 +69,12 @@ shutdown (void)
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NONBLOCK);
}
void
floating_point_exception_handler (int whatever)
{
// Sys_Warn("floating point exception\n");
signal (SIGFPE, floating_point_exception_handler);
}
int
main (int c, const char *v[])
{
double time, oldtime, newtime;
signal (SIGFPE, SIG_IGN);
memset (&host_parms, 0, sizeof (host_parms));
COM_InitArgv (c, v);

View file

@ -80,8 +80,6 @@ main (int argc, const char **argv)
{
double time, oldtime, newtime;
signal (SIGFPE, SIG_IGN);
memset (&host_parms, 0, sizeof (host_parms));
COM_InitArgv (argc, argv);

View file

@ -96,8 +96,6 @@ startup (void)
Sys_Error ("This version of " PROGRAM
" requires at least Win95 or NT 4.0");
}
#else
signal (SIGFPE, SIG_IGN);
#endif
}

View file

@ -70,12 +70,6 @@ shutdown (void)
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NONBLOCK);
}
void
floating_point_exception_handler (int whatever)
{
signal (SIGFPE, floating_point_exception_handler);
}
int skipframes;
int
@ -84,9 +78,6 @@ main (int c, const char *v[])
// static char cwd[1024];
double time, oldtime, newtime;
// signal(SIGFPE, floating_point_exception_handler);
signal (SIGFPE, SIG_IGN);
memset (&host_parms, 0, sizeof (host_parms));
COM_InitArgv (c, v);