Merge pull request #3591 from directhex/mono_libdir_fallback
[mono.git] / mono / metadata / loader.c
index 2195d22618f6180bcf37e2755ebdcdac3ee6dcfc..3d85497bfe0a094a8154c6277ba693e8a910f157 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:
  *
@@ -475,7 +194,7 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
        fname = mono_metadata_string_heap (image, cols [MONO_MEMBERREF_NAME]);
 
        if (!mono_verifier_verify_memberref_field_signature (image, cols [MONO_MEMBERREF_SIGNATURE], NULL)) {
-               mono_error_set_bad_image (error, image, "Bad field '%s' signature 0x%08x", class_index, token);
+               mono_error_set_bad_image (error, image, "Bad field '%u' signature 0x%08x", class_index, token);
                return NULL;
        }
 
@@ -490,7 +209,7 @@ field_from_memberref (MonoImage *image, guint32 token, MonoClass **retklass,
                klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_SPEC | nindex, context, error);
                break;
        default:
-               mono_error_set_bad_image (error, image, "Bad field field '%s' signature 0x%08x", class_index, token);
+               mono_error_set_bad_image (error, image, "Bad field field '%u' signature 0x%08x", class_index, token);
        }
 
        if (!klass)
@@ -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);
        }
 
@@ -582,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) {
@@ -598,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);
                }
        }
 
@@ -611,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;
 }
 
@@ -1164,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;
 }
@@ -1242,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;
 }
 
@@ -1287,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;
                }
@@ -1314,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.
  *
@@ -1349,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;
@@ -1360,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;
@@ -1415,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
@@ -1881,7 +1597,6 @@ mono_get_method_from_token (MonoImage *image, guint32 token, MonoClass *klass,
 
                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
                if (result && handle_class != mono_defaults.methodhandle_class) {
@@ -1952,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;
@@ -1987,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;
 }
 
@@ -2428,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));
@@ -2519,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