X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fassembly.c;h=10dbacfd70d12d4a01c83c08c8e879f9d3f92331;hb=b50dc8d84850e0452a7a4d742ed0a0fa46fe491e;hp=dbae3e620219b4092d34ca2ad784216ab1384a18;hpb=c4b5bae7d19ad070d1d2ba808ac8377d07f56e8e;p=mono.git diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c index dbae3e62021..10dbacfd70d 100644 --- a/mono/metadata/assembly.c +++ b/mono/metadata/assembly.c @@ -28,7 +28,13 @@ #include #include #include -#include +#include + +#ifndef PLATFORM_WIN32 +#include +#include +#include +#endif /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */ typedef struct { @@ -149,7 +155,7 @@ static void check_path_env (void) { const char *path; - char **splitted; + char **splitted, **dest; path = g_getenv ("MONO_PATH"); if (!path) @@ -158,7 +164,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; @@ -173,7 +186,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) @@ -182,7 +195,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; @@ -325,6 +345,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. * @@ -350,7 +371,7 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r) if (!l->public_key_token [0] || !r->public_key_token [0]) return TRUE; - if (strcmp (l->public_key_token, r->public_key_token)) + if (strcmp ((char*)l->public_key_token, (char*)r->public_key_token)) return FALSE; return TRUE; @@ -371,7 +392,7 @@ search_loaded (MonoAssemblyName* aname, gboolean refonly) * 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, GetCurrentThread ()); + 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)) @@ -405,8 +426,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 @@ -421,8 +444,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) @@ -436,10 +461,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 @@ -457,14 +483,151 @@ 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) if (config_dir == NULL) config_dir = MONO_CFG_DIR; +#endif mono_assembly_setrootdir (assembly_dir); mono_set_config_dir (config_dir); } +#ifndef PLATFORM_WIN32 + +static char * +compute_base (char *path) +{ + char *p = rindex (path, '/'); + if (p == NULL) + 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")) + return NULL; + + *p = 0; + p = rindex (path, '/'); + if (p == NULL) + return NULL; + + if (strcmp (p, "/bin") != 0) + return NULL; + *p = 0; + return path; +} + +static void +fallback (void) +{ + mono_set_dirs (MONO_ASSEMBLIES, MONO_CFG_DIR); +} + +static void +set_dirs (char *exe) +{ + char *base; + char *config, *lib, *mono; + struct stat buf; + + /* + * Only /usr prefix is treated specially + */ + if (strncmp (exe, MONO_BINDIR, strlen (MONO_BINDIR)) == 0 || (base = compute_base (exe)) == NULL){ + fallback (); + return; + } + + config = g_build_filename (base, "etc", NULL); + lib = g_build_filename (base, "lib", NULL); + mono = g_build_filename (lib, "mono/1.0", NULL); + if (stat (mono, &buf) == -1) + fallback (); + else { + mono_set_dirs (lib, config); + } + + g_free (config); + g_free (lib); + g_free (mono); +} + +#endif /* PLATFORM_WIN32 */ + +#ifdef UNDER_CE +#undef GetModuleFileName +#define GetModuleFileName ceGetModuleFileNameA + +DWORD ceGetModuleFileNameA(HMODULE hModule, char* lpFilename, DWORD nSize) +{ + DWORD res = 0; + wchar_t* wbuff = (wchar_t*)LocalAlloc(LPTR, nSize*2); + res = GetModuleFileNameW(hModule, wbuff, nSize); + if (res) { + int len = wcslen(wbuff); + WideCharToMultiByte(CP_ACP, 0, wbuff, len, lpFilename, len, NULL, NULL); + } + LocalFree(wbuff); + return res; +} +#endif + +/** + * mono_set_rootdir: + * + * Registers the root directory for the Mono runtime, for Linux and Solaris 10, + * this auto-detects the prefix where Mono was installed. + */ +void +mono_set_rootdir (void) +{ +#ifdef PLATFORM_WIN32 + gunichar2 moddir [MAXPATHLEN]; + gchar *bindir, *installdir, *root, *utf8name, *config; + + GetModuleFileNameW (NULL, moddir, MAXPATHLEN); + utf8name = g_utf16_to_utf8 (moddir, -1, NULL, NULL, NULL); + bindir = g_path_get_dirname (utf8name); + installdir = g_path_get_dirname (bindir); + root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL); + + config = g_build_filename (root, "..", "etc", NULL); + mono_set_dirs (root, config); + + g_free (config); + g_free (root); + g_free (installdir); + g_free (bindir); + g_free (utf8name); +#else + char buf [4096]; + int s; + char *str; + + /* Linux style */ + s = readlink ("/proc/self/exe", buf, sizeof (buf)-1); + + if (s != -1){ + buf [s] = 0; + set_dirs (buf); + return; + } + + /* Solaris 10 style */ + str = g_strdup_printf ("/proc/%d/path/a.out", getpid ()); + s = readlink (str, buf, sizeof (buf)-1); + g_free (str); + if (s != -1){ + buf [s] = 0; + set_dirs (buf); + return; + } + fallback (); +#endif +} + /** * mono_assemblies_init: * @@ -539,11 +702,15 @@ 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) @@ -704,7 +871,7 @@ mono_assembly_load_reference (MonoImage *image, int index) * a non loaded reference using the ReflectionOnly api */ if (!reference) - reference = (gpointer)-1; + reference = REFERENCE_MISSING; } else reference = mono_assembly_load (&aname, image->assembly->basedir, &status); @@ -734,13 +901,21 @@ mono_assembly_load_reference (MonoImage *image, int index) mono_assemblies_lock (); if (reference == NULL) { /* Flag as not found */ - reference = (gpointer)-1; - } else { - mono_assembly_addref (reference); + reference = REFERENCE_MISSING; } - if (!image->references [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", + 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", + image->assembly->aname.name, image->assembly); + } + image->references [index] = reference; + } mono_assemblies_unlock (); if (image->references [index] != reference) { @@ -803,6 +978,17 @@ mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data) assembly_load_hook = hook; } +static void +free_assembly_load_hooks (void) +{ + AssemblyLoadHook *hook, *next; + + for (hook = assembly_load_hook; hook; hook = next) { + next = hook->next; + g_free (hook); + } +} + typedef struct AssemblySearchHook AssemblySearchHook; struct AssemblySearchHook { AssemblySearchHook *next; @@ -858,6 +1044,17 @@ mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_da mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE); } +static void +free_assembly_search_hooks (void) +{ + AssemblySearchHook *hook, *next; + + for (hook = assembly_search_hook; hook; hook = next) { + next = hook->next; + g_free (hook); + } +} + void mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data) { @@ -944,6 +1141,22 @@ mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpoint assembly_refonly_preload_hook = hook; } +static void +free_assembly_preload_hooks (void) +{ + AssemblyPreLoadHook *hook, *next; + + for (hook = assembly_preload_hook; hook; hook = next) { + next = hook->next; + g_free (hook); + } + + for (hook = assembly_refonly_preload_hook; hook; hook = next) { + next = hook->next; + g_free (hook); + } +} + static gchar * absolute_dir (const gchar *filename) { @@ -982,11 +1195,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); @@ -1035,24 +1249,6 @@ mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *statu return NULL; } -static MonoImage* -do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status, gboolean refonly) -{ - MonoImage *image = NULL; - - if (bundles != NULL){ - image = mono_assembly_open_from_bundle (filename, status, refonly); - - if (image != NULL) - return image; - } - mono_assemblies_lock (); - image = mono_image_open_full (filename, status, refonly); - mono_assemblies_unlock (); - - return image; -} - MonoAssembly * mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly) { @@ -1098,14 +1294,32 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader probing location: '%s'.", filename); - image = do_mono_assembly_open (fname, status, refonly); + image = NULL; + + if (bundles != NULL) + image = mono_assembly_open_from_bundle (fname, status, refonly); + + if (!image) { + mono_assemblies_lock (); + image = mono_image_open_full (fname, status, refonly); + mono_assemblies_unlock (); + } if (!image){ - *status = MONO_IMAGE_ERROR_ERRNO; + if (*status == MONO_IMAGE_OK) + *status = MONO_IMAGE_ERROR_ERRNO; g_free (fname); return NULL; } + if (image->assembly) { + /* Already loaded by another appdomain */ + mono_assembly_invoke_load_hook (image->assembly); + mono_image_close (image); + g_free (fname); + return image->assembly; + } + ass = mono_assembly_load_from_full (image, fname, status, refonly); if (ass) { @@ -1115,11 +1329,55 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo mono_config_for_assembly (ass->image); } + /* Clear the reference added by mono_image_open */ + mono_image_close (image); + g_free (fname); return ass; } +/* + * 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. + */ +static void +load_friend_assemblies (MonoAssembly* ass) +{ + int i; + MonoCustomAttrInfo* attrs = mono_custom_attrs_from_assembly (ass); + if (!attrs) + return; + for (i = 0; i < attrs->num_attrs; ++i) { + MonoCustomAttrEntry *attr = &attrs->attrs [i]; + MonoAssemblyName *aname; + const guchar *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; + /* 0xFF means null string, see custom attr format */ + if (data [0] != 1 || data [1] != 0 || data [2] == 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)) { + ass->friend_assembly_names = g_slist_prepend (ass->friend_assembly_names, aname); + } else { + g_free (aname); + } + } + mono_custom_attrs_free (attrs); +} + /** * mono_assembly_open: * @filename: Opens the assembly pointed out by this name @@ -1128,8 +1386,9 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo * mono_assembly_open opens the PE-image pointed by @filename, and * loads any external assemblies referenced by it. * - * NOTE: we could do lazy loading of the assemblies. Or maybe not worth - * it. + * Return: a pointer to the MonoAssembly if @filename contains a valid + * assembly or NULL on error. Details about the error are stored in the + * @status variable. */ MonoAssembly * mono_assembly_open (const char *filename, MonoImageOpenStatus *status) @@ -1139,13 +1398,20 @@ mono_assembly_open (const char *filename, MonoImageOpenStatus *status) MonoAssembly * mono_assembly_load_from_full (MonoImage *image, const char*fname, - MonoImageOpenStatus *status, gboolean refonly) + MonoImageOpenStatus *status, gboolean refonly) { 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) { gchar *tmp_fn; @@ -1179,10 +1445,14 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, ass->basedir = base_dir; ass->ref_only = refonly; ass->image = image; - ass->ref_count = 1; + + /* Add a non-temporary reference because of ass->image */ + mono_image_addref (image); mono_assembly_fill_assembly_name (image, &ass->aname); + 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); + /* * Atomically search the loaded list and add ourselves to it if necessary. */ @@ -1200,24 +1470,25 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, } } ass_loading = refonly ? assemblies_refonly_loading : assemblies_loading; - loading = g_hash_table_lookup (ass_loading, GetCurrentThread ()); + loading = g_hash_table_lookup (ass_loading, (gpointer)GetCurrentThreadId ()); loading = g_list_prepend (loading, ass); - g_hash_table_insert (ass_loading, GetCurrentThread (), loading); + 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, GetCurrentThread ()); + 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, GetCurrentThread ()); + g_hash_table_remove (ass_loading, (gpointer)GetCurrentThreadId ()); else - g_hash_table_insert (ass_loading, GetCurrentThread (), loading); + g_hash_table_insert (ass_loading, (gpointer)GetCurrentThreadId (), loading); if (*status != MONO_IMAGE_OK) { mono_assemblies_unlock (); mono_assembly_close (ass); @@ -1235,6 +1506,8 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, } loaded_assemblies = g_list_prepend (loaded_assemblies, ass); + if (mono_defaults.internals_visible_class) + load_friend_assemblies (ass); mono_assemblies_unlock (); mono_assembly_invoke_load_hook (ass); @@ -1250,12 +1523,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) { @@ -1346,31 +1619,45 @@ build_assembly_name (const char *name, const char *version, const char *culture, { 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->name = g_strdup (name); if (culture) { - if (g_strcasecmp (culture, "neutral") == 0) + if (g_ascii_strcasecmp (culture, "neutral") == 0) aname->culture = g_strdup (""); else aname->culture = g_strdup (culture); } - if (token && strncmp (token, "null", 4) != 0) - g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH); + if (token && strncmp (token, "null", 4) != 0) { + char *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)) { @@ -1476,14 +1763,15 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole } /** -* mono_assembly_name_parse: -* @name: name to parse -* @aname: the destination assembly name -* Returns: true if the name could be parsed. -* -* Parses an assembly qualified type name and assigns the name, -* version, culture and token to the provided assembly name object. -*/ + * 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) { @@ -1872,7 +2160,22 @@ 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) { @@ -1881,6 +2184,7 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage MonoAssemblyName maped_aname, maped_name_pp; int ext_index; const char *ext; + int len; aname = mono_assembly_remap_version (aname, &maped_aname); @@ -1905,12 +2209,16 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage return mono_assembly_load_corlib (mono_get_runtime_info (), status); } + len = strlen (aname->name); for (ext_index = 0; ext_index < 2; ext_index ++) { ext = ext_index == 0 ? ".dll" : ".exe"; - if (strstr (aname->name, ".dll")) + if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) { filename = g_strdup (aname->name); - else + /* Don't try appending .dll/.exe if it already has one of those extensions */ + ext_index++; + } else { filename = g_strconcat (aname->name, ext, NULL); + } result = mono_assembly_load_from_gac (aname, filename, status, refonly); if (result) { @@ -1943,6 +2251,18 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage return result; } +/** + * mono_assembly_load: + * @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 + * + * 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. + * + * 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 (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status) { @@ -1964,6 +2284,13 @@ mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly) return res; } +/** + * mono_assembly_loaded: + * @aname: an assembly to look for. + * + * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to + * a MonoAssembly that matches the MonoAssemblyName specified. + */ MonoAssembly* mono_assembly_loaded (MonoAssemblyName *aname) { @@ -1980,23 +2307,50 @@ mono_assembly_loaded (MonoAssemblyName *aname) void mono_assembly_close (MonoAssembly *assembly) { + GSList *tmp; g_return_if_fail (assembly != NULL); - if (InterlockedDecrement (&assembly->ref_count)) + if (assembly == REFERENCE_MISSING) return; + /* Might be 0 already */ + if (InterlockedDecrement (&assembly->ref_count) > 0) + return; + + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly); + mono_assemblies_lock (); loaded_assemblies = g_list_remove (loaded_assemblies, assembly); mono_assemblies_unlock (); - /* assemblies belong to domains, so the domain code takes care of unloading the - * referenced assemblies - */ + + 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); + for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) { + MonoAssemblyName *fname = tmp->data; + mono_assembly_name_free (fname); + g_free (fname); + } + g_slist_free (assembly->friend_assembly_names); g_free (assembly->basedir); - if (!assembly->dynamic) + if (assembly->dynamic) { + g_free ((char*)assembly->aname.culture); + } else { g_free (assembly); + } } MonoImage* @@ -2030,6 +2384,34 @@ mono_assembly_foreach (GFunc func, gpointer user_data) g_list_free (copy); } +/** + * mono_assemblies_cleanup: + * + * Free all resources used by this module. + */ +void +mono_assemblies_cleanup (void) +{ + GSList *l; + + 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; + + mono_assembly_binding_info_free (info); + g_free (info); + } + g_slist_free (loaded_assembly_bindings); + + free_assembly_load_hooks (); + free_assembly_search_hooks (); + free_assembly_preload_hooks (); +} + /* * Holds the assembly of the application, for * System.Diagnostics.Process::MainModule @@ -2039,16 +2421,25 @@ static MonoAssembly *main_assembly=NULL; void mono_assembly_set_main (MonoAssembly *assembly) { - main_assembly=assembly; + main_assembly = assembly; } +/** + * mono_assembly_get_main: + * + * Returns: the assembly for the application, the first assembly that is loaded by the VM + */ MonoAssembly * mono_assembly_get_main (void) { - return(main_assembly); + return (main_assembly); } -/* +/** + * mono_assembly_get_image: + * @assembly: The assembly to retrieve the image from + * + * Returns: the MonoImage associated with this assembly. */ MonoImage* mono_assembly_get_image (MonoAssembly *assembly)