Fri Sep 14 14:04:31 CEST 2007 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / class.c
index abe75cd9ecebd06b9aa51879525b310ea24791e9..c927d3fb8bc2147d8c83c4470e60249909342a6f 100644 (file)
@@ -18,7 +18,6 @@
 #endif
 #include <mono/metadata/image.h>
 #include <mono/metadata/assembly.h>
-#include <mono/metadata/cil-coff.h>
 #include <mono/metadata/metadata.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/tabledefs.h>
@@ -31,6 +30,8 @@
 #include <mono/metadata/reflection.h>
 #include <mono/metadata/exception.h>
 #include <mono/metadata/security-manager.h>
+#include <mono/metadata/security-core-clr.h>
+#include <mono/metadata/attrdefs.h>
 #include <mono/os/gc_wrapper.h>
 #include <mono/utils/mono-counters.h>
 
@@ -186,6 +187,13 @@ _mono_type_get_assembly_name (MonoClass *klass, GString *str)
                ta->aname.public_key_token [0] ? (char *)ta->aname.public_key_token : "null");
 }
 
+static inline void
+mono_type_name_check_byref (MonoType *type, GString *str)
+{
+       if (type->byref)
+               g_string_append_c (str, '&');
+}
+
 static void
 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                            MonoTypeNameFormat format)
@@ -208,6 +216,9 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                for (i = 1; i < rank; i++)
                        g_string_append_c (str, ',');
                g_string_append_c (str, ']');
+               
+               mono_type_name_check_byref (type, str);
+
                if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
                        _mono_type_get_assembly_name (type->data.array->eklass, str);
                break;
@@ -221,6 +232,9 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                mono_type_get_name_recurse (
                        &type->data.klass->byval_arg, str, FALSE, nested_format);
                g_string_append (str, "[]");
+               
+               mono_type_name_check_byref (type, str);
+
                if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
                        _mono_type_get_assembly_name (type->data.klass, str);
                break;
@@ -234,6 +248,9 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                mono_type_get_name_recurse (
                        type->data.type, str, FALSE, nested_format);
                g_string_append_c (str, '*');
+
+               mono_type_name_check_byref (type, str);
+
                if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
                        _mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
                break;
@@ -242,6 +259,9 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
        case MONO_TYPE_MVAR:
                g_assert (type->data.generic_param->name);
                g_string_append (str, type->data.generic_param->name);
+       
+               mono_type_name_check_byref (type, str);
+
                break;
        default:
                klass = mono_class_from_mono_type (type);
@@ -314,6 +334,9 @@ mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
                        else
                                g_string_append_c (str, ']');
                }
+
+               mono_type_name_check_byref (type, str);
+
                if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
                    (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
                        _mono_type_get_assembly_name (klass, str);
@@ -349,9 +372,6 @@ mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
 
        mono_type_get_name_recurse (type, result, FALSE, format);
 
-       if (type->byref)
-               g_string_append_c (result, '&');
-
        return g_string_free (result, FALSE);
 }
 
@@ -1181,15 +1201,18 @@ mono_class_layout_fields (MonoClass *class)
                break;
        }
 
+#if NO_UNALIGNED_ACCESS
        if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
                /*
                 * For small structs, set min_align to at least the struct size, since the
                 * JIT memset/memcpy code assumes this and generates unaligned accesses
                 * otherwise. See #78990 for a testcase.
+                * FIXME: Fix the memset/memcpy code instead.
                 */
                if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer))
                        class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject));
        }
+#endif
 
        class->size_inited = 1;
 
@@ -1864,6 +1887,18 @@ mono_class_setup_vtable (MonoClass *class)
        return;
 }
 
+static void
+check_core_clr_override_method (MonoClass *class, MonoMethod *override, MonoMethod *base)
+{
+       MonoSecurityCoreCLRLevel override_level = mono_security_core_clr_method_level (override, FALSE);
+       MonoSecurityCoreCLRLevel base_level = mono_security_core_clr_method_level (base, FALSE);
+
+       if (override_level != base_level && base_level == MONO_SECURITY_CORE_CLR_CRITICAL) {
+               class->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+               class->exception_data = NULL;
+       }
+}
+
 /*
  * LOCKING: this is supposed to be called with the loader lock held.
  */
