Merge pull request #2880 from kumpera/fix_5644
authormonojenkins <jo.shields+jenkins@xamarin.com>
Wed, 20 Apr 2016 22:50:38 +0000 (23:50 +0100)
committermonojenkins <jo.shields+jenkins@xamarin.com>
Wed, 20 Apr 2016 22:50:38 +0000 (23:50 +0100)
[verifier] Do method visibility checks for virtual final methods. Enable type visibility for all methods. Fixes #5644.

I cannot repro the issue mentioned in the comments of mono_method_can_access_method.

* FIXME:
* with generics calls to explicit interface implementations can be expressed
* directly: the method is private, but we must allow it. This may be opening
* a hole or the generics code should handle this differently.
* Maybe just ensure the interface type is public.

@monojenkins merge

mcs/class/corlib/Test/System/DelegateTest.cs
mono/metadata/class.c

index ae5a82908c861894674a758b8ba8496d5027da2a..e1d95dc93f00f563a4a7415708b3714d5a107a4f 100644 (file)
@@ -1251,7 +1251,7 @@ namespace MonoTests.System
                        }
                }
        
-               delegate int IntNoArgs ();
+               public delegate int IntNoArgs ();
 
                [Test]
                public void CreateDelegateWithAbstractMethods ()
index 17da478b5e9c1f089d76de0bc275da6ab5e21077..91d31b60cc5eece43d13deef99d9933319b734b9 100644 (file)
@@ -10017,6 +10017,8 @@ is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
        return FALSE;
 }
 
+static gboolean debug_check;
+
 MonoClass *
 mono_class_get_generic_type_definition (MonoClass *klass)
 {
@@ -10160,6 +10162,9 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass)
 {
        int access_level;
 
+       if (access_klass == member_klass)
+               return TRUE;
+
        if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
                return TRUE;
 
@@ -10308,26 +10313,15 @@ mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
 gboolean
 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
 {
-       int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
-       if (!can) {
-               MonoClass *nested = method->klass->nested_in;
-               while (nested) {
-                       can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
-                       if (can)
-                               return TRUE;
-                       nested = nested->nested_in;
-               }
+       gboolean res = mono_method_can_access_method_full (method, called, NULL);
+       if (!res) {
+               printf ("FAILED TO VERIFY %s calling %s\n", mono_method_full_name (method, 1), mono_method_full_name (called, 1));
+               debug_check = TRUE;
+               mono_method_can_access_method_full (method, called, NULL);
+               debug_check = FALSE;
        }
-       /* 
-        * FIXME:
-        * with generics calls to explicit interface implementations can be expressed
-        * directly: the method is private, but we must allow it. This may be opening
-        * a hole or the generics code should handle this differently.
-        * Maybe just ensure the interface type is public.
-        */
-       if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
-               return TRUE;
-       return can;
+
+       return res;
 }
 
 /*
@@ -10344,10 +10338,12 @@ mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
 gboolean
 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
 {
+       if (debug_check) printf ("CHECKING %s -> %s (%p)\n", mono_method_full_name (method, 1), mono_method_full_name (called, 1), context_klass);
        MonoClass *access_class = method->klass;
        MonoClass *member_class = called->klass;
        int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
        if (!can) {
+               if (debug_check) printf ("\tcan_access_member failed\n");
                MonoClass *nested = access_class->nested_in;
                while (nested) {
                        can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
@@ -10355,13 +10351,18 @@ mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, Mono
                                break;
                        nested = nested->nested_in;
                }
+               if (!can && debug_check) printf ("\tcan_access_member nest check failed\n");
        }
 
        if (!can)
                return FALSE;
 
+       if (debug_check) printf ("\ttype checking %s(%p) -> %s(%p)\n", 
+               mono_type_get_full_name (access_class), access_class,
+               mono_type_get_full_name (member_class), member_class);
        can = can_access_type (access_class, member_class);
        if (!can) {
+               if (debug_check) printf ("\tcan_access_type check failed\n");
                MonoClass *nested = access_class->nested_in;
                while (nested) {
                        can = can_access_type (nested, member_class);
@@ -10369,6 +10370,7 @@ mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, Mono
                                break;
                        nested = nested->nested_in;
                }
+               if (!can && debug_check) printf ("\tcan_access_type nest check failed\n");
        }
 
        if (!can)
@@ -10376,8 +10378,10 @@ mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, Mono
 
        if (called->is_inflated) {
                MonoMethodInflated * infl = (MonoMethodInflated*)called;
-               if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
+               if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst)) {
+                       if (debug_check) printf ("\tginst check failed\n");
                        return FALSE;
+               }
        }
                
        return TRUE;