Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MissingMethodException when pointer to TypedReference is used #13077

Closed
sakno opened this issue Jul 15, 2019 · 7 comments · Fixed by dotnet/coreclr#25817
Closed

MissingMethodException when pointer to TypedReference is used #13077

sakno opened this issue Jul 15, 2019 · 7 comments · Fixed by dotnet/coreclr#25817

Comments

@sakno
Copy link
Contributor

sakno commented Jul 15, 2019

I found strange runtime behavior that causes MissingMethodException but Roslyn compiles everything successfully.
I'm developing a library which has a method that allow to convert T& into TypedReference. This typed cannot be as return type as well as ref TypedReference so I decided to use pointer to this type.

public static unsafe void AsTypedReference<T>(ref T managedPtr, TypedReference* reference)
{
  *reference = __makeref(managedPtr);
}

This code compiles successfully but when I trying to call it I get System.MissingMethodException : Method not found: 'Void AsTypedReference(!!0 ByRef, System.TypedReference*)'
To fix this error, I replaced TypedReference* with void*. Now everything is fine.

However, I think that this problem should be fixed at .NET level:

  1. Fix Roslyn Compiler and prevent usage of pointer to TypedReference
  2. Fix CLR and allow to use pointer to this type. In this case, type TypedReference& should by allowed by Roslyn Compiler as well.

The issue is reproduced on Windows 10 and Ubuntu Linux 18.04.2 LTS, x86_64, .NET Core version 2.2.301.

@MichalStrehovsky
Copy link
Member

Can you provide more detail so that we can repro this?

I tried

class Program
{

    public static unsafe void AsTypedReference<T>(ref T managedPtr, TypedReference* reference)
    {
        *reference = __makeref(managedPtr);
    }
    static unsafe void Main()
    {
        int x = default;
        AsTypedReference(ref x, null);
    }
}

Then I also tried this with InlineIL.Fody and that works too:

using System;
using System.Runtime.CompilerServices;
using static InlineIL.IL;
using static InlineIL.IL.Emit;

namespace FodySample
{
    using typedref = TypedReference;    //IL compliant alias to TypedReference

    unsafe class Program
    {
        public static readonly void* NullPtr = IntPtr.Zero.ToPointer();

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void AsTypedReference<T>(ref T managedPtr, TypedReference* reference)
        {
            if (reference == NullPtr)
                throw new ArgumentNullException(nameof(reference));
            Push(reference);
            Push(ref managedPtr);
            Mkrefany(typeof(T));
            Stobj(typeof(typedref));
            Ret();
        }

        static void Main(string[] args)
        {
            var reference = default(TypedReference);
            var i = 20;
            AsTypedReference(ref i, &reference);

            Console.WriteLine(__reftype(reference));
            Console.WriteLine(__refvalue(reference, int));
        }
    }
}

@sakno
Copy link
Contributor Author

sakno commented Jul 16, 2019

@MichalStrehovsky I tried to execute this method from XUnit test. I'll try to reproduce this from Main method without XUnit.

@sakno
Copy link
Contributor Author

sakno commented Jul 16, 2019

@MichalStrehovsky, the bug is reproducible outside of Xunit test. Did you tried it on the same version of .NET Core and OS as specified in my first post?
Ah, I forgot one more thing, method AsTypedReference should be in .NET Standard library, not in .NET Core.

@MichalStrehovsky
Copy link
Member

Could you attach project file(s) with a repro? It will make things easier.

@sakno
Copy link
Contributor Author

sakno commented Jul 19, 2019

I get a different result in the sandbox with simple solution containing .NET Standard library and Core App:

  1. It is allowed to declare method with parameter TypedReference*
  2. It is not allowed to call it using pointer to TypedReference.

CS057 error is produced by compiler:

CS0570	'TypedReferenceHelper.AsTypedReference<T>(ref T, ?)' is not supported by the language

I think this happening because my main project uses Fody Weaver to rewrite assembly and somehow deceives the compiler.

However, I went the other way and decided to resolve such method through Reflection. Voila, now the error is reproducible at runtime whenever compilation successful. A new error is

System.TypeLoadException: 'Could not load type 'System.TypedReference*' from assembly 'System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'.'

That's a root exception which causes MissingMethodException in my case. CLR type loader cannot recognize pointer to TypedReference.

Repro solution is attached to this post.
repro-demo.zip

@MichalStrehovsky
Copy link
Member

Thanks for the repro! This is reproducible even without the netstandard library. We just block type handles for TypedReference*. I'm not clear on why. I created a pull request that removes the blocking.

As for the C# compiler error you were seeing, I would bet a dollar that the assembly rewriting damaged the method signature in some way. It would be helpful if you could attach the assembly that has the problem.

@sakno
Copy link
Contributor Author

sakno commented Jul 22, 2019

Method signature is Ok, I checked it using ikdasm from Mono (ildasm alternative on Linux). Unfortunately, I removed the code from my assembly. However, it is possible to repeat it in pure IL or Fody InlineIL Weaver. IL assembler allows to declare pointer to TypedReference as well.

@msftgits msftgits transferred this issue from dotnet/coreclr Jan 31, 2020
@msftgits msftgits added this to the Future milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 12, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants