Merge pull request #2820 from kumpera/license-change-rebased
[mono.git] / mono / metadata / loader.c
index 0566fe2d1028268ae0b92dd1531422364d750289..56992b3612738bd5ea800a0a50edc2817068c202 100644 (file)
@@ -17,6 +17,7 @@
  * TODO:
  *   This should keep track of the assembly versions that we are loading.
  *
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 #include <config.h>
 #include <glib.h>
@@ -506,13 +507,17 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
        }
 
        /* FIXME: This needs a cache, especially for generic instances, since
-        * mono_metadata_parse_type () allocates everything from a mempool.
+        * we ask mono_metadata_parse_type_checked () to allocates everything from a mempool.
+        * FIXME part2, mono_metadata_parse_type_checked actually allows for a transient type instead.
+        * FIXME part3, transient types are not 100% transient, so we need to take care of that first.
         */
        sig_type = (MonoType *)find_cached_memberref_sig (image, cols [MONO_MEMBERREF_SIGNATURE]);
        if (!sig_type) {
-               sig_type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
+               MonoError inner_error;
+               sig_type = mono_metadata_parse_type_checked (image, NULL, 0, FALSE, ptr, &ptr, &inner_error);
                if (sig_type == NULL) {
-                       mono_error_set_field_load (error, klass, fname, "Could not parse field '%s' signature %08x", fname, token);
+                       mono_error_set_field_load (error, klass, fname, "Could not parse field '%s' signature %08x due to: %s", fname, token, mono_error_get_message (&inner_error));
+                       mono_error_cleanup (&inner_error);
                        return NULL;
                }
                sig_type = (MonoType *)cache_memberref_sig (image, cols [MONO_MEMBERREF_SIGNATURE], sig_type);
@@ -534,17 +539,14 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
 /*
  * mono_field_from_token:
  * @deprecated use the _checked variant
+ * Notes: runtime code MUST not use this function
 */
 MonoClassField*
 mono_field_from_token (MonoImage *image, guint32 token, MonoClass **retklass, MonoGenericContext *context)
 {
        MonoError error;
        MonoClassField *res = mono_field_from_token_checked (image, token, retklass, context, &error);
-       mono_loader_assert_no_error ();
-       if (!mono_error_ok (&error)) {
-               mono_loader_set_error_from_mono_error (&error);
-               mono_error_cleanup (&error);
-       }
+       g_assert (mono_error_ok (&error));
        return res;
 }
 
@@ -562,7 +564,9 @@ mono_field_from_token_checked (MonoImage *image, guint32 token, MonoClass **retk
                MonoClass *handle_class;
 
                *retklass = NULL;
-               result = (MonoClassField *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context);
+               MonoError inner_error;
+               result = (MonoClassField *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context, &inner_error);
+               mono_error_cleanup (&inner_error);
                // This checks the memberref type as well
                if (!result || handle_class != mono_defaults.fieldhandle_class) {
                        mono_error_set_bad_image (error, image, "Bad field token 0x%08x", token);
@@ -682,7 +686,7 @@ find_method_in_class (MonoClass *klass, const char *name, const char *qname, con
        See mono/tests/generic-type-load-exception.2.il
        FIXME we should better report this error to the caller
         */
-       if (!klass->methods || klass->exception_type) {
+       if (!klass->methods || mono_class_has_failure (klass)) {
                mono_error_set_type_load_class (error, klass, "Could not find method due to a type load error"); //FIXME get the error from the class 
 
                return NULL;
@@ -871,48 +875,58 @@ mono_inflate_generic_signature (MonoMethodSignature *sig, MonoGenericContext *co
 }
 
 static MonoMethodHeader*
-inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context)
+inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context, MonoError *error)
 {
-       MonoMethodHeader *res;
-       int i;
-       res = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + sizeof (gpointer) * header->num_locals);
+       size_t locals_size = sizeof (gpointer) * header->num_locals;
+       size_t clauses_size = header->num_clauses * sizeof (MonoExceptionClause);
+       size_t header_size = MONO_SIZEOF_METHOD_HEADER + locals_size + clauses_size; 
+       MonoMethodHeader *res = (MonoMethodHeader *)g_malloc0 (header_size);
+       res->num_locals = header->num_locals;
+       res->clauses = (MonoExceptionClause *) &res->locals [res->num_locals] ;
+       memcpy (res->clauses, header->clauses, clauses_size);
+
        res->code = header->code;
        res->code_size = header->code_size;
        res->max_stack = header->max_stack;
        res->num_clauses = header->num_clauses;
        res->init_locals = header->init_locals;
-       res->num_locals = header->num_locals;
-       res->clauses = header->clauses;
-       for (i = 0; i < header->num_locals; ++i)
-               res->locals [i] = mono_class_inflate_generic_type (header->locals [i], context);
+
+       res->is_transient = TRUE;
+
+       mono_error_init (error);
+
+       for (int i = 0; i < header->num_locals; ++i) {
+               res->locals [i] = mono_class_inflate_generic_type_checked (header->locals [i], context, error);
+               if (!is_ok (error))
+                       goto fail;
+       }
        if (res->num_clauses) {
-               res->clauses = (MonoExceptionClause *)g_memdup (header->clauses, sizeof (MonoExceptionClause) * res->num_clauses);
-               for (i = 0; i < header->num_clauses; ++i) {
+               for (int i = 0; i < header->num_clauses; ++i) {
                        MonoExceptionClause *clause = &res->clauses [i];
                        if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
                                continue;
-                       clause->data.catch_class = mono_class_inflate_generic_class (clause->data.catch_class, context);
+                       clause->data.catch_class = mono_class_inflate_generic_class_checked (clause->data.catch_class, context, error);
+                       if (!is_ok (error))
+                               goto fail;
                }
        }
        return res;
+fail:
+       g_free (res);
+       return NULL;
 }
 
 /*
  * token is the method_ref/def/spec token used in a call IL instruction.
+ * @deprecated use the _checked variant
+ * Notes: runtime code MUST not use this function
  */
 MonoMethodSignature*
 mono_method_get_signature_full (MonoMethod *method, MonoImage *image, guint32 token, MonoGenericContext *context)
 {
        MonoError error;
        MonoMethodSignature *res = mono_method_get_signature_checked (method, image, token, context, &error);
-
-       mono_loader_assert_no_error ();
-
-       if (!res) {
-               g_assert (!mono_error_ok (&error));
-               mono_loader_set_error_from_mono_error (&error);
-               mono_error_cleanup (&error); /* FIXME Don't swallow the error */
-       }
+       mono_error_cleanup (&error);
        return res;
 }
 
@@ -934,8 +948,10 @@ mono_method_get_signature_checked (MonoMethod *method, MonoImage *image, guint32
 
        if (table == MONO_TABLE_METHODSPEC) {
                /* the verifier (do_invoke_method) will turn the NULL into a verifier error */
-               if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || !method->is_inflated)
+               if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || !method->is_inflated) {
+                       mono_error_set_bad_image (error, image, "Method is a pinvoke or open generic");
                        return NULL;
+               }
 
                return mono_method_signature_checked (method, error);
        }
@@ -1001,19 +1017,17 @@ mono_method_get_signature_checked (MonoMethod *method, MonoImage *image, guint32
        return sig;
 }
 
+/*
+ * token is the method_ref/def/spec token used in a call IL instruction.
+ * @deprecated use the _checked variant
+ * Notes: runtime code MUST not use this function
+ */
 MonoMethodSignature*
 mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
 {
        MonoError error;
        MonoMethodSignature *res = mono_method_get_signature_checked (method, image, token, NULL, &error);
-
-       mono_loader_assert_no_error ();
-
-       if (!res) {
-               g_assert (!mono_error_ok (&error));
-               mono_loader_set_error_from_mono_error (&error);
-               mono_error_cleanup (&error); /* FIXME Don't swallow the error */
-       }
+       mono_error_cleanup (&error);
        return res;
 }
 
@@ -1024,7 +1038,7 @@ mono_method_search_in_array_class (MonoClass *klass, const char *name, MonoMetho
        int i;
 
        mono_class_setup_methods (klass);
-       g_assert (!klass->exception_type); /*FIXME this should not fail, right?*/
+       g_assert (!mono_class_has_failure (klass)); /*FIXME this should not fail, right?*/
        for (i = 0; i < klass->method.count; ++i) {
                MonoMethod *method = klass->methods [i];
                if (strcmp (method->name, name) == 0 && sig->param_count == method->signature->param_count)
@@ -1866,7 +1880,8 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
        if (image_is_dynamic (image)) {
                MonoClass *handle_class;
 
-               result = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context);
+               result = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context, error);
+               mono_error_assert_ok (error);
                mono_loader_assert_no_error ();
 
                // This checks the memberref type as well
@@ -1980,7 +1995,10 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
 MonoMethod *
 mono_get_method (MonoImage *image, guint32 token, MonoClass *klass)
 {
-       return mono_get_method_full (image, token, klass, NULL);
+       MonoError error;
+       MonoMethod *result = mono_get_method_checked (image, token, klass, NULL, &error);
+       mono_error_cleanup (&error);
+       return result;
 }
 
 MonoMethod *
@@ -1989,11 +2007,7 @@ mono_get_method_full (MonoImage *image, guint32 token, MonoClass *klass,
 {
        MonoError error;
        MonoMethod *result = mono_get_method_checked (image, token, klass, context, &error);
-       mono_loader_assert_no_error ();
-       if (!mono_error_ok (&error)) {
-               mono_loader_set_error_from_mono_error (&error);
-               mono_error_cleanup (&error);
-       }
+       mono_error_cleanup (&error);
        return result;
 }
 
@@ -2136,12 +2150,7 @@ mono_get_method_constrained (MonoImage *image, guint32 token, MonoClass *constra
 {
        MonoError error;
        MonoMethod *result = mono_get_method_constrained_checked (image, token, constrained_class, context, cil_method, &error);
-
-       mono_loader_assert_no_error ();
-       if (!mono_error_ok (&error)) {
-               mono_loader_set_error_from_mono_error (&error);
-               mono_error_cleanup (&error);
-       }
+       mono_error_cleanup (&error);
        return result;
 }
 
@@ -2796,45 +2805,37 @@ mono_method_get_token (MonoMethod *method)
 }
 
 MonoMethodHeader*
-mono_method_get_header (MonoMethod *method)
+mono_method_get_header_checked (MonoMethod *method, MonoError *error)
 {
        int idx;
        guint32 rva;
        MonoImage* img;
        gpointer loc;
-       MonoMethodHeader *header;
        MonoGenericContainer *container;
 
-       if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
-               return NULL;
-
+       mono_error_init (error);
        img = method->klass->image;
 
+       if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+               mono_error_set_bad_image (error, img, "Method has no body");
+               return NULL;
+       }
+
        if (method->is_inflated) {
                MonoMethodInflated *imethod = (MonoMethodInflated *) method;
                MonoMethodHeader *header, *iheader;
 
-               header = mono_method_get_header (imethod->declaring);
+               header = mono_method_get_header_checked (imethod->declaring, error);
                if (!header)
                        return NULL;
 
-               iheader = inflate_generic_header (header, mono_method_get_context (method));
+               iheader = inflate_generic_header (header, mono_method_get_context (method), error);
                mono_metadata_free_mh (header);
-
-               mono_image_lock (img);
-
-               if (imethod->header) {
-                       mono_metadata_free_mh (iheader);
-                       mono_image_unlock (img);
-                       return imethod->header;
+               if (!iheader) {
+                       return NULL;
                }
 
-               mono_memory_barrier ();
-               imethod->header = iheader;
-
-               mono_image_unlock (img);
-
-               return imethod->header;
+               return iheader;
        }
 
        if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
@@ -2851,12 +2852,16 @@ mono_method_get_header (MonoMethod *method)
        idx = mono_metadata_token_index (method->token);
        rva = mono_metadata_decode_row_col (&img->tables [MONO_TABLE_METHOD], idx - 1, MONO_METHOD_RVA);
 
-       if (!mono_verifier_verify_method_header (img, rva, NULL))
+       if (!mono_verifier_verify_method_header (img, rva, NULL)) {
+               mono_error_set_bad_image (error, img, "Invalid method header, failed verification");
                return NULL;
+       }
 
        loc = mono_image_rva_map (img, rva);
-       if (!loc)
+       if (!loc) {
+               mono_error_set_bad_image (error, img, "Method has zero rva");
                return NULL;
+       }
 
        /*
         * When parsing the types of local variables, we must pass any container available
@@ -2865,11 +2870,19 @@ mono_method_get_header (MonoMethod *method)
        container = mono_method_get_generic_container (method);
        if (!container)
                container = method->klass->generic_container;
-       header = mono_metadata_parse_mh_full (img, container, (const char *)loc);
+       return mono_metadata_parse_mh_full (img, container, (const char *)loc, error);
+}
 
+MonoMethodHeader*
+mono_method_get_header (MonoMethod *method)
+{
+       MonoError error;
+       MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
+       mono_error_cleanup (&error);
        return header;
 }
 
+
 guint32
 mono_method_get_flags (MonoMethod *method, guint32 *iflags)
 {
@@ -2895,7 +2908,7 @@ mono_method_get_index (MonoMethod *method)
                return mono_metadata_token_index (method->token);
 
        mono_class_setup_methods (klass);
-       if (klass->exception_type)
+       if (mono_class_has_failure (klass))
                return 0;
        for (i = 0; i < klass->method.count; ++i) {
                if (method == klass->methods [i]) {