Created
April 4, 2023 07:48
-
-
Save rioki/1ffb0d24d00e46f4894ee16c947f771f to your computer and use it in GitHub Desktop.
CrashWatchdog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This program is free software. It comes without any warranty, to | |
// the extent permitted by applicable law. You can redistribute it | |
// and/or modify it under the terms of the Do What The Fuck You Want | |
// To Public License, Version 2, as published by Sam Hocevar. See | |
// http://www.wtfpl.net/ for more details. | |
#include "CrashWatchdog.h" | |
#include <stdexcept> | |
#include <array> | |
#include <string> | |
#include <string_view> | |
#include <eh.h> | |
#include <dbghelp.h> | |
namespace dbg | |
{ | |
// Wrapper around CreateFile / CloseHandle API | |
class Win32File | |
{ | |
public: | |
Win32File(const std::filesystem::path& fileName) | |
{ | |
handle = CreateFileW(fileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |
if (handle == INVALID_HANDLE_VALUE) | |
{ | |
throw std::runtime_error("Failed to open file for writing"); | |
} | |
} | |
~Win32File() | |
{ | |
CloseHandle(handle); | |
} | |
operator HANDLE () | |
{ | |
return handle; | |
} | |
private: | |
HANDLE handle = NULL; | |
Win32File(const Win32File&) = delete; | |
Win32File& operator = (const Win32File&) = delete; | |
}; | |
std::wstring GetTempPathEx() | |
{ | |
std::array<wchar_t, MAX_PATH> buff; | |
auto r = GetTempPathW(static_cast<DWORD>(buff.size()), buff.data()); | |
if (r == 0) | |
{ | |
throw std::runtime_error("Failed to get %TEMP% path."); | |
} | |
return std::wstring(buff.data()); | |
} | |
std::wstring GetTempFileNameEx(const std::wstring_view pathName, const std::wstring_view prefix) | |
{ | |
std::array<wchar_t, MAX_PATH> buff; | |
auto r = GetTempFileNameW(pathName.data(), prefix.data(), 0, buff.data()); | |
if (r == 0) | |
{ | |
throw std::runtime_error("Failed to get temp file name."); | |
} | |
return std::wstring(buff.data()); | |
} | |
std::wstring GetDumpFileName() | |
{ | |
return GetTempFileNameEx(GetTempPathEx(), L"cfc"); | |
} | |
MINIDUMP_EXCEPTION_INFORMATION GetExceptionInfo(EXCEPTION_POINTERS* exceptionPointers) | |
{ | |
auto exceptionInfo = MINIDUMP_EXCEPTION_INFORMATION{}; | |
exceptionInfo.ThreadId = GetCurrentThreadId(); | |
exceptionInfo.ExceptionPointers = exceptionPointers; | |
exceptionInfo.ClientPointers = TRUE; | |
return exceptionInfo; | |
} | |
std::wstring WriteCrashDump(EXCEPTION_POINTERS* exceptionPointers = nullptr) | |
{ | |
try | |
{ | |
auto dumpFile = GetDumpFileName(); | |
auto dumpFileHandle = Win32File(dumpFile); | |
auto process = GetCurrentProcess(); | |
auto processId = GetCurrentProcessId(); | |
auto exceptionInfo = GetExceptionInfo(exceptionPointers); | |
auto result = MiniDumpWriteDump(process, processId, dumpFileHandle, MiniDumpNormal, &exceptionInfo, 0, 0); | |
if (result == FALSE) | |
{ | |
throw std::runtime_error("MiniDumpWriteDump failed."); | |
} | |
return dumpFile; | |
} | |
catch (const std::exception& ex) | |
{ | |
MessageBoxA(NULL, ex.what(), "Failed to write Crash Dump", MB_ICONERROR|MB_OK); | |
return L"Failed"; | |
} | |
} | |
LONG __stdcall HandleUnhendledExceptionFilter(EXCEPTION_POINTERS* pExPtrs) | |
{ | |
auto file = WriteCrashDump(pExPtrs); | |
auto msg = std::wstring(L"Process Crashed.\nCrash Dump written to: ") + file; | |
MessageBoxW(NULL, msg.data(), L"Unexpected Error", MB_ICONERROR | MB_OK); | |
exit(EXIT_FAILURE); | |
} | |
CrashWatchdog::CrashWatchdog() | |
{ | |
m_oldUnhandledExceptionFilter = SetUnhandledExceptionFilter(HandleUnhendledExceptionFilter); | |
} | |
CrashWatchdog::~CrashWatchdog() | |
{ | |
SetUnhandledExceptionFilter(m_oldUnhandledExceptionFilter); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This program is free software. It comes without any warranty, to | |
// the extent permitted by applicable law. You can redistribute it | |
// and/or modify it under the terms of the Do What The Fuck You Want | |
// To Public License, Version 2, as published by Sam Hocevar. See | |
// http://www.wtfpl.net/ for more details. | |
#pragma once | |
#define WIN32_LEAN_AND_MEAN | |
#define NOMINMAX | |
#include <windows.h> | |
namespace dbg | |
{ | |
//! Utility that overrides crash handling functions and pumps stack at the appropriate time. | |
class CrashWatchdog | |
{ | |
public: | |
//! Install crash handlers | |
CrashWatchdog(); | |
//! Reset state | |
~CrashWatchdog(); | |
private: | |
LPTOP_LEVEL_EXCEPTION_FILTER m_oldUnhandledExceptionFilter = nullptr; | |
CrashWatchdog(const CrashWatchdog&) = delete; | |
CrashWatchdog& operator = (const CrashWatchdog&) = delete; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment