Open MrJul opened 6 months ago
Tagging subscribers to this area: @dotnet/area-system-reflection-emit See info in area-owners.md if you want to be subscribed.
The method
public static unsafe void M1<T>(delegate*<void> action) => action();
uses an unnecessary generic.
Changing that to
public static unsafe void M1(delegate*<void> action) => action();
and
il.EmitCall(OpCodes.Call, m1.MakeGenericMethod(typeof(string)), null);
to
il.EmitCall(OpCodes.Call, m1, null);
works for me.
@steveharter, I think the principle here is that the code should work regardless of the generic being unnecessary.
A more complex example that uses the generic could be created and the same issue would still exist, that the API cannot be called.
Consider for example:
public static unsafe T M1<T>(delegate*<T> func) => func();
This is indeed an issue, but moving to v10.
The workaround is to use IntPtr
instead of the strongly-typed function pointer:
public static unsafe void M1<T>(IntPtr action) => ((delegate*<void>)action)();
The issue is the code in SignatureHelper.AddOneArgTypeHelperWorker
doesn't know how to add a signature, only type tokens and a function pointer needs to be a signature every time it is used (there is no token). My WIP for this is at https://github.com/steveharter/runtime/tree/Issue100020. Somewhat unrelated, that branch also adds support for Ldftn+Call
since we now can obtain the return type and parameter types from a function pointer, although we need to verify we want to support that. Normally, one would use Ldftn+CallI
where il.EmitCallI()
requires the signature be specified instead of obtaining from a MethodInfo
.
See also https://github.com/dotnet/runtime/issues/75348 for other remaining function pointer work around Invoke.
Description
It isn't possible to emit a dynamic assembly using
System.Reflection.Emit
that emits a call to a generic method having a function pointer as an argument. The code fails with aArgumentNullException
Reproduction Steps
This program emits a method equivalent to the following C# code:
Expected behavior
The method is correctly emitted and runs.
Actual behavior
The
EmitCall()
fails with aArgumentNullException
.Stack trace:
Regression?
Technically in .NET 7 the emit phase works, which now fails in .NET 8.
That doesn't really matter since the emitted code can't run in .NET 7: it searches for a
C.M1(IntPtr)
overload, which doesn't exist.Known Workarounds
Using
IntPtr
instead of a function pointer parameter works.Configuration
.NET 8.0.2 Windows 11 22631.3296 x64
Other information
Remarks:
DynamicMethod
instead of a dynamic assembly.The
GetTypeRefNested
method probably isn't meant to be called for function pointers, as it seems to be assuming that a proper type (not a function pointer) was passed, here:https://github.com/dotnet/runtime/blob/ffe7e26ccc29f5ca1737dd7d84fa98b1b7c10d5f/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeModuleBuilder.cs#L208
FullName
isnull
for a function pointer, causing theGetTypeRef
to fail: https://github.com/dotnet/runtime/blob/ffe7e26ccc29f5ca1737dd7d84fa98b1b7c10d5f/src/coreclr/vm/commodule.cpp#L42