merge 99244:99306
authorJb Evain <jbevain@gmail.com>
Sat, 29 Mar 2008 20:43:06 +0000 (20:43 -0000)
committerJb Evain <jbevain@gmail.com>
Sat, 29 Mar 2008 20:43:06 +0000 (20:43 -0000)
svn path=/branches/jb/ml2/mono/; revision=99307

mono/metadata/ChangeLog
mono/metadata/class-internals.h
mono/metadata/class.c
mono/metadata/mono-config.h
mono/metadata/verify.c
mono/utils/ChangeLog
mono/utils/mono-logger.h

index d17483252f1e09253b71ef9d9a47e2fd41017c36..c28fd8fbde9c717a604c646704e0f6e9ee4330f6 100644 (file)
@@ -1,3 +1,17 @@
+2008-03-29 Rodrigo Kumpera  <rkumpera@novell.com>
+
+       * class.c: New functions mono_method_can_access_field_full and
+       mono_method_can_access_method_full. They perform type visibility
+       and type site check.
+
+       * class-internal.h: Added exported functions.
+
+       * verify.c: Use new functions to implement proper visibility checks.
+
+2008-03-29  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-config.h: Add missing G_BEGIN_DECLS/G_END_DECLS. Fixes #375188.
+
 2008-03-28  Dick Porter  <dick@ximian.com>
 
        * process.c (process_get_fileversion): Use the first language ID
index 8ba1f1d5ff67a6a70c679f9a95635b450b6f321c..b82a09209a8769410415e3edb9f043931ee8905e 100644 (file)
@@ -995,4 +995,10 @@ mono_class_unregister_image_generic_subclasses (MonoImage *image) MONO_INTERNAL;
 void
 mono_class_unregister_domain_generic_vtables (MonoDomain *domain) MONO_INTERNAL;
 
+gboolean
+mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass) MONO_INTERNAL;
+
+gboolean
+mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass) MONO_INTERNAL;
+
 #endif /* __MONO_METADATA_CLASS_INTERBALS_H__ */
index d1fad0b76670fc6fba0a7a494e3484c2b93aef96..2cd4c838425e982bd4a098fd86a529d80ae03536 100644 (file)
@@ -6628,6 +6628,46 @@ mono_class_get_exception_for_failure (MonoClass *klass)
        }
 }
 
+static gboolean
+is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
+ {
+       do {
+               if (outer_klass == inner_klass)
+                       return TRUE;
+               inner_klass = inner_klass->nested_in;
+       } while (inner_klass);
+       return FALSE;
+}
+
+/*
+ * Subtype can only access parent members with family protection if the site object
+ * is subclass of Subtype. For example:
+ * class A { protected int x; }
+ * class B : A {
+ *     void valid_access () {
+ *             B b;
+ *             b.x = 0;
+ *  }
+ *  void invalid_access () {
+ *             A a;
+ *             a.x = 0;
+ *  }
+ * }
+ * */
+static gboolean
+is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
+{
+       if (!mono_class_has_parent (access_klass, member_klass))
+               return FALSE;
+
+       if (context_klass == NULL)
+               return TRUE;
+       /*if access_klass is not member_klass context_klass must be type compat*/
+       if (access_klass != member_klass && !mono_class_has_parent (context_klass, access_klass))
+               return FALSE;
+       return TRUE;
+}
+
 static gboolean
 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
 {
@@ -6670,9 +6710,50 @@ get_generic_definition_class (MonoClass *klass)
        return NULL;
 }
 
+static gboolean
+can_access_type (MonoClass *access_klass, MonoClass *member_klass)
+{
+       int access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+
+       if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
+               return TRUE;
+
+       if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
+               return FALSE;
+
+       switch (access_level) {
+       case TYPE_ATTRIBUTE_NOT_PUBLIC:
+               return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+
+       case TYPE_ATTRIBUTE_PUBLIC:
+               return TRUE;
+
+       case TYPE_ATTRIBUTE_NESTED_PUBLIC:
+               return TRUE;
+
+       case TYPE_ATTRIBUTE_NESTED_PRIVATE:
+               return is_nesting_type (member_klass, access_klass);
+
+       case TYPE_ATTRIBUTE_NESTED_FAMILY:
+               return mono_class_has_parent (access_klass, member_klass->nested_in); 
+
+       case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
+               return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+
+       case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
+               return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
+                       mono_class_has_parent (access_klass, member_klass->nested_in);
+
+       case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
+               return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
+                       mono_class_has_parent (access_klass, member_klass->nested_in);
+       }
+       return FALSE;
+}
+
 /* FIXME: check visibility of type, too */
 static gboolean
