diff --git a/components/crashcatcher/windows_crashcatcher.cpp b/components/crashcatcher/windows_crashcatcher.cpp index d9ef00ef77..f17078a4a1 100644 --- a/components/crashcatcher/windows_crashcatcher.cpp +++ b/components/crashcatcher/windows_crashcatcher.cpp @@ -129,6 +129,8 @@ namespace Crash if (mShm == nullptr) throw std::runtime_error("Failed to map crash catcher shared memory"); + mShm->mMonitorStatus = CrashSHM::Status::Uninitialised; + mShmMutex = CreateMutexW(&attributes, FALSE, NULL); if (mShmMutex == nullptr) throw std::runtime_error("Failed to create crash catcher shared memory mutex"); @@ -234,13 +236,31 @@ namespace Crash signalMonitor(); - // must remain until monitor has finished - waitMonitor(); + try + { + // give monitor a chance to start dumping + // do this in try/catch as dumping might take longer than the timeout and an exception will be thrown when + // we're resumed + waitMonitor(); + } + catch (std::exception) + { + } - std::string message = "OpenMW has encountered a fatal error.\nCrash dump saved to '" - + Misc::StringUtils::u8StringToString(getCrashDumpPath(*mShm).u8string()) - + "'.\nPlease report this to https://gitlab.com/OpenMW/openmw/issues !"; - SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), nullptr); + shmLock(); + CrashSHM::Status monitorStatus = mShm->mMonitorStatus; + shmUnlock(); + + if (monitorStatus == CrashSHM::Status::DumpedSuccessfully) + { + + std::string message = "OpenMW has encountered a fatal error.\nCrash dump saved to '" + + Misc::StringUtils::u8StringToString(getCrashDumpPath(*mShm).u8string()) + + "'.\nPlease report this to https://gitlab.com/OpenMW/openmw/issues !"; + SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), nullptr); + } + else if (monitorStatus == CrashSHM::Status::Dumping) + SDL_ShowSimpleMessageBox(0, "Fatal Error", "Timed out while creating crash dump", nullptr); } } // namespace Crash diff --git a/components/crashcatcher/windows_crashmonitor.cpp b/components/crashcatcher/windows_crashmonitor.cpp index 8398528ec9..de5f64a54c 100644 --- a/components/crashcatcher/windows_crashmonitor.cpp +++ b/components/crashcatcher/windows_crashmonitor.cpp @@ -163,6 +163,7 @@ namespace Crash void CrashMonitor::run() { + mShm->mMonitorStatus = CrashSHM::Status::Monitoring; try { // app waits for monitor start up, let it continue @@ -231,6 +232,18 @@ namespace Crash void CrashMonitor::handleCrash(bool isFreeze) { + shmLock(); + mShm->mMonitorStatus = CrashSHM::Status::Dumping; + shmUnlock(); + + auto failedDumping = [this](const std::string& message) { + Log(Debug::Error) << "CrashMonitor: " << message; + shmLock(); + mShm->mMonitorStatus = CrashSHM::Status::FailedDumping; + shmUnlock(); + SDL_ShowSimpleMessageBox(0, "Failed to create crash dump", message.c_str(), nullptr); + }; + DWORD processId = GetProcessId(mAppProcessHandle); const char* env = getenv("OPENMW_FULL_MEMDUMP"); @@ -238,7 +251,10 @@ namespace Crash { HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); if (dbghelp == NULL) + { + failedDumping("Could not load dbghelp.dll"); return; + } using MiniDumpWirteDumpFn = BOOL(WINAPI*)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, @@ -246,11 +262,17 @@ namespace Crash MiniDumpWirteDumpFn miniDumpWriteDump = (MiniDumpWirteDumpFn)GetProcAddress(dbghelp, "MiniDumpWriteDump"); if (miniDumpWriteDump == NULL) + { + failedDumping("Could not get MiniDumpWriteDump address"); return; + } std::wstring utf16Path = (isFreeze ? getFreezeDumpPath(*mShm) : getCrashDumpPath(*mShm)).native(); if (utf16Path.empty()) + { + failedDumping("Empty dump path"); return; + } if (utf16Path.length() > MAX_PATH) utf16Path = LR"(\\?\)" + utf16Path; @@ -258,9 +280,17 @@ namespace Crash HANDLE hCrashLog = CreateFileW(utf16Path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hCrashLog == NULL || hCrashLog == INVALID_HANDLE_VALUE) + { + failedDumping("Bad dump file handle"); return; + } if (auto err = GetLastError(); err != ERROR_ALREADY_EXISTS && err != 0) + { + std::stringstream ss; + ss << "Error opening dump file: " << std::hex << err; + failedDumping(ss.str()); return; + } EXCEPTION_POINTERS exp; exp.ContextRecord = &mShm->mCrashed.mContext; @@ -274,15 +304,28 @@ namespace Crash if (env) type = static_cast(type | MiniDumpWithFullMemory); - miniDumpWriteDump(mAppProcessHandle, processId, hCrashLog, type, &infos, 0, 0); + if (!miniDumpWriteDump(mAppProcessHandle, processId, hCrashLog, type, &infos, 0, 0)) + { + auto err = GetLastError(); + std::stringstream ss; + ss << "Error while writing dump: " << std::hex << err; + failedDumping(ss.str()); + return; + } + else + { + shmLock(); + mShm->mMonitorStatus = CrashSHM::Status::DumpedSuccessfully; + shmUnlock(); + } } catch (const std::exception& e) { - Log(Debug::Error) << "CrashMonitor: " << e.what(); + failedDumping(e.what()); } catch (...) { - Log(Debug::Error) << "CrashMonitor: unknown exception"; + failedDumping("Unknown exception"); } } diff --git a/components/crashcatcher/windows_crashshm.hpp b/components/crashcatcher/windows_crashshm.hpp index b919757890..2cad54b17a 100644 --- a/components/crashcatcher/windows_crashshm.hpp +++ b/components/crashcatcher/windows_crashshm.hpp @@ -22,6 +22,17 @@ namespace Crash Event mEvent; + enum class Status + { + Uninitialised, + Monitoring, + Dumping, + DumpedSuccessfully, + FailedDumping + }; + + Status mMonitorStatus; + struct Startup { HANDLE mAppProcessHandle;