From 17bf75fd3593956471edf0df4dfc70e80732b300 Mon Sep 17 00:00:00 2001 From: Dennis Brakhane Date: Thu, 16 Jan 2025 08:42:40 +0100 Subject: [PATCH] linux: add simple crash handler that dumps stacktrace (#1020) Since the Linux version seems much more unstable than the Windows one, having more information where the crash occured will help with figuring out where the problems are. This commit adds a simple crash handler that dumps out the stacktrace, it's only supported on Linux. --- Editor/CMakeLists.txt | 6 ++++ Editor/main_SDL2.cpp | 70 ++++++++++++++++++++++++++++++++++++++++ WickedEngine/wiBacklog.h | 4 +-- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index 7062ca2c7e..99503f29cc 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -26,6 +26,12 @@ else () ) set(LIB_DXCOMPILER "libdxcompiler.so") + # needed for proper names in crash stacktrace + set_target_properties(WickedEngineEditor + PROPERTIES + ENABLE_EXPORTS ON + ) + endif () # Copy content to build folder: diff --git a/Editor/main_SDL2.cpp b/Editor/main_SDL2.cpp index aaaffa4815..38491a855e 100644 --- a/Editor/main_SDL2.cpp +++ b/Editor/main_SDL2.cpp @@ -6,6 +6,13 @@ #include "icon.c" +#ifdef __linux__ +# include +# include +# include +# include +#endif + using namespace std; Editor editor; @@ -92,8 +99,71 @@ void set_window_icon(SDL_Window *window) { SDL_FreeSurface(icon); } +#ifdef __linux__ + +void crash_handler(int sig) +{ + void* btbuf[100]; + + char outbuf[256]; + + size_t size = backtrace(btbuf, 100); + snprintf( + outbuf, sizeof(outbuf), + "Signal: %i (%s)\n" + "Version: %s\nStacktrace:\n", + sig, + sigdescr_np(sig), + wi::version::GetVersionString() + ); + + fprintf( + stderr, + "\e[31m" // red + "The editor just crashed, sorry about that! If you make a bug report, please include the following information:\n\n%s", + outbuf + ); + backtrace_symbols_fd(btbuf, size, STDERR_FILENO); // backtrace_symbols does a malloc which could crash, backtrace_symbols_fd does not. + fprintf(stderr, "\e[m"); // back to normal + + // finally, we also try to write the crash data to a file + // this might fail because we're in a weird state right now, but there's no harm done if it doesn't work + + // Use C interface because some stuff in the c++ stdlib could be calling malloc + + const char* filename = "wicked-editor-crash-log.txt"; + + FILE* logfile = fopen(filename, "w"); + + if (logfile != nullptr) + { + fputs(outbuf, logfile); + fflush(logfile); + backtrace_symbols_fd(btbuf, size, fileno(logfile)); + fclose(logfile); + char cwdbuf[200]; + fprintf(stderr, "\e[1mcrash log written to %s/%s\e[m\n", getcwd(cwdbuf, sizeof(cwdbuf)), filename); + } + exit(1); +} + +#endif + int main(int argc, char *argv[]) { + +#ifdef __linux__ + // dummy backtrace() call to force libgcc to be loaded ahead of time. + // Otherwise it might lead to malloc calls in the crash_handler, which we want to avoid + void* dummy[1]; + backtrace(dummy, 1); + + for (int sig : std::array{SIGABRT, SIGBUS, SIGILL, SIGFPE, SIGSEGV}) + { + signal(sig, crash_handler); + } +#endif + wi::arguments::Parse(argc, argv); sdl2::sdlsystem_ptr_t system = sdl2::make_sdlsystem(SDL_INIT_EVERYTHING | SDL_INIT_EVENTS); diff --git a/WickedEngine/wiBacklog.h b/WickedEngine/wiBacklog.h index c5ce5501a8..897561d64f 100644 --- a/WickedEngine/wiBacklog.h +++ b/WickedEngine/wiBacklog.h @@ -8,8 +8,8 @@ #include #include -#define wilog_level(str,level,...) {char text[1024] = {}; snprintf(text, sizeof(text), str, ## __VA_ARGS__); wi::backlog::post(text, level);} -#define wilog_messagebox(str,...) {char text[1024] = {}; snprintf(text, sizeof(text), str, ## __VA_ARGS__); wi::backlog::post(text, wi::backlog::LogLevel::Error); wi::helper::messageBox(text, "Error!");} +#define wilog_level(str,level,...) {char text[1024]; snprintf(text, sizeof(text), str, ## __VA_ARGS__); wi::backlog::post(text, level);} +#define wilog_messagebox(str,...) {char text[1024]; snprintf(text, sizeof(text), str, ## __VA_ARGS__); wi::backlog::post(text, wi::backlog::LogLevel::Error); wi::helper::messageBox(text, "Error!");} #define wilog_warning(str,...) {wilog_level(str, wi::backlog::LogLevel::Warning, ## __VA_ARGS__);} #define wilog_error(str,...) {wilog_level(str, wi::backlog::LogLevel::Error, ## __VA_ARGS__);} #define wilog(str,...) {wilog_level(str, wi::backlog::LogLevel::Default, ## __VA_ARGS__);}