2009-12-05 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / class.c
index 26af1cbfba9fee2650bd040fbc2dc079c3f704f1..4c38f9284eb39c689c0ee00a39013ba48f2dbd80 100644 (file)
@@ -68,6 +68,8 @@ static int generic_array_methods (MonoClass *class);
 static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos);
 
 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
+static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
+
 
 void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
 void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
@@ -566,7 +568,9 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
                if (!gclass->context.class_inst->is_open)
                        return NULL;
 
-               inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context);
+               inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
+               if (!mono_error_ok (error))
+                       return NULL;
                if (inst != gclass->context.class_inst)
                        gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
 
@@ -589,7 +593,9 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont
                        return NULL;
 
                /* We can't use context->class_inst directly, since it can have more elements */
-               inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context);
+               inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
+               if (!mono_error_ok (error))
+                       return NULL;
                if (inst == container->context.class_inst)
                        return NULL;
 
@@ -775,15 +781,20 @@ mono_class_inflate_generic_class (MonoClass *gklass, MonoGenericContext *context
 static MonoGenericContext
 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with)
 {
+       MonoError error;
        MonoGenericInst *class_inst = NULL;
        MonoGenericInst *method_inst = NULL;
        MonoGenericContext res;
 
-       if (context->class_inst)
-               class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with);
+       if (context->class_inst) {
+               class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, &error);
+               g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
+       }
 
-       if (context->method_inst)
-               method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with);
+       if (context->method_inst) {
+               method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, &error);
+               g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
+       }
 
        res.class_inst = class_inst;
        res.method_inst = method_inst;
@@ -1099,6 +1110,26 @@ mono_class_find_enum_basetype (MonoClass *class)
        return NULL;
 }
 
+/*
+ * Checks for MonoClass::exception_type without resolving all MonoType's into MonoClass'es
+ * It doesn't resolve generic instances, only check the GTD.
+ */
+static gboolean
+mono_type_has_exceptions (MonoType *type)
+{
+       switch (type->type) {
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_VALUETYPE:
+       case MONO_TYPE_SZARRAY:
+               return type->data.klass->exception_type;
+       case MONO_TYPE_ARRAY:
+               return type->data.array->eklass->exception_type;
+       case MONO_TYPE_GENERICINST:
+               return type->data.generic_class->container_class->exception_type;
+       }
+       return FALSE;
+}
+
 /** 
  * mono_class_setup_fields:
  * @class: The class to initialize
@@ -1285,6 +1316,16 @@ mono_class_setup_fields (MonoClass *class)
                        blittable = class->element_class->blittable;
                }
 
+               if (mono_type_has_exceptions (field->type)) {
+                       char *class_name = mono_type_get_full_name (class);
+                       char *type_name = mono_type_full_name (field->type);
+
+                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
+                       g_free (class_name);
+                       g_free (type_name);
+                       break;
+               }
                /* The def_value of fields is compute lazily during vtable creation */
        }
 
