Merge pull request #3626 from lateralusX/jlorenss/win-api-family-support-eglib
[mono.git] / mono / metadata / loader.c
index 50468c5536a52de19c037f525a0aa713dd890dfb..e2a91f0975fb4ee6dea5c401e23e545c8038dad3 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>
@@ -66,11 +67,6 @@ static guint32 memberref_sig_cache_size;
 static guint32 methods_size;
 static guint32 signatures_size;
 
-/*
- * This TLS variable contains the last type load error encountered by the loader.
- */
-MonoNativeTlsKey loader_error_thread_id;
-
 /*
  * This TLS variable holds how many times the current thread has acquired the loader 
  * lock.
@@ -102,7 +98,6 @@ mono_loader_init ()
                mono_os_mutex_init_recursive (&global_loader_data_mutex);
                loader_lock_inited = TRUE;
 
-               mono_native_tls_alloc (&loader_error_thread_id, NULL);
                mono_native_tls_alloc (&loader_lock_nest_id, NULL);
 
                mono_counters_init ();
@@ -124,7 +119,6 @@ mono_loader_cleanup (void)
 {
        dllmap_cleanup ();
 
-       mono_native_tls_free (loader_error_thread_id);
        mono_native_tls_free (loader_lock_nest_id);
 
        mono_coop_mutex_destroy (&loader_mutex);
@@ -132,281 +126,6 @@ mono_loader_cleanup (void)
        loader_lock_inited = FALSE;     
 }
 
-/*
- * Handling of type load errors should be done as follows:
- *
- *   If something could not be loaded, the loader should call one of the
- * mono_loader_set_error_XXX functions ()
- * with the appropriate arguments, then return NULL to report the failure. The error 
- * should be propagated until it reaches code which can throw managed exceptions. At that
- * point, an exception should be thrown based on the information returned by
- * mono_loader_get_last_error (). Then the error should be cleared by calling 
- * mono_loader_clear_error ().
- */
-
-static void
-set_loader_error (MonoLoaderError *error)
-{
-       mono_loader_clear_error ();
-       mono_native_tls_set_value (loader_error_thread_id, error);
-}
-
-/**
- * mono_loader_set_error_assembly_load:
- *
- * Set the loader error for this thread. 
- */
-void
-mono_loader_set_error_assembly_load (const char *assembly_name, gboolean ref_only)
-{
-       MonoLoaderError *error;
-
-       if (mono_loader_get_last_error ()) 
-               return;
-
-       error = g_new0 (MonoLoaderError, 1);
-       error->exception_type = MONO_EXCEPTION_FILE_NOT_FOUND;
-       error->assembly_name = g_strdup (assembly_name);
-       error->ref_only = ref_only;
-
-       /* 
-        * This is not strictly needed, but some (most) of the loader code still
-        * can't deal with load errors, and this message is more helpful than an
-        * assert.
-        */
-       if (ref_only)
-               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.", assembly_name);
-       else
-               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "Could not load file or assembly '%s' or one of its dependencies.", assembly_name);
-
-       set_loader_error (error);
-}
-
-/**
- * mono_loader_set_error_type_load:
- *
- * Set the loader error for this thread. 
- */
-void
-mono_loader_set_error_type_load (const char *class_name, const char *assembly_name)
-{
-       MonoLoaderError *error;
-
-       if (mono_loader_get_last_error ()) 
-               return;
-
-       error = g_new0 (MonoLoaderError, 1);
-       error->exception_type = MONO_EXCEPTION_TYPE_LOAD;
-       error->class_name = g_strdup (class_name);
-       error->assembly_name = g_strdup (assembly_name);
-
-       /* 
-        * This is not strictly needed, but some (most) of the loader code still
-        * can't deal with load errors, and this message is more helpful than an
-        * assert.
-        */
-       mono_trace_warning (MONO_TRACE_TYPE, "The class %s could not be loaded, used in %s", class_name, assembly_name);
-
-       set_loader_error (error);
-}
-
-/*
- * mono_loader_set_error_method_load:
- *
- *   Set the loader error for this thread. MEMBER_NAME should point to a string
- * inside metadata.
- */
-void
-mono_loader_set_error_method_load (const char *class_name, const char *member_name)
-{
-       MonoLoaderError *error;
-
-       /* FIXME: Store the signature as well */
-       if (mono_loader_get_last_error ())
-               return;
-
-       error = g_new0 (MonoLoaderError, 1);
-       error->exception_type = MONO_EXCEPTION_MISSING_METHOD;
-       error->class_name = g_strdup (class_name);
-       error->member_name = member_name;
-
-       set_loader_error (error);
-}
-
-/*
- * mono_loader_set_error_field_load:
- *
- * Set the loader error for this thread. MEMBER_NAME should point to a string
- * inside metadata.
- */
-void
-mono_loader_set_error_field_load (MonoClass *klass, const char *member_name)
-{
-       MonoLoaderError *error;
-
-       /* FIXME: Store the signature as well */
-       if (mono_loader_get_last_error ())
-               return;
-
-       error = g_new0 (MonoLoaderError, 1);
-       error->exception_type = MONO_EXCEPTION_MISSING_FIELD;
-       error->klass = klass;
-       error->member_name = member_name;
-
-       set_loader_error (error);
-}
-
-/*
- * mono_loader_set_error_bad_image:
- *
- * Set the loader error for this thread. 
- */
-void
-mono_loader_set_error_bad_image (char *msg)
-{
-       MonoLoaderError *error;
-
-       if (mono_loader_get_last_error ())
-               return;
-
-       error = g_new0 (MonoLoaderError, 1);
-       error->exception_type = MONO_EXCEPTION_BAD_IMAGE;
-       error->msg = msg;
-
-       set_loader_error (error);
-}      
-
-
-/*
- * mono_loader_get_last_error:
- *
- *   Returns information about the last type load exception encountered by the loader, or
- * NULL. After use, the exception should be cleared by calling mono_loader_clear_error.
- */
-MonoLoaderError*
-mono_loader_get_last_error (void)
-{
-       return (MonoLoaderError*)mono_native_tls_get_value (loader_error_thread_id);
-}
-
-void
-mono_loader_assert_no_error (void)
-{
-       MonoLoaderError *error = mono_loader_get_last_error ();
-
-       if (error) {
-               g_print ("Unhandled loader error: %x, %s %s %s\n", error->exception_type, error->msg, error->assembly_name, error->class_name);
-               g_assert_not_reached ();
-       }
-}
-
-/**
- * mono_loader_clear_error:
- *
- * Disposes any loader error messages on this thread
- */
-void
-mono_loader_clear_error (void)
-{
-       MonoLoaderError *ex = (MonoLoaderError*)mono_native_tls_get_value (loader_error_thread_id);
-
-       if (ex) {
-               g_free (ex->class_name);
-               g_free (ex->assembly_name);
-               g_free (ex->msg);
-               g_free (ex);
-
-               mono_native_tls_set_value (loader_error_thread_id, NULL);
-       }
-}
-
-/**
- * mono_loader_error_prepare_exception:
- * @error: The MonoLoaderError to turn into an exception
- *
- * This turns a MonoLoaderError into an exception that can be thrown
- * and resets the Mono Loader Error state during this process.
- *
- */
-MonoException *
-mono_loader_error_prepare_exception (MonoLoaderError *error)
-{
-       MonoException *ex = NULL;
-
-       switch (error->exception_type) {
-       case MONO_EXCEPTION_TYPE_LOAD: {
-               char *cname = g_strdup (error->class_name);
-               char *aname = g_strdup (error->assembly_name);
-               MonoString *class_name;
-               
-               mono_loader_clear_error ();
-               
-               class_name = mono_string_new (mono_domain_get (), cname);
-
-               ex = mono_get_exception_type_load (class_name, aname);
-               g_free (cname);
-               g_free (aname);
-               break;
-        }
-       case MONO_EXCEPTION_MISSING_METHOD: {
-               char *cname = g_strdup (error->class_name);
-               char *aname = g_strdup (error->member_name);
-               
-               mono_loader_clear_error ();
-               ex = mono_get_exception_missing_method (cname, aname);
-               g_free (cname);
-               g_free (aname);
-               break;
-       }
-               
-       case MONO_EXCEPTION_MISSING_FIELD: {
-               char *class_name;
-               char *cmembername = g_strdup (error->member_name);
-               if (error->klass)
-                       class_name = mono_type_get_full_name (error->klass);
-               else
-                       class_name = g_strdup ("");
-
-               mono_loader_clear_error ();
-               
-               ex = mono_get_exception_missing_field (class_name, cmembername);
-               g_free (class_name);
-               g_free (cmembername);
-               break;
-        }
-       
-       case MONO_EXCEPTION_FILE_NOT_FOUND: {
-               char *msg;
-               char *filename;
-
-               if (error->ref_only)
-                       msg = g_strdup_printf ("Cannot resolve dependency to assembly '%s' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.", error->assembly_name);
-               else
-                       msg = g_strdup_printf ("Could not load file or assembly '%s' or one of its dependencies.", error->assembly_name);
-               filename = g_strdup (error->assembly_name);
-               /* Has to call this before calling anything which might call mono_class_init () */
-               mono_loader_clear_error ();
-               ex = mono_get_exception_file_not_found2 (msg, mono_string_new (mono_domain_get (), filename));
-               g_free (msg);
-               g_free (filename);
-               break;
-       }
-
-       case MONO_EXCEPTION_BAD_IMAGE: {
-               char *msg = g_strdup (error->msg);
-               mono_loader_clear_error ();
-               ex = mono_get_exception_bad_image_format (msg);
-               g_free (msg);
-               break;
-       }
-
-       default:
-               g_assert_not_reached ();
-       }
-
-       return ex;
-}
-
 /*
  * find_cached_memberref_sig:
  *
@@ -528,7 +247,6 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
        field = mono_class_get_field_from_name_full (klass, fname, sig_type);
 
        if (!field) {
-               mono_loader_assert_no_error ();
                mono_error_set_field_load (error, klass, fname, "Could not find field '%s'", fname);
        }
 
@@ -563,7 +281,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);
@@ -580,7 +300,6 @@ mono_field_from_token_checked (MonoImage *image, guint32 token, MonoClass **retk
 
        if (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF) {
                field = field_from_memberref (image, token, retklass, context, error);
-               mono_loader_assert_no_error ();
        } else {
                type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
                if (!type) {
@@ -596,10 +315,7 @@ mono_field_from_token_checked (MonoImage *image, guint32 token, MonoClass **retk
                        *retklass = k;
                field = mono_class_get_field (k, token);
                if (!field) {
-                       if (mono_loader_get_last_error ())
-                               mono_error_set_from_loader_error (error);
-                       else
-                               mono_error_set_bad_image (error, image, "Could not resolve field token 0x%08x", token);
+                       mono_error_set_bad_image (error, image, "Could not resolve field token 0x%08x", token);
                }
        }
 
@@ -609,7 +325,6 @@ mono_field_from_token_checked (MonoImage *image, guint32 token, MonoClass **retk
                mono_image_unlock (image);
        }
 
-       mono_loader_assert_no_error ();
        return field;
 }
 
@@ -874,27 +589,31 @@ mono_inflate_generic_signature (MonoMethodSignature *sig, MonoGenericContext *co
 static MonoMethodHeader*
 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;
+
+       res->is_transient = TRUE;
 
        mono_error_init (error);
 
-       for (i = 0; i < header->num_locals; ++i) {
+       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;
@@ -919,7 +638,7 @@ mono_method_get_signature_full (MonoMethod *method, MonoImage *image, guint32 to
 {
        MonoError error;
        MonoMethodSignature *res = mono_method_get_signature_checked (method, image, token, context, &error);
-       g_assert (mono_error_ok (&error));
+       mono_error_cleanup (&error);
        return res;
 }
 
@@ -1020,7 +739,7 @@ mono_method_get_signature (MonoMethod *method, MonoImage *image, guint32 token)
 {
        MonoError error;
        MonoMethodSignature *res = mono_method_get_signature_checked (method, image, token, NULL, &error);
-       g_assert (mono_error_ok (&error));
+       mono_error_cleanup (&error);
        return res;
 }
 
@@ -1158,19 +877,14 @@ method_from_memberref (MonoImage *image, guint32 idx, MonoGenericContext *typesp
                g_free (msig);
                msig = g_string_free (s, FALSE);
 
-               if (mono_loader_get_last_error ()) /* FIXME find_method and mono_method_search_in_array_class can leak a loader error */
-                       mono_error_set_from_loader_error (error);
-               else
-                       mono_error_set_method_load (error, klass, mname, "Could not find method %s", msig);
+               mono_error_set_method_load (error, klass, mname, "Could not find method %s", msig);
 
                g_free (msig);
        }
 
-       mono_loader_assert_no_error ();
        return method;
 
 fail:
-       mono_loader_assert_no_error ();
        g_assert (!mono_error_ok (error));
        return NULL;
 }
@@ -1236,7 +950,6 @@ method_from_methodspec (MonoImage *image, MonoGenericContext *context, guint32 i
        new_context.method_inst = inst;
 
        method = mono_class_inflate_generic_method_full_checked (method, klass, &new_context, error);
-       mono_loader_assert_no_error ();
        return method;
 }
 
@@ -1281,6 +994,7 @@ mono_dllmap_lookup_list (MonoDllMap *dll_map, const char *dll, const char* func,
                         */
                }
                if (dll_map->func && strcmp (dll_map->func, func) == 0) {
+                       *rdll = dll_map->target;
                        *rfunc = dll_map->target_func;
                        break;
                }
@@ -1308,7 +1022,7 @@ mono_dllmap_lookup (MonoImage *assembly, const char *dll, const char* func, cons
  * @dll: The name of the external library, as it would be found in the DllImport declaration.  If prefixed with 'i:' the matching of the library name is done without case sensitivity
  * @func: if not null, the mapping will only applied to the named function (the value of EntryPoint)
  * @tdll: The name of the library to map the specified @dll if it matches.
- * @tfunc: if func is not NULL, the name of the function that replaces the invocation
+ * @tfunc: The name of the function that replaces the invocation.  If NULL, it is replaced with a copy of @func.
  *
  * LOCKING: Acquires the loader lock.
  *
@@ -1343,7 +1057,7 @@ mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, cons
                entry->dll = dll? g_strdup (dll): NULL;
                entry->target = tdll? g_strdup (tdll): NULL;
                entry->func = func? g_strdup (func): NULL;
-               entry->target_func = tfunc? g_strdup (tfunc): NULL;
+               entry->target_func = tfunc? g_strdup (tfunc): (func? g_strdup (func): NULL);
 
                global_loader_data_lock ();
                entry->next = global_dll_map;
@@ -1354,7 +1068,7 @@ mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, cons
                entry->dll = dll? mono_image_strdup (assembly, dll): NULL;
                entry->target = tdll? mono_image_strdup (assembly, tdll): NULL;
                entry->func = func? mono_image_strdup (assembly, func): NULL;
-               entry->target_func = tfunc? mono_image_strdup (assembly, tfunc): NULL;
+               entry->target_func = tfunc? mono_image_strdup (assembly, tfunc): (func? mono_image_strdup (assembly, func): NULL);
 
                mono_image_lock (assembly);
                entry->next = assembly->dll_map;
@@ -1409,6 +1123,14 @@ cached_module_load (const char *name, int flags, char **err)
        return res;
 }
 
