BepInEx / HarmonyX

Harmony built on top of MonoMod.RuntimeDetours with additional features
MIT License
329 stars 42 forks source link

Label Jump #87

Closed littlecattle closed 1 month ago

littlecattle commented 8 months ago

Transpiler has label issue for specific CIL. Applying an empty Transpiler Patch to the following function will change the jump label position. leave IL_002f was modified to leave IL_0024, causing unexpected execution.

using HarmonyLib;
using HarmonyLib.Tools;
using System.Reflection.Emit;

namespace Test
{
    [HarmonyDebug]
    public class Program
    {
        static void Test()
        {
            int i = 0;
            try
            {
                if (i == 0)
                {
                    try
                    {
                        Console.WriteLine("jump");
                        goto Label;
                    }
                    finally {}
                }
                Console.WriteLine("test");
            Label:;
            }
            finally {}
        }

        [HarmonyPatch(typeof(Program), "Test")]
        [HarmonyTranspiler]
        public static IEnumerable<CodeInstruction> TestTranspiler(IEnumerable<CodeInstruction> instructions)
        {
            return instructions;
            // temp solve
            var codeMatcher = new CodeMatcher(instructions);
            codeMatcher.MatchForward(false, new [] {new CodeMatch(OpCodes.Leave)});
            codeMatcher.Insert(codeMatcher.Instruction);
            return codeMatcher.InstructionEnumeration();

        }

        static void Main(string[] args)
        {
            HarmonyFileLog.Enabled = true;
            Harmony.CreateAndPatchAll(typeof(Program));
            Test();
        }
    }
}

log

[IL] Generated patch (System.Void DMD<Test.Program::Test>?66572856::Test.Program::Test()):
.locals init (
    System.Int32 V_0
    System.Boolean V_1
)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
.try
{
  IL_0003: nop
  IL_0004: ldloc.0
  IL_0005: ldc.i4.0
  IL_0006: ceq
  IL_0008: stloc.1
  IL_0009: ldloc.1
  IL_000a: brfalse IL_0024
  IL_000f: nop
  .try
  {
    IL_0010: nop
    IL_0011: ldstr "jump"
    IL_0016: call System.Void System.Console::WriteLine(System.String)
    IL_001b: nop
    IL_001c: leave IL_0024
  } // end .try
  finally
  {
    IL_0021: nop
    IL_0022: nop
    IL_0023: endfinally
  } // end handler (finally)
  IL_0024: ldstr "test"
  IL_0029: call System.Void System.Console::WriteLine(System.String)
  IL_002e: nop
  IL_002f: nop
  IL_0030: nop
  IL_0031: nop
  IL_0032: leave IL_003a
} // end .try
finally
{
  IL_0037: nop
  IL_0038: nop
  IL_0039: endfinally
} // end handler (finally)
IL_003a: ret
ManlyMarco commented 8 months ago

Likely related to #77

ManlyMarco commented 1 month ago

Fixed in latest releases.