runtime: Calli with thiscall convention fails at runtime
This program (IL at the bottom of the issue) causes .net core 3.1 to fail with:
Unhandled exception. System.InvalidProgramException: Common Language Runtime detected an invalid program.
at UnmanagedFunctionPointer.Main()
The program defines a delegate type that takes a pointer to a structure and a float, and returns a structure that contains a field from that first pointer and the float. It then creates a thiscall
function pointer stub around the delegate by using Marshal.CreateFunctionPointerForDelegate
, and calli
’s that pointer. On .net framework, this correctly prints 12.3. On .net core, this fails with the above exception. /cc @jkoritzinsky
.assembly UnmanagedFunctionPointer
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = (
01 00 08 00 00 00 00 00
)
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (
01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78
63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01
)
.custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
01 00 07 01 00 00 00 00
)
.permissionset reqmin = {
[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {
property bool SkipVerification = bool(true)
}
}
.hash algorithm 0x00008004 // SHA1
.ver 0:0:0:0
}
.module UnmanagedFunctionPointer.dll
.class public sequential ansi sealed beforefieldinit ReturnWrapper
extends [mscorlib]System.ValueType
{
// Fields
.field public int32 i1
.field public float32 f2
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
int32 i1,
float32 f2
) cil managed
{
// Method begins at RVA 0x205a
// Code size 16 (0x10)
.maxstack 8
nop
ldarg.0
ldarg.1
stfld int32 ReturnWrapper::i1
ldarg.0
ldarg.2
stfld float32 ReturnWrapper::f2
ret
} // end of method ReturnWrapper::.ctor
} // end of class ReturnWrapper
.class public sequential ansi sealed beforefieldinit S
extends [mscorlib]System.ValueType
{
// Fields
.field public int32 i
// Methods
.method public hidebysig static
valuetype ReturnWrapper GetReturn (
valuetype S* s,
float32 f
) cil managed
{
// Method begins at RVA 0x208c
// Code size 18 (0x12)
.maxstack 2
.locals init (
[0] valuetype ReturnWrapper
)
nop
ldarg.0
ldfld int32 S::i
ldarg.1
newobj instance void ReturnWrapper::.ctor(int32, float32)
ret
} // end of method S::GetReturn
} // end of class S
.class public auto ansi beforefieldinit UnmanagedFunctionPointer
extends [mscorlib]System.Object
{
// Nested Types
.class nested private auto ansi sealed MultipleParams
extends [mscorlib]System.MulticastDelegate
{
.custom instance void [mscorlib]System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute::.ctor(valuetype [mscorlib]System.Runtime.InteropServices.CallingConvention) = (
01 00 04 00 00 00 00 00
)
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method MultipleParams::.ctor
.method public hidebysig newslot virtual
instance valuetype ReturnWrapper Invoke (
valuetype S* s,
float32 f
) runtime managed
{
} // end of method MultipleParams::Invoke
.method public hidebysig newslot virtual
instance class [mscorlib]System.IAsyncResult BeginInvoke (
valuetype S* s,
float32 f,
class [mscorlib]System.AsyncCallback callback,
object 'object'
) runtime managed
{
} // end of method MultipleParams::BeginInvoke
.method public hidebysig newslot virtual
instance valuetype ReturnWrapper EndInvoke (
class [mscorlib]System.IAsyncResult result
) runtime managed
{
} // end of method MultipleParams::EndInvoke
} // end of class MultipleParams
// Methods
.method public hidebysig static
void Main () cil managed
{
// Method begins at RVA 0x20e0
// Code size 37 (0x25)
.maxstack 4
.entrypoint
.locals init (
[0] native int,
[1] valuetype S,
[2] valuetype ReturnWrapper
)
nop
ldnull
ldftn valuetype ReturnWrapper S::GetReturn(valuetype S*, float32)
newobj instance void UnmanagedFunctionPointer/MultipleParams::.ctor(object, native int)
call native int [mscorlib]System.Runtime.InteropServices.Marshal::GetFunctionPointerForDelegate<class UnmanagedFunctionPointer/MultipleParams>(!!0)
stloc.0
ldloc.0
box [mscorlib]System.IntPtr
call void [mscorlib]System.GC::KeepAlive(object)
ldloca.s 1
initobj [UnmanagedFunctionPointer]S
ldloca.s 1
ldc.i4.1
stfld int32 [UnmanagedFunctionPointer]S::i
ldloca.s 1
conv.u
ldc.r4 2.3
ldloc.0
calli unmanaged thiscall valuetype ReturnWrapper(valuetype S*, float32)
stloc.2
ldloc.2
ldfld int32 [UnmanagedFunctionPointer]ReturnWrapper::i1
call void [mscorlib]System.Console::Write(int32)
ldloc.2
ldfld float32 [UnmanagedFunctionPointer]ReturnWrapper::f2
call void [mscorlib]System.Console::Write(float32)
ret
} // end of method UnmanagedFunctionPointer::GetFuncPtrMultipleParams
} // end of class UnmanagedFunctionPointer
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 22 (22 by maintainers)
I think we have an issue tracking it but we haven’t decided on the final shape (if we’re going to do Thiscall + Stdcall or make a new type CallConvInstanceMethod to avoid confusion)
Is this an internal issue? If not, can you link it? I couldn’t find it anywhere on the runtime repo.