diff --git a/src/lib.cpp b/src/lib.cpp index 4ebaa1f..6a73ed6 100644 --- a/src/lib.cpp +++ b/src/lib.cpp @@ -13,6 +13,11 @@ static System SYS; static int IsInit = 0; +void SolveSpace::Platform::FatalError(std::string message) { + fprintf(stderr, "%s", message.c_str()); + abort(); +} + void Group::GenerateEquations(IdList *) { // Nothing to do for now. } diff --git a/src/platform/gui.h b/src/platform/gui.h index 9be2753..a283675 100644 --- a/src/platform/gui.h +++ b/src/platform/gui.h @@ -76,6 +76,12 @@ std::string AcceleratorDescription(const KeyboardEvent &accel); // Interfaces //----------------------------------------------------------------------------- +// Handling fatal errors. +#if defined(__GNUC__) +__attribute__((noreturn)) +#endif +void FatalError(std::string message); + // A native settings store. class Settings { public: diff --git a/src/platform/guigtk.cpp b/src/platform/guigtk.cpp index bb47de8..21921c2 100644 --- a/src/platform/guigtk.cpp +++ b/src/platform/guigtk.cpp @@ -25,6 +25,15 @@ namespace SolveSpace { namespace Platform { +//----------------------------------------------------------------------------- +// Fatal errors +//----------------------------------------------------------------------------- + +void FatalError(std::string message) { + fprintf(stderr, "%s", message.c_str()); + abort(); +} + //----------------------------------------------------------------------------- // Settings //----------------------------------------------------------------------------- diff --git a/src/platform/guimac.mm b/src/platform/guimac.mm index 3c4fbdd..f4e292f 100644 --- a/src/platform/guimac.mm +++ b/src/platform/guimac.mm @@ -52,6 +52,33 @@ static NSString* Wrap(const std::string &s) { namespace SolveSpace { namespace Platform { +//----------------------------------------------------------------------------- +// Fatal errors +//----------------------------------------------------------------------------- + +// This gets put into the "Application Specific Information" field in crash +// reporter dialog. +typedef struct { + unsigned version __attribute__((aligned(8))); + const char *message __attribute__((aligned(8))); + const char *signature __attribute__((aligned(8))); + const char *backtrace __attribute__((aligned(8))); + const char *message2 __attribute__((aligned(8))); + void *reserved __attribute__((aligned(8))); + void *reserved2 __attribute__((aligned(8))); +} crash_info_t; + +#define CRASH_VERSION 4 + +crash_info_t crashAnnotation __attribute__((section("__DATA,__crash_info"))) = { + CRASH_VERSION, NULL, NULL, NULL, NULL, NULL, NULL +}; + +void FatalError(std::string message) { + crashAnnotation.message = message.c_str(); + abort(); +} + //----------------------------------------------------------------------------- // Settings //----------------------------------------------------------------------------- diff --git a/src/platform/guinone.cpp b/src/platform/guinone.cpp index 67d9c1e..1273d38 100644 --- a/src/platform/guinone.cpp +++ b/src/platform/guinone.cpp @@ -18,6 +18,35 @@ std::shared_ptr CreateRenderer() { namespace Platform { +//----------------------------------------------------------------------------- +// Fatal errors +//----------------------------------------------------------------------------- + +void FatalError(std::string message) { + fprintf(stderr, "%s", message.c_str()); + +#if !defined(LIBRARY) && defined(HAVE_BACKTRACE) + static void *ptrs[1024] = {}; + size_t nptrs = backtrace(ptrs, sizeof(ptrs) / sizeof(ptrs[0])); + char **syms = backtrace_symbols(ptrs, nptrs); + + fprintf(stderr, "Backtrace:\n"); + if(syms != NULL) { + for(size_t i = 0; i < nptrs; i++) { + fprintf(stderr, "%2zu: %s\n", i, syms[i]); + } + } else { + for(size_t i = 0; i < nptrs; i++) { + fprintf(stderr, "%2zu: %p\n", i, ptrs[i]); + } + } +#else + fprintf(stderr, "Backtrace support not compiled in.\n"); +#endif + + abort(); +} + //----------------------------------------------------------------------------- // Settings //----------------------------------------------------------------------------- diff --git a/src/platform/guiwin.cpp b/src/platform/guiwin.cpp index 2918b1d..b42f9e9 100644 --- a/src/platform/guiwin.cpp +++ b/src/platform/guiwin.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 @@ -102,6 +103,34 @@ static int Clamp(int x, int a, int b) { return max(a, min(x, b)); } +//----------------------------------------------------------------------------- +// Fatal errors +//----------------------------------------------------------------------------- + +bool handlingFatalError = false; + +void FatalError(std::string message) { + // Indicate that we're handling a fatal error, to avoid re-entering application code + // and potentially crashing even harder. + handlingFatalError = true; + + message += "\nGenerate debug report?"; + switch(MessageBoxW(NULL, Platform::Widen(message).c_str(), + L"Fatal error — SolveSpace", + MB_ICONERROR|MB_TASKMODAL|MB_SETFOREGROUND|MB_TOPMOST| + MB_OKCANCEL|MB_DEFBUTTON2)) { + case IDOK: + abort(); + + case IDCANCEL: + default: { + WCHAR appPath[MAX_PATH] = {}; + GetModuleFileNameW(NULL, appPath, sizeof(appPath)); + ShellExecuteW(NULL, L"open", appPath, NULL, NULL, SW_SHOW); + _exit(1); + } + } +} //----------------------------------------------------------------------------- // Settings //----------------------------------------------------------------------------- diff --git a/src/platform/platform.h b/src/platform/platform.h index ede348b..06ae19f 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -9,13 +9,6 @@ namespace Platform { -// Handling fatal errors. -#if defined(__GNUC__) -__attribute__((noreturn)) -#endif -void FatalError(std::string message); -extern bool handlingFatalError; - // UTF-8 ⟷ UTF-16 conversion, for Windows. #if defined(WIN32) std::string Narrow(const wchar_t *s); diff --git a/src/platform/unixutil.cpp b/src/platform/unixutil.cpp index 6bb1236..85a4179 100644 --- a/src/platform/unixutil.cpp +++ b/src/platform/unixutil.cpp @@ -27,35 +27,6 @@ void dbp(const char *str, ...) fputc('\n', stderr); } -namespace Platform { - -void FatalError(std::string message) { - fprintf(stderr, "%s", message.c_str()); - -#if !defined(LIBRARY) && defined(HAVE_BACKTRACE) - static void *ptrs[1024] = {}; - size_t nptrs = backtrace(ptrs, sizeof(ptrs) / sizeof(ptrs[0])); - char **syms = backtrace_symbols(ptrs, nptrs); - - fprintf(stderr, "Backtrace:\n"); - if(syms != NULL) { - for(size_t i = 0; i < nptrs; i++) { - fprintf(stderr, "%2zu: %s\n", i, syms[i]); - } - } else { - for(size_t i = 0; i < nptrs; i++) { - fprintf(stderr, "%2zu: %p\n", i, ptrs[i]); - } - } -#else - fprintf(stderr, "Backtrace support not compiled in.\n"); -#endif - - abort(); -} - -} - //----------------------------------------------------------------------------- // A separate heap, on which we allocate expressions. Maybe a bit faster, // since fragmentation is less of a concern, and it also makes it possible diff --git a/src/platform/w32util.cpp b/src/platform/w32util.cpp index e00aaab..eeaef9b 100644 --- a/src/platform/w32util.cpp +++ b/src/platform/w32util.cpp @@ -35,35 +35,6 @@ void dbp(const char *str, ...) #endif } -namespace Platform { - -bool handlingFatalError = false; - -void FatalError(std::string message) { - // Indicate that we're handling a fatal error, to avoid re-entering application code - // and potentially crashing even harder. - handlingFatalError = true; - - message += "\nGenerate debug report?"; - switch(MessageBoxW(NULL, Platform::Widen(message).c_str(), - L"Fatal error — SolveSpace", - MB_ICONERROR|MB_TASKMODAL|MB_SETFOREGROUND|MB_TOPMOST| - MB_OKCANCEL|MB_DEFBUTTON2)) { - case IDOK: - abort(); - - case IDCANCEL: - default: { - WCHAR appPath[MAX_PATH] = {}; - GetModuleFileNameW(NULL, appPath, sizeof(appPath)); - ShellExecuteW(NULL, L"open", appPath, NULL, NULL, SW_SHOW); - _exit(1); - } - } -} - -} - //----------------------------------------------------------------------------- // A separate heap, on which we allocate expressions. Maybe a bit faster, // since no fragmentation issues whatsoever, and it also makes it possible