X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fassembly.c;h=0314d2e585d0c7e443df5c6d57bd1388de16f02b;hb=5c1e94c5e72c65bfe3a608ee998afab5770e60b5;hp=4a50672bd797c48753b0a1e36404db3de48b0319;hpb=c4a3b30460c7ea1a1fb3c97cfc8478555714af2f;p=mono.git diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c index 4a50672bd79..0314d2e585d 100644 --- a/mono/metadata/assembly.c +++ b/mono/metadata/assembly.c @@ -15,14 +15,16 @@ #include #include "assembly.h" #include "image.h" -#include "cil-coff.h" #include "rawbuffer.h" +#include "object-internals.h" #include #include #include +#include #include #include #include +#include #include #include #include @@ -72,7 +74,6 @@ static const AssemblyVersionMap framework_assemblies [] = { {"Mono.Cairo", 0}, {"Mono.CompilerServices.SymbolWriter", 0}, {"Mono.Data", 0}, - {"Mono.Data.SqliteClient", 0}, {"Mono.Data.SybaseClient", 0}, {"Mono.Data.Tds", 0}, {"Mono.Data.TdsClient", 0}, @@ -120,12 +121,6 @@ static MonoAssembly *corlib; #define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex) static CRITICAL_SECTION assemblies_mutex; -/* A hastable of thread->assembly list mappings */ -static GHashTable *assemblies_loading; - -/* A hashtable of reflection only load thread->assemblies mappings */ -static GHashTable *assemblies_refonly_loading; - /* If defined, points to the bundled assembly information */ const MonoBundledAssembly **bundles; @@ -151,11 +146,25 @@ encode_public_tok (const guchar *token, gint32 len) return res; } +/** + * mono_public_tokens_are_equal: + * @pubt1: first public key token + * @pubt2: second public key token + * + * Compare two public key tokens and return #TRUE is they are equal and #FALSE + * otherwise. + */ +gboolean +mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2) +{ + return g_strcasecmp ((char*)pubt1, (char*)pubt2) == 0; +} + static void check_path_env (void) { const char *path; - char **splitted; + char **splitted, **dest; path = g_getenv ("MONO_PATH"); if (!path) @@ -164,7 +173,14 @@ check_path_env (void) splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000); if (assemblies_path) g_strfreev (assemblies_path); - assemblies_path = splitted; + assemblies_path = dest = splitted; + while (*splitted){ + if (**splitted) + *dest++ = *splitted; + splitted++; + } + *dest = *splitted; + if (g_getenv ("MONO_DEBUG") == NULL) return; @@ -179,7 +195,7 @@ check_path_env (void) static void check_extra_gac_path_env (void) { const char *path; - char **splitted; + char **splitted, **dest; path = g_getenv ("MONO_GAC_PREFIX"); if (!path) @@ -188,7 +204,14 @@ check_extra_gac_path_env (void) { splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000); if (extra_gac_paths) g_strfreev (extra_gac_paths); - extra_gac_paths = splitted; + extra_gac_paths = dest = splitted; + while (*splitted){ + if (**splitted) + *dest++ = *splitted; + splitted++; + } + *dest = *splitted; + if (g_getenv ("MONO_DEBUG") == NULL) return; @@ -215,7 +238,7 @@ assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *ana if (info->culture && strcmp (info->culture, aname->culture)) return FALSE; - if (strcmp ((const char *)info->public_key_token, (const char *)aname->public_key_token)) + if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token)) return FALSE; return TRUE; @@ -331,6 +354,7 @@ check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name) * @r: second assembly. * * Compares two MonoAssemblyNames and returns whether they are equal. + * * This compares the names, the cultures, the release version and their * public tokens. * @@ -356,7 +380,7 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r) if (!l->public_key_token [0] || !r->public_key_token [0]) return TRUE; - if (strcmp ((char*)l->public_key_token, (char*)r->public_key_token)) + if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token)) return FALSE; return TRUE; @@ -365,26 +389,11 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r) static MonoAssembly* search_loaded (MonoAssemblyName* aname, gboolean refonly) { - GList *tmp; MonoAssembly *ass; - GList *loading; ass = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE); if (ass) return ass; - - /* - * The assembly might be under load by this thread. In this case, it is - * safe to return an incomplete instance to prevent loops. - */ - loading = g_hash_table_lookup (refonly ? assemblies_refonly_loading : assemblies_loading, (gpointer)GetCurrentThreadId ()); - for (tmp = loading; tmp; tmp = tmp->next) { - ass = tmp->data; - if (!mono_assembly_names_equal (aname, &ass->aname)) - continue; - - return ass; - } return NULL; } @@ -411,8 +420,10 @@ load_in_path (const char *basename, const char** search_path, MonoImageOpenStatu * @root_dir: The pathname of the root directory where we will locate assemblies * * This routine sets the internal default root directory for looking up - * assemblies. This is used by Windows installations to compute dynamically - * the place where the Mono assemblies are located. + * assemblies. + * + * This is used by Windows installations to compute dynamically the + * place where the Mono assemblies are located. * */ void @@ -427,8 +438,10 @@ mono_assembly_setrootdir (const char *root_dir) /** * mono_assembly_getrootdir: + * + * Obtains the root directory used for looking up assemblies. * - * Returns: The internal root directory used for looking up assemblies + * Returns: a string with the directory, this string should not be freed. */ G_CONST_RETURN gchar * mono_assembly_getrootdir (void) @@ -442,10 +455,11 @@ mono_assembly_getrootdir (void) * @config_dir: the base directory for configuration files * * This routine is used internally and by developers embedding - * the runtime into their own applications. There are a number - * of cases to consider: Mono as a system-installed package that - * is available on the location preconfigured or Mono in a relocated - * location. + * the runtime into their own applications. + * + * There are a number of cases to consider: Mono as a system-installed + * package that is available on the location preconfigured or Mono in + * a relocated location. * * If you are using a system-installed Mono, you can pass NULL * to both parameters. If you are not, you should compute both @@ -627,9 +641,6 @@ mono_assemblies_init (void) check_extra_gac_path_env (); InitializeCriticalSection (&assemblies_mutex); - - assemblies_loading = g_hash_table_new (NULL, NULL); - assemblies_refonly_loading = g_hash_table_new (NULL, NULL); } gboolean @@ -654,16 +665,18 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname) aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER]; aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG]; if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) { - gchar* token = g_malloc (8); + guchar* token = g_malloc (8); gchar* encoded; + const gchar* pkey; int len; - aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]); - len = mono_metadata_decode_blob_size (aname->public_key, (const char**)&aname->public_key); + pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]); + len = mono_metadata_decode_blob_size (pkey, &pkey); + aname->public_key = (guchar*)pkey; mono_digest_get_public_token (token, aname->public_key, len); encoded = encode_public_tok (token, 8); - g_strlcpy (aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH); + g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH); g_free (encoded); g_free (token); @@ -674,7 +687,7 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname) } if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) { - aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]); + aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]); } else aname->public_key = 0; @@ -682,22 +695,26 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname) return TRUE; } -/* +/** * mono_stringify_assembly_name: + * @aname: the assembly name. * - * Convert @aname into its string format. The returned string is dynamically + * Convert @aname into its string format. The returned string is dynamically * allocated and should be freed by the caller. + * + * Returns: a newly allocated string with a string representation of + * the assembly name. */ char* mono_stringify_assembly_name (MonoAssemblyName *aname) { return g_strdup_printf ( - "%s, Version=%d.%d.%d.%d, Culture=%s%s%s", + "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s", aname->name, aname->major, aname->minor, aname->build, aname->revision, aname->culture && *aname->culture? aname->culture: "neutral", - aname->public_key_token [0] ? ", PublicKeyToken=" : "", - aname->public_key_token [0] ? (char *)aname->public_key_token : ""); + aname->public_key_token [0] ? (char *)aname->public_key_token : "null", + (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : ""); } static gchar* @@ -710,12 +727,12 @@ assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags) len = mono_metadata_decode_blob_size (public_tok, &public_tok); if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) { - gchar token [8]; - mono_digest_get_public_token (token, public_tok, len); + guchar token [8]; + mono_digest_get_public_token (token, (guchar*)public_tok, len); return encode_public_tok (token, 8); } - return encode_public_tok (public_tok, len); + return encode_public_tok ((guchar*)public_tok, len); } /** @@ -810,7 +827,7 @@ mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *an if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) { gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags); - g_strlcpy (aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH); + g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH); g_free (token); } else { memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH); @@ -829,6 +846,11 @@ mono_assembly_load_reference (MonoImage *image, int index) * it inside a critical section. */ mono_assemblies_lock (); + if (!image->references) { + MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF]; + + image->references = g_new0 (MonoAssembly *, t->rows + 1); + } reference = image->references [index]; mono_assemblies_unlock (); if (reference) @@ -836,12 +858,17 @@ mono_assembly_load_reference (MonoImage *image, int index) mono_assembly_get_assemblyref (image, index, &aname); - if (image->assembly->ref_only) { + 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); - else + 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); + } + /* * Here we must advice that the error was due to * a non loaded reference using the ReflectionOnly api @@ -849,7 +876,7 @@ mono_assembly_load_reference (MonoImage *image, int index) if (!reference) reference = REFERENCE_MISSING; } else - reference = mono_assembly_load (&aname, image->assembly->basedir, &status); + reference = mono_assembly_load (&aname, image->assembly? image->assembly->basedir: NULL, &status); if (reference == NULL){ char *extra_msg = g_strdup (""); @@ -870,7 +897,7 @@ mono_assembly_load_reference (MonoImage *image, int index) " Public Key: %s\n%s", image->name, aname.name, index, aname.major, aname.minor, aname.build, aname.revision, - strlen(aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg); + strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg); g_free (extra_msg); } @@ -883,10 +910,12 @@ mono_assembly_load_reference (MonoImage *image, int index) if (!image->references [index]) { if (reference != REFERENCE_MISSING){ mono_assembly_addref (reference); - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n", + if (image->assembly) + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n", image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count); } else { - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n", + if (image->assembly) + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n", image->assembly->aname.name, image->assembly); } @@ -903,22 +932,8 @@ mono_assembly_load_reference (MonoImage *image, int index) void mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status) { - MonoTableInfo *t; - int i; - + /* This is a no-op now but it is part of the embedding API so we can't remove it */ *status = MONO_IMAGE_OK; - - t = &image->tables [MONO_TABLE_ASSEMBLYREF]; - - image->references = g_new0 (MonoAssembly *, t->rows + 1); - - /* resolve assembly references for modules */ - for (i = 0; i < image->module_count; i++){ - if (image->modules [i]) { - image->modules [i]->assembly = image->assembly; - mono_assembly_load_references (image->modules [i], status); - } - } } typedef struct AssemblyLoadHook AssemblyLoadHook; @@ -1171,11 +1186,12 @@ absolute_dir (const gchar *filename) list = g_list_reverse (list); /* Ignores last data pointer, which should be the filename */ - for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next) + for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){ if (tmp->data) g_string_append_printf (result, "%s%c", (char *) tmp->data, G_DIR_SEPARATOR); - + } + res = result->str; g_string_free (result, FALSE); g_list_free (list); @@ -1197,17 +1213,23 @@ absolute_dir (const gchar *filename) * defined bundles, if found, returns the MonoImage for it, if not found * returns NULL */ -static MonoImage * +MonoImage * mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly) { int i; - char *name = g_path_get_basename (filename); + char *name; MonoImage *image = NULL; /* * we do a very simple search for bundled assemblies: it's not a general * purpose assembly loading mechanism. */ + + if (!bundles) + return NULL; + + name = g_path_get_basename (filename); + mono_assemblies_lock (); for (i = 0; !image && bundles [i]; ++i) { if (strcmp (bundles [i]->name, name) == 0) { @@ -1313,15 +1335,19 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo } /* - * load_friend_assemblies: + * mono_load_friend_assemblies: * @ass: an assembly * * Load the list of friend assemblies that are allowed to access * the assembly's internal types and members. They are stored as assembly * names in custom attributes. + * + * 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. */ -static void -load_friend_assemblies (MonoAssembly* ass) +void +mono_assembly_load_friends (MonoAssembly* ass) { int i; MonoCustomAttrInfo* attrs = mono_custom_attrs_from_assembly (ass); @@ -1330,21 +1356,21 @@ load_friend_assemblies (MonoAssembly* ass) for (i = 0; i < attrs->num_attrs; ++i) { MonoCustomAttrEntry *attr = &attrs->attrs [i]; MonoAssemblyName *aname; - const guchar *data; + const gchar *data; guint slen; /* Do some sanity checking */ if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class) continue; if (attr->data_size < 4) continue; - data = attr->data; + data = (const char*)attr->data; /* 0xFF means null string, see custom attr format */ - if (data [0] != 1 || data [1] != 0 || data [2] == 0xFF) + if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF) continue; slen = 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)) { + if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) { ass->friend_assembly_names = g_slist_prepend (ass->friend_assembly_names, aname); } else { g_free (aname); @@ -1377,8 +1403,12 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, { MonoAssembly *ass, *ass2; char *base_dir; - GList *loading; - GHashTable *ass_loading; + + if (!image->tables [MONO_TABLE_ASSEMBLY].rows) { + /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */ + *status = MONO_IMAGE_IMAGE_INVALID; + return NULL; + } #if defined (PLATFORM_WIN32) { @@ -1398,14 +1428,6 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, base_dir = absolute_dir (fname); #endif - /* - * To avoid deadlocks and scalability problems, we load assemblies outside - * the assembly lock. This means that multiple threads might try to load - * the same assembly at the same time. The first one to load it completely - * "wins", the other threads free their copy and use the one loaded by - * the winning thread. - */ - /* * Create assembly struct, and enter it into the assembly cache */ @@ -1414,11 +1436,22 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, ass->ref_only = refonly; ass->image = image; - /* Add a non-temporary reference because of ass->image */ - mono_image_addref (image); + mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD); mono_assembly_fill_assembly_name (image, &ass->aname); + if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) { + // MS.NET doesn't support loading other mscorlibs + g_free (ass); + g_free (base_dir); + mono_image_addref (mono_defaults.corlib); + *status = MONO_IMAGE_OK; + return mono_defaults.corlib->assembly; + } + + /* 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); /* @@ -1429,57 +1462,27 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, /* avoid loading the same assembly twice for now... */ ass2 = search_loaded (&ass->aname, refonly); if (ass2) { + mono_assemblies_unlock (); g_free (ass); g_free (base_dir); mono_image_close (image); *status = MONO_IMAGE_OK; - mono_assemblies_unlock (); return ass2; } } - ass_loading = refonly ? assemblies_refonly_loading : assemblies_loading; - loading = g_hash_table_lookup (ass_loading, (gpointer)GetCurrentThreadId ()); - loading = g_list_prepend (loading, ass); - g_hash_table_insert (ass_loading, (gpointer)GetCurrentThreadId (), loading); - mono_assemblies_unlock (); g_assert (image->assembly == NULL); image->assembly = ass; - mono_assembly_load_references (image, status); - - mono_assemblies_lock (); - - loading = g_hash_table_lookup (ass_loading, (gpointer)GetCurrentThreadId ()); - loading = g_list_remove (loading, ass); - if (loading == NULL) - /* Prevent memory leaks */ - g_hash_table_remove (ass_loading, (gpointer)GetCurrentThreadId ()); - else - g_hash_table_insert (ass_loading, (gpointer)GetCurrentThreadId (), loading); - if (*status != MONO_IMAGE_OK) { - mono_assemblies_unlock (); - mono_assembly_close (ass); - return NULL; - } - - if (ass->aname.name) { - ass2 = search_loaded (&ass->aname, refonly); - if (ass2) { - /* Somebody else has loaded the assembly before us */ - mono_assemblies_unlock (); - mono_assembly_close (ass); - return ass2; - } - } - loaded_assemblies = g_list_prepend (loaded_assemblies, ass); if (mono_defaults.internals_visible_class) - load_friend_assemblies (ass); + mono_assembly_load_friends (ass); mono_assemblies_unlock (); mono_assembly_invoke_load_hook (ass); + mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK); + return ass; } @@ -1491,12 +1494,12 @@ mono_assembly_load_from (MonoImage *image, const char *fname, } /** -* mono_assembly_name_free: -* @aname: assembly name to free -* -* Frees the provided assembly name object. -* (it does not frees the object itself, only the name members). -*/ + * mono_assembly_name_free: + * @aname: assembly name to free + * + * Frees the provided assembly name object. + * (it does not frees the object itself, only the name members). + */ void mono_assembly_name_free (MonoAssemblyName *aname) { @@ -1583,24 +1586,36 @@ parse_public_key (const gchar *key, gchar** pubkey) } static gboolean -build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, 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, MonoAssemblyName *aname, gboolean save_public_key) { gint major, minor, build, revision; gint len; + gint version_parts; gchar *pkey, *pkeyptr, *encoded, tok [8]; memset (aname, 0, sizeof (MonoAssemblyName)); if (version) { - if (sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4) + version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision); + if (version_parts < 2 || version_parts > 4) return FALSE; + /* FIXME: we should set build & revision to -1 (instead of 0) + if these are not set in the version string. That way, later on, + we can still determine if these were specified. */ aname->major = major; aname->minor = minor; - aname->build = build; - aname->revision = revision; + if (version_parts >= 3) + aname->build = build; + else + aname->build = 0; + if (version_parts == 4) + aname->revision = revision; + else + aname->revision = 0; } + aname->flags = flags; aname->name = g_strdup (name); if (culture) { @@ -1611,13 +1626,19 @@ build_assembly_name (const char *name, const char *version, const char *culture, } if (token && strncmp (token, "null", 4) != 0) { - char *lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH); + char *lower; + + /* the constant includes the ending NULL, hence the -1 */ + if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) { + return FALSE; + } + lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH); g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH); g_free (lower); } - if (key && strncmp (key, "null", 4) != 0) { - if (!parse_public_key (key, &pkey)) { + if (key) { + if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey)) { mono_assembly_name_free (aname); return FALSE; } @@ -1634,7 +1655,7 @@ build_assembly_name (const char *name, const char *version, const char *culture, else g_free (pkey); } - + return TRUE; } @@ -1650,30 +1671,36 @@ 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, aname, FALSE); + res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, aname, FALSE); g_strfreev (parts); return res; } gboolean -mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined) +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 *version = NULL; gchar *culture = NULL; gchar *token = NULL; gchar *key = NULL; + gchar *retargetable = NULL; gboolean res; gchar *value; gchar **parts; gchar **tmp; gboolean version_defined; + gboolean token_defined; + guint32 flags = 0; if (!is_version_defined) is_version_defined = &version_defined; *is_version_defined = FALSE; + if (!is_token_defined) + is_token_defined = &token_defined; + *is_token_defined = FALSE; - parts = tmp = g_strsplit (name, ",", 4); + parts = tmp = g_strsplit (name, ",", 6); if (!tmp || !*tmp) { g_strfreev (tmp); return FALSE; @@ -1688,51 +1715,90 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole if (!g_ascii_strncasecmp (value, "Version=", 8)) { *is_version_defined = TRUE; version = g_strstrip (value + 8); + if (strlen (version) == 0) { + return FALSE; + } tmp++; continue; } if (!g_ascii_strncasecmp (value, "Culture=", 8)) { culture = g_strstrip (value + 8); + if (strlen (culture) == 0) { + return FALSE; + } tmp++; continue; } if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) { + *is_token_defined = TRUE; token = g_strstrip (value + 15); + if (strlen (token) == 0) { + return FALSE; + } tmp++; continue; } if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) { key = g_strstrip (value + 10); + if (strlen (key) == 0) { + return FALSE; + } tmp++; continue; } - + + if (!g_ascii_strncasecmp (value, "Retargetable=", 13)) { + retargetable = g_strstrip (value + 13); + if (strlen (retargetable) == 0) { + return FALSE; + } + if (!g_ascii_strcasecmp (retargetable, "yes")) { + flags |= ASSEMBLYREF_RETARGETABLE_FLAG; + } else if (g_ascii_strcasecmp (retargetable, "no")) { + return FALSE; + } + tmp++; + continue; + } + + if (!g_ascii_strncasecmp (value, "ProcessorArchitecture=", 22)) { + /* this is ignored for now, until we can change MonoAssemblyName */ + tmp++; + continue; + } + g_strfreev (parts); return FALSE; } - res = build_assembly_name (dllname, version, culture, token, key, aname, save_public_key); + /* 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; + } + + res = build_assembly_name (dllname, version, culture, token, key, flags, + aname, save_public_key); g_strfreev (parts); return res; } /** -* mono_assembly_name_parse: -* @name: name to parse -* @aname: the destination assembly name -* -* Parses an assembly qualified type name and assigns the name, -* version, culture and token to the provided assembly name object. -* -* Returns: true if the name could be parsed. -*/ + * mono_assembly_name_parse: + * @name: name to parse + * @aname: the destination assembly name + * + * Parses an assembly qualified type name and assigns the name, + * version, culture and token to the provided assembly name object. + * + * Returns: true if the name could be parsed. + */ gboolean mono_assembly_name_parse (const char *name, MonoAssemblyName *aname) { - return mono_assembly_name_parse_full (name, aname, FALSE, NULL); + return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL); } static MonoAssembly* @@ -1754,13 +1820,14 @@ probe_for_partial_name (const char *basepath, const char *fullname, MonoAssembly while ((direntry = g_dir_read_name (dirhandle))) { gboolean match = TRUE; - parse_assembly_directory_name (aname->name, direntry, &gac_aname); + if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname)) + continue; if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0) match = FALSE; if (match && strlen ((char*)aname->public_key_token) > 0 && - strcmp ((char*)aname->public_key_token, (char*)gac_aname.public_key_token) != 0) + !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token)) match = FALSE; if (match) { @@ -1864,7 +1931,13 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta if (res) res->in_gac = TRUE; - + else { + MonoDomain *domain = mono_domain_get (); + MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), FALSE); + if (refasm) + res = refasm->assembly; + } + g_free (fullname); mono_assembly_name_free (aname); @@ -2026,6 +2099,7 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImag gchar *name, *version, *culture, *fullpath, *subpath; gint32 len; gchar **paths; + char *pubtok; if (aname->public_key_token [0] == 0) { return NULL; @@ -2046,9 +2120,11 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImag culture = g_strdup (""); } + pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH); version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major, aname->minor, aname->build, aname->revision, - culture, aname->public_key_token); + culture, pubtok); + g_free (pubtok); subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL); g_free (name); @@ -2117,24 +2193,11 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus * return corlib; } -/** - * mono_assembly_load_full: - * @aname: A MonoAssemblyName with the assembly name to load. - * @basedir: A directory to look up the assembly at. - * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation - * @refonly: Whether this assembly is being opened in "reflection-only" mode. - * - * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it - * attempts to load the assembly from that directory before probing the standard locations. - * - * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no - * assembly binding takes place. - * - * Returns: the assembly referenced by @aname loaded or NULL on error. On error the - * value pointed by status is updated with an error code. - */ MonoAssembly* -mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly) +mono_assembly_load_full_nosearch (MonoAssemblyName *aname, + const char *basedir, + MonoImageOpenStatus *status, + gboolean refonly) { MonoAssembly *result; char *fullpath, *filename; @@ -2202,9 +2265,33 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage return result; } - /* Try a postload search hook */ - result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE); + return result; +} +/** + * mono_assembly_load_full: + * @aname: A MonoAssemblyName with the assembly name to load. + * @basedir: A directory to look up the assembly at. + * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation + * @refonly: Whether this assembly is being opened in "reflection-only" mode. + * + * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it + * attempts to load the assembly from that directory before probing the standard locations. + * + * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no + * assembly binding takes place. + * + * Returns: the assembly referenced by @aname loaded or NULL on error. On error the + * value pointed by status is updated with an error code. + */ +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; } @@ -2274,24 +2361,16 @@ mono_assembly_close (MonoAssembly *assembly) if (InterlockedDecrement (&assembly->ref_count) > 0) return; + mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly); + mono_debug_close_image (assembly->image); + mono_assemblies_lock (); loaded_assemblies = g_list_remove (loaded_assemblies, assembly); mono_assemblies_unlock (); - if (assembly->image->references) { - int i; - - for (i = 0; assembly->image->references [i]; i++) { - if (assembly->image->references [i]) - mono_assembly_close (assembly->image->references [i]); - } - - g_free (assembly->image->references); - assembly->image->references = NULL; - } - assembly->image->assembly = NULL; mono_image_close (assembly->image); @@ -2308,19 +2387,14 @@ mono_assembly_close (MonoAssembly *assembly) } else { g_free (assembly); } + + mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD); } MonoImage* mono_assembly_load_module (MonoAssembly *assembly, guint32 idx) { - MonoImageOpenStatus status; - MonoImage *module; - - module = mono_image_load_file_for_image (assembly->image, idx); - if (module) - mono_assembly_load_references (module, &status); - - return module; + return mono_image_load_file_for_image (assembly->image, idx); } void @@ -2353,9 +2427,6 @@ mono_assemblies_cleanup (void) DeleteCriticalSection (&assemblies_mutex); - g_hash_table_destroy (assemblies_loading); - g_hash_table_destroy (assemblies_refonly_loading); - for (l = loaded_assembly_bindings; l; l = l->next) { MonoAssemblyBindingInfo *info = l->data;