Created
December 11, 2019 17:36
-
-
Save xoofx/c4a9777eaafb47ca70ff30c64f314137 to your computer and use it in GitHub Desktop.
Example of the ldflda opcode crashing on Mono (5.21 and 6.4.0)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Create a .NET Core project, target also net472 | |
// Requires to install NuGet package InlineIL.Fody https://github.com/ltrzesniewski/InlineIL.Fody in your project | |
// Run this program | |
using System; | |
using InlineIL; | |
namespace PlayIL | |
{ | |
class Program | |
{ | |
// The following program will generate a crash in Mono (Tested on Mono 5.21 and 6.4.0) | |
// | |
// CheckLdFldLdFlda | |
// Unhandled Exception: | |
// System.InvalidProgramException: Invalid IL code in PlayIL.Program:CheckLdFldLdFlda (PlayIL.Program/RootStruct): IL_0006: ldflda 0x0a000004 | |
// at PlayIL.Program.Main (System.String[] args) [0x0004b] in <5cd1d0b45a8f4b03b56221d0e2065d86>:0 | |
// [ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidProgramException: Invalid IL code in PlayIL.Program:CheckLdFldLdFlda (PlayIL.Program/RootStruct): IL_0006: ldflda 0x0a000004 | |
// at PlayIL.Program.Main (System.String[] args) [0x0004b] in <5cd1d0b45a8f4b03b56221d0e2065d86>:0 | |
// | |
// As ldflda is not supported if the input this "pointer" is actually not a pointer but a value on the stack | |
// While this is supported by .NET CLR and also according to the specs | |
static void Main(string[] args) | |
{ | |
Console.WriteLine("CheckLdFldLdFlda"); | |
var rootStruct = new RootStruct() { Nested = new NestedStruct() { SubNested = new SubNestedStruct() { SubSubNested = new SubSubNestedStruct() { Value = 10 } } } }; | |
Console.WriteLine(CheckLdFldLdFlda(rootStruct)); | |
// Comment these on Mono | |
Console.WriteLine("CheckLdFldLdFldaWithCall"); | |
rootStruct = new RootStruct() { Nested = new NestedStruct() { SubNested = new SubNestedStruct() { SubSubNested = new SubSubNestedStruct() { Value = 11 } } } }; | |
Console.WriteLine(CheckLdFldLdFldaWithCall(rootStruct)); | |
// Comment these on Mono | |
Console.WriteLine("CheckLdFldLdFldaWithLdElem"); | |
Console.WriteLine(CheckLdFldLdFldaWithLdElem()); | |
} | |
public static int CheckLdFldLdFlda(RootStruct rootStruct) | |
{ | |
IL.Emit.Ldarg(nameof(rootStruct)); | |
IL.Emit.Ldfld(new FieldRef(typeof(RootStruct), nameof(RootStruct.Nested))); | |
// ldflda taking directly a NestedStruct instance on the evaluation stack, not a pointer | |
IL.Emit.Ldflda(new FieldRef(typeof(NestedStruct), nameof(NestedStruct.SubNested))); | |
IL.Emit.Ldfld(new FieldRef(typeof(SubNestedStruct), nameof(SubNestedStruct.SubSubNested))); | |
IL.Emit.Ldfld(new FieldRef(typeof(SubSubNestedStruct), nameof(SubSubNestedStruct.Value))); | |
return IL.Return<int>(); | |
} | |
public static int CheckLdFldLdFldaWithCall(RootStruct rootStruct) | |
{ | |
IL.Emit.Ldarg(nameof(rootStruct)); | |
IL.Emit.Ldfld(new FieldRef(typeof(RootStruct), nameof(RootStruct.Nested))); | |
IL.Emit.Call(new MethodRef(new TypeRef(typeof(Program)), nameof(NestedStructGoThrough))); | |
IL.Emit.Ldfld(new FieldRef(typeof(NestedStruct), nameof(NestedStruct.SubNested))); | |
// ldflda taking directly a NestedStruct instance on the evaluation stack, not a pointer | |
IL.Emit.Ldflda(new FieldRef(typeof(SubNestedStruct), nameof(SubNestedStruct.SubSubNested))); | |
IL.Emit.Ldfld(new FieldRef(typeof(SubSubNestedStruct), nameof(SubSubNestedStruct.Value))); | |
return IL.Return<int>(); | |
} | |
public static int CheckLdFldLdFldaWithLdElem() | |
{ | |
IL.Emit.Ldsfld(new FieldRef(typeof(RootStruct), nameof(RootStruct.RootStructArray))); | |
IL.Emit.Ldc_I4_1(); | |
IL.Emit.Ldelem_Any(new TypeRef(typeof(RootStruct))); | |
IL.Emit.Ldfld(new FieldRef(typeof(RootStruct), nameof(RootStruct.Nested))); | |
// ldflda taking directly a NestedStruct instance on the evaluation stack, not a pointer | |
IL.Emit.Ldflda(new FieldRef(typeof(NestedStruct), nameof(NestedStruct.SubNested))); | |
IL.Emit.Ldfld(new FieldRef(typeof(SubNestedStruct), nameof(SubNestedStruct.SubSubNested))); | |
IL.Emit.Ldfld(new FieldRef(typeof(SubSubNestedStruct), nameof(SubSubNestedStruct.Value))); | |
return IL.Return<int>(); | |
} | |
private static SubNestedStruct NestedStructGoThrough(NestedStruct nested) | |
{ | |
return nested.SubNested; | |
} | |
public struct RootStruct | |
{ | |
public static readonly RootStruct[] RootStructArray = new RootStruct[] | |
{ | |
new RootStruct(), | |
new RootStruct() {Nested = new NestedStruct() {SubNested = new SubNestedStruct() {SubSubNested = new SubSubNestedStruct() {Value = 12}}}} | |
}; | |
public NestedStruct Nested; | |
} | |
public struct NestedStruct | |
{ | |
public SubNestedStruct SubNested; | |
} | |
public struct SubNestedStruct | |
{ | |
public SubSubNestedStruct SubSubNested; | |
} | |
public struct SubSubNestedStruct | |
{ | |
public int Value; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment