diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index f7667d6d98..f0210e58e1 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -33,6 +33,9 @@ #include #include #include +#if !defined(_MSC_VER) +#include +#endif #include "../../safeguards.h" @@ -45,6 +48,10 @@ #define PRINTF_LOC "%.8" PRINTF_SIZEX_SUFFIX #endif +#if !defined(_MSC_VER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) +#pragma GCC diagnostic ignored "-Wclobbered" +#endif + /** * Windows implementation for the crash logger. */ @@ -57,6 +64,13 @@ class CrashLogWindows : public CrashLog { char *LogStacktrace(char *buffer, const char *last) const override; char *LogRegisters(char *buffer, const char *last) const override; char *LogModules(char *buffer, const char *last) const override; + +protected: +#if !defined(_MSC_VER) + char *TryCrashLogFaultSection(char *buffer, const char *last, const char *section_name, CrashLogSectionWriter writer) override; + void CrashLogFaultSectionCheckpoint(char *buffer) const override; +#endif + public: #if defined(_MSC_VER) int WriteCrashDump(char *filename, const char *filename_last) const override; @@ -94,6 +108,11 @@ public: * Points to the current crash log. */ static CrashLogWindows *current; + +#if !defined(_MSC_VER) + char *internal_fault_saved_buffer = nullptr; + jmp_buf internal_fault_jmp_buf; +#endif }; /* static */ CrashLogWindows *CrashLogWindows::current = nullptr; @@ -678,6 +697,53 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c } #endif /* _MSC_VER || WITH_DBGHELP */ +#if !defined(_MSC_VER) + /** + * Set up a longjmp to be called from the vectored exception handler for the case where we trigger another exception + * during the course of calling the given log section writer. + * + * If an exception does occur, restore the buffer pointer to either the original value, or + * the value provided in any later checkpoint. + * Insert a message describing the problem and give up on the section. + */ + /* virtual */ char *CrashLogWindows::TryCrashLogFaultSection(char *buffer, const char *last, const char *section_name, CrashLogSectionWriter writer) + { + this->FlushCrashLogBuffer(); + this->internal_fault_saved_buffer = buffer; + + int exception_num = setjmp(this->internal_fault_jmp_buf); + if (exception_num != 0) { + if (this->internal_fault_saved_buffer == nullptr) { + /* if we get here, things are unrecoverable */ + ExitProcess(43); + } + + buffer = this->internal_fault_saved_buffer; + this->internal_fault_saved_buffer = nullptr; + + buffer += seprintf(buffer, last, "\nSomething went seriously wrong when attempting to fill the '%s' section of the crash log: exception: %.8X.\n", section_name, exception_num); + buffer += seprintf(buffer, last, "This is probably due to an invalid pointer or other corrupt data.\n\n"); + + return buffer; + } + + buffer = writer(this, buffer, last); + this->internal_fault_saved_buffer = nullptr; + return buffer; + } + + /* virtual */ void CrashLogWindows::CrashLogFaultSectionCheckpoint(char *buffer) const + { + CrashLogWindows *self = const_cast(this); + + if (self->internal_fault_saved_buffer != nullptr && buffer > self->internal_fault_saved_buffer) { + self->internal_fault_saved_buffer = buffer; + } + + self->FlushCrashLogBuffer(); + } +#endif /* !_MSC_VER */ + extern bool CloseConsoleLogIfActive(); static void ShowCrashlogWindow(); @@ -763,6 +829,12 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) static LONG WINAPI VectoredExceptionHandler(EXCEPTION_POINTERS *ep) { +#if !defined(_MSC_VER) + if (CrashLogWindows::current != nullptr && CrashLogWindows::current->internal_fault_saved_buffer != nullptr) { + longjmp(CrashLogWindows::current->internal_fault_jmp_buf, ep->ExceptionRecord->ExceptionCode); + } +#endif + if (ep->ExceptionRecord->ExceptionCode == 0xC0000374 /* heap corruption */) { return ExceptionHandler(ep); }