]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
sys: implement signal handling on all platforms
authorbones_was_here <bones_was_here@xonotic.au>
Mon, 1 Jan 2024 12:55:45 +0000 (22:55 +1000)
committerbones_was_here <bones_was_here@xonotic.au>
Wed, 3 Jan 2024 01:11:36 +0000 (11:11 +1000)
Prints a stack trace when crashing if using glibc.

Signed-off-by: bones_was_here <bones_was_here@xonotic.au>
cl_main.c
host.c
makefile.inc
sys_shared.c
vid_null.c

index 6b557283ad5ed540ca9714818cbcb8027e5ca364..7dffe2c8a46db87ae24e7d4065b397a45ec277a3 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -439,6 +439,8 @@ void CL_DisconnectEx(qbool kicked, const char *fmt, ... )
                                MSG_WriteByte(&buf, clc_disconnect);
                                if(cls.protocol == PROTOCOL_DARKPLACES8)
                                        MSG_WriteString(&buf, reason);
+                               // DP8 TODO: write a simpler func that Sys_HandleCrash() calls
+                               // to send a disconnect message indicating we crashed
                        }
                        NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, 0, false);
                        NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000, 0, false);
diff --git a/host.c b/host.c
index 7c89c589f69f203e9de180eed8ea825b62b48fef..fdfb6836bbcdce8b88772cdb3c0fa30dddd3b096 100644 (file)
--- a/host.c
+++ b/host.c
@@ -448,10 +448,10 @@ static void Host_Init (void)
        Sys_Init_Commands();
        COM_Init_Commands();
 
-       // initialize filesystem (including fs_basedir, fs_gamedir, -game, scr_screenshot_name)
+       // initialize filesystem (including fs_basedir, fs_gamedir, -game, scr_screenshot_name, gamename)
        FS_Init();
 
-       // construct a version string for the corner of the console
+       // ASAP! construct a version string for the corner of the console and for crash messages
        dpsnprintf (engineversion, sizeof (engineversion), "%s %s%s, buildstring: %s", gamename, DP_OS_NAME, cls.state == ca_dedicated ? " dedicated" : "", buildstring);
        Con_Printf("%s\n", engineversion);
 
index fc39741582424ff1b38354b9cf7f01f29f63949d..40b70e21f5956f590891a8dc33fa01edb84b7661 100644 (file)
@@ -216,8 +216,10 @@ CMD_UNIXMKDIR=mkdir -p
 ##### Linux specific variables #####
 
 # Link
-LDFLAGS_LINUXSV=$(LDFLAGS_UNIXCOMMON) -lrt -ldl
-LDFLAGS_LINUXSDL=$(LDFLAGS_UNIXCOMMON) -lrt -ldl $(LDFLAGS_UNIXSDL)
+# -rdynamic allows glibc backtrace_symbols_fd() to convert addresses to function names
+# with a much smaller binary than with full debug symbols
+LDFLAGS_LINUXSV=$(LDFLAGS_UNIXCOMMON) -lrt -ldl -rdynamic
+LDFLAGS_LINUXSDL=$(LDFLAGS_UNIXCOMMON) -lrt -ldl -rdynamic $(LDFLAGS_UNIXSDL)
 
 
 ##### Mac OS X specific variables #####
index 457abe36a9a26e1776b2158698b3a014662daad3..e92eb94f71296215231e8fa58e41199245f51a08 100644 (file)
@@ -890,10 +890,83 @@ void Sys_MakeProcessMean (void)
 }
 #endif
 
