[Exception] Added better exception handling so that when the users are morons it explains exactly what happened to them.... cause they're morons

This commit is contained in:
TheApadayo 2017-02-09 16:16:49 -05:00
parent 16a2d93801
commit 23ff36d590
5 changed files with 55 additions and 22 deletions

View File

@ -20,6 +20,7 @@ namespace Components
Loader::Register(new Flags()); Loader::Register(new Flags());
Loader::Register(new Singleton()); 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 Auth());
Loader::Register(new Bans()); Loader::Register(new Bans());
@ -58,7 +59,6 @@ namespace Components
Loader::Register(new Changelog()); Loader::Register(new Changelog());
Loader::Register(new Dedicated()); Loader::Register(new Dedicated());
Loader::Register(new Discovery()); Loader::Register(new Discovery());
Loader::Register(new Exception());
Loader::Register(new FastFiles()); Loader::Register(new FastFiles());
Loader::Register(new FrameTime()); Loader::Register(new FrameTime());
Loader::Register(new Gametypes()); Loader::Register(new Gametypes());

View File

@ -24,27 +24,52 @@ namespace Components
return EXCEPTION_CONTINUE_EXECUTION; 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); auto minidump = MinidumpUpload::CreateQueuedMinidump(ExceptionInfo, Exception::MiniDumpType);
if (!minidump) 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!"); OutputDebugStringA("Failed to create new minidump!");
Utils::OutputDebugLastError(); Utils::OutputDebugLastError();
TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode);
} }
else else
{ {
delete minidump; 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; return EXCEPTION_CONTINUE_SEARCH;
} }
@ -62,33 +87,29 @@ namespace Components
return SetUnhandledExceptionFilter(&Exception::ExceptionFilter); return SetUnhandledExceptionFilter(&Exception::ExceptionFilter);
} }
void Exception::SetMiniDumpType() void Exception::SetMiniDumpType(bool codeseg, bool dataseg)
{ {
Exception::MiniDumpType = MiniDumpIgnoreInaccessibleMemory; Exception::MiniDumpType = MiniDumpIgnoreInaccessibleMemory;
Exception::MiniDumpType |= MiniDumpWithUnloadedModules;
Exception::MiniDumpType |= MiniDumpWithThreadInfo;
Exception::MiniDumpType |= MiniDumpWithFullMemoryInfo;
Exception::MiniDumpType |= MiniDumpWithHandleData; Exception::MiniDumpType |= MiniDumpWithHandleData;
Exception::MiniDumpType |= MiniDumpWithTokenInformation; Exception::MiniDumpType |= MiniDumpScanMemory;
Exception::MiniDumpType |= MiniDumpWithProcessThreadData; 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; Exception::MiniDumpType |= MiniDumpWithCodeSegs;
} }
else if (Flags::HasFlag("reallybigminidumps")) if (dataseg)
{ {
Exception::MiniDumpType |= MiniDumpWithModuleHeaders;
Exception::MiniDumpType |= MiniDumpWithCodeSegs;
Exception::MiniDumpType |= MiniDumpWithDataSegs; Exception::MiniDumpType |= MiniDumpWithDataSegs;
} }
} }
Exception::Exception() Exception::Exception()
{ {
Exception::SetMiniDumpType(); Exception::SetMiniDumpType(Flags::HasFlag("bigminidumps"), Flags::HasFlag("reallybigminidumps"));
#ifdef DEBUG #ifdef DEBUG
// Display DEBUG branding, so we know we're on a debug build // Display DEBUG branding, so we know we're on a debug build

View File

@ -14,7 +14,7 @@ namespace Components
static LPTOP_LEVEL_EXCEPTION_FILTER Hook(); static LPTOP_LEVEL_EXCEPTION_FILTER Hook();
static int MiniDumpType; static int MiniDumpType;
static void SetMiniDumpType(); static void SetMiniDumpType(bool codeseg, bool dataseg);
private: private:
static LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo); static LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo);

View File

@ -36,6 +36,17 @@ namespace Utils
LocalFree(messageBuffer); 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<LPSTR>(&messageBuffer), 0, nullptr);
std::string message(messageBuffer, size);
LocalFree(messageBuffer);
return message;
}
bool IsWineEnvironment() bool IsWineEnvironment()
{ {
HMODULE hntdll = GetModuleHandleA("ntdll.dll"); HMODULE hntdll = GetModuleHandleA("ntdll.dll");

View File

@ -5,6 +5,7 @@ namespace Utils
std::string GetMimeType(std::string url); std::string GetMimeType(std::string url);
std::string ParseChallenge(std::string data); std::string ParseChallenge(std::string data);
void OutputDebugLastError(); void OutputDebugLastError();
std::string GetLastWindowsError();
bool IsWineEnvironment(); bool IsWineEnvironment();