diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 39571c43..8bb53622 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -20,6 +20,7 @@ namespace Components Loader::Register(new Flags()); Loader::Register(new Singleton()); + Loader::Register(new Exception()); // install our exception handler as early as posssible to get better debug dumps from startup crashes Loader::Register(new Auth()); Loader::Register(new Bans()); @@ -58,7 +59,6 @@ namespace Components Loader::Register(new Changelog()); Loader::Register(new Dedicated()); Loader::Register(new Discovery()); - Loader::Register(new Exception()); Loader::Register(new FastFiles()); Loader::Register(new FrameTime()); Loader::Register(new Gametypes()); diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index bb7e863a..43730a8c 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -24,27 +24,52 @@ namespace Components return EXCEPTION_CONTINUE_EXECUTION; } + const char* errorStr; + if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) + { + errorStr = "Termination because of a stack overflow."; + } + else + { + errorStr = Utils::String::VA("Fatal error (0x%08X) at 0x%08X.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); + } + + bool doFullDump = Flags::HasFlag("bigdumps") || Flags::HasFlag("reallybigdumps"); + if (!doFullDump) + { + if (MessageBoxA(NULL, + Utils::String::VA("IW4x has encountered an exception and needs to close.\n" + "%s\n" // errorStr + "Would you like to create a full crash dump for the developers? (this can be almost 100mb)", errorStr), + "IW4x Error!", MB_YESNO | MB_ICONERROR) == IDYES) + { + doFullDump = true; + } + } + + if (doFullDump) + { + Exception::SetMiniDumpType(true, false); + } + auto minidump = MinidumpUpload::CreateQueuedMinidump(ExceptionInfo, Exception::MiniDumpType); if (!minidump) { + MessageBoxA(NULL, "Minidump Error", + Utils::String::VA("There was an error creating the minidump (%s)! Hit OK to close the program.", Utils::GetLastWindowsError()), MB_OK | MB_ICONERROR); OutputDebugStringA("Failed to create new minidump!"); Utils::OutputDebugLastError(); + TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode); } else { delete minidump; } - if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) + if (ExceptionInfo->ExceptionRecord->ExceptionFlags == EXCEPTION_NONCONTINUABLE) { - Logger::Error("Termination because of a stack overflow.\n"); + TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode); } - else - { - Logger::Error("Fatal error (0x%08X) at 0x%08X.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); - } - - //TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode); return EXCEPTION_CONTINUE_SEARCH; } @@ -62,33 +87,29 @@ namespace Components return SetUnhandledExceptionFilter(&Exception::ExceptionFilter); } - void Exception::SetMiniDumpType() + void Exception::SetMiniDumpType(bool codeseg, bool dataseg) { Exception::MiniDumpType = MiniDumpIgnoreInaccessibleMemory; - Exception::MiniDumpType |= MiniDumpWithUnloadedModules; - Exception::MiniDumpType |= MiniDumpWithThreadInfo; - Exception::MiniDumpType |= MiniDumpWithFullMemoryInfo; Exception::MiniDumpType |= MiniDumpWithHandleData; - Exception::MiniDumpType |= MiniDumpWithTokenInformation; + Exception::MiniDumpType |= MiniDumpScanMemory; Exception::MiniDumpType |= MiniDumpWithProcessThreadData; - Exception::MiniDumpType |= MiniDumpWithFullAuxiliaryState; + Exception::MiniDumpType |= MiniDumpWithFullMemoryInfo; + Exception::MiniDumpType |= MiniDumpWithThreadInfo; + //Exception::MiniDumpType |= MiniDumpWithModuleHeaders; - if (Flags::HasFlag("bigminidumps")) + if (codeseg) { - Exception::MiniDumpType |= MiniDumpWithModuleHeaders; Exception::MiniDumpType |= MiniDumpWithCodeSegs; } - else if (Flags::HasFlag("reallybigminidumps")) + if (dataseg) { - Exception::MiniDumpType |= MiniDumpWithModuleHeaders; - Exception::MiniDumpType |= MiniDumpWithCodeSegs; Exception::MiniDumpType |= MiniDumpWithDataSegs; } } Exception::Exception() { - Exception::SetMiniDumpType(); + Exception::SetMiniDumpType(Flags::HasFlag("bigminidumps"), Flags::HasFlag("reallybigminidumps")); #ifdef DEBUG // Display DEBUG branding, so we know we're on a debug build diff --git a/src/Components/Modules/Exception.hpp b/src/Components/Modules/Exception.hpp index 3d2c1f86..3ebdf764 100644 --- a/src/Components/Modules/Exception.hpp +++ b/src/Components/Modules/Exception.hpp @@ -14,7 +14,7 @@ namespace Components static LPTOP_LEVEL_EXCEPTION_FILTER Hook(); static int MiniDumpType; - static void SetMiniDumpType(); + static void SetMiniDumpType(bool codeseg, bool dataseg); private: static LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo); diff --git a/src/Utils/Utils.cpp b/src/Utils/Utils.cpp index 8d09eb8e..e0fcfd8b 100644 --- a/src/Utils/Utils.cpp +++ b/src/Utils/Utils.cpp @@ -36,6 +36,17 @@ namespace Utils LocalFree(messageBuffer); } + std::string GetLastWindowsError() + { + DWORD errorMessageID = ::GetLastError(); + LPSTR messageBuffer = nullptr; + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&messageBuffer), 0, nullptr); + std::string message(messageBuffer, size); + LocalFree(messageBuffer); + return message; + } + bool IsWineEnvironment() { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); diff --git a/src/Utils/Utils.hpp b/src/Utils/Utils.hpp index 7fb14f8a..13b25be9 100644 --- a/src/Utils/Utils.hpp +++ b/src/Utils/Utils.hpp @@ -5,6 +5,7 @@ namespace Utils std::string GetMimeType(std::string url); std::string ParseChallenge(std::string data); void OutputDebugLastError(); + std::string GetLastWindowsError(); bool IsWineEnvironment();