[reflection] Set correct reflected type in MonoMethod.get_base_method
authorAleksey Kliger <aleksey@xamarin.com>
Wed, 22 Mar 2017 19:08:59 +0000 (15:08 -0400)
committerAleksey Kliger (λgeek) <akliger@gmail.com>
Thu, 23 Mar 2017 14:31:53 +0000 (10:31 -0400)
It can be the case that we have two different System.MonoMethod objects that both
point to the same native MonoMethod* but have two different reflected types.
(For example if we call derivedType.GetMethod("f") where f is virtual and
derivedType corresponds to a class that did not override a base definition.  In
that case, the MonoMethod* corresponds to the parent type's f method, but the
reflected type is derivedType)

In this case, GetBaseDefinition will return the same MonoMethod* but the
reflected type of the result should be the base type, not the derived type.

mono/metadata/icall.c

index 2f3b7f7f27fc1a5dec9a8c1d2adb5193ed908486..9e82d04380846297cadfd2550f81f44face86260 100644 (file)
@@ -7285,10 +7285,20 @@ ves_icall_MonoMethod_get_base_method (MonoReflectionMethodHandle m, gboolean def
 
        MonoMethod *base = mono_method_get_base_method (method, definition, error);
        return_val_if_nok (error, MONO_HANDLE_CAST (MonoReflectionMethod, NULL_HANDLE));
-       if (base == method)
-               return m;
-       else
-               return mono_method_get_object_handle (mono_domain_get (), base, NULL, error);
+       if (base == method) {
+               /* we want to short-circuit and return 'm' here. But we should
+                  return the same method object that
+                  mono_method_get_object_handle, below would return.  Since
+                  that call takes NULL for the reftype argument, it will take
+                  base->klass as the reflected type for the MonoMethod.  So we
+                  need to check that m also has base->klass as the reflected
+                  type. */
+               MonoReflectionTypeHandle orig_reftype = MONO_HANDLE_NEW_GET (MonoReflectionType, m, reftype);
+               MonoClass *orig_klass = mono_class_from_mono_type (MONO_HANDLE_GETVAL (orig_reftype, type));
+               if (base->klass == orig_klass)
+                       return m;
+       }
+       return mono_method_get_object_handle (mono_domain_get (), base, NULL, error);
 }
 
 ICALL_EXPORT MonoStringHandle