-int main (int argc, char **argv)
+/** Halt and try not to catch fire.
+ * Writing to any file could corrupt it,
+ * any uneccessary code could crash while we crash.
+ * No malloc() (libgcc should be loaded already) or Con_Printf() allowed here.
+ */
+static void Sys_HandleCrash(int sig)
+{
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+       // Before doing anything else grab the stack frame addresses
+       #include <execinfo.h>
+       void *stackframes[32];
+       int framecount = backtrace(stackframes, 32);
+#endif
+
+       // Windows doesn't have strsignal()
+       const char *sigdesc;
+       switch (sig)
+       {
+#ifndef WIN32 // or SIGBUS
+               case SIGBUS:  sigdesc = "Bus error"; break;
+#endif
+               case SIGILL:  sigdesc = "Illegal instruction"; break;
+               case SIGABRT: sigdesc = "Aborted"; break;
+               case SIGFPE:  sigdesc = "Floating point exception"; break;
+               case SIGSEGV: sigdesc = "Segmentation fault"; break;
+               default:      sigdesc = "Yo dawg, we hit a bug while hitting a bug";
+       }
+
+       fprintf(stderr, "\n\n\e[1;37;41m    Engine Crash: %s (%d)    \e[m\n", sigdesc, sig);
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+       // the first two addresses will be in this function and in signal() in libc
+       backtrace_symbols_fd(stackframes + 2, framecount - 2, fileno(stderr));
+#endif
+       fprintf(stderr, "\e[1m%s\e[m\n", engineversion);
+
+       // DP8 TODO: send a disconnect message indicating we crashed, see CL_DisconnectEx()
+
+       // don't want a dead window left blocking the OS UI or the crash dialog
+       VID_Shutdown();
+       S_StopAllSounds();
+
+       Sys_SDL_Dialog("Engine Crash", sigdesc);
+
+       exit (sig);
+}
+
+static void Sys_HandleSignal(int sig)
+{
+#ifdef WIN32
+       // Windows users will likely never see this so no point replicating strsignal()
+       Con_Printf("\nReceived signal %d, exiting...\n", sig);
+#else
+       Con_Printf("\nReceived %s signal (%d), exiting...\n", strsignal(sig), sig);
+#endif
+       host.state = host_shutdown;
+}
+
+/// SDL2 only handles SIGINT and SIGTERM by default and doesn't log anything
+static void Sys_InitSignals(void)
 {
-       signal(SIGFPE, SIG_IGN);
+// Windows docs say its signal() only accepts these ones
+       signal(SIGABRT, Sys_HandleCrash);
+       signal(SIGFPE,  Sys_HandleCrash);
+       signal(SIGILL,  Sys_HandleCrash);
+       signal(SIGINT,  Sys_HandleSignal);
+       signal(SIGSEGV, Sys_HandleCrash);
+       signal(SIGTERM, Sys_HandleSignal);
+#ifndef WIN32
+       signal(SIGHUP,  Sys_HandleSignal);
+       signal(SIGQUIT, Sys_HandleSignal);
+       signal(SIGBUS,  Sys_HandleCrash);
+       signal(SIGPIPE, Sys_HandleSignal);
+#endif
+}
 
+int main (int argc, char **argv)
+{
        sys.argc = argc;
        sys.argv = (const char **)argv;
 
@@ -917,6 +990,8 @@ int main (int argc, char **argv)
        Sys_AllowProfiling(true);
 #endif
 
+       Sys_InitSignals();
+
        Host_Main();
 
        Sys_Quit(0);
index fb3cba08bdeeaf2f06f584a7f20561caea9cd6bc..b8621dc5e50aadf024ac3badfc334cf4e2eb5364 100644 (file)
@@ -29,37 +29,12 @@ void VID_Shutdown(void)
 {
 }
 
-#ifndef WIN32
-static void signal_handler(int sig)
-{
-       Con_Printf("Received signal %d, exiting...\n", sig);
-       Sys_Quit(1);
-}
-
-static void InitSig(void)
-{
-       signal(SIGHUP, signal_handler);
-       signal(SIGINT, signal_handler);
-       signal(SIGQUIT, signal_handler);
-       signal(SIGILL, signal_handler);
-       signal(SIGTRAP, signal_handler);
-       signal(SIGIOT, signal_handler);
-       signal(SIGBUS, signal_handler);
-       signal(SIGFPE, signal_handler);
-       signal(SIGSEGV, signal_handler);
-       signal(SIGTERM, signal_handler);
-}
-#endif
-
 void VID_Finish (void)
 {
 }
 
 void VID_Init(void)
 {
-#ifndef WIN32
-       InitSig(); // trap evil signals
-#endif
 }
 
 qbool VID_InitMode(viddef_mode_t *mode)