Merge pull request #2198 from BrzVlad/feature-concurrent-work
[mono.git] / mono / metadata / assembly.c
index 15d60411420a0e041ea0b2fdcfaec9ea6465b01f..c44dffda11e2777e042f822e00e0d02ce301b18d 100644 (file)
@@ -28,6 +28,7 @@
 #include <mono/io-layer/io-layer.h>
 #include <mono/utils/mono-uri.h>
 #include <mono/metadata/mono-config.h>
+#include <mono/metadata/mono-config-dirs.h>
 #include <mono/utils/mono-digest.h>
 #include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/mono-path.h>
@@ -74,6 +75,9 @@ static char **extra_gac_paths = NULL;
  * The integer number is an index in the MonoRuntimeInfo structure, whose
  * values can be found in domain.c - supported_runtimes. Look there
  * to understand what remapping will be made.
+ *
+ * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
+ *
  */
 static const AssemblyVersionMap framework_assemblies [] = {
        {"Accessibility", 0},
@@ -84,6 +88,8 @@ static const AssemblyVersionMap framework_assemblies [] = {
        {"I18N.Other", 0},
        {"I18N.Rare", 0},
        {"I18N.West", 0},
+       {"Microsoft.Build.Engine", 2},
+       {"Microsoft.Build.Framework", 2},
        {"Microsoft.VisualBasic", 1},
        {"Microsoft.VisualC", 1},
        {"Mono.Cairo", 0},
@@ -102,6 +108,7 @@ static const AssemblyVersionMap framework_assemblies [] = {
        {"Npgsql", 0},
        {"PEAPI", 0},
        {"System", 0},
+       {"System.ComponentModel.Composition", 2},
        {"System.ComponentModel.DataAnnotations", 2},
        {"System.Configuration", 0},
        {"System.Configuration.Install", 0},
@@ -117,6 +124,8 @@ static const AssemblyVersionMap framework_assemblies [] = {
        {"System.Drawing", 0},
        {"System.Drawing.Design", 0},
        {"System.EnterpriseServices", 0},
+       {"System.IdentityModel", 3},
+       {"System.IdentityModel.Selectors", 3},
        {"System.Management", 0},
        {"System.Messaging", 0},
        {"System.Net", 2},
@@ -124,6 +133,7 @@ static const AssemblyVersionMap framework_assemblies [] = {
        {"System.Runtime.Serialization", 3},
        {"System.Runtime.Serialization.Formatters.Soap", 0},
        {"System.Security", 0},
+       {"System.ServiceModel", 3},
        {"System.ServiceModel.Web", 2},
        {"System.ServiceProcess", 0},
        {"System.Transactions", 0},
@@ -169,10 +179,12 @@ mono_set_corlib_data (void *data, size_t size)
 
 #endif
 
+static char* unquote (const char *str);
+
 /* This protects loaded_assemblies and image->references */
-#define mono_assemblies_lock() EnterCriticalSection (&assemblies_mutex)
-#define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex)
-static CRITICAL_SECTION assemblies_mutex;
+#define mono_assemblies_lock() mono_mutex_lock (&assemblies_mutex)
+#define mono_assemblies_unlock() mono_mutex_unlock (&assemblies_mutex)
+static mono_mutex_t assemblies_mutex;
 
 /* If defined, points to the bundled assembly information */
 const MonoBundledAssembly **bundles;
@@ -183,7 +195,9 @@ static mono_mutex_t assembly_binding_mutex;
 static GSList *loaded_assembly_bindings = NULL;
 
 static MonoAssembly*
-mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload);
+mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
+static MonoAssembly*
+mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
 static MonoBoolean
 mono_assembly_is_in_gac (const gchar *filanem);
 
@@ -560,14 +574,10 @@ mono_assembly_getrootdir (void)
 void
 mono_set_dirs (const char *assembly_dir, const char *config_dir)
 {
-#if defined (MONO_ASSEMBLIES)
        if (assembly_dir == NULL)
-               assembly_dir = MONO_ASSEMBLIES;
-#endif
-#if defined (MONO_CFG_DIR)
+               assembly_dir = mono_config_get_assemblies_dir ();
        if (config_dir == NULL)
-               config_dir = MONO_CFG_DIR;
-#endif
+               config_dir = mono_config_get_cfg_dir ();
        mono_assembly_setrootdir (assembly_dir);
        mono_set_config_dir (config_dir);
 }
@@ -582,7 +592,7 @@ compute_base (char *path)
                return NULL;
 
        /* Not a well known Mono executable, we are embedded, cant guess the base  */
-       if (strcmp (p, "/mono") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis") && strcmp (p, "/mint") && strcmp (p, "/monodiet"))
+       if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
                return NULL;
            
        *p = 0;
@@ -599,7 +609,7 @@ compute_base (char *path)
 static void
 fallback (void)
 {
-       mono_set_dirs (MONO_ASSEMBLIES, MONO_CFG_DIR);
+       mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
 }
 
 static G_GNUC_UNUSED void
@@ -608,11 +618,14 @@ set_dirs (char *exe)
        char *base;
        char *config, *lib, *mono;
        struct stat buf;
+       const char *bindir;
        
        /*
         * Only /usr prefix is treated specially
         */
-       if (strncmp (exe, MONO_BINDIR, strlen (MONO_BINDIR)) == 0 || (base = compute_base (exe)) == NULL){
+       bindir = mono_config_get_bin_dir ();
+       g_assert (bindir);
+       if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
                fallback ();
                return;
        }
@@ -739,7 +752,7 @@ mono_assemblies_init (void)
        check_path_env ();
        check_extra_gac_path_env ();
 
-       InitializeCriticalSection (&assemblies_mutex);
+       mono_mutex_init_recursive (&assemblies_mutex);
        mono_mutex_init (&assembly_binding_mutex);
 }
 
@@ -1090,12 +1103,12 @@ mono_assembly_load_reference (MonoImage *image, int index)
        if (image->assembly && image->assembly->ref_only) {
                /* We use the loaded corlib */
                if (!strcmp (aname.name, "mscorlib"))
-                       reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
+                       reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
                else {
                        reference = mono_assembly_loaded_full (&aname, TRUE);
                        if (!reference)
                                /* Try a postload search hook */
-                               reference = mono_assembly_invoke_search_hook_internal (&aname, TRUE, TRUE);
+                               reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
                }
 
                /*
@@ -1111,9 +1124,9 @@ mono_assembly_load_reference (MonoImage *image, int index)
                 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
                 * example bug-349190.2.cs and who knows how much more code in the wild.
                 */
-               reference = mono_assembly_load (&aname, NULL, &status);
+               reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
                if (!reference && image->assembly)
-                       reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
+                       reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
        }
 
        if (reference == NULL){
@@ -1232,13 +1245,36 @@ struct AssemblySearchHook {
 AssemblySearchHook *assembly_search_hook = NULL;
 
 static MonoAssembly*
-mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload)
+mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
 {
        AssemblySearchHook *hook;
 
        for (hook = assembly_search_hook; hook; hook = hook->next) {
                if ((hook->refonly == refonly) && (hook->postload == postload)) {
-                       MonoAssembly *ass = hook->func (aname, hook->user_data);
+                       MonoAssembly *ass;
+                       /**
+                         * A little explanation is in order here.
+                         *
+                         * The default postload search hook needs to know the requesting assembly to report it to managed code.
+                         * The embedding API exposes a search hook that doesn't take such argument.
+                         *
+                         * The original fix would call the default search hook before all the registered ones and pass
+                         * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
+                         * rely on. Which is the ordering between user hooks and the default runtime hook.
+                         *
+                         * Registering the hook after mono_jit_init would let your hook run before the default one and
+                         * when using it to handle non standard app layouts this could save your app from a massive amount
+                         * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
+                         * are all using this trick and if we broke this assumption they would be very disapointed at us.
+                         *
+                         * So what's the fix? We register the default hook using regular means and special case it when iterating
+                         * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
+                         * assembly.
+                         */
+                       if (hook->func == (void*)mono_domain_assembly_postload_search)
+                               ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
+                       else
+                               ass = hook->func (aname, hook->user_data);
                        if (ass)
                                return ass;
                }
@@ -1250,7 +1286,7 @@ mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean ref
 MonoAssembly*
 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
 {
-       return mono_assembly_invoke_search_hook_internal (aname, FALSE, FALSE);
+       return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
 }
 
 static void
@@ -1552,6 +1588,7 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo
        
        image = NULL;
 
+       // If VM built with mkbundle
        loaded_from_bundle = FALSE;
        if (bundles != NULL) {
                image = mono_assembly_open_from_bundle (fname, status, refonly);
@@ -1648,7 +1685,6 @@ mono_assembly_load_friends (MonoAssembly* ass)
                MonoCustomAttrEntry *attr = &attrs->attrs [i];
                MonoAssemblyName *aname;
                const gchar *data;
-               guint slen;
                /* Do some sanity checking */
                if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class)
                        continue;
@@ -1658,7 +1694,7 @@ mono_assembly_load_friends (MonoAssembly* ass)
                /* 0xFF means null string, see custom attr format */
                if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
                        continue;
-               slen = mono_metadata_decode_value (data + 2, &data);
+               mono_metadata_decode_value (data + 2, &data);
                aname = g_new0 (MonoAssemblyName, 1);
                /*g_print ("friend ass: %s\n", data);*/
                if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
@@ -1764,7 +1800,7 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
         * assemblies lock.
         */
        if (ass->aname.name) {
-               ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, refonly, FALSE);
+               ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
                if (ass2) {
                        g_free (ass);
                        g_free (base_dir);
@@ -2045,11 +2081,19 @@ gboolean
 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
 {
        gchar *dllname;
+       gchar *dllname_uq;
        gchar *version = NULL;
+       gchar *version_uq;
        gchar *culture = NULL;
+       gchar *culture_uq;
        gchar *token = NULL;
+       gchar *token_uq;
        gchar *key = NULL;
+       gchar *key_uq;
        gchar *retargetable = NULL;
+       gchar *retargetable_uq;
+       gchar *procarch;
+       gchar *procarch_uq;
        gboolean res;
        gchar *value, *part_name;
        guint32 part_name_len;
@@ -2121,29 +2165,42 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole
 
                if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
                        retargetable = value;
-                       if (strlen (retargetable) == 0) {
-                               goto cleanup_and_fail;
-                       }
+                       retargetable_uq = unquote (retargetable);
+                       if (retargetable_uq != NULL)
+                               retargetable = retargetable_uq;
+
                        if (!g_ascii_strcasecmp (retargetable, "yes")) {
                                flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
                        } else if (g_ascii_strcasecmp (retargetable, "no")) {
+                               free (retargetable_uq);
                                goto cleanup_and_fail;
                        }
+
+                       free (retargetable_uq);
                        tmp++;
                        continue;
                }
 
                if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
-                       if (!g_ascii_strcasecmp (value, "MSIL"))
+                       procarch = value;
+                       procarch_uq = unquote (procarch);
+                       if (procarch_uq != NULL)
+                               procarch = procarch_uq;
+
+                       if (!g_ascii_strcasecmp (procarch, "MSIL"))
                                arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
-                       else if (!g_ascii_strcasecmp (value, "X86"))
+                       else if (!g_ascii_strcasecmp (procarch, "X86"))
                                arch = MONO_PROCESSOR_ARCHITECTURE_X86;
-                       else if (!g_ascii_strcasecmp (value, "IA64"))
+                       else if (!g_ascii_strcasecmp (procarch, "IA64"))
                                arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
-                       else if (!g_ascii_strcasecmp (value, "AMD64"))
+                       else if (!g_ascii_strcasecmp (procarch, "AMD64"))
                                arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
-                       else
+                       else {
+                               free (procarch_uq);
                                goto cleanup_and_fail;
+                       }
+
+                       free (procarch_uq);
                        tmp++;
                        continue;
                }
@@ -2157,8 +2214,26 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole
                goto cleanup_and_fail;
        }
 
-       res = build_assembly_name (dllname, version, culture, token, key, flags, arch,
-               aname, save_public_key);
+       dllname_uq = unquote (dllname);
+       version_uq = unquote (version);
+       culture_uq = unquote (culture);
+       token_uq = unquote (token);
+       key_uq = unquote (key);
+
+       res = build_assembly_name (
+               dllname_uq == NULL ? dllname : dllname_uq,
+               version_uq == NULL ? version : version_uq,
+               culture_uq == NULL ? culture : culture_uq,
+               token_uq == NULL ? token : token_uq,
+               key_uq == NULL ? key : key_uq,
+               flags, arch, aname, save_public_key);
+
+       free (dllname_uq);
+       free (version_uq);
+       free (culture_uq);
+       free (token_uq);
+       free (key_uq);
+
        g_strfreev (parts);
        return res;
 
@@ -2167,6 +2242,29 @@ cleanup_and_fail:
        return FALSE;
 }
 
+static char*
+unquote (const char *str)
+{
+       gint slen;
+       const char *end;
+
+       if (str == NULL)
+               return NULL;
+
+       slen = strlen (str);
+       if (slen < 2)
+               return NULL;
+
+       if (*str != '\'' && *str != '\"')
+               return NULL;
+
+       end = str + slen - 1;
+       if (*str != *end)
+               return NULL;
+
+       return g_strndup (str + 1, slen - 2);
+}
+
 /**
  * mono_assembly_name_parse:
  * @name: name to parse
@@ -2367,7 +2465,7 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta
                res->in_gac = TRUE;
        else {
                MonoDomain *domain = mono_domain_get ();
-               MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), FALSE);
+               MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE);
                if (refasm)
                        res = refasm->assembly;
        }
@@ -2823,6 +2921,7 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *
                return corlib;
        }
 
+       // In native client, Corlib is embedded in the executable as static variable corlibData
 #if defined(__native_client__)
        if (corlibData != NULL && corlibSize != 0) {
                int status = 0;
@@ -2839,6 +2938,7 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *
        }
 #endif
 
+       // A nonstandard preload hook may provide a special mscorlib assembly
        aname = mono_assembly_name_new ("mscorlib.dll");
        corlib = invoke_assembly_preload_hook (aname, assemblies_path);
        mono_assembly_name_free (aname);
@@ -2846,16 +2946,16 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *
        if (corlib != NULL)
                return corlib;
 
-       if (assemblies_path) {
+       // This unusual directory layout can occur if mono is being built and run out of its own source repo
+       if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
                corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
                if (corlib)
                        return corlib;
        }
 
-       /* Load corlib from mono/<version> */
-       
+       /* Normal case: Load corlib from mono/<version> */
        corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
-       if (assemblies_path) {
+       if (assemblies_path) { // Custom assemblies path
                corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
                if (corlib) {
                        g_free (corlib_file);
@@ -2947,6 +3047,17 @@ mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
        return result;
 }
 
+MonoAssembly*
+mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
+{
+       MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
+
+       if (!result)
+               /* Try a postload search hook */
+               result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
+       return result;
+}
+
 /**
  * mono_assembly_load_full:
  * @aname: A MonoAssemblyName with the assembly name to load.
@@ -2966,12 +3077,7 @@ mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
 MonoAssembly*
 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
 {
-       MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
-       
-       if (!result)
-               /* Try a postload search hook */
-               result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE);
-       return result;
+       return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
 }
 
 /**
@@ -2989,9 +3095,9 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage
 MonoAssembly*
 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
 {
-       return mono_assembly_load_full (aname, basedir, status, FALSE);
+       return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
 }
-       
+
 MonoAssembly*
 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
 {
@@ -3000,7 +3106,7 @@ mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
 
        aname = mono_assembly_remap_version (aname, &maped_aname);
 
-       res = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE);
+       res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
 
        return res;
 }
@@ -3024,7 +3130,7 @@ mono_assembly_release_gc_roots (MonoAssembly *assembly)
        if (assembly == NULL || assembly == REFERENCE_MISSING)
                return;
 
-       if (assembly->dynamic) {
+       if (assembly_is_dynamic (assembly)) {
                int i;
                MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
                for (i = 0; i < dynimg->image.module_count; ++i)
@@ -3087,7 +3193,7 @@ mono_assembly_close_finish (MonoAssembly *assembly)
        if (assembly->image)
                mono_image_close_finish (assembly->image);
 
-       if (assembly->dynamic) {
+       if (assembly_is_dynamic (assembly)) {
                g_free ((char*)assembly->aname.culture);
        } else {
                g_free (assembly);
@@ -3142,7 +3248,7 @@ mono_assemblies_cleanup (void)
 {
        GSList *l;
 
-       DeleteCriticalSection (&assemblies_mutex);
+       mono_mutex_destroy (&assemblies_mutex);
        mono_mutex_destroy (&assembly_binding_mutex);
 
        for (l = loaded_assembly_bindings; l; l = l->next) {
@@ -3217,6 +3323,20 @@ mono_assembly_get_image (MonoAssembly *assembly)
        return assembly->image;
 }
 
+/**
+ * mono_assembly_get_name:
+ * @assembly: The assembly to retrieve the name from
+ *
+ * The returned name's lifetime is the same as @assembly's.
+ *
+ * Returns: the MonoAssemblyName associated with this assembly.
+ */
+MonoAssemblyName *
+mono_assembly_get_name (MonoAssembly *assembly)
+{
+       return &assembly->aname;
+}
+
 void
 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
 {