+void
+mono_loader_register_module (const char *name, MonoDl *module)
+{
+       if (!global_module_map)
+               global_module_map = g_hash_table_new (g_str_hash, g_str_equal);
+       g_hash_table_insert (global_module_map, g_strdup (name), module);
+}
+
 static MonoDl *internal_module;
 
 static gboolean
@@ -1873,8 +1595,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);
-               mono_loader_assert_no_error ();
+               result = (MonoMethod *)mono_lookup_dynamic_token_class (image, token, TRUE, &handle_class, context, error);
+               mono_error_assert_ok (error);
 
                // This checks the memberref type as well
                if (result && handle_class != mono_defaults.methodhandle_class) {
@@ -1945,7 +1667,6 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
         */
        if (*sig & 0x10) {
                generic_container = mono_metadata_load_generic_params (image, token, container);
-               mono_loader_assert_no_error (); /* FIXME don't swallow this error. */
        }
        if (generic_container) {
                result->is_generic = TRUE;
@@ -1980,7 +1701,6 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
        if (generic_container)
                mono_method_set_generic_container (result, generic_container);
 
-       mono_loader_assert_no_error ();
        return result;
 }
 
@@ -2421,8 +2141,6 @@ mono_method_get_wrapper_data (MonoMethod *method, guint32 id)
        g_assert (method != NULL);
        g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
 
-       if (method->is_inflated)
-               method = ((MonoMethodInflated *) method)->declaring;
        data = (void **)((MonoMethodWrapper *)method)->method_data;
        g_assert (data != NULL);
        g_assert (id <= GPOINTER_TO_UINT (*data));
@@ -2512,7 +2230,7 @@ mono_stack_walk_async_safe (MonoStackWalkAsyncSafe func, void *initial_sig_conte
        AsyncStackWalkUserData ud = { func, user_data };
 
        mono_sigctx_to_monoctx (initial_sig_context, &ctx);
-       mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (async_stack_walk_adapter, NULL, MONO_UNWIND_SIGNAL_SAFE, &ud);
+       mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (async_stack_walk_adapter, &ctx, MONO_UNWIND_SIGNAL_SAFE, &ud);
 }
 
 static gboolean
@@ -2797,50 +2515,37 @@ mono_method_get_token (MonoMethod *method)
 }
 
 MonoMethodHeader*
-mono_method_get_header (MonoMethod *method)
+mono_method_get_header_checked (MonoMethod *method, MonoError *error)
 {
-       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), &error);
+               iheader = inflate_generic_header (header, mono_method_get_context (method), error);
                mono_metadata_free_mh (header);
                if (!iheader) {
-                       mono_loader_set_error_from_mono_error (&error);
                        return NULL;
                }
 
-               mono_image_lock (img);
-
-               if (imethod->header) {
-                       mono_metadata_free_mh (iheader);
-                       mono_image_unlock (img);
-                       return imethod->header;
-               }
-
-               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) {
@@ -2857,12 +2562,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
@@ -2871,13 +2580,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, &error);
-       if (!header)
-               mono_loader_set_error_from_mono_error (&error);
+       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)
 {