Bug 53690 - MethodInfo returned by GetRuntimeInterfaceMap(...).TargetMethods not equal to MethodInfo returned by GetMethod
Summary: MethodInfo returned by GetRuntimeInterfaceMap(...).TargetMethods not equal to...
Status: RESOLVED FIXED
Alias: None
Product: Runtime
Classification: Mono
Component: Reflection ()
Version: 4.8.0 (C9)
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Aleksey Kliger
URL:
Depends on:
Blocks:
 
Reported: 2017-03-22 05:25 UTC by Daniel Lo Nigro
Modified: 2017-03-23 14:40 UTC (History)
3 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Repro code (1.31 KB, text/plain)
2017-03-22 05:25 UTC, Daniel Lo Nigro
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Daniel Lo Nigro 2017-03-22 05:25:36 UTC
Created attachment 20542 [details]
Repro code

Description of Problem:
ASP.NET Core MVC uses this snippet of code to filter out IDisposable's "Dispose" method from URL routing (https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultApplicationModelProvider.cs#L630):

        private bool IsIDisposableMethod(MethodInfo methodInfo)
        {
            // Ideally we do not want Dispose method to be exposed as an action. However there are some scenarios where a user
            // might want to expose a method with name "Dispose" (even though they might not be really disposing resources)
            // Example: A controller deriving from MVC's Controller type might wish to have a method with name Dispose,
            // in which case they can use the "new" keyword to hide the base controller's declaration.

            // Find where the method was originally declared
            var baseMethodInfo = methodInfo.GetBaseDefinition();
            var declaringTypeInfo = baseMethodInfo.DeclaringType.GetTypeInfo();

            return
                (typeof(IDisposable).GetTypeInfo().IsAssignableFrom(declaringTypeInfo) &&
                 declaringTypeInfo.GetRuntimeInterfaceMap(typeof(IDisposable)).TargetMethods[0] == baseMethodInfo);
        }


However, this check is not working correctly in Mono. The error seems to be that the MethodInfo returned by GetRuntimeInterfaceMap(typeof(IDisposable)).TargetMethods[0] is different to the MethodInfo returned by GetMethod, even though they point to the same method.


Steps to reproduce the problem:
See attached code "DisposableTest.cs" for a repro case


Actual Results:
Output after running the attached code on Mono:
Regular class:
IsAssignableFrom: True
TargetMethod is equal (==): True
TargetMethod is equal (Equals): True
baseMethodInfo: Void Dispose() attribs=ReuseSlot, Public, Final, Virtual, HideBySig, NewSlot
targetMethod:   Void Dispose() attribs=ReuseSlot, Public, Final, Virtual, HideBySig, NewSlot

Inheritance:
IsAssignableFrom: True
TargetMethod is equal (==): False
TargetMethod is equal (Equals): False
baseMethodInfo: Void Dispose() attribs=ReuseSlot, Public, Final, Virtual, HideBySig, NewSlot
targetMethod:   Void Dispose() attribs=ReuseSlot, Public, Final, Virtual, HideBySig, NewSlot


Notice "TargetMethod is equal (==): False"

Expected Results:
Output after running the attached test case on Windows:
Regular class:
IsAssignableFrom: True
TargetMethod is equal (==): True
TargetMethod is equal (Equals): True
baseMethodInfo: Void Dispose() attribs=PrivateScope, Public, Final, Virtual, HideBySig, VtableLayoutMask
targetMethod:   Void Dispose() attribs=PrivateScope, Public, Final, Virtual, HideBySig, VtableLayoutMask

Inheritance:
IsAssignableFrom: True
TargetMethod is equal (==): True
TargetMethod is equal (Equals): True
baseMethodInfo: Void Dispose() attribs=PrivateScope, Public, Final, Virtual, HideBySig, VtableLayoutMask
targetMethod:   Void Dispose() attribs=PrivateScope, Public, Final, Virtual, HideBySig, VtableLayoutMask

Notice "TargetMethod is equal (==): True"

How often does this happen? 
Consistently
Comment 1 Aleksey Kliger 2017-03-22 15:35:56 UTC
In the repro code, in the "inheritance" case, the baseMethodInfo.ReflectedType is "Bar" but firstTargetMethod.ReflectedType is "Foo" on Mono.

On .NET Framework, we get "Foo" for DeclaringType and ReflectedType in all cases.