Repository navigation
Open
Labels
Milestone
Description
Description
It was noticed that Mono does not handle function pointer type equality and type compatibility the same way CoreCLR does.
There seem to be two related underlying issues:
- 1. Mono should ignore custom modifiers on function pointer parameters and calling convention when comparing function pointer types
- 2. Mono should properly implement
isinstin case of testing function pointer type compatibility against array of function pointers (respecting 1. from above)
Noticed in #89712 while enabling function pointer introspection API with Mono reflection in runtime tests:
runtime/src/libraries/System.Runtime/tests/System/Type/FunctionPointerTests.Runtime.cs
Lines 8 to 12 in b68382b
| // These are runtime-specific tests not shared with MetadataLoadContext. | |
| // Using arrays in the manner below allows for use of the "is" keyword. | |
| // The use of 'object' will call into the runtime to compare but using a strongly-typed | |
| // function pointer without 'object' causes C# to hard-code the result. | |
| public partial class FunctionPointerTests |
Repro
Here is a sample program to illustrate the behaviours:
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace HelloWorld
{
internal unsafe class Program
{
private const BindingFlags Bindings = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
public static delegate* unmanaged[Cdecl]<int> fptr1;
public static delegate* unmanaged[Stdcall]<int> fptr2;
private static void Main(string[] args)
{
FieldInfo fi1 = typeof(Program).GetField(nameof(Program.fptr1), Bindings);
Type ft1 = fi1.FieldType;
FieldInfo fi2 = typeof(Program).GetField(nameof(Program.fptr2), Bindings);
Type ft2 = fi2.FieldType;
if (ft1 == ft2)
Console.WriteLine("Function pointer types are equal");
else
Console.WriteLine("Function pointer types are not equal");
object arrayOfFptrs1 = new delegate*<int>[1];
if (arrayOfFptrs1 is delegate*<int>[])
Console.WriteLine("Is type compatible");
else
Console.WriteLine("Is not type compatible");
object arrayOfFptrs2 = new delegate*<ref int, void>[1];
if (arrayOfFptrs2 is delegate*<out int, void>[])
Console.WriteLine("Is type compatible");
else
Console.WriteLine("Is not type compatible");
}
}
}Expected behaviour
Program should output:
Function pointer types are equal
Is type compatible
Is type compatible
Actual behaviour
Program outputs:
Function pointer types are not equal
Is not type compatible
Is not type compatible
Reacted by Tanveer Badar
Activity
ivanpovazan commentedon Aug 10, 2023
/cc: @lambdageek
lambdageek commentedon Aug 10, 2023
This is partly because mono detects the "unmanaged" calling convention on function pointer signatures during loading and then eagerly looks at the custom modifiers and adjusts the calling convention right away on the MonoMethodSignature. It seems that instead we should leave it as "unmanaged" and only dip into the cmods in the marshaling logic that actually needs to pick a calling convention.
Fix function pointer type compatibility for isinst (issue #90308)
Simplify test to use int[] instead of function pointer array
Fix function pointer type compatibility for isinst (issue dotnet#90308)
Remove isinst changes (moved to separate PR)
Fix pointer array copying and various array pinning regressions in Co…