From 448ef94a0bdfe5aa7c4db011ac2904e477688e37 Mon Sep 17 00:00:00 2001 From: Jade Macho Date: Mon, 11 Oct 2021 01:00:09 +0200 Subject: [PATCH 1/2] Replace Harmony with up-to-date RuntimeDetour --- Dalamud/Dalamud.cs | 28 ++++++------ Dalamud/Dalamud.csproj | 3 +- Dalamud/Plugin/Internal/PluginManager.cs | 54 +++++++++++++----------- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index dbce79ae9..c27c04626 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -2,6 +2,7 @@ using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; @@ -23,7 +24,7 @@ using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Ipc.Internal; using Dalamud.Support; -using HarmonyLib; +using MonoMod.RuntimeDetour; using Serilog; using Serilog.Core; using Serilog.Events; @@ -383,17 +384,20 @@ namespace Dalamud /// uses pseudo-handles to access memory, to prevent permission errors. /// It should never be called manually. /// - /// The equivalent of `this`. - /// The result from the original method. - [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1313:Parameter names should begin with lower-case letter", Justification = "Enforced naming for special injected parameters")] - private static void ProcessHandlePatch(Process __instance, ref IntPtr __result) + /// A delegate that acts as the original method. + /// The equivalent of `this`. + /// A pseudo-handle for the current process, or the result from the original method. + private static IntPtr ProcessHandlePatch(Func orig, Process self) { - if (__instance.Id == Environment.ProcessId) + var result = orig(self); + + if (self.Id == Environment.ProcessId) { - __result = (IntPtr)0xFFFFFFFF; + result = (IntPtr)0xFFFFFFFF; } - // Log.Verbose($"Process.Handle // {__instance.ProcessName} // {__result:X}"); + // Log.Verbose($"Process.Handle // {self.ProcessName} // {result:X}"); + return result; } private static void SerilogOnLogLine(object? sender, (string Line, LogEventLevel Level, DateTimeOffset TimeStamp, Exception? Exception) e) @@ -406,13 +410,11 @@ namespace Dalamud private void ApplyProcessPatch() { - var harmony = new Harmony("goatcorp.dalamud"); - var targetType = typeof(Process); - var handleTarget = AccessTools.PropertyGetter(targetType, nameof(Process.Handle)); - var handlePatch = AccessTools.Method(typeof(Dalamud), nameof(Dalamud.ProcessHandlePatch)); - harmony.Patch(handleTarget, postfix: new(handlePatch)); + var handleTarget = targetType.GetProperty(nameof(Process.Handle)).GetGetMethod(); + var handlePatch = typeof(Dalamud).GetMethod(nameof(Dalamud.ProcessHandlePatch), BindingFlags.NonPublic | BindingFlags.Static); + _ = new Hook(handleTarget, handlePatch); } } } diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index d5218ddf0..892a5db2d 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -65,10 +65,9 @@ - - + diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index 31794aaa8..579e5a2fd 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -20,7 +20,7 @@ using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal.Exceptions; using Dalamud.Plugin.Internal.Types; using Dalamud.Utility; -using HarmonyLib; +using MonoMod.RuntimeDetour; using Newtonsoft.Json; namespace Dalamud.Plugin.Internal @@ -1074,26 +1074,29 @@ namespace Dalamud.Plugin.Internal /// This patch facilitates resolving the assembly location for plugins that are loaded via byte[]. /// It should never be called manually. /// - /// The equivalent of `this`. - /// The result from the original method. - [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1313:Parameter names should begin with lower-case letter", Justification = "Enforced naming for special injected parameters")] - private static void AssemblyLocationPatch(Assembly __instance, ref string __result) + /// A delegate that acts as the original method. + /// The equivalent of `this`. + /// The plugin location, or the result from the original method. + private static string AssemblyLocationPatch(Func orig, Assembly self) { - if (string.IsNullOrEmpty(__result)) + var result = orig(self); + + if (string.IsNullOrEmpty(result)) { foreach (var assemblyName in GetStackFrameAssemblyNames()) { if (PluginLocations.TryGetValue(assemblyName, out var data)) { - __result = data.Location; + result = data.Location; break; } } } - __result ??= string.Empty; + result ??= string.Empty; - Log.Verbose($"Assembly.Location // {__instance.FullName} // {__result}"); + Log.Verbose($"Assembly.Location // {self.FullName} // {result}"); + return result; } /// @@ -1101,26 +1104,29 @@ namespace Dalamud.Plugin.Internal /// This patch facilitates resolving the assembly location for plugins that are loaded via byte[]. /// It should never be called manually. /// - /// The equivalent of `this`. - /// The result from the original method. - [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1313:Parameter names should begin with lower-case letter", Justification = "Enforced naming for special injected parameters")] - private static void AssemblyCodeBasePatch(Assembly __instance, ref string __result) + /// A delegate that acts as the original method. + /// The equivalent of `this`. + /// The plugin code base, or the result from the original method. + private static string AssemblyCodeBasePatch(Func orig, Assembly self) { - if (string.IsNullOrEmpty(__result)) + var result = orig(self); + + if (string.IsNullOrEmpty(result)) { foreach (var assemblyName in GetStackFrameAssemblyNames()) { if (PluginLocations.TryGetValue(assemblyName, out var data)) { - __result = data.CodeBase; + result = data.CodeBase; break; } } } - __result ??= string.Empty; + result ??= string.Empty; - Log.Verbose($"Assembly.CodeBase // {__instance.FullName} // {__result}"); + Log.Verbose($"Assembly.CodeBase // {self.FullName} // {result}"); + return result; } private static IEnumerable GetStackFrameAssemblyNames() @@ -1140,18 +1146,16 @@ namespace Dalamud.Plugin.Internal private void ApplyPatches() { - var harmony = new Harmony("goatcorp.dalamud.pluginmanager"); - var targetType = typeof(PluginManager).Assembly.GetType(); - var locationTarget = AccessTools.PropertyGetter(targetType, nameof(Assembly.Location)); - var locationPatch = AccessTools.Method(typeof(PluginManager), nameof(PluginManager.AssemblyLocationPatch)); - harmony.Patch(locationTarget, postfix: new(locationPatch)); + var locationTarget = targetType.GetProperty(nameof(Assembly.Location)).GetGetMethod(); + var locationPatch = typeof(PluginManager).GetMethod(nameof(PluginManager.AssemblyLocationPatch), BindingFlags.NonPublic | BindingFlags.Static); + _ = new Hook(locationTarget, locationPatch); #pragma warning disable SYSLIB0012 // Type or member is obsolete - var codebaseTarget = AccessTools.PropertyGetter(targetType, nameof(Assembly.CodeBase)); - var codebasePatch = AccessTools.Method(typeof(PluginManager), nameof(PluginManager.AssemblyCodeBasePatch)); - harmony.Patch(codebaseTarget, postfix: new(codebasePatch)); + var codebaseTarget = targetType.GetProperty(nameof(Assembly.CodeBase)).GetGetMethod(); + var codebasePatch = typeof(PluginManager).GetMethod(nameof(PluginManager.AssemblyCodeBasePatch), BindingFlags.NonPublic | BindingFlags.Static); + _ = new Hook(codebaseTarget, codebasePatch); #pragma warning restore SYSLIB0012 // Type or member is obsolete } From 1bc167f133d974d81b27301e55efabde9efbde04 Mon Sep 17 00:00:00 2001 From: Raymond Date: Sun, 10 Oct 2021 21:28:12 -0400 Subject: [PATCH 2/2] Explicitly use the monomod assembly name Not needed, but helps differentiate between a Reloaded hook a little. Also: utilize Dispose. --- Dalamud/Dalamud.cs | 23 ++++++++++++----------- Dalamud/Plugin/Internal/PluginManager.cs | 12 ++++++++---- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index c27c04626..b2d4c1108 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; @@ -24,7 +23,6 @@ using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Ipc.Internal; using Dalamud.Support; -using MonoMod.RuntimeDetour; using Serilog; using Serilog.Core; using Serilog.Events; @@ -46,6 +44,7 @@ namespace Dalamud private readonly ManualResetEvent unloadSignal; private readonly ManualResetEvent finishUnloadSignal; + private MonoMod.RuntimeDetour.Hook processMonoHook; private bool hasDisposedPlugins = false; #endregion @@ -358,6 +357,8 @@ namespace Dalamud SerilogEventSink.Instance.LogLine -= SerilogOnLogLine; + this.processMonoHook?.Dispose(); + Log.Debug("Dalamud::Dispose() OK!"); } catch (Exception ex) @@ -379,6 +380,14 @@ namespace Dalamud Log.Debug("Reset ExceptionFilter, old: {0}", oldFilter); } + private static void SerilogOnLogLine(object? sender, (string Line, LogEventLevel Level, DateTimeOffset TimeStamp, Exception? Exception) e) + { + if (e.Exception == null) + return; + + Troubleshooting.LogException(e.Exception, e.Line); + } + /// /// Patch method for the class Process.Handle. This patch facilitates fixing Reloaded so that it /// uses pseudo-handles to access memory, to prevent permission errors. @@ -400,21 +409,13 @@ namespace Dalamud return result; } - private static void SerilogOnLogLine(object? sender, (string Line, LogEventLevel Level, DateTimeOffset TimeStamp, Exception? Exception) e) - { - if (e.Exception == null) - return; - - Troubleshooting.LogException(e.Exception, e.Line); - } - private void ApplyProcessPatch() { var targetType = typeof(Process); var handleTarget = targetType.GetProperty(nameof(Process.Handle)).GetGetMethod(); var handlePatch = typeof(Dalamud).GetMethod(nameof(Dalamud.ProcessHandlePatch), BindingFlags.NonPublic | BindingFlags.Static); - _ = new Hook(handleTarget, handlePatch); + this.processMonoHook = new MonoMod.RuntimeDetour.Hook(handleTarget, handlePatch); } } } diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index 579e5a2fd..c9ede6123 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Compression; using System.Linq; @@ -20,7 +19,6 @@ using Dalamud.Logging.Internal; using Dalamud.Plugin.Internal.Exceptions; using Dalamud.Plugin.Internal.Types; using Dalamud.Utility; -using MonoMod.RuntimeDetour; using Newtonsoft.Json; namespace Dalamud.Plugin.Internal @@ -137,6 +135,9 @@ namespace Dalamud.Plugin.Internal Log.Error(ex, $"Error disposing {plugin.Name}"); } } + + this.assemblyLocationMonoHook?.Dispose(); + this.assemblyCodeBaseMonoHook?.Dispose(); } /// @@ -1063,6 +1064,9 @@ namespace Dalamud.Plugin.Internal /// internal partial class PluginManager { + private MonoMod.RuntimeDetour.Hook assemblyLocationMonoHook; + private MonoMod.RuntimeDetour.Hook assemblyCodeBaseMonoHook; + /// /// A mapping of plugin assembly name to patch data. Used to fill in missing data due to loading /// plugins via byte[]. @@ -1150,12 +1154,12 @@ namespace Dalamud.Plugin.Internal var locationTarget = targetType.GetProperty(nameof(Assembly.Location)).GetGetMethod(); var locationPatch = typeof(PluginManager).GetMethod(nameof(PluginManager.AssemblyLocationPatch), BindingFlags.NonPublic | BindingFlags.Static); - _ = new Hook(locationTarget, locationPatch); + this.assemblyLocationMonoHook = new MonoMod.RuntimeDetour.Hook(locationTarget, locationPatch); #pragma warning disable SYSLIB0012 // Type or member is obsolete var codebaseTarget = targetType.GetProperty(nameof(Assembly.CodeBase)).GetGetMethod(); var codebasePatch = typeof(PluginManager).GetMethod(nameof(PluginManager.AssemblyCodeBasePatch), BindingFlags.NonPublic | BindingFlags.Static); - _ = new Hook(codebaseTarget, codebasePatch); + this.assemblyCodeBaseMonoHook = new MonoMod.RuntimeDetour.Hook(codebaseTarget, codebasePatch); #pragma warning restore SYSLIB0012 // Type or member is obsolete }