-can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
+can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
 {
        MonoClass *member_generic_def;
        if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
@@ -6685,7 +6766,7 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_
                else
                        access_container = access_klass->generic_class->container_class;
 
-               if (can_access_member (access_container, member_generic_def, access_level))
+               if (can_access_member (access_container, member_generic_def, context_klass, access_level))
                        return TRUE;
        }
 
@@ -6698,18 +6779,18 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_
        case FIELD_ATTRIBUTE_PRIVATE:
                return access_klass == member_klass;
        case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
-               if (mono_class_has_parent (access_klass, member_klass) &&
+               if (is_valid_family_access (access_klass, member_klass, context_klass) &&
                    can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
                        return TRUE;
                return FALSE;
        case FIELD_ATTRIBUTE_ASSEMBLY:
                return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
        case FIELD_ATTRIBUTE_FAMILY:
-               if (mono_class_has_parent (access_klass, member_klass))
+               if (is_valid_family_access (access_klass, member_klass, context_klass))
                        return TRUE;
                return FALSE;
        case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
-               if (mono_class_has_parent (access_klass, member_klass))
+               if (is_valid_family_access (access_klass, member_klass, context_klass))
                        return TRUE;
                return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
        case FIELD_ATTRIBUTE_PUBLIC:
@@ -6722,11 +6803,11 @@ gboolean
 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
 {
        /* FIXME: check all overlapping fields */
-       int can = can_access_member (method->klass, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+       int can = can_access_member (method->klass, field->parent, NULL, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
        if (!can) {
                MonoClass *nested = method->klass->nested_in;
                while (nested) {
-                       can = can_access_member (nested, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+                       can = can_access_member (nested, field->parent, NULL, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
                        if (can)
                                return TRUE;
                        nested = nested->nested_in;
@@ -6738,11 +6819,11 @@ 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, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+       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, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+                       can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
                        if (can)
                                return TRUE;
                        nested = nested->nested_in;
@@ -6760,6 +6841,78 @@ mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
        return can;
 }
 
+/*
+ * mono_method_can_access_method_with_context:
+ * @method: The caller method 
+ * @called: The called method 
+ * @context_klass:TThe static type on stack of the owner @called object used
+ * 
+ * This function must be used with instance calls, as they have more strict family accessibility.
+ * It can be used with static mehthod, but context_klass should be NULL.
+ * 
+ * Returns: TRUE if caller have proper visibility and acessibility to @called
+ */
+gboolean
+mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *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) {
+               MonoClass *nested = access_class->nested_in;
+               while (nested) {
+                       can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+                       if (can)
+                               return TRUE;
+                       nested = nested->nested_in;
+               }
+       }
+
+       if (!can)
+               return FALSE;
+
+       if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class)))
+               return FALSE;
+       return TRUE;
+}
+
+
+/*
+ * mono_method_can_access_method_with_context:
+ * @method: The caller method 
+ * @field: The accessed field
+ * @context_klass: The static type on stack of the owner @field object used
+ * 
+ * This function must be used with instance fields, as they have more strict family accessibility.
+ * It can be used with static fields, but context_klass should be NULL.
+ * 
+ * Returns: TRUE if caller have proper visibility and acessibility to @field
+ */
+gboolean
+mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
+{
+       MonoClass *access_class = method->klass;
+       MonoClass *member_class = field->parent;
+       /* FIXME: check all overlapping fields */
+       int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+       if (!can) {
+               MonoClass *nested = access_class->nested_in;
+               while (nested) {
+                       can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+                       if (can)
+                               return TRUE;
+                       nested = nested->nested_in;
+               }
+       }
+
+       if (!can)
+               return FALSE;
+
+       if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class)))
+               return FALSE;
+       return TRUE;
+}
+
 /**
  * mono_type_is_valid_enum_basetype:
  * @type: The MonoType to check
index 0b104ad117464a7f0d4ffdd2431cce247ef35f9c..d8f76aafcf41e7b2a9686903cc40d4e1567f0b72 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __MONO_METADATA_CONFIG_H__
 #define __MONO_METADATA_CONFIG_H__
 
+G_BEGIN_DECLS
+
 const char* mono_get_config_dir (void);
 void        mono_set_config_dir (const char *dir);
 
@@ -19,5 +21,7 @@ void mono_config_parse_memory (const char *buffer);
 
 const char* mono_config_string_for_assembly_file (const char *filename);
 
+G_END_DECLS
+
 #endif /* __MONO_METADATA_CONFIG_H__ */
 
