Description
Changing IL instructions with ILCursor throws an InvalidProgramException when the hook is applied. This issue was introduced since 93a3d9d. Using net472 and Mono from Unity 2022.3.33f1. Does not throw when running from the CoreCLR runtime.
System.InvalidProgramException: Invalid IL code in (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition:DMD<DMD<>?953292825::ConsoleApp5.Program::Original> (): IL_0076: call 0x0000001d
at (wrapper managed-to-native) System.RuntimeMethodHandle.GetFunctionPointer(intptr)
at System.RuntimeMethodHandle.GetFunctionPointer () [0x00000] in <812f0de03a50406495fcf89f8084dfd4>:0
at MonoMod.Core.Platforms.Runtimes.MonoRuntime.Compile (System.Reflection.MethodBase method) [0x00008] in <c8544a96d826479bab87939de32bc508>:0
at MonoMod.Core.Platforms.PlatformTriple.Compile (System.Reflection.MethodBase method) [0x00047] in <c8544a96d826479bab87939de32bc508>:0
at MonoMod.RuntimeDetour.DetourManager+ManagedDetourState.UpdateEndOfChain () [0x000e1] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.DetourManager+ManagedDetourState.AddILHook (MonoMod.RuntimeDetour.DetourManager+SingleILHookState ilhook, System.Boolean takeLock) [0x000e9] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook.Apply () [0x00052] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook..ctor (System.Reflection.MethodBase method, MonoMod.Cil.ILContext+Manipulator manipulator, MonoMod.Core.IDetourFactory factory, MonoMod.RuntimeDetour.DetourConfig config, System.Boolean applyByDefault) [0x00098] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook..ctor (System.Reflection.MethodBase source, MonoMod.Cil.ILContext+Manipulator manip, MonoMod.RuntimeDetour.DetourConfig config, System.Boolean applyByDefault) [0x00008] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook..ctor (System.Reflection.MethodBase source, MonoMod.Cil.ILContext+Manipulator manip, MonoMod.RuntimeDetour.DetourConfig config) [0x00000] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook..ctor (System.Reflection.MethodBase source, MonoMod.Cil.ILContext+Manipulator manip) [0x00008] in <e0f4e58211844eec912c979914e6364b>:0
at ConsoleApp5.Program.Main (System.String[] args) [0x00055] in <f214ce8aacc74f19b7bc22b2b72acef0>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidProgramException: Invalid IL code in (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition:DMD<DMD<>?953292825::ConsoleApp5.Program::Original> (): IL_0076: call 0x0000001d
at (wrapper managed-to-native) System.RuntimeMethodHandle.GetFunctionPointer(intptr)
at System.RuntimeMethodHandle.GetFunctionPointer () [0x00000] in <812f0de03a50406495fcf89f8084dfd4>:0
at MonoMod.Core.Platforms.Runtimes.MonoRuntime.Compile (System.Reflection.MethodBase method) [0x00008] in <c8544a96d826479bab87939de32bc508>:0
at MonoMod.Core.Platforms.PlatformTriple.Compile (System.Reflection.MethodBase method) [0x00047] in <c8544a96d826479bab87939de32bc508>:0
at MonoMod.RuntimeDetour.DetourManager+ManagedDetourState.UpdateEndOfChain () [0x000e1] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.DetourManager+ManagedDetourState.AddILHook (MonoMod.RuntimeDetour.DetourManager+SingleILHookState ilhook, System.Boolean takeLock) [0x000e9] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook.Apply () [0x00052] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook..ctor (System.Reflection.MethodBase method, MonoMod.Cil.ILContext+Manipulator manipulator, MonoMod.Core.IDetourFactory factory, MonoMod.RuntimeDetour.DetourConfig config, System.Boolean applyByDefault) [0x00098] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook..ctor (System.Reflection.MethodBase source, MonoMod.Cil.ILContext+Manipulator manip, MonoMod.RuntimeDetour.DetourConfig config, System.Boolean applyByDefault) [0x00008] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook..ctor (System.Reflection.MethodBase source, MonoMod.Cil.ILContext+Manipulator manip, MonoMod.RuntimeDetour.DetourConfig config) [0x00000] in <e0f4e58211844eec912c979914e6364b>:0
at MonoMod.RuntimeDetour.ILHook..ctor (System.Reflection.MethodBase source, MonoMod.Cil.ILContext+Manipulator manip) [0x00008] in <e0f4e58211844eec912c979914e6364b>:0
at ConsoleApp5.Program.Main (System.String[] args) [0x00055] in <f214ce8aacc74f19b7bc22b2b72acef0>:0
Example
using System.Reflection;
using System.Runtime.CompilerServices;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
namespace ConsoleApp5
{
internal class Program
{
private class SomeType
{
public int index { get; set; }
}
private static readonly List<SomeType>[] _list = new List<SomeType>[3];
private static void Main(string[] args)
{
for (var i = 0; i < 3; i++)
{
_list[i] = new List<SomeType>(3);
}
var original = typeof(Program).GetMethod(nameof(Original), BindingFlags.Static | BindingFlags.NonPublic);
new ILHook(original, Hook1).Apply();
new ILHook(original, Hook2).Apply();
}
private static void Original()
{
var random = new Random();
var enumerable = Enumerable.Range(0, 50).Select(i => new SomeType { index = random.Next(0, 3) });
foreach (var item in enumerable)
{
_ = _list[item.index];
}
}
private static void Hook1(ILContext il)
{
var cursor = new ILCursor(il);
cursor.GotoNext(
MoveType.After,
x => x.Match(OpCodes.Ldloc_2),
x => x.Match(OpCodes.Callvirt),
x => x.Match(OpCodes.Ldelem_Ref));
cursor.Index--;
cursor.Emit(OpCodes.Ldc_I4_0);
cursor.Emit(OpCodes.Ldc_I4_3);
cursor.EmitCall(typeof(Program).GetMethod(nameof(Clamp), new[] { typeof(int), typeof(int), typeof(int) }));
}
private static void Hook2(ILContext il)
{
var cursor = new ILCursor(il);
if (!cursor.TryGotoNext(
MoveType.After,
x => x.Match(OpCodes.Ldloc_2),
x => x.Match(OpCodes.Callvirt),
x => x.Match(OpCodes.Ldelem_Ref)))
{
cursor.Index = cursor.Instrs.Count;
}
else
{
cursor.Index--;
}
cursor.Emit(OpCodes.Ldc_I4_0);
cursor.Emit(OpCodes.Ldc_I4_3);
cursor.EmitCall(typeof(Program).GetMethod(nameof(Clamp), new[] { typeof(int), typeof(int), typeof(int) })!);
if (!cursor.TryGotoNext(
MoveType.Before,
x => x.Match(OpCodes.Ldloc_1),
x => x.Match(OpCodes.Callvirt),
x => x.Match(OpCodes.Stloc_S)))
{
cursor.Index = cursor.Instrs.Count;
}
cursor.Emit(OpCodes.Ret);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Clamp(int value, int min, int max)
{
if (min > max)
throw new ArgumentException($"'{min}' cannot be greater than {max}.");
if (value < min)
return min;
return value > max ? max : value;
}
}
}
Description
Changing IL instructions with
ILCursorthrows anInvalidProgramExceptionwhen the hook is applied. This issue was introduced since 93a3d9d. Using net472 and Mono from Unity 2022.3.33f1. Does not throw when running from the CoreCLR runtime.Example