From f4af8e509b34ddeca5042badfbba3b9437b74888 Mon Sep 17 00:00:00 2001 From: marzent Date: Thu, 15 Feb 2024 00:05:18 +0100 Subject: [PATCH] make Dalamud handle top-level SEH --- Dalamud.Boot/veh.cpp | 61 +++++++++++++++++++++++----------- Dalamud.Boot/xivfixes.cpp | 45 ------------------------- Dalamud.Boot/xivfixes.h | 1 - Dalamud.Injector/EntryPoint.cs | 5 ++- 4 files changed, 45 insertions(+), 67 deletions(-) diff --git a/Dalamud.Boot/veh.cpp b/Dalamud.Boot/veh.cpp index fc8689af7..4eeddba88 100644 --- a/Dalamud.Boot/veh.cpp +++ b/Dalamud.Boot/veh.cpp @@ -6,6 +6,7 @@ #include "logging.h" #include "utils.h" +#include "hooks.h" #include "crashhandler_shared.h" #include "DalamudStartInfo.h" @@ -24,6 +25,7 @@ PVOID g_veh_handle = nullptr; bool g_veh_do_full_dump = false; +std::optional> g_HookSetUnhandledExceptionFilter; HANDLE g_crashhandler_process = nullptr; HANDLE g_crashhandler_event = nullptr; @@ -143,21 +145,7 @@ static void append_injector_launch_args(std::vector& args) LONG exception_handler(EXCEPTION_POINTERS* ex) { - if (ex->ExceptionRecord->ExceptionCode == 0x12345678) - { - // pass - } - else - { - if (!is_whitelist_exception(ex->ExceptionRecord->ExceptionCode)) - return EXCEPTION_CONTINUE_SEARCH; - - if (!is_ffxiv_address(L"ffxiv_dx11.exe", ex->ContextRecord->Rip) && - !is_ffxiv_address(L"cimgui.dll", ex->ContextRecord->Rip)) - return EXCEPTION_CONTINUE_SEARCH; - } - - // block any other exceptions hitting the veh while the messagebox is open + // block any other exceptions hitting the handler while the messagebox is open const auto lock = std::lock_guard(g_exception_handler_mutex); exception_info exinfo{}; @@ -167,7 +155,7 @@ LONG exception_handler(EXCEPTION_POINTERS* ex) exinfo.ExceptionRecord = ex->ExceptionRecord ? *ex->ExceptionRecord : EXCEPTION_RECORD{}; const auto time_now = std::chrono::system_clock::now(); auto lifetime = std::chrono::duration_cast( - time_now.time_since_epoch()).count() + time_now.time_since_epoch()).count() - std::chrono::duration_cast( g_time_start.time_since_epoch()).count(); exinfo.nLifetime = lifetime; @@ -178,7 +166,7 @@ LONG exception_handler(EXCEPTION_POINTERS* ex) if (void* fn; const auto err = static_cast(g_clr->get_function_pointer( L"Dalamud.EntryPoint, Dalamud", L"VehCallback", - L"Dalamud.EntryPoint+VehDelegate, Dalamud", + L"Dalamud.EntryPoint+VehDelegate, Dalamud", nullptr, nullptr, &fn))) { stackTrace = std::format(L"Failed to read stack trace: 0x{:08x}", err); @@ -188,7 +176,7 @@ LONG exception_handler(EXCEPTION_POINTERS* ex) stackTrace = static_cast(fn)(); // Don't free it, as the program's going to be quit anyway } - + exinfo.dwStackTraceLength = static_cast(stackTrace.size()); exinfo.dwTroubleshootingPackDataLength = static_cast(g_startInfo.TroubleshootingPackData.size()); if (DWORD written; !WriteFile(g_crashhandler_pipe_write, &exinfo, static_cast(sizeof exinfo), &written, nullptr) || sizeof exinfo != written) @@ -217,13 +205,44 @@ LONG exception_handler(EXCEPTION_POINTERS* ex) return EXCEPTION_CONTINUE_SEARCH; } +LONG WINAPI structured_exception_handler(EXCEPTION_POINTERS* ex) +{ + return exception_handler(ex); +} + +LONG WINAPI vectored_exception_handler(EXCEPTION_POINTERS* ex) +{ + if (ex->ExceptionRecord->ExceptionCode == 0x12345678) + { + // pass + } + else + { + if (!is_whitelist_exception(ex->ExceptionRecord->ExceptionCode)) + return EXCEPTION_CONTINUE_SEARCH; + + if (!is_ffxiv_address(L"ffxiv_dx11.exe", ex->ContextRecord->Rip) && + !is_ffxiv_address(L"cimgui.dll", ex->ContextRecord->Rip)) + return EXCEPTION_CONTINUE_SEARCH; + } + + return exception_handler(ex); +} + bool veh::add_handler(bool doFullDump, const std::string& workingDirectory) { if (g_veh_handle) return false; - g_veh_handle = AddVectoredExceptionHandler(1, exception_handler); - SetUnhandledExceptionFilter(nullptr); + g_veh_handle = AddVectoredExceptionHandler(TRUE, vectored_exception_handler); + + g_HookSetUnhandledExceptionFilter.emplace("kernel32.dll!SetUnhandledExceptionFilter (lpTopLevelExceptionFilter)", "kernel32.dll", "SetUnhandledExceptionFilter", 0); + g_HookSetUnhandledExceptionFilter->set_detour([](LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) -> LPTOP_LEVEL_EXCEPTION_FILTER + { + logging::I("Overwriting UnhandledExceptionFilter from {} to {}", reinterpret_cast(lpTopLevelExceptionFilter), reinterpret_cast(structured_exception_handler)); + return g_HookSetUnhandledExceptionFilter->call_original(structured_exception_handler); + }); + SetUnhandledExceptionFilter(structured_exception_handler); g_veh_do_full_dump = doFullDump; g_time_start = std::chrono::system_clock::now(); @@ -355,6 +374,8 @@ bool veh::remove_handler() if (g_veh_handle && RemoveVectoredExceptionHandler(g_veh_handle) != 0) { g_veh_handle = nullptr; + g_HookSetUnhandledExceptionFilter.reset(); + SetUnhandledExceptionFilter(nullptr); return true; } return false; diff --git a/Dalamud.Boot/xivfixes.cpp b/Dalamud.Boot/xivfixes.cpp index e16dd6e5a..39cce53c9 100644 --- a/Dalamud.Boot/xivfixes.cpp +++ b/Dalamud.Boot/xivfixes.cpp @@ -513,50 +513,6 @@ void xivfixes::backup_userdata_save(bool bApply) { } } -void xivfixes::clr_failfast_hijack(bool bApply) -{ - static const char* LogTag = "[xivfixes:clr_failfast_hijack]"; - static std::optional> s_HookClrFatalError; - static std::optional> s_HookSetUnhandledExceptionFilter; - - if (bApply) - { - if (!g_startInfo.BootEnabledGameFixes.contains("clr_failfast_hijack")) { - logging::I("{} Turned off via environment variable.", LogTag); - return; - } - - s_HookClrFatalError.emplace("kernel32.dll!RaiseFailFastException (import, backup_userdata_save)", "kernel32.dll", "RaiseFailFastException", 0); - s_HookSetUnhandledExceptionFilter.emplace("kernel32.dll!SetUnhandledExceptionFilter (lpTopLevelExceptionFilter)", "kernel32.dll", "SetUnhandledExceptionFilter", 0); - - s_HookClrFatalError->set_detour([](PEXCEPTION_RECORD pExceptionRecord, - _In_opt_ PCONTEXT pContextRecord, - _In_ DWORD dwFlags) - { - MessageBoxW(nullptr, L"An error in a Dalamud plugin was detected and the game cannot continue.\n\nPlease take a screenshot of this error message and let us know about it.", L"Dalamud", MB_OK | MB_ICONERROR); - - return s_HookClrFatalError->call_original(pExceptionRecord, pContextRecord, dwFlags); - }); - - s_HookSetUnhandledExceptionFilter->set_detour([](LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) -> LPTOP_LEVEL_EXCEPTION_FILTER - { - logging::I("{} SetUnhandledExceptionFilter", LogTag); - return nullptr; - }); - - logging::I("{} Enable", LogTag); - } - else - { - if (s_HookClrFatalError) { - logging::I("{} Disable ClrFatalError", LogTag); - s_HookClrFatalError.reset(); - s_HookSetUnhandledExceptionFilter.reset(); - } - } -} - - void xivfixes::prevent_icmphandle_crashes(bool bApply) { static const char* LogTag = "[xivfixes:prevent_icmphandle_crashes]"; @@ -598,7 +554,6 @@ void xivfixes::apply_all(bool bApply) { { "disable_game_openprocess_access_check", &disable_game_openprocess_access_check }, { "redirect_openprocess", &redirect_openprocess }, { "backup_userdata_save", &backup_userdata_save }, - { "clr_failfast_hijack", &clr_failfast_hijack }, { "prevent_icmphandle_crashes", &prevent_icmphandle_crashes } } ) { diff --git a/Dalamud.Boot/xivfixes.h b/Dalamud.Boot/xivfixes.h index 701913c88..f534ad7dd 100644 --- a/Dalamud.Boot/xivfixes.h +++ b/Dalamud.Boot/xivfixes.h @@ -6,7 +6,6 @@ namespace xivfixes { void disable_game_openprocess_access_check(bool bApply); void redirect_openprocess(bool bApply); void backup_userdata_save(bool bApply); - void clr_failfast_hijack(bool bApply); void prevent_icmphandle_crashes(bool bApply); void apply_all(bool bApply); diff --git a/Dalamud.Injector/EntryPoint.cs b/Dalamud.Injector/EntryPoint.cs index 9e2b95657..c784ec1d1 100644 --- a/Dalamud.Injector/EntryPoint.cs +++ b/Dalamud.Injector/EntryPoint.cs @@ -394,7 +394,10 @@ namespace Dalamud.Injector startInfo.BootShowConsole = args.Contains("--console"); startInfo.BootEnableEtw = args.Contains("--etw"); startInfo.BootLogPath = GetLogPath(startInfo.LogPath, "dalamud.boot", startInfo.LogName); - startInfo.BootEnabledGameFixes = new List { "prevent_devicechange_crashes", "disable_game_openprocess_access_check", "redirect_openprocess", "backup_userdata_save", "prevent_icmphandle_crashes" }; + startInfo.BootEnabledGameFixes = new List { + "prevent_devicechange_crashes", "disable_game_openprocess_access_check", + "redirect_openprocess", "backup_userdata_save", "prevent_icmphandle_crashes", + }; startInfo.BootDotnetOpenProcessHookMode = 0; startInfo.BootWaitMessageBox |= args.Contains("--msgbox1") ? 1 : 0; startInfo.BootWaitMessageBox |= args.Contains("--msgbox2") ? 2 : 0;