Skip to content

Commit

Permalink
Implemented a proper crash handler
Browse files Browse the repository at this point in the history
  • Loading branch information
yeshjho committed Feb 18, 2024
1 parent bb4a8fd commit 6864776
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 57 deletions.
6 changes: 4 additions & 2 deletions Typoon/Typoon.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<ClCompile Include="platform\windows\clipboard.cpp" />
<ClCompile Include="platform\windows\command.cpp" />
<ClCompile Include="platform\windows\common.cpp" />
<ClCompile Include="platform\windows\crash_handler.cpp" />
<ClCompile Include="platform\windows\hotkey.cpp" />
<ClCompile Include="platform\windows\log.cpp" />
<ClCompile Include="platform\windows\tray_icon.cpp" />
Expand All @@ -40,6 +41,7 @@
<ClInclude Include="input_multicast\input_multicast.h" />
<ClInclude Include="low_level\clipboard.h" />
<ClInclude Include="low_level\command.h" />
<ClInclude Include="low_level\crash_handler.h" />
<ClInclude Include="low_level\fake_input.h" />
<ClInclude Include="low_level\filesystem.h" />
<ClInclude Include="low_level\file_change_watcher.h" />
Expand Down Expand Up @@ -117,7 +119,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Imm32.lib;gdiplus.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Imm32.lib;gdiplus.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
Expand All @@ -141,7 +143,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Imm32.lib;gdiplus.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Imm32.lib;gdiplus.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
Expand Down
6 changes: 6 additions & 0 deletions Typoon/Typoon.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
<ClCompile Include="match\trigger_trees_per_program.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="platform\windows\crash_handler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="utils\logger.h">
Expand Down Expand Up @@ -155,6 +158,9 @@
<ClInclude Include="match\trigger_trees_per_program.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="low_level\crash_handler.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Typoon.rc">
Expand Down
4 changes: 4 additions & 0 deletions Typoon/low_level/crash_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once


void initialize_crash_handler();
2 changes: 2 additions & 0 deletions Typoon/low_level/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ const std::filesystem::path& get_app_data_path();
const std::filesystem::path& get_config_file_path();

std::filesystem::path get_log_file_path();

std::filesystem::path get_crash_file_path();
25 changes: 0 additions & 25 deletions Typoon/match/trigger_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ void TriggerTree::Reconstruct(std::string_view matchesString, std::function<void
onFinish = std::move(onFinish),
didCallOnFinish = false](const std::stop_token& stopToken) mutable
{
try {
#define STOP if (stopToken.stop_requested()) { if (onFinish && !didCallOnFinish) { didCallOnFinish = true; onFinish(); } return; }

STOP
Expand Down Expand Up @@ -373,29 +372,6 @@ void TriggerTree::Reconstruct(std::string_view matchesString, std::function<void
logger.Log(ELogLevel::INFO, mMatchFile, "Trigger tree construction finished");

#undef STOP
}
catch (const std::exception& e)
{
logger.Log(ELogLevel::ERROR, mMatchFile, "Exception while constructing trigger tree", e.what());
show_notification(L"Match File Load Failed!",
L"An exception occurred while parsing the match file.\nPlease report this with a log file.", false);
if (onFinish && !didCallOnFinish)
{
didCallOnFinish = true;
onFinish();
}
}
catch (...)
{
logger.Log(ELogLevel::ERROR, mMatchFile, "Unknown exception while constructing trigger tree");
show_notification(L"Match File Load Failed!",
L"An exception occurred while parsing the match file.\nPlease report this with a log file.", false);
if (onFinish && !didCallOnFinish)
{
didCallOnFinish = true;
onFinish();
}
}
} };
}

Expand Down Expand Up @@ -494,7 +470,6 @@ void TriggerTree::OnInput(const InputMessage(&inputs)[MAX_INPUT_COUNT], int leng
return false;
}
);

return;
}

Expand Down
52 changes: 52 additions & 0 deletions Typoon/platform/windows/crash_handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "../../low_level/crash_handler.h"

#include <Windows.h>
#include <DbgHelp.h>

#include "log.h"
#include "../../low_level/filesystem.h"


BOOL WINAPI mini_dump_callback(void* currentModule, const PMINIDUMP_CALLBACK_INPUT input, PMINIDUMP_CALLBACK_OUTPUT output)
{
if (input->CallbackType == IncludeModuleCallback && input->IncludeModule.BaseOfImage != reinterpret_cast<unsigned long long>(currentModule))
{
output->ModuleWriteFlags = ModuleWriteModule | ModuleWriteCvRecord | ModuleWriteTlsData;
}

return true;
}