@@ -1294,8 +1335,8 @@ mono_class_setup_fields (MonoClass *class)
        class->blittable = blittable;
 
        if (class->enumtype && !mono_class_enum_basetype (class)) {
-               if (!((strcmp (class->name, "Enum") == 0) && (strcmp (class->name_space, "System") == 0)))
-                       G_BREAKPOINT ();
+               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+               return;
        }
        if (explicit_size && real_size) {
                class->instance_size = MAX (real_size, class->instance_size);
@@ -3335,7 +3376,13 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                MonoMethod *decl = overrides [i*2];
                if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
                        int dslot;
-                       dslot = mono_method_get_vtable_slot (decl) + mono_class_interface_offset (class, decl->klass);
+                       dslot = mono_method_get_vtable_slot (decl);
+                       if (dslot == -1) {
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                               return;
+                       }
+
+                       dslot += mono_class_interface_offset (class, decl->klass);
                        vtable [dslot] = overrides [i*2 + 1];
                        vtable [dslot]->slot = dslot;
                        if (!override_map)
@@ -3524,6 +3571,11 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
                                                        mono_security_core_clr_check_override (class, cm, m1);
 
                                                slot = mono_method_get_vtable_slot (m1);
+                                               if (slot == -1) {
+                                                       mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                                                       return;
+                                               }
+
                                                g_assert (cm->slot < max_vtsize);
                                                if (!override_map)
                                                        override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
@@ -3672,14 +3724,18 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o
 /*
  * mono_method_get_vtable_slot:
  *
- *   Returns method->slot, computing it if neccesary.
+ *   Returns method->slot, computing it if neccesary. Return -1 on failure.
  * LOCKING: Acquires the loader lock.
+ *
+ * FIXME Use proper MonoError machinery here.
  */
 int
 mono_method_get_vtable_slot (MonoMethod *method)
 {
        if (method->slot == -1) {
                mono_class_setup_vtable (method->klass);
+               if (method->klass->exception_type)
+                       return -1;
                g_assert (method->slot != -1);
        }
        return method->slot;
@@ -3691,7 +3747,9 @@ mono_method_get_vtable_slot (MonoMethod *method)
  *
  * Returns the index into the runtime vtable to access the method or,
  * in the case of a virtual generic method, the virtual generic method
- * thunk.
+ * thunk. Returns -1 on failure.
+ *
+ * FIXME Use proper MonoError machinery here.
  */
 int
 mono_method_get_vtable_index (MonoMethod *method)
@@ -4484,6 +4542,9 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        guint32 field_last, method_last;
        guint32 nesting_tokeen;
 
+       if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows)
+               return NULL;
+
        mono_loader_lock ();
 
        if ((class = mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
@@ -4491,8 +4552,6 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
                return class;
        }
 
-       g_assert (mono_metadata_token_table (type_token) == MONO_TABLE_TYPEDEF);
-
        mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
        
        name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
@@ -4545,8 +4604,15 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token)
        }
 
        /* do this early so it's available for interfaces in setup_mono_type () */
-       if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token)))
+       if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
                class->nested_in = mono_class_create_from_typedef (image, nesting_tokeen);
+               if (!class->nested_in) {
+                       mono_internal_hash_table_remove (&image->class_cache, GUINT_TO_POINTER (type_token));
+                       mono_loader_unlock ();
+                       mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
+                       return NULL;
+               }
+       }
 
        mono_class_setup_parent (class, parent);
 
@@ -4768,6 +4834,7 @@ make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is
 {
        MonoClass *klass, **ptr;
        int count, pos, i;
+       MonoGenericContainer *container = mono_generic_param_owner (param);
 
        if (!image)
                /* FIXME: */
@@ -4784,7 +4851,18 @@ make_generic_param_class (MonoGenericParam *param, MonoImage *image, gboolean is
                sprintf ((char*)klass->name, "%d", n);
        }
 
-       klass->name_space = "";
+       if (container) {
+               if (is_mvar) {
+                       MonoMethod *omethod = container->owner.method;
+                       klass->name_space = (omethod && omethod->klass) ? omethod->klass->name_space : "";
+               } else {
+                       MonoClass *oklass = container->owner.klass;
+                       klass->name_space = oklass ? oklass->name_space : "";
+               }
+       } else {
+               klass->name_space = "";
+       }
+
        mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
 
        count = 0;
@@ -5101,15 +5179,25 @@ mono_class_from_mono_type (MonoType *type)
  * @context: the generic context used to evaluate generic instantiations in
  */
 static MonoType *
-mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate)
+mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
 {
-       MonoError error;
        MonoType *t = mono_type_create_from_typespec (image, type_spec);
-       if (!t)
+
+       mono_error_init (error);
+       *did_inflate = FALSE;
+
+       if (!t) {
+               char *name = mono_class_name_from_token (image, type_spec);
+               char *assembly = mono_assembly_name_from_token (image, type_spec);
+               mono_error_set_type_load_name (error, name, assembly, "Could not resolve typespec token %08x", type_spec);
                return NULL;
+       }
+
        if (context && (context->class_inst || context->method_inst)) {
-               MonoType *inflated = inflate_generic_type (NULL, t, context, &error);
-               g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
+               MonoType *inflated = inflate_generic_type (NULL, t, context, error);
+
+               if (!mono_error_ok (error))
+                       return NULL;
 
                if (inflated) {
                        t = inflated;
@@ -5126,12 +5214,12 @@ mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGener
  * @context: the generic context used to evaluate generic instantiations in
  */
 static MonoClass *
-mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context)
+mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
 {
        MonoClass *ret;
        gboolean inflated = FALSE;
-       MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated);
-       if (!t)
+       MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
+       if (!mono_error_ok (error))
                return NULL;
        ret = mono_class_from_mono_type (t);
        if (inflated)
@@ -5667,6 +5755,9 @@ mono_class_name_from_token (MonoImage *image, guint32 type_token)
                MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
                guint tidx = mono_metadata_token_index (type_token);
 
+               if (tidx > tt->rows)
+                       return g_strdup_printf ("Invalid type token 0x%08x", type_token);
+
                mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
                name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
                nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
@@ -5679,8 +5770,11 @@ mono_class_name_from_token (MonoImage *image, guint32 type_token)
        case MONO_TOKEN_TYPE_REF: {
                guint32 cols [MONO_TYPEREF_SIZE];
                MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEREF];
+               guint tidx = mono_metadata_token_index (type_token);
 
-               mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
+               if (tidx > t->rows)
+                       return g_strdup_printf ("Invalid type token 0x%08x", type_token);
+               mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
                name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
                nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
                if (strlen (nspace) == 0)
@@ -5692,10 +5786,8 @@ mono_class_name_from_token (MonoImage *image, guint32 type_token)
        case MONO_TOKEN_TYPE_SPEC:
                return g_strdup_printf ("Typespec 0x%08x", type_token);
        default:
-               g_assert_not_reached ();
+               return g_strdup_printf ("Invalid type token 0x%08x", type_token);
        }
-
-       return NULL;
 }
 
 static char *
