Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HarmonyILManipulator on method w/ HarmonyTranspiler results in InvalidCastException #54

Open
6thmoon opened this issue Nov 11, 2022 · 2 comments

Comments

@6thmoon
Copy link

6thmoon commented Nov 11, 2022

It appears that ILPatternMatchingExt expects ILLabel as branch operand but instead receives Instruction after running the Transpiler. Here is the stack trace displayed in the BepInEx console:

Click to expand...
[Error  :  HarmonyX] Failed to patch void Test.Plugin::Example(): System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidCastException: Specified cast is not valid.
  at MonoMod.Cil.ILPatternMatchingExt.MatchBr (Mono.Cecil.Cil.Instruction instr, MonoMod.Cil.ILLabel& value) [0x0002b] in <6733e342b5b549bba815373898724469>:IL_002B 
  at Test.Plugin+<>c.<Manipulate>b__3_0 (Mono.Cecil.Cil.Instruction instruction) [0x00000] in <16905bc0082a4b6088e041b87217eb81>:IL_0000 
  at MonoMod.Cil.ILCursor.TryGotoNext (MonoMod.Cil.MoveType moveType, System.Func`2[Mono.Cecil.Cil.Instruction,System.Boolean][] predicates) [0x00034] in <6733e342b5b549bba815373898724469>:IL_0034 
  at MonoMod.Cil.ILCursor.GotoNext (MonoMod.Cil.MoveType moveType, System.Func`2[Mono.Cecil.Cil.Instruction,System.Boolean][] predicates) [0x00000] in <6733e342b5b549bba815373898724469>:IL_0000 
  at MonoMod.Cil.ILCursor.GotoNext (System.Func`2[Mono.Cecil.Cil.Instruction,System.Boolean][] predicates) [0x00000] in <6733e342b5b549bba815373898724469>:IL_0000 
  at Test.Plugin.Manipulate (MonoMod.Cil.ILContext context) [0x00006] in <16905bc0082a4b6088e041b87217eb81>:IL_0006 
  at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in <44afb4564e9347cf99a1865351ea8f4a>:IL_0032 
   --- End of inner exception stack trace ---
  at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x0004b] in <44afb4564e9347cf99a1865351ea8f4a>:IL_004B 
  at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <44afb4564e9347cf99a1865351ea8f4a>:IL_0000 
  at HarmonyLib.Public.Patching.HarmonyManipulator.ApplyManipulators (MonoMod.Cil.ILContext ctx, System.Reflection.MethodBase original, System.Collections.Generic.List`1[T] ilManipulators, HarmonyLib.Internal.Util.ILEmitter+Label retLabel) [0x000ea] in <474744d65d8e460fa08cd5fd82b5d65f>:IL_00EA 
  at HarmonyLib.Public.Patching.HarmonyManipulator.WriteImpl () [0x0030d] in <474744d65d8e460fa08cd5fd82b5d65f>:IL_030D 