@@ -1923,6 +1958,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
                        g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
+
+                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                               check_core_clr_override_method (class, vtable [dslot], decl);
                }
        }
 
@@ -1973,6 +2011,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                                mono_secman_inheritancedemand_method (cm, im);
                                                        }
 
+                                                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                                                               check_core_clr_override_method (class, cm, im);
+
                                                        g_assert (io + l <= max_vtsize);
                                                        vtable [io + l] = cm;
                                                }
@@ -2023,6 +2064,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                                mono_secman_inheritancedemand_method (cm, im);
                                                        }
 
+                                                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                                                               check_core_clr_override_method (class, cm, im);
+
                                                        g_assert (io + l <= max_vtsize);
                                                        vtable [io + l] = cm;
                                                        break;
@@ -2060,6 +2104,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                                mono_secman_inheritancedemand_method (cm, im);
                                                        }
 
+                                                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                                                               check_core_clr_override_method (class, cm, im);
+
                                                        g_assert (io + l <= max_vtsize);
                                                        vtable [io + l] = cm;
                                                        break;
@@ -2184,6 +2231,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                        mono_secman_inheritancedemand_method (cm, m1);
                                                }
 
+                                               if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                                                       check_core_clr_override_method (class, cm, m1);
+
                                                slot = k->methods [j]->slot;
                                                g_assert (cm->slot < max_vtsize);
                                                if (!override_map)
@@ -2216,6 +2266,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                        if (!override_map)
                                override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
                        g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
+
+                       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+                               check_core_clr_override_method (class, vtable [decl->slot], decl);
                }
        }
 
@@ -2455,6 +2508,24 @@ set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error)
        }
 }
 
+static void
+check_core_clr_inheritance (MonoClass *class)
+{
+       MonoSecurityCoreCLRLevel class_level, parent_level;
+       MonoClass *parent = class->parent;
+
+       if (!parent)
+               return;
+
+       class_level = mono_security_core_clr_class_level (class);
+       parent_level = mono_security_core_clr_class_level (parent);
+
+       if (class_level < parent_level) {
+               class->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+               class->exception_data = NULL;
+       }
+}
+
 /**
  * mono_class_init:
  * @class: the class to initialize
@@ -2504,6 +2575,9 @@ mono_class_init (MonoClass *class)
                mono_secman_inheritancedemand_class (class, class->parent);
        }
 
+       if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+               check_core_clr_inheritance (class);
+
        if (mono_debugger_start_class_init_func)
                mono_debugger_start_class_init_func (class);
 
@@ -3499,7 +3573,7 @@ mono_class_from_mono_type (MonoType *type)
  * @type_spec:  typespec token
  * @context: the generic context used to evaluate generic instantiations in
  */
-static MonoClass *
+static MonoType *
 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
 {
        MonoType *t = mono_type_create_from_typespec (image, type_spec);
@@ -4076,7 +4150,7 @@ mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *c
        MonoClass *class = NULL;
 
        if (image->dynamic)
-               return mono_lookup_dynamic_token (image, type_token);
+               return mono_lookup_dynamic_token (image, type_token, context);
 
        switch (type_token & 0xff000000){
        case MONO_TOKEN_TYPE_DEF:
@@ -4120,7 +4194,7 @@ mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *co
 
        //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
        if (image->dynamic)
-               return mono_class_get_type (mono_lookup_dynamic_token (image, type_token));
+               return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context));
 
        if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
                MonoClass *class = mono_class_get_full (image, type_token, context);
@@ -4477,6 +4551,24 @@ mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
        return FALSE;
 }
 
+static gboolean
+mono_class_has_variant_generic_params (MonoClass *klass)
+{
+       int i;
+       MonoGenericContainer *container;
+
+       if (!klass->generic_class)
+               return FALSE;
+
+       container = klass->generic_class->container_class->generic_container;
+
+       for (i = 0; i < container->type_argc; ++i)
+               if (container->type_params [i].flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
+                       return TRUE;
+
+       return FALSE;
+}
+
 gboolean
 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
 {
@@ -4503,6 +4595,52 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
 
                if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
                        return TRUE;
+
+               if (mono_class_has_variant_generic_params (klass)) {
+                       if (oklass->generic_class) {
+                               int i;
+                               gboolean match = FALSE;
+                               MonoClass *container_class1 = klass->generic_class->container_class;
+                               MonoClass *container_class2 = oklass->generic_class->container_class;
+
+                               /* 
+                                * Check whenever the generic definition of oklass implements the 
+                                * generic definition of klass. The IMPLEMENTS_INTERFACE stuff is not usable
+                                * here since the relevant tables are not set up.
+                                */
+                               for (i = 0; i < container_class2->interface_offsets_count; ++i)
+                                       if ((container_class2->interfaces_packed [i] == container_class1) || (container_class2->interfaces_packed [i]->generic_class && (container_class2->interfaces_packed [i]->generic_class->container_class == container_class1)))
+                                               match = TRUE;
+
+                               if (match) {
+                                       MonoGenericContainer *container;
+
+                                       container = klass->generic_class->container_class->generic_container;
+
+                                       match = TRUE;
+                                       for (i = 0; i < container->type_argc; ++i) {
+                                               MonoClass *param1_class = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [i]);
+                                               MonoClass *param2_class = mono_class_from_mono_type (oklass->generic_class->context.class_inst->type_argv [i]);
+
+                                               /*
+                                                * The _VARIANT and _COVARIANT constants should read _COVARIANT and
+                                                * _CONTRAVARIANT, but they are in a public header so we can't fix it.
+                                                */
+                                               if (param1_class != param2_class) {
+                                                       if ((container->type_params [i].flags & MONO_GEN_PARAM_VARIANT) && mono_class_is_assignable_from (param1_class, param2_class))
+                                                               ;
+                                                       else if (((container->type_params [i].flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
+                                                               ;
+                                                       else
+                                                               match = FALSE;
+                                               }
+                                       }
+
+                                       if (match)
+                                               return TRUE;
+                               }
+                       }
+               }
        } else if (klass->rank) {
                MonoClass *eclass, *eoclass;
 
@@ -4673,7 +4811,7 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
 {
        if (image->dynamic) {
                MonoClass *tmp_handle_class;
-               gpointer obj = mono_lookup_dynamic_token_class (image, token, &tmp_handle_class);
+               gpointer obj = mono_lookup_dynamic_token_class (image, token, &tmp_handle_class, context);
 
                g_assert (tmp_handle_class);
                if (handle_class)
@@ -4758,17 +4896,17 @@ mono_install_lookup_dynamic_token (MonoLookupDynamicToken func)
 }
 
 gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token)
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
 {
        MonoClass *handle_class;
 
-       return lookup_dynamic (image, token, &handle_class);
+       return lookup_dynamic (image, token, &handle_class, context);
 }
 
 gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class, MonoGenericContext *context)
 {
-       return lookup_dynamic (image, token, handle_class);
+       return lookup_dynamic (image, token, handle_class, context);
 }
 
 static MonoGetCachedClassInfo get_cached_class_info = NULL;
@@ -5673,14 +5811,31 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
        return FALSE;
 }
 
+/*
+ * If klass is a generic type or if it is derived from a generic type, return the
+ * MonoClass of the generic definition
+ * Returns NULL if not found
+ */
+static MonoClass*
+get_generic_definition_class (MonoClass *klass)
+{
+       while (klass) {
+               if (klass->generic_class && klass->generic_class->container_class)
+                       return klass->generic_class->container_class;
+               klass = klass->parent;
+       }
+       return NULL;
+}
+
 /* FIXME: check visibility of type, too */
 static gboolean
 can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
 {
-       if (access_klass->generic_class && member_klass->generic_class &&
-           access_klass->generic_class->container_class && member_klass->generic_class->container_class) {
+       MonoClass *member_generic_def;
+       if (access_klass->generic_class && access_klass->generic_class->container_class && 
+                       (member_generic_def = get_generic_definition_class (member_klass))) {
                if (can_access_member (access_klass->generic_class->container_class,
-                                      member_klass->generic_class->container_class, access_level))
+                                      member_generic_def, access_level))
                        return TRUE;
        }