Skip to content

UnmanagedCallersOnly fails in Debug mode, with SuppressGCTransition and certain signatures #46184

@kevzhao2

Description

@kevzhao2

Description

The following code results in Fatal error. Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code..

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

unsafe class Program
{
    [DllImport("NativeDll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void set_callback(delegate* unmanaged[Cdecl]<int, void> callback);

    [DllImport("NativeDll", CallingConvention = CallingConvention.Cdecl), SuppressGCTransition]
    public static extern void set_value(void* unused, int value);

    [DllImport("NativeDll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void call_callback(void* unused, int unused2);

    [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
    private static void PrintInt(int value)
    {
        Console.WriteLine(value);
        Console.ReadKey(true);
    }

    static void Main()
    {
        set_callback(&PrintInt);
        set_value(null, 1234);
        call_callback(null, 1234);  // crashes here!
    }
}
void (*globalCallback)(int value) = nullptr;
int globalValue = 0;

extern "C" __declspec(dllexport) void set_callback(void (*callback)(int value)) {
	globalCallback = callback;
}

extern "C" __declspec(dllexport) void set_value(void*, int value) {
	globalValue = value;
}

extern "C" __declspec(dllexport) void call_callback(void*, int) {
	globalCallback(globalValue);
}

Configuration

.NET Version: 5.0.101
OS: Windows 10 (18363.1256)
Architecture: x64

Regression?

N/A, since a lot of this stuff didn't even exist on 3.1.

Other information

Notably, if at least one of the following is true, then the crash no longer occurs:

  1. x86 is used instead of x64.
  2. SuppressGCTransition is removed from set_value.
  3. set_value is modified to take a long instead of an int.
  4. call_callback is modified to take a long instead of an int.
  5. The code is run under Release mode.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions