X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=717f93c7b8ce1558c4944335b1099534e26f6e34;hb=3144c62025db782c6e2d72615c41a5c294a0ee67;hp=3989e7ac134f582577d32c0e2842957a42ae5288;hpb=1005b511507e5f508a090d57c59542717c029eda;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index 3989e7ac134..717f93c7b8c 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include MonoStats mono_stats; @@ -491,8 +493,10 @@ mono_class_is_open_constructed_type (MonoType *t) } static MonoType* -inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context) +inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error) { + mono_error_init (error); + switch (type->type) { case MONO_TYPE_MVAR: { MonoType *nt; @@ -502,8 +506,9 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont return NULL; if (num >= inst->type_argc) { MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param); - g_error ("MVAR %d (%s) cannot be expanded in this context with %d instantiations", + mono_error_set_bad_image (error, image->module_name, "MVAR %d (%s) cannot be expanded in this context with %d instantiations", num, info ? info->name : "", inst->type_argc); + return NULL; } /* @@ -524,8 +529,9 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont return NULL; if (num >= inst->type_argc) { MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param); - g_error ("VAR %d (%s) cannot be expanded in this context with %d instantiations", + mono_error_set_bad_image (error, image->module_name, "VAR %d (%s) cannot be expanded in this context with %d instantiations", num, info ? info->name : "", inst->type_argc); + return NULL; } nt = mono_metadata_type_dup (image, inst->type_argv [num]); nt->byref = type->byref; @@ -534,8 +540,8 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont } case MONO_TYPE_SZARRAY: { MonoClass *eclass = type->data.klass; - MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context); - if (!inflated) + MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error); + if (!inflated || !mono_error_ok (error)) return NULL; nt = mono_metadata_type_dup (image, type); nt->data.klass = mono_class_from_mono_type (inflated); @@ -544,8 +550,8 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont } case MONO_TYPE_ARRAY: { MonoClass *eclass = type->data.array->eklass; - MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context); - if (!inflated) + MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error); + if (!inflated || !mono_error_ok (error)) return NULL; nt = mono_metadata_type_dup (image, type); nt->data.array = g_memdup (nt->data.array, sizeof (MonoArrayType)); @@ -643,6 +649,7 @@ mono_class_get_generic_class (MonoClass *klass) * @mempool: a mempool * @type: a type * @context: a generics context + * @error: error context * * The same as mono_class_inflate_generic_type, but allocates the MonoType * from mempool if it is non-NULL. If it is NULL, the MonoType is @@ -651,12 +658,15 @@ mono_class_get_generic_class (MonoClass *klass) * modified by the caller, and it should be freed using mono_metadata_free_type (). */ MonoType* -mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context) +mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error) { - MonoType *inflated = NULL; + MonoType *inflated = NULL; + mono_error_init (error); if (context) - inflated = inflate_generic_type (image, type, context); + inflated = inflate_generic_type (image, type, context, error); + if (!mono_error_ok (error)) + return NULL; if (!inflated) { MonoType *shared = mono_metadata_get_shared_type (type); @@ -681,12 +691,40 @@ mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, * generics context @context. * * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated - * on the heap and is owned by the caller. + * on the heap and is owned by the caller. Returns NULL on error. + * + * @deprecated Please use mono_class_inflate_generic_type_checked instead */ MonoType* mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context) { - return mono_class_inflate_generic_type_with_mempool (NULL, type, context); + MonoError error; + MonoType *result; + result = mono_class_inflate_generic_type_checked (type, context, &error); + + if (!mono_error_ok (&error)) { + mono_error_cleanup (&error); + return NULL; + } + return result; +} + +/* + * mono_class_inflate_generic_type: + * @type: a type + * @context: a generics context + * @error: error context to use + * + * If @type is a generic type and @context is not NULL, instantiate it using the + * generics context @context. + * + * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated + * on the heap and is owned by the caller. + */ +MonoType* +mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error) +{ + return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error); } /* @@ -698,10 +736,13 @@ mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context) static MonoType* mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context) { + MonoError error; MonoType *inflated = NULL; - if (context) - inflated = inflate_generic_type (image, type, context); + if (context) { + inflated = inflate_generic_type (image, type, context, &error); + g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/ + } if (!inflated) return type; @@ -718,10 +759,12 @@ mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoG MonoClass* mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context) { + MonoError error; MonoClass *res; MonoType *inflated; - inflated = mono_class_inflate_generic_type (&gklass->byval_arg, context); + inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, &error); + g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/ res = mono_class_from_mono_type (inflated); mono_metadata_free_type (inflated); @@ -891,7 +934,11 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin result->klass = klass_hint; if (!result->klass) { - MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context); + MonoError error; + MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, &error); + + g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/ + result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass; if (inflated) mono_metadata_free_type (inflated); @@ -1071,7 +1118,7 @@ mono_class_setup_fields (MonoClass *class) gboolean explicit_size; MonoClassField *field; MonoGenericContainer *container = NULL; - MonoClass *gklass = NULL; + MonoClass *gtd = class->generic_class ? mono_class_get_generic_type_definition (class) : NULL; if (class->size_inited) return; @@ -1086,12 +1133,16 @@ mono_class_setup_fields (MonoClass *class) return; } - if (class->generic_class) { - MonoClass *gklass = class->generic_class->container_class; - mono_class_setup_fields (gklass); - top = gklass->field.count; - class->field.first = gklass->field.first; - class->field.count = gklass->field.count; + if (gtd) { + mono_class_setup_fields (gtd); + if (gtd->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + return; + } + + top = gtd->field.count; + class->field.first = gtd->field.first; + class->field.count = gtd->field.count; } class->instance_size = 0; @@ -1101,8 +1152,13 @@ mono_class_setup_fields (MonoClass *class) if (class->parent) { /* For generic instances, class->parent might not have been initialized */ mono_class_init (class->parent); - if (!class->parent->size_inited) + if (!class->parent->size_inited) { mono_class_setup_fields (class->parent); + if (class->parent->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + return; + } + } class->instance_size += class->parent->instance_size; class->min_align = class->parent->min_align; /* we use |= since it may have been set already */ @@ -1149,17 +1205,9 @@ mono_class_setup_fields (MonoClass *class) if (class->generic_container) { container = class->generic_container; - } else if (class->generic_class) { - gklass = class->generic_class->container_class; - container = gklass->generic_container; + } else if (gtd) { + container = gtd->generic_container; g_assert (container); - - mono_class_setup_fields (gklass); - - if (gklass->exception_type) { - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); - return; - } } /* @@ -1171,8 +1219,8 @@ mono_class_setup_fields (MonoClass *class) field->parent = class; - if (class->generic_class) { - MonoClassField *gfield = &gklass->fields [i]; + if (gtd) { + MonoClassField *gfield = >d->fields [i]; field->name = mono_field_get_name (gfield); /*This memory must come from the image mempool as we don't have a chance to free it.*/ @@ -1220,8 +1268,13 @@ mono_class_setup_fields (MonoClass *class) blittable = FALSE; } else { MonoClass *field_class = mono_class_from_mono_type (field->type); - if (field_class) + if (field_class) { mono_class_setup_fields (field_class); + if (field_class->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + break; + } + } if (!field_class || !field_class->blittable) blittable = FALSE; } @@ -1701,9 +1754,14 @@ mono_class_setup_methods (MonoClass *class) } } - if (MONO_CLASS_IS_INTERFACE (class)) - for (i = 0; i < class->method.count; ++i) - methods [i]->slot = i; + if (MONO_CLASS_IS_INTERFACE (class)) { + int slot = 0; + /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/ + for (i = 0; i < class->method.count; ++i) { + if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL) + methods [i]->slot = slot++; + } + } /* Needed because of the double-checking locking pattern */ mono_memory_barrier (); @@ -2475,6 +2533,37 @@ find_array_interface (MonoClass *klass, const char *name) return -1; } +/* + * Return the number of virtual methods. + * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods. + * FIXME It would be nice if this information could be cached somewhere. + */ +static int +count_virtual_methods (MonoClass *class) +{ + int i, count = 0; + guint32 flags; + class = mono_class_get_generic_type_definition (class); /*We can find this information by looking at the GTD*/ + + if (class->methods || !MONO_CLASS_HAS_STATIC_METADATA (class)) { + mono_class_setup_methods (class); + + for (i = 0; i < class->method.count; ++i) { + flags = class->methods [i]->flags; + if (flags & METHOD_ATTRIBUTE_VIRTUAL) + ++count; + } + } else { + for (i = 0; i < class->method.count; ++i) { + flags = mono_metadata_decode_table_row_col (class->image, MONO_TABLE_METHOD, class->method.first + i, MONO_METHOD_FLAGS); + + if (flags & METHOD_ATTRIBUTE_VIRTUAL) + ++count; + } + } + return count; +} + /* * LOCKING: this is supposed to be called with the loader lock held. */ @@ -2541,6 +2630,24 @@ setup_interface_offsets (MonoClass *class, int cur_slot) interface_offsets_full [i] = -1; } + for (k = class->parent; k ; k = k->parent) { + ifaces = mono_class_get_implemented_interfaces (k); + if (ifaces) { + for (i = 0; i < ifaces->len; ++i) { + int io; + ic = g_ptr_array_index (ifaces, i); + + /*Force the sharing of interface offsets between parent and subtypes.*/ + io = mono_class_interface_offset (k, ic); + g_assert (io >= 0); + interfaces_full [ic->interface_id] = ic; + interface_offsets_full [ic->interface_id] = io; + } + g_ptr_array_free (ifaces, TRUE); + } + } + + ifaces = mono_class_get_implemented_interfaces (class); if (ifaces) { for (i = 0; i < ifaces->len; ++i) { @@ -2549,30 +2656,11 @@ setup_interface_offsets (MonoClass *class, int cur_slot) continue; interfaces_full [ic->interface_id] = ic; interface_offsets_full [ic->interface_id] = cur_slot; - cur_slot += ic->method.count; + cur_slot += count_virtual_methods (ic); } g_ptr_array_free (ifaces, TRUE); } - for (k = class->parent; k ; k = k->parent) { - ifaces = mono_class_get_implemented_interfaces (k); - if (ifaces) { - for (i = 0; i < ifaces->len; ++i) { - ic = g_ptr_array_index (ifaces, i); - - if (interface_offsets_full [ic->interface_id] == -1) { - int io = mono_class_interface_offset (k, ic); - - g_assert (io >= 0); - - interfaces_full [ic->interface_id] = ic; - interface_offsets_full [ic->interface_id] = io; - } - } - g_ptr_array_free (ifaces, TRUE); - } - } - if (MONO_CLASS_IS_INTERFACE (class)) { interfaces_full [class->interface_id] = class; interface_offsets_full [class->interface_id] = cur_slot; @@ -2768,9 +2856,11 @@ mono_class_setup_vtable (MonoClass *class) #define DEBUG_INTERFACE_VTABLE_CODE 0 #define TRACE_INTERFACE_VTABLE_CODE 0 #define VERIFY_INTERFACE_VTABLE_CODE 0 +#define VTABLE_SELECTOR (1) #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE) #define DEBUG_INTERFACE_VTABLE(stmt) do {\ + if (!(VTABLE_SELECTOR)) break; \ stmt;\ } while (0) #else @@ -2779,6 +2869,7 @@ mono_class_setup_vtable (MonoClass *class) #if TRACE_INTERFACE_VTABLE_CODE #define TRACE_INTERFACE_VTABLE(stmt) do {\ + if (!(VTABLE_SELECTOR)) break; \ stmt;\ } while (0) #else @@ -2787,6 +2878,7 @@ mono_class_setup_vtable (MonoClass *class) #if VERIFY_INTERFACE_VTABLE_CODE #define VERIFY_INTERFACE_VTABLE(stmt) do {\ + if (!(VTABLE_SELECTOR)) break; \ stmt;\ } while (0) #else @@ -3074,10 +3166,9 @@ print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, Mono } static gboolean -verify_class_overrides (MonoClass *class, GPtrArray *ifaces, MonoMethod **overrides, int onum) +verify_class_overrides (MonoClass *class, MonoMethod **overrides, int onum) { int i; - gboolean found; for (i = 0; i < onum; ++i) { MonoMethod *decl = overrides [i * 2]; @@ -3097,38 +3188,14 @@ verify_class_overrides (MonoClass *class, GPtrArray *ifaces, MonoMethod **overri } if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) { - if (body->flags & METHOD_ATTRIBUTE_STATIC) - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type")); - else - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type")); - return FALSE; - } - - found = FALSE; - /*We can't use mono_class_is_assignable_from since it requires the class to be fully initialized*/ - if (ifaces) { - int j; - for (j = 0; j < ifaces->len; j++) { - MonoClass *ic = g_ptr_array_index (ifaces, j); - if (decl->klass == ic) { - found = TRUE; - break; - } - } - } - - if (!found) { - MonoClass *parent = class; - while (parent) { - if (decl->klass == parent) { - found = TRUE; - break; - } - parent = parent->parent; - } + if (body->flags & METHOD_ATTRIBUTE_STATIC) + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a static method in a base type")); + else + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Cannot override a non virtual method in a base type")); + return FALSE; } - if (!found) { + if (!mono_class_is_assignable_from_slow (decl->klass, class)) { mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup ("Method overrides a class or interface that extended or implemented by this type")); return FALSE; } @@ -3149,7 +3216,6 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o gboolean security_enabled = mono_is_security_manager_active (); MonoMethod *cm; gpointer class_iter; - gboolean *is_static_iface_slot; #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE) int first_non_interface_slot; #endif @@ -3157,13 +3223,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o if (class->vtable) return; - ifaces = mono_class_get_implemented_interfaces (class); - - if (overrides && !verify_class_overrides (class, ifaces, overrides, onum)) { - if (ifaces) - g_ptr_array_free (ifaces, TRUE); + if (overrides && !verify_class_overrides (class, overrides, onum)) return; - } + + ifaces = mono_class_get_implemented_interfaces (class); if (ifaces) { for (i = 0; i < ifaces->len; i++) { @@ -3186,8 +3249,6 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o vtable = alloca (sizeof (gpointer) * max_vtsize); memset (vtable, 0, sizeof (gpointer) * max_vtsize); - is_static_iface_slot = g_new0 (gboolean, max_vtsize); - /* printf ("METAINIT %s.%s\n", class->name_space, class->name); */ cur_slot = setup_interface_offsets (class, cur_slot); @@ -3238,7 +3299,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o for (i = 0; i < parent->interface_offsets_count; i++) { MonoClass *parent_interface = parent->interfaces_packed [i]; int interface_offset = mono_class_interface_offset (class, parent_interface); - + /*FIXME this is now dead code as this condition will never hold true. + Since interface offsets are inherited then the offset of an interface implemented + by a parent will never be the out of it's vtable boundary. + */ if (interface_offset >= parent->vtable_size) { int parent_interface_offset = mono_class_interface_offset (parent, parent_interface); int j; @@ -3309,10 +3373,8 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o int im_slot = ic_offset + im->slot; MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL; - if (im->flags & METHOD_ATTRIBUTE_STATIC) { - is_static_iface_slot [im_slot] = TRUE; + if (im->flags & METHOD_ATTRIBUTE_STATIC) continue; - } // If there is an explicit implementation, just use it right away, // otherwise look for a matching method @@ -3446,6 +3508,10 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o cm->slot = slot; } + /*Non final newslot methods must be given a non-interface vtable slot*/ + if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0) + cm->slot = -1; + if (cm->slot < 0) cm->slot = cur_slot++; @@ -3487,7 +3553,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o /* Ensure that all vtable slots are filled with concrete instance methods */ if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) { for (i = 0; i < cur_slot; ++i) { - if ((vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) && !is_static_iface_slot [i]) { + if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) { char *type_name = mono_type_get_full_name (class); char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none"); mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf ("Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name)); @@ -3498,8 +3564,6 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o } } - g_free (is_static_iface_slot); - if (class->generic_class) { MonoClass *gklass = class->generic_class->container_class; @@ -3537,7 +3601,7 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&class->byval_arg), class->vtable_size, icount); - for (i = 0; i < class->vtable_size; ++i) { + for (i = 0; i < cur_slot; ++i) { MonoMethod *cm; cm = vtable [i]; @@ -3556,15 +3620,15 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o ic = class->interfaces [i]; printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n", mono_class_interface_offset (class, ic), - ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg)); + count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg)); } for (k = class->parent; k ; k = k->parent) { for (i = 0; i < k->interface_count; i++) { ic = k->interfaces [i]; - printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n", + printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n", mono_class_interface_offset (class, ic), - ic->method.count, ic->interface_id, mono_type_full_name (&ic->byval_arg)); + count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg)); } } } @@ -3824,6 +3888,16 @@ mono_class_init (MonoClass *class) class->init_pending = 1; + if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) { + MonoClass *element_class = class->element_class; + if (!element_class->inited) + mono_class_init (element_class); + if (element_class->exception_type != MONO_EXCEPTION_NONE) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + goto fail; + } + } + /* CAS - SecurityAction.InheritanceDemand */ if (mono_is_security_manager_active () && class->parent && (class->parent->flags & TYPE_ATTRIBUTE_HAS_SECURITY)) { mono_secman_inheritancedemand_class (class, class->parent); @@ -3925,8 +3999,10 @@ mono_class_init (MonoClass *class) class->has_cctor = gklass->has_cctor; mono_class_setup_vtable (gklass); - if (gklass->exception_type) + if (gklass->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); goto fail; + } class->vtable_size = gklass->vtable_size; } else { @@ -4014,12 +4090,20 @@ mono_class_init (MonoClass *class) if (class->parent) { /* This will compute class->parent->vtable_size for some classes */ mono_class_init (class->parent); - if (class->parent->exception_type || mono_loader_get_last_error ()) + if (class->parent->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + goto fail; + } + if (mono_loader_get_last_error ()) goto fail; if (!class->parent->vtable_size) { /* FIXME: Get rid of this somehow */ mono_class_setup_vtable (class->parent); - if (class->parent->exception_type || mono_loader_get_last_error ()) + if (class->parent->exception_type) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + goto fail; + } + if (mono_loader_get_last_error ()) goto fail; } setup_interface_offsets (class, class->parent->vtable_size); @@ -4199,6 +4283,30 @@ mono_class_setup_mono_type (MonoClass *class) } +/* + * COM initialization (using mono_init_com_types) is delayed until needed. + * However when a [ComImport] attribute is present on a type it will trigger + * the initialization. This is not a problem unless the BCL being executed + * lacks the types that COM depends on (e.g. Variant on Silverlight). + */ +static void +init_com_from_comimport (MonoClass *class) +{ + /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */ + if ((mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)) { + /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */ + if (!mono_security_core_clr_determine_platform_image (class->image)) { + /* but it can not be made available for application (i.e. user code) since all COM calls + * are considered native calls. In this case we fail with a TypeLoadException (just like + * Silverlight 2 does */ + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + return; + } + } + /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */ + mono_init_com_types (); +} + /* * LOCKING: this assumes the loader lock is held */ @@ -4225,7 +4333,7 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) if (!MONO_CLASS_IS_INTERFACE (class)) { /* Imported COM Objects always derive from __ComObject. */ if (MONO_CLASS_IS_IMPORT (class)) { - mono_init_com_types (); + init_com_from_comimport (class); if (parent == mono_defaults.object_class) parent = mono_defaults.com_object_class; } @@ -4276,7 +4384,7 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) } else { /* initialize com types if COM interfaces are present */ if (MONO_CLASS_IS_IMPORT (class)) - mono_init_com_types (); + init_com_from_comimport (class); class->parent = NULL; } @@ -4413,6 +4521,16 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) /* uses ->valuetype, which is initialized by mono_class_setup_parent above */ mono_class_setup_mono_type (class); + if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS) + class->unicode = 1; + +#ifdef PLATFORM_WIN32 + if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS) + class->unicode = 1; +#endif + + class->cast_class = class->element_class = class; + if (!class->enumtype) { if (!mono_metadata_interfaces_from_typedef_full ( image, type_token, &interfaces, &icount, FALSE, context)){ @@ -4426,16 +4544,6 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) class->interfaces_inited = 1; } - if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS) - class->unicode = 1; - -#if PLATFORM_WIN32 - if ((class->flags & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS) - class->unicode = 1; -#endif - - class->cast_class = class->element_class = class; - /*g_print ("Load class %s\n", name);*/ /* @@ -4963,11 +5071,14 @@ mono_class_from_mono_type (MonoType *type) static MonoType * mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate) { + MonoError error; MonoType *t = mono_type_create_from_typespec (image, type_spec); if (!t) return NULL; if (context && (context->class_inst || context->method_inst)) { - MonoType *inflated = inflate_generic_type (NULL, t, context); + MonoType *inflated = inflate_generic_type (NULL, t, context, &error); + g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/ + if (inflated) { t = inflated; *did_inflate = TRUE; @@ -5110,6 +5221,9 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) mono_class_init (eclass); if (!eclass->size_inited) mono_class_setup_fields (eclass); + if (eclass->exception_type) /*FIXME we fail the array type, but we have to let other fields be set.*/ + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + class->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE; class->rank = rank; @@ -5263,6 +5377,8 @@ static MonoClassField * mono_class_get_field_idx (MonoClass *class, int idx) { mono_class_setup_fields_locking (class); + if (class->exception_type) + return NULL; while (class) { if (class->image->uncompressed_metadata) { @@ -5343,6 +5459,9 @@ mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoTyp int i; mono_class_setup_fields_locking (klass); + if (klass->exception_type) + return NULL; + while (klass) { for (i = 0; i < klass->field.count; ++i) { MonoClassField *field = &klass->fields [i]; @@ -5378,6 +5497,9 @@ mono_class_get_field_token (MonoClassField *field) int i; mono_class_setup_fields_locking (klass); + if (klass->exception_type) + return 0; + while (klass) { for (i = 0; i < klass->field.count; ++i) { if (&klass->fields [i] == field) { @@ -5669,9 +5791,8 @@ mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *co if (!type) { char *name = mono_class_name_from_token (image, type_token); char *assembly = mono_assembly_name_from_token (image, type_token); - if (inflated) - mono_metadata_free_type (type); mono_loader_set_error_type_load (name, assembly); + return NULL; } if (inflated) { @@ -5789,6 +5910,7 @@ mono_image_add_to_name_cache (MonoImage *image, const char *nspace, { GHashTable *nspace_table; GHashTable *name_cache; + guint32 old_index; mono_image_lock (image); @@ -5800,6 +5922,10 @@ mono_image_add_to_name_cache (MonoImage *image, const char *nspace, nspace_table = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table); } + + if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name)))) + g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name); + g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index)); mono_image_unlock (image); @@ -5816,7 +5942,7 @@ find_nocase (gpointer key, gpointer value, gpointer user_data) char *name = (char*)key; FindUserData *data = (FindUserData*)user_data; - if (!data->value && (g_strcasecmp (name, (char*)data->key) == 0)) + if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0)) data->value = value; } @@ -5885,7 +6011,7 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char continue; n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); - if (g_strcasecmp (n, name) == 0 && g_strcasecmp (nspace, name_space) == 0) + if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0) return mono_class_get (image, MONO_TOKEN_TYPE_DEF | i); } return NULL; @@ -6236,6 +6362,67 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) return mono_class_has_parent (oklass, klass); } +/*Check if @candidate implements the interface @target*/ +static gboolean +mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate) +{ + int i; + + do { + if (candidate == target) + return TRUE; + + /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/ + if (candidate->image->dynamic && !candidate->wastypebuilder) { + MonoReflectionTypeBuilder *tb = candidate->reflection_info; + int j; + if (tb->interfaces) { + for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) { + MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j); + MonoClass *iface_class = mono_class_from_mono_type (iface->type); + if (iface_class == target || mono_class_implement_interface_slow (target, iface_class)) + return TRUE; + } + } + } else { + /*setup_interfaces don't mono_class_init anything*/ + mono_class_setup_interfaces (candidate); + for (i = 0; i < candidate->interface_count; ++i) { + if (candidate->interfaces [i] == target || mono_class_implement_interface_slow (target, candidate->interfaces [i])) + return TRUE; + } + } + candidate = candidate->parent; + } while (candidate); + + return FALSE; +} + +/* + * Check if @oklass can be assigned to @klass. + * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context. + */ +gboolean +mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate) +{ + if (candidate == target) + return TRUE; + if (target == mono_defaults.object_class) + return TRUE; + + /*setup_supertypes don't mono_class_init anything */ + mono_class_setup_supertypes (candidate); + mono_class_setup_supertypes (target); + + if (mono_class_has_parent (candidate, target)) + return TRUE; + + /*If target is not an interface there is no need to check them.*/ + if (!MONO_CLASS_IS_INTERFACE (target)) + return FALSE; + return mono_class_implement_interface_slow (target, candidate); +} + /** * mono_class_get_cctor: * @klass: A MonoClass pointer @@ -7624,6 +7811,14 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed) return TRUE; if (!accessed || !accessing) return FALSE; + + /* extra safety under CoreCLR - the runtime does not verify the strongname signatures + * anywhere so untrusted friends are not safe to access platform's code internals */ + if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) { + if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image)) + return FALSE; + } + mono_assembly_load_friends (accessed); for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) { MonoAssemblyName *friend = tmp->data; @@ -7713,6 +7908,10 @@ can_access_type (MonoClass *access_klass, MonoClass *member_klass) if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in)) return FALSE; + /*Non nested type with nested visibility. We just fail it.*/ + if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL) + return FALSE; + switch (access_level) { case TYPE_ATTRIBUTE_NOT_PUBLIC: return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);