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

[mono] UnsafeAccessor to a virtual method on a base class through a derived type asserts #89212

Closed
vitek-karas opened this issue Jul 19, 2023 · 13 comments

Comments

@vitek-karas
Copy link
Member

    class InheritanceBase
    {
        protected virtual string BaseVirtual() => $"{nameof(InheritanceBase)}.{nameof(BaseVirtual)}";
    }

    class InheritanceDerived : InheritanceBase
    {
    }

    [Fact]
    public static void Verify_InheritanceMethodResolution()
    {
        var instance = new InheritanceDerived();
        Assert.Equal($"{nameof(InheritanceBase)}.{nameof(BaseVirtual)}", BaseVirtual(instance));

        [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(BaseVirtual))]
        extern static string BaseVirtual(InheritanceDerived target);
    }

This fails with

* Assertion at F:\dotnet\runtime4\src\mono\mono\metadata\marshal-lightweight.c:2508, condition `target_method->klass == target_class' not met

@lambdageek - could you please route this to the right area/person

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 19, 2023
@vitek-karas
Copy link
Member Author

Actually this fails on NativeAOT as well (at runtime!):

System.MissingMethodException: Method not found: 'BaseVirtual'.
   at Internal.Runtime.TypeLoaderExceptionHelper.CreateMissingMethodException(ExceptionStringID, String) + 0x63
   at Internal.Runtime.CompilerHelpers.ThrowHelpers.ThrowMissingMethodException(ExceptionStringID, String) + 0x25
   at UnsafeAccessorsTests.<Verify_InheritanceMethodResolution_BaseViaDerived>g__BaseVirtual|33_0(UnsafeAccessorsTests.InheritanceDerived target) + 0x1f
   at UnsafeAccessorsTests.Verify_InheritanceMethodResolution_BaseViaDerived() + 0x4b

CoreCLR works and the same code without UnsafeAccessor:

var instance = new InheritanceDerived();
instance.BaseVirtual();

will also work (probably on all runtimes, although I didn't try that).

@AaronRobinsonMSFT @MichalStrehovsky what do you think - should this work?

@MichalStrehovsky
Copy link
Member

Well method BaseVirtual is not on InheritanceDerived so this is not expected to work.

This is what I brough up in #86932 (comment) and was rejected.

@AaronRobinsonMSFT AaronRobinsonMSFT added area-System.Runtime.CompilerServices untriaged New issue has not been triaged by the area owner and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jul 19, 2023
@AaronRobinsonMSFT
Copy link
Member

@vitek-karas If I update as following it works, right?

        [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(BaseVirtual))]
        extern static string BaseVirtual(InheritanceBase target);

If so, I don't see why one would declare this as InheritanceDerived, when the target method is defined on a different type. It isn't as if I can know about non-public methods by looking at a derived type. The first thing I would do would be to look at InheritanceDerived, not see a non-public method and be rather confused.

@AaronRobinsonMSFT AaronRobinsonMSFT removed the untriaged New issue has not been triaged by the area owner label Jul 19, 2023
@AaronRobinsonMSFT AaronRobinsonMSFT added this to the Future milestone Jul 19, 2023
@MichalStrehovsky
Copy link
Member

Does this work with CoreCLR?

@vitek-karas
Copy link
Member Author

Yes - it does work on CoreCLR.

@MichalStrehovsky
Copy link
Member

Yes - it does work on CoreCLR.

@AaronRobinsonMSFT I think this should be in 8.0. We need to either block this in CoreCLR, or fix in NativeAOT/Mono.

@AaronRobinsonMSFT AaronRobinsonMSFT modified the milestones: Future, 8.0.0 Jul 19, 2023
@MichalStrehovsky
Copy link
Member

Btw, I think the CoreCLR behavior is the correct one

@vitek-karas
Copy link
Member Author

Personally I agree with Michal's comment in the other issue that this "should" work. That said I'd be fine if we said that we don't want this to work. But then all runtimes should behave consistently.
Especially differences between CoreCLR and NativeAOT are dangerous (since we promise that AOTed apps behave the same as non-AOTed app)

@AaronRobinsonMSFT
Copy link
Member

Personally I agree with Michal's comment in the other issue that this "should" work.

What needs to happen then in NativeAOT? Based on some offline conversations with @fanyang-mono, I believe she is looking into enabling it on mono.

@MichalStrehovsky
Copy link
Member

What needs to happen then in NativeAOT?

We'd walk into the base type, like we do when resolving a MemberRef:

// Try to resolve the name and signature in the current type, or any of the base types.

(I assume it matches what CoreCLR does in the UnsafeAccessor case too.)

@AaronRobinsonMSFT
Copy link
Member

(I assume it matches what CoreCLR does in the UnsafeAccessor case too.)

Yep. I just used the MethodIterator. Seems like it does that under the covers but it wasn't obvious.

@lambdageek
Copy link
Member

I think the work in Mono is just to replace the assert that the target class is equal to the method's class by a check that the target class is assignable to the method's class.

@fanyang-mono
Copy link
Member

This has been resolved via #89217.

@ghost ghost locked as resolved and limited conversation to collaborators Aug 24, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants