From 529e8de4640820c96cb63d772a78a2a06573f94e Mon Sep 17 00:00:00 2001 From: Anairkoen Schno Date: Thu, 26 Mar 2020 17:42:06 -0500 Subject: [PATCH] Added a bunch of checks to streamline upgrades --- Doorstop/Proxy/main.c | 15 ++++-- Doorstop/Proxy/proxy.def | 1 + IPA.Loader/Config/ConfigRuntime.cs | 28 ++++++---- .../GeneratedStoreImpl/IGeneratedStore.cs | 40 +++++++++----- IPA.Loader/Utilities/CriticalSection.cs | 54 +++++++++++-------- 5 files changed, 91 insertions(+), 47 deletions(-) diff --git a/Doorstop/Proxy/main.c b/Doorstop/Proxy/main.c index d78db0f4..5d3d51f9 100644 --- a/Doorstop/Proxy/main.c +++ b/Doorstop/Proxy/main.c @@ -38,8 +38,14 @@ EXTERN_C IMAGE_DOS_HEADER __ImageBase; // This is provided by MSVC with the info HANDLE unhandledMutex; void ownMonoJitParseOptions(int argc, char * argv[]); BOOL setOptions = FALSE; +BOOL shouldBreakOnUnhandledException = TRUE; -void unhandledException(void* exc, void* data) +__declspec(dllexport) void SetIgnoreUnhandledExceptions(BOOL ignore) +{ + shouldBreakOnUnhandledException = ignore; +} + +void unhandledException(void* exc, void* data) { WaitForSingleObject(unhandledMutex, INFINITE); @@ -86,11 +92,14 @@ void unhandledException(void* exc, void* data) MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, len);*/ wchar_t* wstr = mono_string_to_utf16(mstr); + if (shouldBreakOnUnhandledException) + { #ifdef _VERBOSE - ASSERT(FALSE, L"Uncaught exception; see doorstop.log for details"); + ASSERT(FALSE, L"Uncaught exception; see doorstop.log for details"); #else - ASSERT_F(FALSE, L"Uncaught exception: %wS", wstr); + ASSERT_F(FALSE, L"Uncaught exception: %wS", wstr); #endif + } mono_free(wstr); mono_free(str); diff --git a/Doorstop/Proxy/proxy.def b/Doorstop/Proxy/proxy.def index 2b5dcf3a..097d7434 100644 --- a/Doorstop/Proxy/proxy.def +++ b/Doorstop/Proxy/proxy.def @@ -52,3 +52,4 @@ EXPORTS WinHttpWriteData @50 SetGetMessageHook @51 SetPeekMessageHook @52 + SetIgnoreUnhandledExceptions @53 \ No newline at end of file diff --git a/IPA.Loader/Config/ConfigRuntime.cs b/IPA.Loader/Config/ConfigRuntime.cs index e59d13a0..0729d5ff 100644 --- a/IPA.Loader/Config/ConfigRuntime.cs +++ b/IPA.Loader/Config/ConfigRuntime.cs @@ -64,17 +64,23 @@ namespace IPA.Config => ShutdownRuntime(); internal static void ShutdownRuntime() { - watcherTrackConfigs.Clear(); - var watchList = watchers.ToArray(); - watchers.Clear(); - - foreach (var pair in watchList) - pair.Value.EnableRaisingEvents = false; - - loadScheduler.Join(); // we can wait for the loads to finish - saveThread.Abort(); // eww, but i don't like any of the other potential solutions - - SaveAll(); + try + { + watcherTrackConfigs.Clear(); + var watchList = watchers.ToArray(); + watchers.Clear(); + + foreach (var pair in watchList) + pair.Value.EnableRaisingEvents = false; + + loadScheduler.Join(); // we can wait for the loads to finish + saveThread.Abort(); // eww, but i don't like any of the other potential solutions + + SaveAll(); + } + catch + { + } } public static void RegisterConfig(Config cfg) diff --git a/IPA.Loader/Config/Stores/GeneratedStoreImpl/IGeneratedStore.cs b/IPA.Loader/Config/Stores/GeneratedStoreImpl/IGeneratedStore.cs index 413535ba..483d239b 100644 --- a/IPA.Loader/Config/Stores/GeneratedStoreImpl/IGeneratedStore.cs +++ b/IPA.Loader/Config/Stores/GeneratedStoreImpl/IGeneratedStore.cs @@ -59,7 +59,18 @@ namespace IPA.Config.Stores internal static MethodInfo ImplSignalChangedMethod = typeof(Impl).GetMethod(nameof(ImplSignalChanged)); public static void ImplSignalChanged(IGeneratedStore s) => FindImpl(s).SignalChanged(); - public void SignalChanged() => resetEvent.Set(); + public void SignalChanged() + { + try + { + resetEvent.Set(); + } + catch (ObjectDisposedException e) + { + Logger.config.Error($"ObjectDisposedException while signalling a change for generated store {generated?.GetType()}"); + Logger.config.Error(e); + } + } internal static MethodInfo ImplInvokeChangedMethod = typeof(Impl).GetMethod(nameof(ImplInvokeChanged)); public static void ImplInvokeChanged(IGeneratedStore s) => FindImpl(s).InvokeChanged(); @@ -131,18 +142,23 @@ namespace IPA.Config.Stores public void Dispose() => Dispose(true); private void Dispose(bool addToStore) - { - if (data.owns) - { - data.impl.inChangeTransaction = false; - data.impl.InvokeChanged(); - } + { + if (data.owns) + { + data.impl.inChangeTransaction = false; + data.impl.InvokeChanged(); + } data.nested?.Dispose(); - if (data.ownsWrite) - data.impl.ReleaseWrite(); - - if (addToStore) - freeTransactionObjs.Push(this); + try + { + if (data.ownsWrite) + data.impl.ReleaseWrite(); + } + catch + { + } + if (addToStore) + freeTransactionObjs.Push(this); } ~ChangeTransactionObj() => Dispose(false); diff --git a/IPA.Loader/Utilities/CriticalSection.cs b/IPA.Loader/Utilities/CriticalSection.cs index 026692cc..60930b50 100644 --- a/IPA.Loader/Utilities/CriticalSection.cs +++ b/IPA.Loader/Utilities/CriticalSection.cs @@ -35,6 +35,14 @@ namespace IPA.Utilities Win32.SetConsoleCtrlHandler(registeredHandler, false); Win32.SetConsoleCtrlHandler(registeredHandler, true); WinHttp.SetPeekMessageHook(PeekMessageHook); + + AppDomain.CurrentDomain.ProcessExit -= OnProcessExit; + AppDomain.CurrentDomain.ProcessExit += OnProcessExit; + } + + private static void OnProcessExit(object sender, EventArgs args) + { + WinHttp.SetIgnoreUnhandledExceptions(true); } private static class WinHttp @@ -52,7 +60,11 @@ namespace IPA.Utilities [DllImport("bsipa-doorstop")] public static extern void SetPeekMessageHook( [MarshalAs(UnmanagedType.FunctionPtr)] - PeekMessageHook hook); + PeekMessageHook hook); + + [DllImport("bsipa-doorstop")] + public static extern void SetIgnoreUnhandledExceptions( + [MarshalAs(UnmanagedType.Bool)] bool ignore); } private static Win32.ConsoleCtrlDelegate _handler = null; @@ -106,29 +118,29 @@ namespace IPA.Utilities private static volatile bool exitRecieved = false; - /// - /// A struct that allows using blocks to manage an execute section. + /// + /// A struct that allows using blocks to manage an execute section. /// - public struct AutoExecuteSection : IDisposable - { - private readonly bool constructed; - internal AutoExecuteSection(bool val) - { - constructed = val && !isInExecuteSection; - if (constructed) - EnterExecuteSection(); - } - - void IDisposable.Dispose() - { - if (constructed) - ExitExecuteSection(); - } + public struct AutoExecuteSection : IDisposable + { + private readonly bool constructed; + internal AutoExecuteSection(bool val) + { + constructed = val && !isInExecuteSection; + if (constructed) + EnterExecuteSection(); + } + + void IDisposable.Dispose() + { + if (constructed) + ExitExecuteSection(); + } } - /// - /// Creates an for automated management of an execute section. - /// + /// + /// Creates an for automated management of an execute section. + /// /// the new that manages the section public static AutoExecuteSection ExecuteSection() => new AutoExecuteSection(true);