dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.41k stars 4.76k forks source link

Calling instance-based methods with function pointers is not supported #110061

Closed steveharter closed 9 hours ago

steveharter commented 10 hours ago

Calling a managed function pointer on an instance that returns a non-primitive value type (perhaps based on length?) will return random values and causes stack\heap issues later.

_UPDATED:_ I assume calling a function pointer on an instance method is supposed to work, provided the signature is correct for having the first parameter being the correct type (here "object" was used, but "TestClass" has the same result since it is a reference type). However, the function pointer spec says that instance methods are not supported (at least initially; not sure what transpired since then).

Note the IL looks correct, and the method is actually called.

This does not appear to be a regression.

Repro: the long property works but Guid doesn't, and a subsequent call to the long property returns a corrupted value.

public class TestClass
{
    public Guid _guid = new Guid("12300000-0000-0000-0000-000000000456");
    public int _long = 42;

    public Guid MyGuid => _guid;
    public long MyLong => _long;
}

internal unsafe class Program
{
    static void Main(string[] args)
    {
        MethodInfo method;
        IntPtr fp;

        TestClass testClass = new();

        fp = typeof(TestClass).GetMethod("get_MyLong").MethodHandle.GetFunctionPointer();
        delegate* managed<object, long> fpLong = (delegate* managed<object, long>)fp;
        long vLong = fpLong(testClass);
        Console.WriteLine(vLong); //42
        testClass._long++;
        vLong = fpLong(testClass);
        Console.WriteLine(vLong); //43

        fp = typeof(TestClass).GetMethod("get_MyGuid").MethodHandle.GetFunctionPointer();
        delegate* managed<object, Guid> fGuid = (delegate* managed<object, Guid>)fp;
        Guid vGuid = fGuid(testClass);
        Console.WriteLine(vGuid);           // 00000000-0000-0000-0000-000000000000 (wrong)
        Console.WriteLine(testClass._guid); // 12300000-0000-0000-0000-000000000456

        vLong = fpLong(testClass);
        Console.WriteLine(vLong); // random number (not 43)
    }
}
dotnet-policy-service[bot] commented 10 hours ago

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch See info in area-owners.md if you want to be subscribed.

steveharter commented 10 hours ago

Closing; wrong repro

steveharter commented 10 hours ago

Reopened; updated repro

steveharter commented 9 hours ago

Closing for now; the spec proposes "instance" keyword:

unsafe class Instance {
    void Use() {
        delegate* instance<Instance, string> f = &ToString;
        f(this);
    }
}
MichalPetryka commented 8 hours ago

says that instance methods are not supported (at least initially; not sure what transpired since then).

AFAIR LDM decided they're too nieche too expose in C#, but they should be fully functional in IL.

I assume if they were to be exposed in C#, it'd only be explicitthis ones since I don't see a way to reasonably handle ones with implicit this.