[Error  : Unity Log] InvalidCastException: Specified cast is not valid.
Stack trace:
MonoMod.Cil.ILPatternMatchingExt.MatchBr (Mono.Cecil.Cil.Instruction instr, MonoMod.Cil.ILLabel& value) (at <6733e342b5b549bba815373898724469>:IL_002B)
Test.Plugin+<>c.<Manipulate>b__3_0 (Mono.Cecil.Cil.Instruction instruction) (at <16905bc0082a4b6088e041b87217eb81>:IL_0000)
MonoMod.Cil.ILCursor.TryGotoNext (MonoMod.Cil.MoveType moveType, System.Func`2[Mono.Cecil.Cil.Instruction,System.Boolean][] predicates) (at <6733e342b5b549bba815373898724469>:IL_0034)
MonoMod.Cil.ILCursor.GotoNext (MonoMod.Cil.MoveType moveType, System.Func`2[Mono.Cecil.Cil.Instruction,System.Boolean][] predicates) (at <6733e342b5b549bba815373898724469>:IL_0000)
MonoMod.Cil.ILCursor.GotoNext (System.Func`2[Mono.Cecil.Cil.Instruction,System.Boolean][] predicates) (at <6733e342b5b549bba815373898724469>:IL_0000)
Test.Plugin.Manipulate (MonoMod.Cil.ILContext context) (at <16905bc0082a4b6088e041b87217eb81>:IL_0006)
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <44afb4564e9347cf99a1865351ea8f4a>:IL_0032)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <44afb4564e9347cf99a1865351ea8f4a>:IL_004B)
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at <44afb4564e9347cf99a1865351ea8f4a>:IL_0000)
HarmonyLib.Public.Patching.HarmonyManipulator.ApplyManipulators (MonoMod.Cil.ILContext ctx, System.Reflection.MethodBase original, System.Collections.Generic.List`1[T] ilManipulators, HarmonyLib.Internal.Util.ILEmitter+Label retLabel) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_00EA)
HarmonyLib.Public.Patching.HarmonyManipulator.WriteImpl () (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_030D)
Rethrow as HarmonyException: IL Compile Error (unknown location)
HarmonyLib.Public.Patching.HarmonyManipulator.WriteImpl () (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0378)
HarmonyLib.Public.Patching.HarmonyManipulator.Process (MonoMod.Cil.ILContext ilContext, System.Reflection.MethodBase originalMethod) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0042)
HarmonyLib.Public.Patching.HarmonyManipulator.Manipulate (System.Reflection.MethodBase original, HarmonyLib.PatchInfo patchInfo, MonoMod.Cil.ILContext ctx) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0006)
HarmonyLib.Public.Patching.HarmonyManipulator.Manipulate (System.Reflection.MethodBase original, MonoMod.Cil.ILContext ctx) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0007)
HarmonyLib.Public.Patching.ManagedMethodPatcher.Manipulator (MonoMod.Cil.ILContext ctx) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0012)
MonoMod.Cil.ILContext.Invoke (MonoMod.Cil.ILContext+Manipulator manip) (at <6733e342b5b549bba815373898724469>:IL_0087)
MonoMod.RuntimeDetour.ILHook+Context.InvokeManipulator (Mono.Cecil.MethodDefinition def, MonoMod.Cil.ILContext+Manipulator cb) (at <4e2760c7517c4ea79c633d67e84b319f>:IL_0012)
DMD<Refresh>?-1925063936._MonoMod_RuntimeDetour_ILHook+Context::Refresh (MonoMod.RuntimeDetour.ILHook+Context this) (at <75e4ac05845642588cd961442b944b7f>:IL_00EA)
DMD<>?-1925063936.Trampoline<MonoMod.RuntimeDetour.ILHook+Context::Refresh>?1807096832 (System.Object ) (at <1242ad070f5f425c8b0fba06324360e4>:IL_0020)
HarmonyLib.Internal.RuntimeFixes.StackTraceFixes.OnILChainRefresh (System.Object self) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0000)
MonoMod.RuntimeDetour.ILHook.Apply () (at <4e2760c7517c4ea79c633d67e84b319f>:IL_0059)
HarmonyLib.Public.Patching.ManagedMethodPatcher.DetourTo (System.Reflection.MethodBase replacement) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0047)
Rethrow as HarmonyException: IL Compile Error (unknown location)
HarmonyLib.Public.Patching.ManagedMethodPatcher.DetourTo (System.Reflection.MethodBase replacement) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_005F)
HarmonyLib.PatchFunctions.UpdateWrapper (System.Reflection.MethodBase original, HarmonyLib.PatchInfo patchInfo) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0033)
Rethrow as HarmonyException: IL Compile Error (unknown location)
HarmonyLib.PatchClassProcessor.ReportException (System.Exception exception, System.Reflection.MethodBase original) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0045)
HarmonyLib.PatchClassProcessor.Patch () (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0095)
HarmonyLib.Harmony.PatchAll (System.Type type) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_0008)
HarmonyLib.Harmony.CreateAndPatchAll (System.Type type, System.String harmonyInstanceId) (at <474744d65d8e460fa08cd5fd82b5d65f>:IL_001E)
Test.Plugin.Awake () (at <16905bc0082a4b6088e041b87217eb81>:IL_0000)
UnityEngine.GameObject:AddComponent(Type)
BepInEx.Bootstrap.Chainloader:Start()
FlashWindow:.cctor()

BepInEx package used was the latest version - 5.4.21, running on Windows 10. I tried a few different combinations of .NET framework and Unity game engine with the same results. The following code illustrates a simple way to reproduce this error:

using HarmonyLib;
using MonoMod.Cil;
using System;
using System.Collections.Generic;

namespace Test
{
    [BepInEx.BepInPlugin("local.test.plugin", "TestPlugin", "0.0.0")]
    class Plugin : BepInEx.BaseUnityPlugin
    {
        void Awake() => Harmony.CreateAndPatchAll(typeof(Plugin));
        void Example()              // Generate a branch instruction.
             => Console.WriteLine(DateTime.Now.Second % 2 == 0 ? "even" : "odd");

        [HarmonyTranspiler, HarmonyPatch(typeof(Plugin), nameof(Example))]
        static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> instructions)
             => instructions;       // In theory, this does nothing. However...

        [HarmonyILManipulator, HarmonyPatch(typeof(Plugin), nameof(Example))]
        static void Manipulate(ILContext context)
             // `InvalidCastException` thrown when matching branch instruction.
             => new ILCursor(context).GotoNext(instruction => instruction.MatchBr(out _));
    }
}

Of course, this is a rather contrived example. The real situation where this may arise is when two separate plugins are attempting to patch the same method in game - one using ILManipulator, while the other leverages a Transpiler. Interestingly enough, the issue did not occur upon replacing the HarmonyILManipulator with an identical MonoMod IL hook.

@6thmoon
Copy link
Author

6thmoon commented Jun 21, 2023

Any comment? It doesn't come up often, but there have been a few users affected by this.

@Zaggy1024
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants