X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fassembly.c;h=482762d0e1a213d9a113743cd28905e159aa3aa4;hb=5b558abeeb255a3179d4ca6a85617e051c6abd38;hp=d120662b1429e903252073e3edb43aacfb0b92b9;hpb=cc9fa96a3163b4ac0b2df0726c72963017d802d6;p=mono.git diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c index d120662b142..482762d0e1a 100644 --- a/mono/metadata/assembly.c +++ b/mono/metadata/assembly.c @@ -4,8 +4,8 @@ * Author: * Miguel de Icaza (miguel@ximian.com) * - * (C) 2001 Ximian, Inc. http://www.ximian.com - * + * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) + * Copyright 2004-2009 Novell, Inc (http://www.novell.com) */ #include #include @@ -15,7 +15,6 @@ #include #include "assembly.h" #include "image.h" -#include "rawbuffer.h" #include "object-internals.h" #include #include @@ -29,16 +28,21 @@ #include #include #include -#include +#include +#include #include #include -#ifndef PLATFORM_WIN32 +#ifndef HOST_WIN32 #include #include #include #endif +#ifdef PLATFORM_MACOSX +#include +#endif + /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */ typedef struct { const char* assembly_name; @@ -58,6 +62,7 @@ static char **assemblies_path = NULL; /* Contains the list of directories that point to auxiliary GACs */ 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. */ @@ -88,8 +93,12 @@ static const AssemblyVersionMap framework_assemblies [] = { {"Npgsql", 0}, {"PEAPI", 0}, {"System", 0}, + {"System.ComponentModel.DataAnnotations", 2}, + {"System.Configuration", 0}, {"System.Configuration.Install", 0}, + {"System.Core", 2}, {"System.Data", 0}, + {"System.Data.Linq", 2}, {"System.Data.OracleClient", 0}, {"System.Data.SqlXml", 0}, {"System.Design", 0}, @@ -103,13 +112,17 @@ static const AssemblyVersionMap framework_assemblies [] = { {"System.Runtime.Serialization.Formatters.Soap", 0}, {"System.Security", 0}, {"System.ServiceProcess", 0}, + {"System.Transactions", 2}, {"System.Web", 0}, + {"System.Web.Abstractions", 2}, {"System.Web.Mobile", 0}, + {"System.Web.Routing", 2}, {"System.Web.Services", 0}, {"System.Windows.Forms", 0}, {"System.Xml", 0}, {"mscorlib", 0} }; +#endif /* * keeps track of loaded assemblies @@ -117,6 +130,27 @@ static const AssemblyVersionMap framework_assemblies [] = { static GList *loaded_assemblies = NULL; static MonoAssembly *corlib; +#if defined(__native_client__) + +/* On Native Client, allow mscorlib to be loaded from memory */ +/* instead of loaded off disk. If these are not set, default */ +/* mscorlib loading will take place */ + +/* NOTE: If mscorlib data is passed to mono in this way then */ +/* it needs to remain allocated during the use of mono. */ + +static void *corlibData = NULL; +static size_t corlibSize = 0; + +void +mono_set_corlib_data (void *data, size_t size) +{ + corlibData = data; + corlibSize = size; +} + +#endif + /* This protects loaded_assemblies and image->references */ #define mono_assemblies_lock() EnterCriticalSection (&assemblies_mutex) #define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex) @@ -130,6 +164,8 @@ static GSList *loaded_assembly_bindings = NULL; static MonoAssembly* mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload); +static MonoBoolean +mono_assembly_is_in_gac (const gchar *filanem); static gchar* encode_public_tok (const guchar *token, gint32 len) @@ -158,16 +194,26 @@ encode_public_tok (const guchar *token, gint32 len) gboolean mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2) { - return g_strcasecmp ((char*)pubt1, (char*)pubt2) == 0; + return memcmp (pubt1, pubt2, 16) == 0; } +/* 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; char **splitted, **dest; +#ifdef __native_client__ + path = nacl_mono_path; +#else path = g_getenv ("MONO_PATH"); +#endif if (!path) return; @@ -185,6 +231,7 @@ check_path_env (void) if (g_getenv ("MONO_DEBUG") == NULL) return; + splitted = assemblies_path; while (*splitted) { if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR)) g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted); @@ -218,7 +265,7 @@ check_extra_gac_path_env (void) { while (*splitted) { if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR)) - g_warning ("'%s' in MONO_GAC_PATH doesn't exist or has wrong permissions.", *splitted); + g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted); splitted++; } @@ -227,16 +274,19 @@ check_extra_gac_path_env (void) { static gboolean assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname) { + if (!info || !info->name) + return FALSE; + if (strcmp (info->name, aname->name)) return FALSE; if (info->major != aname->major || info->minor != aname->minor) return FALSE; - if ((info->culture != NULL) != (aname->culture != NULL)) + if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0])) return FALSE; - if (info->culture && strcmp (info->culture, aname->culture)) + if (info->culture && aname->culture && strcmp (info->culture, aname->culture)) return FALSE; if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token)) @@ -248,6 +298,9 @@ assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *ana static void mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info) { + if (!info) + return; + g_free (info->name); g_free (info->culture); } @@ -387,18 +440,6 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r) return TRUE; } -static MonoAssembly* -search_loaded (MonoAssemblyName* aname, gboolean refonly) -{ - MonoAssembly *ass; - - ass = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE); - if (ass) - return ass; - - return NULL; -} - static MonoAssembly * load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly) { @@ -490,12 +531,12 @@ mono_set_dirs (const char *assembly_dir, const char *config_dir) mono_set_config_dir (config_dir); } -#ifndef PLATFORM_WIN32 +#ifndef HOST_WIN32 static char * compute_base (char *path) { - char *p = rindex (path, '/'); + char *p = strrchr (path, '/'); if (p == NULL) return NULL; @@ -504,7 +545,7 @@ compute_base (char *path) return NULL; *p = 0; - p = rindex (path, '/'); + p = strrchr (path, '/'); if (p == NULL) return NULL; @@ -537,7 +578,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 { @@ -549,7 +590,7 @@ set_dirs (char *exe) g_free (mono); } -#endif /* PLATFORM_WIN32 */ +#endif /* HOST_WIN32 */ /** * mono_set_rootdir: @@ -560,22 +601,57 @@ set_dirs (char *exe) void mono_set_rootdir (void) { -#ifdef PLATFORM_WIN32 - gchar *bindir, *installdir, *root, *name, *config; +#if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM)) + gchar *bindir, *installdir, *root, *name, *resolvedname, *config; - name = mono_get_module_file_name (mono_module_handle); - bindir = g_path_get_dirname (name); +#ifdef HOST_WIN32 + name = mono_get_module_file_name ((HMODULE) &__ImageBase); +#else + { + /* + * _NSGetExecutablePath may return -1 to indicate buf is not large + * enough, but we ignore that case to avoid having to do extra dynamic + * allocation for the path and hope that 4096 is enough - this is + * ok in the Linux/Solaris case below at least... + */ + + gchar buf[4096]; + guint buf_size = sizeof (buf); + + if (_NSGetExecutablePath (buf, &buf_size) == 0) + name = g_strdup (buf); + + if (name == NULL) { + fallback (); + return; + } + } +#endif + + resolvedname = mono_path_resolve_symlinks (name); + + bindir = g_path_get_dirname (resolvedname); installdir = g_path_get_dirname (bindir); root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL); config = g_build_filename (root, "..", "etc", NULL); +#ifdef HOST_WIN32 mono_set_dirs (root, config); +#else + if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS)) + mono_set_dirs (root, config); + else + fallback (); +#endif g_free (config); g_free (root); g_free (installdir); g_free (bindir); g_free (name); + g_free (resolvedname); +#elif defined(DISABLE_MONO_AUTODETECTION) + fallback (); #else char buf [4096]; int s; @@ -689,9 +765,11 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname) char* mono_stringify_assembly_name (MonoAssemblyName *aname) { + const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : ""; + return g_strdup_printf ( - "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s", - aname->name, + "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s", + quote, aname->name, quote, aname->major, aname->minor, aname->build, aname->revision, aname->culture && *aname->culture? aname->culture: "neutral", aname->public_key_token [0] ? (char *)aname->public_key_token : "null", @@ -730,6 +808,7 @@ mono_assembly_addref (MonoAssembly *assembly) InterlockedIncrement (&assembly->ref_count); } +#ifndef DISABLE_ASSEMBLY_REMAPPING static MonoAssemblyName * mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname) { @@ -778,6 +857,7 @@ mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_ana } return aname; } +#endif /* * mono_assembly_get_assemblyref: @@ -860,7 +940,7 @@ mono_assembly_load_reference (MonoImage *image, int index) reference = mono_assembly_load (&aname, image->assembly? image->assembly->basedir: NULL, &status); if (reference == NULL){ - char *extra_msg = g_strdup (""); + char *extra_msg; if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) { extra_msg = g_strdup_printf ("The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (%s).\n", image->assembly != NULL ? image->assembly->basedir : "" ); @@ -870,9 +950,11 @@ mono_assembly_load_reference (MonoImage *image, int index) extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n"); } else if (status == MONO_IMAGE_IMAGE_INVALID) { extra_msg = g_strdup ("The file exists but is not a valid assembly.\n"); + } else { + extra_msg = g_strdup (""); } - g_warning ("The following assembly referenced from %s could not be loaded:\n" + mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n" " Assembly: %s (assemblyref_index=%d)\n" " Version: %d.%d.%d.%d\n" " Public Key: %s\n%s", @@ -892,11 +974,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\n", + 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); } @@ -1141,8 +1223,12 @@ absolute_dir (const gchar *filename) gchar *res; gint i; - if (g_path_is_absolute (filename)) - return g_path_get_dirname (filename); + if (g_path_is_absolute (filename)) { + part = g_path_get_dirname (filename); + res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL); + g_free (part); + return res; + } cwd = g_get_current_dir (); mixed = g_build_filename (cwd, filename, NULL); @@ -1214,7 +1300,7 @@ mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *statu mono_assemblies_lock (); for (i = 0; !image && bundles [i]; ++i) { if (strcmp (bundles [i]->name, name) == 0) { - image = mono_image_open_from_data_full ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly); + image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name); break; } } @@ -1273,7 +1359,10 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader probing location: '%s'.", fname); - new_fname = mono_make_shadow_copy (fname); + + new_fname = NULL; + if (!mono_assembly_is_in_gac (fname)) + new_fname = mono_make_shadow_copy (fname); if (new_fname && new_fname != fname) { g_free (fname); fname = new_fname; @@ -1286,11 +1375,8 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo if (bundles != NULL) image = mono_assembly_open_from_bundle (fname, status, refonly); - if (!image) { - mono_assemblies_lock (); + if (!image) image = mono_image_open_full (fname, status, refonly); - mono_assemblies_unlock (); - } if (!image){ if (*status == MONO_IMAGE_OK) @@ -1324,8 +1410,14 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo return ass; } +static void +free_item (gpointer val, gpointer user_data) +{ + g_free (val); +} + /* - * mono_load_friend_assemblies: + * mono_assembly_load_friends: * @ass: an assembly * * Load the list of friend assemblies that are allowed to access @@ -1335,14 +1427,39 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo * This is an internal method, we need this because when we load mscorlib * we do not have the mono_defaults.internals_visible_class loaded yet, * so we need to load these after we initialize the runtime. + * + * LOCKING: Acquires the assemblies lock plus the loader lock. */ void mono_assembly_load_friends (MonoAssembly* ass) { int i; - MonoCustomAttrInfo* attrs = mono_custom_attrs_from_assembly (ass); - if (!attrs) + MonoCustomAttrInfo* attrs; + GSList *list; + + if (ass->friend_assembly_names_inited) return; + + attrs = mono_custom_attrs_from_assembly (ass); + if (!attrs) { + mono_assemblies_lock (); + ass->friend_assembly_names_inited = TRUE; + mono_assemblies_unlock (); + return; + } + + mono_assemblies_lock (); + if (ass->friend_assembly_names_inited) { + mono_assemblies_unlock (); + return; + } + mono_assemblies_unlock (); + + list = NULL; + /* + * We build the list outside the assemblies lock, the worse that can happen + * is that we'll need to free the allocated list. + */ for (i = 0; i < attrs->num_attrs; ++i) { MonoCustomAttrEntry *attr = &attrs->attrs [i]; MonoAssemblyName *aname; @@ -1361,12 +1478,26 @@ mono_assembly_load_friends (MonoAssembly* ass) aname = g_new0 (MonoAssemblyName, 1); /*g_print ("friend ass: %s\n", data);*/ if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) { - ass->friend_assembly_names = g_slist_prepend (ass->friend_assembly_names, aname); + list = g_slist_prepend (list, aname); } else { g_free (aname); } } mono_custom_attrs_free (attrs); + + mono_assemblies_lock (); + if (ass->friend_assembly_names_inited) { + mono_assemblies_unlock (); + g_slist_foreach (list, free_item, NULL); + g_slist_free (list); + return; + } + ass->friend_assembly_names = list; + + /* Because of the double checked locking pattern above */ + mono_memory_barrier (); + ass->friend_assembly_names_inited = TRUE; + mono_assemblies_unlock (); } /** @@ -1400,7 +1531,7 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, return NULL; } -#if defined (PLATFORM_WIN32) +#if defined (HOST_WIN32) { gchar *tmp_fn; int i; @@ -1442,17 +1573,15 @@ 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\n", 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); /* - * Atomically search the loaded list and add ourselves to it if necessary. + * The load hooks might take locks so we can't call them while holding the + * assemblies lock. */ - mono_assemblies_lock (); if (ass->aname.name) { - /* avoid loading the same assembly twice for now... */ - ass2 = search_loaded (&ass->aname, refonly); + ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, refonly, FALSE); if (ass2) { - mono_assemblies_unlock (); g_free (ass); g_free (base_dir); mono_image_close (image); @@ -1461,17 +1590,31 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, } } - g_assert (image->assembly == NULL); + mono_assemblies_lock (); + + if (image->assembly) { + /* + * This means another thread has already loaded the assembly, but not yet + * called the load hooks so the search hook can't find the assembly. + */ + mono_assemblies_unlock (); + ass2 = image->assembly; + g_free (ass); + g_free (base_dir); + mono_image_close (image); + *status = MONO_IMAGE_OK; + return ass2; + } + image->assembly = ass; loaded_assemblies = g_list_prepend (loaded_assemblies, ass); - if (mono_defaults.internals_visible_class) - mono_assembly_load_friends (ass); -#ifdef PLATFORM_WIN32 + mono_assemblies_unlock (); + +#ifdef HOST_WIN32 if (image->is_module_handle) mono_image_fixup_vtable (image); #endif - mono_assemblies_unlock (); mono_assembly_invoke_load_hook (ass); @@ -1515,7 +1658,15 @@ 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) { + arr = g_strdup ("b77a5c561934e089"); + *pubkey = arr; + } + return TRUE; + } val = g_ascii_xdigit_value (key [0]) << 4; val |= g_ascii_xdigit_value (key [1]); switch (val) { @@ -1557,6 +1708,10 @@ parse_public_key (const gchar *key, gchar** pubkey) bitlen = read32 (header + 12) >> 3; if ((bitlen + 16 + 4) != pkeylen) return FALSE; + + /* parsing is OK and the public key itself is not requested back */ + if (!pubkey) + return TRUE; /* Encode the size of the blob */ offset = 0; @@ -1573,14 +1728,14 @@ parse_public_key (const gchar *key, gchar** pubkey) arr [i] = g_ascii_xdigit_value (key [j++]) << 4; arr [i] |= g_ascii_xdigit_value (key [j++]); } - if (pubkey) - *pubkey = arr; + + *pubkey = arr; return TRUE; } static gboolean -build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, MonoAssemblyName *aname, gboolean save_public_key) +build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, guint32 arch, MonoAssemblyName *aname, gboolean save_public_key) { gint major, minor, build, revision; gint len; @@ -1610,6 +1765,7 @@ build_assembly_name (const char *name, const char *version, const char *culture, } aname->flags = flags; + aname->arch = arch; aname->name = g_strdup (name); if (culture) { @@ -1624,6 +1780,7 @@ build_assembly_name (const char *name, const char *version, const char *culture, /* the constant includes the ending NULL, hence the -1 */ if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) { + mono_assembly_name_free (aname); return FALSE; } lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH); @@ -1665,7 +1822,7 @@ parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemb return FALSE; } - res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, aname, FALSE); + res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE); g_strfreev (parts); return res; } @@ -1686,6 +1843,7 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole gboolean version_defined; gboolean token_defined; guint32 flags = 0; + guint32 arch = PROCESSOR_ARCHITECTURE_NONE; if (!is_version_defined) is_version_defined = &version_defined; @@ -1710,7 +1868,7 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole *is_version_defined = TRUE; version = g_strstrip (value + 8); if (strlen (version) == 0) { - return FALSE; + goto cleanup_and_fail; } tmp++; continue; @@ -1719,7 +1877,7 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole if (!g_ascii_strncasecmp (value, "Culture=", 8)) { culture = g_strstrip (value + 8); if (strlen (culture) == 0) { - return FALSE; + goto cleanup_and_fail; } tmp++; continue; @@ -1729,7 +1887,7 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole *is_token_defined = TRUE; token = g_strstrip (value + 15); if (strlen (token) == 0) { - return FALSE; + goto cleanup_and_fail; } tmp++; continue; @@ -1738,7 +1896,7 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) { key = g_strstrip (value + 10); if (strlen (key) == 0) { - return FALSE; + goto cleanup_and_fail; } tmp++; continue; @@ -1747,19 +1905,31 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole if (!g_ascii_strncasecmp (value, "Retargetable=", 13)) { retargetable = g_strstrip (value + 13); if (strlen (retargetable) == 0) { - return FALSE; + goto cleanup_and_fail; } if (!g_ascii_strcasecmp (retargetable, "yes")) { flags |= ASSEMBLYREF_RETARGETABLE_FLAG; } else if (g_ascii_strcasecmp (retargetable, "no")) { - return FALSE; + goto cleanup_and_fail; } tmp++; continue; } if (!g_ascii_strncasecmp (value, "ProcessorArchitecture=", 22)) { - /* this is ignored for now, until we can change MonoAssemblyName */ + 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; + else + goto cleanup_and_fail; tmp++; continue; } @@ -1770,13 +1940,17 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole /* if retargetable flag is set, then we must have a fully qualified name */ if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) { - return FALSE; + goto cleanup_and_fail; } - res = build_assembly_name (dllname, version, culture, token, key, flags, + res = build_assembly_name (dllname, version, culture, token, key, flags, arch, aname, save_public_key); g_strfreev (parts); return res; + +cleanup_and_fail: + g_strfreev (parts); + return FALSE; } /** @@ -1795,6 +1969,57 @@ mono_assembly_name_parse (const char *name, MonoAssemblyName *aname) return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL); } +/** + * mono_assembly_name_new: + * @name: name to parse + * + * Allocate a new MonoAssemblyName and fill its values from the + * passed @name. + * + * Returns: a newly allocated structure or NULL if there was any failure. + */ +MonoAssemblyName* +mono_assembly_name_new (const char *name) +{ + MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1); + if (mono_assembly_name_parse (name, aname)) + return aname; + g_free (aname); + return NULL; +} + +const char* +mono_assembly_name_get_name (MonoAssemblyName *aname) +{ + return aname->name; +} + +const char* +mono_assembly_name_get_culture (MonoAssemblyName *aname) +{ + return aname->culture; +} + +mono_byte* +mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname) +{ + if (aname->public_key_token [0]) + return aname->public_key_token; + return NULL; +} + +uint16_t +mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision) +{ + if (minor) + *minor = aname->minor; + if (build) + *build = aname->build; + if (revision) + *revision = aname->revision; + return aname->major; +} + static MonoAssembly* probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status) { @@ -1870,7 +2095,10 @@ MonoAssembly* mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status) { MonoAssembly *res; - MonoAssemblyName *aname, base_name, maped_aname; + MonoAssemblyName *aname, base_name; +#ifndef DISABLE_ASSEMBLY_REMAPPING + MonoAssemblyName maped_aname; +#endif gchar *fullname, *gacpath; gchar **paths; @@ -1880,12 +2108,14 @@ 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 res = mono_assembly_loaded (aname); if (res) { @@ -1938,6 +2168,67 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta return res; } +static MonoBoolean +mono_assembly_is_in_gac (const gchar *filename) +{ + const gchar *rootdir; + gchar *gp; + gchar **paths; + + if (filename == NULL) + return FALSE; + + for (paths = extra_gac_paths; paths && *paths; paths++) { + if (strstr (*paths, filename) != *paths) + continue; + + gp = (gchar *) (filename + strlen (*paths)); + if (*gp != G_DIR_SEPARATOR) + continue; + gp++; + if (strncmp (gp, "lib", 3)) + continue; + gp += 3; + if (*gp != G_DIR_SEPARATOR) + continue; + gp++; + if (strncmp (gp, "mono", 4)) + continue; + gp += 4; + if (*gp != G_DIR_SEPARATOR) + continue; + gp++; + if (strncmp (gp, "gac", 3)) + continue; + gp += 3; + if (*gp != G_DIR_SEPARATOR) + continue; + + return TRUE; + } + + rootdir = mono_assembly_getrootdir (); + if (strstr (filename, rootdir) != filename) + return FALSE; + + gp = (gchar *) (filename + strlen (rootdir)); + if (*gp != G_DIR_SEPARATOR) + return FALSE; + gp++; + if (strncmp (gp, "mono", 4)) + return FALSE; + gp += 4; + if (*gp != G_DIR_SEPARATOR) + return FALSE; + gp++; + if (strncmp (gp, "gac", 3)) + return FALSE; + gp += 3; + if (*gp != G_DIR_SEPARATOR) + return FALSE; + return TRUE; +} + static MonoImage* mono_assembly_load_publisher_policy (MonoAssemblyName *aname) { @@ -1953,10 +2244,9 @@ mono_assembly_load_publisher_policy (MonoAssemblyName *aname) } else name = g_strdup (aname->name); - if (aname->culture) { - culture = g_strdup (aname->culture); - g_strdown (culture); - } else + if (aname->culture) + culture = g_utf8_strdown (aname->culture, -1); + else culture = g_strdup (""); pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name); @@ -2023,17 +2313,135 @@ search_binding_loaded (MonoAssemblyName *aname) return NULL; } +static inline gboolean +info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right) +{ + if (left->major != right->major || left->minor != right->minor || + left->build != right->build || left->revision != right->revision) + return FALSE; + + return TRUE; +} + +static inline gboolean +info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right) +{ + if (left->has_old_version_bottom != right->has_old_version_bottom) + return FALSE; + + if (left->has_old_version_top != right->has_old_version_top) + return FALSE; + + if (left->has_new_version != right->has_new_version) + return FALSE; + + if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom)) + return FALSE; + + if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top)) + return FALSE; + + if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version)) + return FALSE; + + return TRUE; +} + +/* LOCKING: assumes all the necessary locks are held */ +static void +assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data) +{ + MonoAssemblyBindingInfo *info_copy; + GSList *tmp; + MonoAssemblyBindingInfo *info_tmp; + MonoDomain *domain = (MonoDomain*)user_data; + + if (!domain) + return; + + for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) { + info_tmp = tmp->data; + if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp)) + return; + } + + info_copy = mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo)); + memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo)); + if (info->name) + info_copy->name = mono_mempool_strdup (domain->mp, info->name); + if (info->culture) + info_copy->culture = mono_mempool_strdup (domain->mp, info->culture); + + domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy); +} + +static inline gboolean +info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname) +{ + if (!info->has_old_version_bottom) + return FALSE; + + if (info->old_version_bottom.major > aname->major || info->old_version_bottom.minor > aname->minor) + return FALSE; + + if (info->has_old_version_top && (info->old_version_top.major < aname->major || info->old_version_top.minor < aname->minor)) + return FALSE; + + /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */ + info->major = aname->major; + info->minor = aname->minor; + + return TRUE; +} + +/* LOCKING: Assumes that we are already locked - both loader and domain locks */ +static MonoAssemblyBindingInfo* +get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname) +{ + MonoAssemblyBindingInfo *info; + GSList *list; + + if (!domain->assembly_bindings) + return NULL; + + info = NULL; + for (list = domain->assembly_bindings; list; list = list->next) { + info = list->data; + if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname)) + break; + info = NULL; + } + + if (info) { + if (info->name && info->public_key_token [0] && info->has_old_version_bottom && + info->has_new_version && assembly_binding_maps_name (info, aname)) + info->is_valid = TRUE; + else + info->is_valid = FALSE; + } + + return info; +} + static MonoAssemblyName* mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name) { MonoAssemblyBindingInfo *info, *info2; MonoImage *ppimage; + MonoDomain *domain; if (aname->public_key_token [0] == 0) return aname; + domain = mono_domain_get (); mono_loader_lock (); info = search_binding_loaded (aname); + if (!info) { + mono_domain_lock (domain); + info = get_per_domain_assembly_binding_info (domain, aname); + mono_domain_unlock (domain); + } + mono_loader_unlock (); if (info) { if (!check_policy_versions (info, aname)) @@ -2043,14 +2451,44 @@ mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_nam return dest_name; } - info = g_new0 (MonoAssemblyBindingInfo, 1); - info->major = aname->major; - info->minor = aname->minor; - - ppimage = mono_assembly_load_publisher_policy (aname); - if (ppimage) { - get_publisher_policy_info (ppimage, aname, info); - mono_image_close (ppimage); + 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); + + mono_config_parse_assembly_bindings (domain_config_file, aname->major, aname->minor, domain, assembly_binding_info_parsed); + domain->assembly_bindings_parsed = TRUE; + g_free (domain_config_file); + } + mono_domain_unlock (domain); + + mono_loader_lock (); + mono_domain_lock (domain); + 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 (); + } + + if (!info) { + info = g_new0 (MonoAssemblyBindingInfo, 1); + info->major = aname->major; + info->minor = aname->minor; + } + + if (!info->is_valid) { + ppimage = mono_assembly_load_publisher_policy (aname); + if (ppimage) { + get_publisher_policy_info (ppimage, aname, info); + mono_image_close (ppimage); + } } /* Define default error value if needed */ @@ -2108,8 +2546,7 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImag } if (aname->culture) { - culture = g_strdup (aname->culture); - g_strdown (culture); + culture = g_utf8_strdown (aname->culture, -1); } else { culture = g_strdup (""); } @@ -2154,17 +2591,40 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImag return result; } - MonoAssembly* mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status) { char *corlib_file; + MonoAssemblyName *aname; if (corlib) { /* g_print ("corlib already loaded\n"); */ return corlib; } - + +#if defined(__native_client__) + if (corlibData != NULL && corlibSize != 0) { + int status = 0; + /* First "FALSE" instructs mono not to make a copy. */ + /* Second "FALSE" says this is not just a ref. */ + MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE); + if (image == NULL || status != 0) + g_print("mono_image_open_from_data_full failed: %d\n", status); + corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE); + if (corlib == NULL || status != 0) + g_print ("mono_assembly_load_from_full failed: %d\n", status); + if (corlib) + return corlib; + } +#endif + + aname = mono_assembly_name_new ("mscorlib.dll"); + corlib = invoke_assembly_preload_hook (aname, assemblies_path); + mono_assembly_name_free (aname); + g_free (aname); + if (corlib != NULL) + return corlib; + if (assemblies_path) { corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE); if (corlib) @@ -2195,12 +2655,17 @@ mono_assembly_load_full_nosearch (MonoAssemblyName *aname, { MonoAssembly *result; char *fullpath, *filename; - MonoAssemblyName maped_aname, maped_name_pp; +#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) @@ -2311,13 +2776,13 @@ 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 - mono_assemblies_lock (); - res = search_loaded (aname, refonly); - mono_assemblies_unlock (); + res = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE); return res; } @@ -2335,25 +2800,23 @@ mono_assembly_loaded (MonoAssemblyName *aname) return mono_assembly_loaded_full (aname, FALSE); } -/** - * mono_assembly_close: - * @assembly: the assembly to release. - * - * This method releases a reference to the @assembly. The assembly is - * only released when all the outstanding references to it are released. +/* + * Returns whether mono_assembly_close_finish() must be called as + * well. See comment for mono_image_close_except_pools() for why we + * unload in two steps. */ -void -mono_assembly_close (MonoAssembly *assembly) +gboolean +mono_assembly_close_except_image_pools (MonoAssembly *assembly) { GSList *tmp; - g_return_if_fail (assembly != NULL); + g_return_val_if_fail (assembly != NULL, FALSE); if (assembly == REFERENCE_MISSING) - return; - + return FALSE; + /* Might be 0 already */ if (InterlockedDecrement (&assembly->ref_count) > 0) - return; + return FALSE; mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD); @@ -2367,7 +2830,8 @@ mono_assembly_close (MonoAssembly *assembly) assembly->image->assembly = NULL; - mono_image_close (assembly->image); + if (!mono_image_close_except_pools (assembly->image)) + assembly->image = NULL; for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) { MonoAssemblyName *fname = tmp->data; @@ -2376,13 +2840,39 @@ mono_assembly_close (MonoAssembly *assembly) } g_slist_free (assembly->friend_assembly_names); g_free (assembly->basedir); + + mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD); + + return TRUE; +} + +void +mono_assembly_close_finish (MonoAssembly *assembly) +{ + g_assert (assembly && assembly != REFERENCE_MISSING); + + if (assembly->image) + mono_image_close_finish (assembly->image); + if (assembly->dynamic) { g_free ((char*)assembly->aname.culture); } else { g_free (assembly); } +} - mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD); +/** + * mono_assembly_close: + * @assembly: the assembly to release. + * + * This method releases a reference to the @assembly. The assembly is + * only released when all the outstanding references to it are released. + */ +void +mono_assembly_close (MonoAssembly *assembly) +{ + if (mono_assembly_close_except_image_pools (assembly)) + mono_assembly_close_finish (assembly); } MonoImage* @@ -2434,6 +2924,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 @@ -2475,10 +2986,12 @@ mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies) bundles = assemblies; } +#define MONO_DECLSEC_FORMAT_10 0x3C #define MONO_DECLSEC_FORMAT_20 0x2E #define MONO_DECLSEC_FIELD 0x53 #define MONO_DECLSEC_PROPERTY 0x54 +#define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"") #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute") #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1) #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification") @@ -2521,6 +3034,16 @@ mono_assembly_try_decode_skip_verification (const char *p, const char *endn) { int i, j, num, len, params_len; + if (*p == MONO_DECLSEC_FORMAT_10) { + gsize read, written; + char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL); + if (res) { + gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL; + g_free (res); + return found; + } + return FALSE; + } if (*p++ != MONO_DECLSEC_FORMAT_20) return FALSE;