long WINAPI on_exception(EXCEPTION_POINTERS* exceptions)
{
constexpr int flags =
MiniDumpNormal |
MiniDumpWithDataSegs |
#ifdef _DEBUG
MiniDumpWithFullMemory |
#endif
MiniDumpWithHandleData |
MiniDumpWithUnloadedModules |
MiniDumpWithIndirectlyReferencedMemory |
MiniDumpWithProcessThreadData |
MiniDumpWithCodeSegs;

MINIDUMP_EXCEPTION_INFORMATION exceptionInfo{ GetCurrentThreadId(), exceptions, false };
MINIDUMP_CALLBACK_INFORMATION callbackInfo{ mini_dump_callback, GetModuleHandle(nullptr) };
const std::filesystem::path& path = get_crash_file_path();
const HANDLE file = CreateFileW(path.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);

logger.Log(reinterpret_cast<unsigned long long>(GetModuleHandle(nullptr)));
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file, static_cast<MINIDUMP_TYPE>(flags), &exceptionInfo, nullptr, &callbackInfo);

return EXCEPTION_CONTINUE_SEARCH;
}


void initialize_crash_handler()
{
SetUnhandledExceptionFilter(on_exception);
unsigned long minimumStackSize = 1024 * 17;
SetThreadStackGuarantee(&minimumStackSize);
}
15 changes: 0 additions & 15 deletions Typoon/platform/windows/file_change_watcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ FileChangeWatcher::FileChangeWatcher(std::function<void(const std::filesystem::p
mThread = std::jthread{
[this](const std::stop_token& stopToken)
{
try
{
while (true)
{
const DWORD result = WaitForMultipleObjectsEx(static_cast<DWORD>(mEvents.size()), mEvents.data(), false, INFINITE, true);
Expand Down Expand Up @@ -80,19 +78,6 @@ FileChangeWatcher::FileChangeWatcher(std::function<void(const std::filesystem::p
readDirectoryChanges(directoryIndex);
}
}
}
catch (const std::exception& e)
{
logger.Log(ELogLevel::ERROR, "Exception while watching files", e.what());
show_notification(L"Exception While Watching Files",
L"An exception occurred while watching files for automatic reload.\nPlease report this with a log file.", false);
}
catch (...)
{
logger.Log(ELogLevel::ERROR, "Unknown exception while watching files");
show_notification(L"Exception While Watching Files",
L"An exception occurred while watching files for automatic reload.\nPlease report this with a log file.", false);
}
}
};
}
Expand Down
13 changes: 13 additions & 0 deletions Typoon/platform/windows/filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,16 @@ std::filesystem::path get_log_file_path()
std::filesystem::create_directories(path.parent_path());
return path;
}


std::filesystem::path get_crash_file_path()
{
using namespace std::chrono;

static const auto tz = current_zone();

const auto now = zoned_time{ tz, system_clock::now() };
std::filesystem::path path = get_app_data_path() / "crashes" / std::format(L"{0:%Y-%m-%d %H-%M-%S}.dmp", now);
std::filesystem::create_directories(path.parent_path());
return path;
}
18 changes: 3 additions & 15 deletions Typoon/platform/windows/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <Windows.h>

#include "../../low_level/clipboard.h"
#include "../../low_level/crash_handler.h"
#include "../../low_level/file_change_watcher.h"
#include "../../low_level/filesystem.h"
#include "../../low_level/hotkey.h"
Expand All @@ -17,8 +18,9 @@


int wWinMain(HINSTANCE hInstance, [[maybe_unused]] HINSTANCE hPrevInstance, [[maybe_unused]] LPWSTR cmdLine, [[maybe_unused]] int cmdShow)
try
{
initialize_crash_handler();

// Prevent multiple instances
CreateMutex(nullptr, false, L"Typoon_{91CC86BD-3107-4BFB-88E2-0A9A1280AB4A}");
if (const DWORD error = GetLastError();
Expand Down Expand Up @@ -194,18 +196,4 @@ try
#endif

return static_cast<int>(msg.wParam);
}
catch (const std::exception& e)
{
logger.Log(ELogLevel::FATAL, "Exception in main", e.what());
show_notification(L"Fatal Exception",
L"An exception occurred and Typoon is shutting down.\nPlease report this with a log file.", false);
return -1;
}
catch (...)
{
logger.Log(ELogLevel::FATAL, "Unknown exception in main");
show_notification(L"Fatal Exception",
L"An exception occurred and Typoon is shutting down.\nPlease report this with a log file.", false);
return -1;
}

0 comments on commit 6864776

Please sign in to comment.