index 141865246037f53954ed4fe0328bc630bfc0e283..59c96c7d2b18bd679a4b2e7d30c2ace8ec568afb 100644 (file)
@@ -2734,9 +2734,11 @@ do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual)
                }
                if (!verify_stack_type_compatibility (ctx, type, &copy))
                        CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature at 0x%04x", ctx->ip_offset));
-       }
 
-       if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method (ctx->method, method))
+               if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, value->type->data.klass))
+                       CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
+
+       } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
                CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
 
        if (sig->ret->type != MONO_TYPE_VOID) {
@@ -2769,7 +2771,7 @@ do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
                !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
                CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
 
-       if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+       if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
                CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
 
        set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
@@ -2799,7 +2801,7 @@ do_store_static_field (VerifyContext *ctx, int token) {
                return;
        }
 
-       if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+       if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
                CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
 
        if (!verify_stack_type_compatibility (ctx, field->type, value))
@@ -2813,7 +2815,7 @@ check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *o
        MonoClass *klass;
 
        /*must be one of: complex type, managed pointer (to complex type), unmanaged pointer (native int) or an instance of a value type */
-       if (!( stack_slot_get_underlying_type (obj) == TYPE_COMPLEX
+       if (!(stack_slot_get_underlying_type (obj) == TYPE_COMPLEX
                || stack_slot_get_type (obj) == TYPE_NATIVE_INT
                || stack_slot_get_type (obj) == TYPE_PTR)) {
                CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument %s to load field at 0x%04x", stack_slot_get_name (obj), ctx->ip_offset));
@@ -2844,11 +2846,9 @@ check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *o
                if (!stack_slot_is_null_literal (obj) && !verify_type_compatibility (ctx, &field->parent->byval_arg, mono_type_get_type_byval (obj->type)))
                        CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not compatible to reference the field at 0x%04x", ctx->ip_offset));
 
-               if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+               if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, obj->type->data.klass))
                        CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
-       }
-
-       if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+       } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
                CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
 
        if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
@@ -3189,7 +3189,7 @@ do_newobj (VerifyContext *ctx, int token)
        if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
                CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
 
-       if (!mono_method_can_access_method (ctx->method, method))
+       if (!mono_method_can_access_method_full (ctx->method, method, NULL))
                CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Constructor not visible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
 
        //FIXME use mono_method_get_signature_full
@@ -3711,7 +3711,7 @@ do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual)
                        CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
        }
        
-       if (!mono_method_can_access_method (ctx->method, method))
+       if (!mono_method_can_access_method_full (ctx->method, method, NULL))
                CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Loaded method is not visible for ldftn/ldvirtftn at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
 
        top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
index 95fc24d3862279a2b1cd426260f73e5e120e0245..fcef8b1417fe141d8b96a5ddd4e0c5d77ef8be58 100644 (file)
@@ -1,3 +1,6 @@
+2008-03-29  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-logger.h: Move G_END_DECLS outside of an #ifdef. Fixes #375107.
 
 2008-03-14  Robert Jordan  <robertj@gmx.net>
 
index 6cb56d27b91c5792548b672b4d20435a80091b34..8fe47fda7caf3485e78691db16f01a5af1bcaa94 100644 (file)
@@ -92,8 +92,8 @@ mono_trace_message(MonoTraceMask mask, const char *format, ...)
        va_end (args);
 }
 
-G_END_DECLS
-
 #endif /* !__GNUC__ */
 
+G_END_DECLS
+
 #endif /* __MONO_LOGGER_H__ */