Description
Description
When using the new PersistedAssemblyBuilder
introduced in .NET 9 and trying to load a field whose type is a function pointer, invalid IL gets generated, causing the application to crash with a System.MissingFieldException
when executed.
(On another note, is there currently a way of generating such fields using ILGenerator
? How do you get a Type
object for a function pointer at runtime?)
Reproduction Steps
The following code reproduces the problem in .NET 9. It doesn't produce a working executable by itself since I did not set the entry point, so to execute code from the generated assembly, you would need to reference it by some other assembly.
using System;
using System.Reflection;
using System.Reflection.Emit;
PersistedAssemblyBuilder ab = new(new("Test"), typeof(object).Assembly);
ModuleBuilder mb = ab.DefineDynamicModule("Test.dll");
TypeBuilder tb = mb.DefineType("Program");
MethodBuilder methb = tb.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static);
methb.SetReturnType(typeof(void));
ILGenerator il = methb.GetILGenerator();
il.Emit(OpCodes.Call, typeof(Container).GetMethod("Init"));
il.Emit(OpCodes.Ldc_I4_2);
il.Emit(OpCodes.Ldc_I4_3);
il.Emit(OpCodes.Ldsfld, typeof(Container).GetField("Method"));
il.EmitCalli(OpCodes.Calli, System.Runtime.InteropServices.CallingConvention.Winapi, typeof(int), [typeof(int), typeof(int)]);
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", BindingFlags.Public | BindingFlags.Static, null, [typeof(int)], []));
il.Emit(OpCodes.Ret);
tb.CreateType();
ab.Save("Test.dll");
public unsafe static class Container
{
public static delegate*<int, int, int> Method;
public static int Add(int a, int b) => a + b;
public static void Init() => Method = &Add;
}
Expected behavior
The following IL is generated as the method body for Test::Main()
when running under .NET Framework 4.8.1:
call void [Issue]Container::Init()
ldc.i4.2
ldc.i4.3
ldsfld method int32 *(int32,int32) [Issue]Container::Method
calli unmanaged stdcall int32(int32,int32)
call void [mscorlib]System.Console::WriteLine(int32)
ret
The generated application runs correctly and prints 5
.
Actual behavior
The following IL is generated when running under .NET 9:
call void [Issue]Container::Init()
ldc.i4.2
ldc.i4.3
ldsfld class [System.Private.CoreLib]$TR$2 [Issue]Container::Method
calli int32(int32,int32)
call void [System.Console]System.Console::WriteLine(int32)
ret
The ldsfld
instruction, instead of correctly using a function pointer as the field type, generates some garbage type (as is displayed by ildasm).
When executed, the following exception is thrown:
Unhandled exception. System.MissingFieldException: Field not found: 'Container.Method'.
at Program.Main()
Regression?
API was newly introduced with .NET 9. Works fine in .NET Framework 4.8.1.
Known Workarounds
Don't know of any.
Configuration
- .NET 9.0.100
- Windows 11 23H2
- Debug, x64
Other information
No response