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_ents;
extern struct cvar_s *pr_deadbeef_locals; extern struct cvar_s *pr_deadbeef_locals;
extern struct cvar_s *pr_boundscheck; extern struct cvar_s *pr_boundscheck;
extern struct cvar_s *pr_faultchecks;
extern const char *pr_gametype; extern const char *pr_gametype;

View file

@ -71,7 +71,7 @@ int Sys_TimeID (void);
// not to hog cpu when paused or debugging // not to hog cpu when paused or debugging
void Sys_MaskFPUExceptions (void); 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); void Sys_PopSignalHook (void);
// send text to the console // send text to the console

View file

@ -36,7 +36,7 @@ static const char rcsid[] =
#ifdef HAVE_STRINGS_H #ifdef HAVE_STRINGS_H
# include <strings.h> # include <strings.h>
#endif #endif
#include <signal.h>
#include <stdarg.h> #include <stdarg.h>
#include "QF/cvar.h" #include "QF/cvar.h"
@ -168,13 +168,6 @@ PR_LeaveFunction (progs_t * pr)
pr->pr_xstatement = pr->pr_stack[pr->pr_depth].s; 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 OPA (*op_a)
#define OPB (*op_b) #define OPB (*op_b)
#define OPC (*op_c) #define OPC (*op_c)
@ -186,6 +179,42 @@ signal_hook (int sig, void *data)
#define FNZ(x) ((x).integer_var && (x).integer_var != 0x80000000) #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 PR_ExecuteProgram

View file

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

View file

@ -583,17 +583,17 @@ static jmp_buf aiee_abort;
typedef struct sh_stack_s { typedef struct sh_stack_s {
struct sh_stack_s *next; struct sh_stack_s *next;
void (*signal_hook)(int,void*); int (*signal_hook)(int,void*);
void *data; void *data;
} sh_stack_t; } sh_stack_t;
static sh_stack_t *sh_stack; static sh_stack_t *sh_stack;
static sh_stack_t *free_sh; static sh_stack_t *free_sh;
static void (*signal_hook)(int,void*); static int (*signal_hook)(int,void*);
static void *signal_hook_data; static void *signal_hook_data;
void void
Sys_PushSignalHook (void (*hook)(int, void *), void *data) Sys_PushSignalHook (int (*hook)(int, void *), void *data)
{ {
sh_stack_t *s; sh_stack_t *s;
@ -639,6 +639,8 @@ aiee (int sig)
static void static void
signal_handler (int sig) signal_handler (int sig)
{ {
int recover = 0;
printf ("Received signal %d, exiting...\n", sig); printf ("Received signal %d, exiting...\n", sig);
switch (sig) { switch (sig) {
@ -660,21 +662,35 @@ signal_handler (int sig)
#endif #endif
signal (SIGILL, aiee); signal (SIGILL, aiee);
signal (SIGSEGV, aiee); signal (SIGSEGV, aiee);
signal (SIGFPE, aiee);
if (!setjmp (aiee_abort)) { if (!setjmp (aiee_abort)) {
if (signal_hook) if (signal_hook)
signal_hook (sig, signal_hook_data); recover = signal_hook (sig, signal_hook_data);
Sys_Shutdown (); Sys_Shutdown ();
} }
if (recover) {
#ifndef _WIN32 #ifndef _WIN32
signal (SIGQUIT, SIG_DFL); signal (SIGQUIT, signal_handler);
signal (SIGTRAP, SIG_DFL); signal (SIGTRAP, signal_handler);
signal (SIGIOT, SIG_DFL); signal (SIGIOT, signal_handler);
signal (SIGBUS, SIG_DFL); signal (SIGBUS, signal_handler);
#endif #endif
signal (SIGILL, SIG_DFL); signal (SIGILL, signal_handler);
signal (SIGSEGV, SIG_DFL); 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 (SIGILL, signal_handler);
signal (SIGSEGV, signal_handler); signal (SIGSEGV, signal_handler);
signal (SIGTERM, 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 Sys_Error ("This version of " PROGRAM
" requires at least Win95 or NT 4.0"); " requires at least Win95 or NT 4.0");
} }
#else
signal (SIGFPE, SIG_IGN);
#endif #endif
} }

View file

@ -69,21 +69,12 @@ shutdown (void)
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~O_NONBLOCK); 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 int
main (int c, const char *v[]) main (int c, const char *v[])
{ {
double time, oldtime, newtime; double time, oldtime, newtime;
signal (SIGFPE, SIG_IGN);
memset (&host_parms, 0, sizeof (host_parms)); memset (&host_parms, 0, sizeof (host_parms));
COM_InitArgv (c, v); COM_InitArgv (c, v);

View file

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

View file

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

View file

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