@@ -5712,9 +5804,12 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
                MonoAssemblyName aname;
                guint32 cols [MONO_TYPEREF_SIZE];
                MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEREF];
-               guint32 idx;
+               guint32 idx = mono_metadata_token_index (type_token);
+
+               if (idx > t->rows)
+                       return g_strdup_printf ("Invalid type token 0x%08x", type_token);
        
-               mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
+               mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
 
                idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLTION_SCOPE_BITS;
                switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLTION_SCOPE_MASK) {
@@ -5756,6 +5851,7 @@ mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
 MonoClass *
 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
 {
+       MonoError error;
        MonoClass *class = NULL;
 
        if (image->dynamic) {
@@ -5776,7 +5872,11 @@ mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *c
                class = mono_class_from_typeref (image, type_token);
                break;
        case MONO_TOKEN_TYPE_SPEC:
-               class = mono_class_create_from_typespec (image, type_token, context);
+               class = mono_class_create_from_typespec (image, type_token, context, &error);
+               if (!mono_error_ok (&error)) {
+                       /*FIXME don't swallow the error message*/
+                       mono_error_cleanup (&error);
+               }
                break;
        default:
                g_warning ("unknown token type %x", type_token & 0xff000000);
@@ -5806,6 +5906,7 @@ mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *c
 MonoType *
 mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
 {
+       MonoError error;
        MonoType *type = NULL;
        gboolean inflated = FALSE;
 
@@ -5818,11 +5919,14 @@ mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *co
                return class ? mono_class_get_type (class) : NULL;
        }
 
-       type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated);
+       type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, &error);
 
-       if (!type) {
+       if (!mono_error_ok (&error)) {
+               /*FIXME don't swalloc the error message.*/
                char *name = mono_class_name_from_token (image, type_token);
                char *assembly = mono_assembly_name_from_token (image, type_token);
+
+               mono_error_cleanup (&error);
                mono_loader_set_error_type_load (name, assembly);
                return NULL;
        }
@@ -6631,6 +6735,8 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
        case MONO_TOKEN_FIELD_DEF: {
                MonoClass *class;
                guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
+               if (!type)
+                       return NULL;
                if (handle_class)
                        *handle_class = mono_defaults.fieldhandle_class;
                class = mono_class_get_full (image, MONO_TOKEN_TYPE_DEF | type, context);
@@ -6776,7 +6882,7 @@ MonoType*
 mono_class_enum_basetype (MonoClass *klass)
 {
        if (klass->element_class == klass)
-               /* SRE */
+               /* SRE or broken types */
                return NULL;
        else
                return &klass->element_class->byval_arg;
@@ -7244,6 +7350,8 @@ mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
                                guint32 cols [MONO_NESTED_CLASS_SIZE];
                                mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
                                nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]);
+                               if (!nclass)
+                                       continue;
                                mono_class_alloc_ext (klass);
                                klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, nclass);