Skip to content

[mono] Function pointer type equality and type compatibility are not properly handled #90308

@ivanpovazan

Description

@ivanpovazan

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 isinst in 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:

// 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions