X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fassembly.c;h=2d0557264401727357c41bfdc125a9068ad3d1e2;hb=60979ce4a41d1be8f9d3d4d38162c0803207b4d5;hp=42411c569915445779335e8adda4a2ed3ea197d5;hpb=038598e503d3db631224288ca5295988c3d22288;p=mono.git diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c index 42411c56991..2d055726440 100644 --- a/mono/metadata/assembly.c +++ b/mono/metadata/assembly.c @@ -6,6 +6,7 @@ * * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) * Copyright 2004-2009 Novell, Inc (http://www.novell.com) + * Copyright 2011 Xamarin, Inc (http://www.xamarin.com) */ #include #include @@ -32,6 +33,8 @@ #include #include #include +#include +#include #ifndef HOST_WIN32 #include @@ -65,6 +68,9 @@ static char **extra_gac_paths = NULL; #ifndef DISABLE_ASSEMBLY_REMAPPING /* The list of system assemblies what will be remapped to the running * runtime version. WARNING: this list must be sorted. + * 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. */ static const AssemblyVersionMap framework_assemblies [] = { {"Accessibility", 0}, @@ -109,9 +115,11 @@ static const AssemblyVersionMap framework_assemblies [] = { {"System.Management", 0}, {"System.Messaging", 0}, {"System.Runtime.Remoting", 0}, + {"System.Runtime.Serialization", 3}, {"System.Runtime.Serialization.Formatters.Soap", 0}, {"System.Security", 0}, {"System.ServiceProcess", 0}, + {"System.Transactions", 0}, {"System.Web", 0}, {"System.Web.Abstractions", 2}, {"System.Web.Mobile", 0}, @@ -196,16 +204,24 @@ mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *p return memcmp (pubt1, pubt2, 16) == 0; } -static void -check_path_env (void) +/** + * mono_set_assemblies_path: + * @path: list of paths that contain directories where Mono will look for assemblies + * + * Use this method to override the standard assembly lookup system and + * override any assemblies coming from the GAC. This is the method + * that supports the MONO_PATH variable. + * + * Notice that MONO_PATH and this method are really a very bad idea as + * it prevents the GAC from working and it prevents the standard + * resolution mechanisms from working. Nonetheless, for some debugging + * situations and bootstrapping setups, this is useful to have. + */ +void +mono_set_assemblies_path (const char* path) { - const char *path; char **splitted, **dest; - path = g_getenv ("MONO_PATH"); - if (!path) - return; - splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000); if (assemblies_path) g_strfreev (assemblies_path); @@ -229,6 +245,27 @@ check_path_env (void) } } +/* Native Client can't get this info from an environment variable so */ +/* it's passed in to the runtime, or set manually by embedding code. */ +#ifdef __native_client__ +char* nacl_mono_path = NULL; +#endif + +static void +check_path_env (void) +{ + const char* path; + path = g_getenv ("MONO_PATH"); +#ifdef __native_client__ + if (!path) + path = nacl_mono_path; +#endif + if (!path || assemblies_path != NULL) + return; + + mono_set_assemblies_path(path); +} + static void check_extra_gac_path_env (void) { const char *path; @@ -530,7 +567,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, "/monodis") && strcmp (p, "/mint") && strcmp (p, "/monodiet")) + if (strcmp (p, "/mono") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis") && strcmp (p, "/mint") && strcmp (p, "/monodiet")) return NULL; *p = 0; @@ -550,7 +587,7 @@ fallback (void) mono_set_dirs (MONO_ASSEMBLIES, MONO_CFG_DIR); } -static void +static G_GNUC_UNUSED void set_dirs (char *exe) { char *base; @@ -567,7 +604,7 @@ set_dirs (char *exe) config = g_build_filename (base, "etc", NULL); lib = g_build_filename (base, "lib", NULL); - mono = g_build_filename (lib, "mono/1.0", NULL); + mono = g_build_filename (lib, "mono/2.0", NULL); if (stat (mono, &buf) == -1) fallback (); else { @@ -614,8 +651,6 @@ mono_set_rootdir (void) fallback (); return; } - - name = mono_path_resolve_symlinks (name); } #endif @@ -799,7 +834,53 @@ mono_assembly_addref (MonoAssembly *assembly) InterlockedIncrement (&assembly->ref_count); } -#ifndef DISABLE_ASSEMBLY_REMAPPING +#define SILVERLIGHT_KEY "7cec85d7bea7798e" +#define WINFX_KEY "31bf3856ad364e35" +#define ECMA_KEY "b77a5c561934e089" +#define MSFINAL_KEY "b03f5f7f11d50a3a" + +typedef struct { + const char *name; + const char *from; + const char *to; +} KeyRemapEntry; + +static KeyRemapEntry key_remap_table[] = { + { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY }, + { "System", SILVERLIGHT_KEY, ECMA_KEY }, + { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY }, + { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY }, + { "System.Core", SILVERLIGHT_KEY, ECMA_KEY }, + { "System.Numerics", WINFX_KEY, ECMA_KEY }, + { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY }, + { "System.ServiceModel", WINFX_KEY, ECMA_KEY }, + { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY }, + { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY }, + { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY }, + { "System.Xml.Linq", WINFX_KEY, ECMA_KEY }, + { "System.Xml.Serialization", WINFX_KEY, MSFINAL_KEY } +}; + +static void +remap_keys (MonoAssemblyName *aname) +{ + int i; + for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) { + const KeyRemapEntry *entry = &key_remap_table [i]; + + if (strcmp (aname->name, entry->name) || + !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from)) + continue; + + memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH); + + mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, + "Remapped public key token of retargetable assembly %s from %s to %s", + aname->name, entry->from, entry->to); + return; + } +} + static MonoAssemblyName * mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname) { @@ -807,8 +888,40 @@ mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_ana int pos, first, last; if (aname->name == NULL) return aname; + current_runtime = mono_get_runtime_info (); + if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) { + const AssemblyVersionSet* vset; + + /* Remap to current runtime */ + vset = ¤t_runtime->version_sets [0]; + + memcpy (dest_aname, aname, sizeof(MonoAssemblyName)); + dest_aname->major = vset->major; + dest_aname->minor = vset->minor; + dest_aname->build = vset->build; + dest_aname->revision = vset->revision; + dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG; + + /* Remap assembly name */ + if (!strcmp (aname->name, "System.Net")) + dest_aname->name = g_strdup ("System"); + + remap_keys (dest_aname); + + mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, + "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d", + aname->name, + aname->major, aname->minor, aname->build, aname->revision, + dest_aname->name, + vset->major, vset->minor, vset->build, vset->revision + ); + + return dest_aname; + } + +#ifndef DISABLE_ASSEMBLY_REMAPPING first = 0; last = G_N_ELEMENTS (framework_assemblies) - 1; @@ -846,9 +959,10 @@ mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_ana first = pos + 1; } } +#endif + return aname; } -#endif /* * mono_assembly_get_assemblyref: @@ -965,11 +1079,11 @@ mono_assembly_load_reference (MonoImage *image, int index) if (reference != REFERENCE_MISSING){ mono_assembly_addref (reference); if (image->assembly) - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d", + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d", image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count); } else { if (image->assembly) - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n", + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n", image->assembly->aname.name, image->assembly); } @@ -1564,7 +1678,7 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, /* Add a non-temporary reference because of ass->image */ mono_image_addref (image); - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s %p -> %s %p: %d", ass->aname.name, ass, image->name, image, image->ref_count); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s[%p] -> %s[%p]: %d", ass->aname.name, ass, image->name, image, image->ref_count); /* * The load hooks might take locks so we can't call them while holding the @@ -1640,7 +1754,7 @@ mono_assembly_name_free (MonoAssemblyName *aname) } static gboolean -parse_public_key (const gchar *key, gchar** pubkey) +parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma) { const gchar *pkey; gchar header [16], val, *arr; @@ -1649,7 +1763,16 @@ parse_public_key (const gchar *key, gchar** pubkey) keylen = strlen (key) >> 1; if (keylen < 1) return FALSE; - + + /* allow the ECMA standard key */ + if (strcmp (key, "00000000000000000400000000000000") == 0) { + if (pubkey) { + *pubkey = g_strdup (key); + *is_ecma = TRUE; + } + return TRUE; + } + *is_ecma = FALSE; val = g_ascii_xdigit_value (key [0]) << 4; val |= g_ascii_xdigit_value (key [1]); switch (val) { @@ -1772,10 +1895,20 @@ build_assembly_name (const char *name, const char *version, const char *culture, } if (key) { - if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey)) { + gboolean is_ecma; + if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) { mono_assembly_name_free (aname); return FALSE; } + + if (is_ecma) { + if (save_public_key) + aname->public_key = (guint8*)pkey; + else + g_free (pkey); + g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH); + return TRUE; + } len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr); // We also need to generate the key token @@ -1810,6 +1943,25 @@ parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemb return res; } +static gboolean +split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value) +{ + char *eqsign = strchr (pair, '='); + if (!eqsign) { + *key = NULL; + *keylen = 0; + *value = NULL; + return FALSE; + } + + *key = (gchar*)pair; + *keylen = eqsign - *key; + while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1])) + (*keylen)--; + *value = g_strstrip (eqsign + 1); + return TRUE; +} + gboolean mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined) { @@ -1820,13 +1972,14 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole gchar *key = NULL; gchar *retargetable = NULL; gboolean res; - gchar *value; + gchar *value, *part_name; + guint32 part_name_len; gchar **parts; gchar **tmp; gboolean version_defined; gboolean token_defined; guint32 flags = 0; - guint32 arch = PROCESSOR_ARCHITECTURE_NONE; + guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE; if (!is_version_defined) is_version_defined = &version_defined; @@ -1846,10 +1999,12 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole tmp++; while (*tmp) { - value = g_strstrip (*tmp); - if (!g_ascii_strncasecmp (value, "Version=", 8)) { + if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value)) + goto cleanup_and_fail; + + if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) { *is_version_defined = TRUE; - version = g_strstrip (value + 8); + version = value; if (strlen (version) == 0) { goto cleanup_and_fail; } @@ -1857,8 +2012,8 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole continue; } - if (!g_ascii_strncasecmp (value, "Culture=", 8)) { - culture = g_strstrip (value + 8); + if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) { + culture = value; if (strlen (culture) == 0) { goto cleanup_and_fail; } @@ -1866,9 +2021,9 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole continue; } - if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) { + if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) { *is_token_defined = TRUE; - token = g_strstrip (value + 15); + token = value; if (strlen (token) == 0) { goto cleanup_and_fail; } @@ -1876,8 +2031,8 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole continue; } - if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) { - key = g_strstrip (value + 10); + if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) { + key = value; if (strlen (key) == 0) { goto cleanup_and_fail; } @@ -1885,8 +2040,8 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole continue; } - if (!g_ascii_strncasecmp (value, "Retargetable=", 13)) { - retargetable = g_strstrip (value + 13); + if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) { + retargetable = value; if (strlen (retargetable) == 0) { goto cleanup_and_fail; } @@ -1899,18 +2054,17 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole continue; } - if (!g_ascii_strncasecmp (value, "ProcessorArchitecture=", 22)) { - char *s = g_strstrip (value + 22); - if (!g_ascii_strcasecmp (s, "None")) - arch = PROCESSOR_ARCHITECTURE_NONE; - else if (!g_ascii_strcasecmp (s, "MSIL")) - arch = PROCESSOR_ARCHITECTURE_MSIL; - else if (!g_ascii_strcasecmp (s, "X86")) - arch = PROCESSOR_ARCHITECTURE_X86; - else if (!g_ascii_strcasecmp (s, "IA64")) - arch = PROCESSOR_ARCHITECTURE_IA64; - else if (!g_ascii_strcasecmp (s, "AMD64")) - arch = PROCESSOR_ARCHITECTURE_AMD64; + if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) { + if (!g_ascii_strcasecmp (value, "None")) + arch = MONO_PROCESSOR_ARCHITECTURE_NONE; + else if (!g_ascii_strcasecmp (value, "MSIL")) + arch = MONO_PROCESSOR_ARCHITECTURE_MSIL; + else if (!g_ascii_strcasecmp (value, "X86")) + arch = MONO_PROCESSOR_ARCHITECTURE_X86; + else if (!g_ascii_strcasecmp (value, "IA64")) + arch = MONO_PROCESSOR_ARCHITECTURE_IA64; + else if (!g_ascii_strcasecmp (value, "AMD64")) + arch = MONO_PROCESSOR_ARCHITECTURE_AMD64; else goto cleanup_and_fail; tmp++; @@ -2079,9 +2233,7 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta { MonoAssembly *res; MonoAssemblyName *aname, base_name; -#ifndef DISABLE_ASSEMBLY_REMAPPING - MonoAssemblyName maped_aname; -#endif + MonoAssemblyName mapped_aname; gchar *fullname, *gacpath; gchar **paths; @@ -2091,14 +2243,12 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta if (!mono_assembly_name_parse (name, aname)) return NULL; -#ifndef DISABLE_ASSEMBLY_REMAPPING /* * If no specific version has been requested, make sure we load the * correct version for system assemblies. */ if ((aname->major | aname->minor | aname->build | aname->revision) == 0) - aname = mono_assembly_remap_version (aname, &maped_aname); -#endif + aname = mono_assembly_remap_version (aname, &mapped_aname); res = mono_assembly_loaded (aname); if (res) { @@ -2437,17 +2587,31 @@ mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_nam if (domain && domain->setup && domain->setup->configuration_file) { mono_domain_lock (domain); if (!domain->assembly_bindings_parsed) { - gchar *domain_config_file = mono_string_to_utf8 (domain->setup->configuration_file); + gchar *domain_config_file_name = mono_string_to_utf8 (domain->setup->configuration_file); + gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE); - mono_config_parse_assembly_bindings (domain_config_file, aname->major, aname->minor, domain, assembly_binding_info_parsed); + if (!domain_config_file_path) + domain_config_file_path = domain_config_file_name; + + mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed); domain->assembly_bindings_parsed = TRUE; - g_free (domain_config_file); + if (domain_config_file_name != domain_config_file_path) + g_free (domain_config_file_name); + g_free (domain_config_file_path); } mono_domain_unlock (domain); mono_loader_lock (); mono_domain_lock (domain); - info = get_per_domain_assembly_binding_info (domain, aname); + info2 = get_per_domain_assembly_binding_info (domain, aname); + + if (info2) { + info = g_memdup (info2, sizeof (MonoAssemblyBindingInfo)); + info->name = g_strdup (info2->name); + info->culture = g_strdup (info2->culture); + info->domain_id = domain->domain_id; + } + mono_domain_unlock (domain); mono_loader_unlock (); } @@ -2630,17 +2794,13 @@ mono_assembly_load_full_nosearch (MonoAssemblyName *aname, { MonoAssembly *result; char *fullpath, *filename; -#ifndef DISABLE_ASSEMBLY_REMAPPING MonoAssemblyName maped_aname; -#endif MonoAssemblyName maped_name_pp; int ext_index; const char *ext; int len; -#ifndef DISABLE_ASSEMBLY_REMAPPING aname = mono_assembly_remap_version (aname, &maped_aname); -#endif /* Reflection only assemblies don't get assembly binding */ if (!refonly) @@ -2751,11 +2911,9 @@ MonoAssembly* mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly) { MonoAssembly *res; -#ifndef DISABLE_ASSEMBLY_REMAPPING MonoAssemblyName maped_aname; aname = mono_assembly_remap_version (aname, &maped_aname); -#endif res = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE); @@ -2775,6 +2933,21 @@ mono_assembly_loaded (MonoAssemblyName *aname) return mono_assembly_loaded_full (aname, FALSE); } +void +mono_assembly_release_gc_roots (MonoAssembly *assembly) +{ + if (assembly == NULL || assembly == REFERENCE_MISSING) + return; + + if (assembly->dynamic) { + int i; + MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image; + for (i = 0; i < dynimg->image.module_count; ++i) + mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]); + mono_dynamic_image_release_gc_roots (dynimg); + } +} + /* * Returns whether mono_assembly_close_finish() must be called as * well. See comment for mono_image_close_except_pools() for why we @@ -2899,6 +3072,27 @@ mono_assemblies_cleanup (void) free_assembly_preload_hooks (); } +/*LOCKING assumes loader lock is held*/ +void +mono_assembly_cleanup_domain_bindings (guint32 domain_id) +{ + GSList **iter = &loaded_assembly_bindings; + + while (*iter) { + GSList *l = *iter; + MonoAssemblyBindingInfo *info = l->data; + + if (info->domain_id == domain_id) { + *iter = l->next; + mono_assembly_binding_info_free (info); + g_free (info); + g_slist_free_1 (l); + } else { + iter = &l->next; + } + } +} + /* * Holds the assembly of the application, for * System.Diagnostics.Process::MainModule