X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fappdomain.c;h=80e36207fca72b4966be7dc13211de6a2fe1a623;hb=ccf4e0f3ad38270a2b31ec5df9569bcc8c1ca2b4;hp=eb6d038b8bf4fb856bca6b0c5e11196fb2dd6781;hpb=33a23c3a09833f962d52284465a86675b7eb9843;p=mono.git diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index eb6d038b8bf..80e36207fca 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -26,7 +26,7 @@ #include #include -#define MONO_CORLIB_VERSION 14 +#define MONO_CORLIB_VERSION 20 CRITICAL_SECTION mono_delegate_section; @@ -68,13 +68,16 @@ mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoAppDomainSetup *setup; MonoAppDomain *ad; MonoClass *class; - + MonoString *arg; + mono_marshal_init (); mono_install_assembly_preload_hook (mono_domain_assembly_preload, NULL); mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL); mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token); + mono_thread_init (start_cb, attach_cb); + class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup"); setup = (MonoAppDomainSetup *) mono_object_new (domain, class); @@ -91,18 +94,21 @@ mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, mono_type_initialization_init (); - mono_thread_init (start_cb, attach_cb); - + /* * Create an instance early since we can't do it when there is no memory. */ - domain->out_of_memory_ex = mono_exception_from_name (mono_defaults.corlib, "System", "OutOfMemoryException"); + arg = mono_string_new (domain, "Out of memory"); + domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL); + /* * These two are needed because the signal handlers might be executing on * an alternate stack, and Boehm GC can't handle that. */ - domain->null_reference_ex = mono_exception_from_name (mono_defaults.corlib, "System", "NullReferenceException"); - domain->stack_overflow_ex = mono_exception_from_name (mono_defaults.corlib, "System", "StackOverflowException"); + arg = mono_string_new (domain, "A null value was found where an object instance was required"); + domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL); + arg = mono_string_new (domain, "The requested operation caused a stack overflow."); + domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL); /* GC init has to happen after thread init */ mono_gc_init (); @@ -255,32 +261,6 @@ mono_domain_set (MonoDomain *domain, gboolean force) return TRUE; } -void -ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup) -{ - MonoDomain* domain = mono_domain_get (); - MonoAssembly *assembly; - gchar *str; - gchar *config_suffix; - - MONO_ARCH_SAVE_REGS; - - if (!domain->entry_assembly) - assembly = mono_root_domain->entry_assembly; - else - assembly = domain->entry_assembly; - - g_assert (assembly); - - setup->application_base = mono_string_new (domain, assembly->basedir); - - config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL); - str = g_build_filename (assembly->basedir, config_suffix, NULL); - g_free (config_suffix); - setup->configuration_file = mono_string_new (domain, str); - g_free (str); -} - MonoObject * ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name) { @@ -536,6 +516,48 @@ mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data) mono_runtime_invoke (method, domain->domain, params, NULL); } +static gchar * +reduce_path (const gchar *dirname) +{ + gchar **parts; + gchar *part; + GList *list, *tmp; + GString *result; + gchar *res; + gint i; + + parts = g_strsplit (dirname, G_DIR_SEPARATOR_S, 0); + list = NULL; + for (i = 0; (part = parts [i]) != NULL; i++) { + if (!strcmp (part, ".")) + continue; + + if (!strcmp (part, "..")) { + if (list && list->next) /* Don't remove root */ + list = g_list_delete_link (list, list); + } else { + list = g_list_prepend (list, part); + } + } + + result = g_string_new (""); + list = g_list_reverse (list); + + for (tmp = list; tmp; tmp = tmp->next) { + gchar *data = (gchar *) tmp->data; + + if (data && *data) + g_string_append_printf (result, "%c%s", G_DIR_SEPARATOR, + (char *) tmp->data); + } + + res = result->str; + g_string_free (result, FALSE); + g_list_free (list); + g_strfreev (parts); + return res; +} + static void set_domain_search_path (MonoDomain *domain) { @@ -546,14 +568,16 @@ set_domain_search_path (MonoDomain *domain) gint npaths = 0; gchar **pvt_split = NULL; GError *error = NULL; + gint appbaselen = -1; if ((domain->search_path != NULL) && !domain->setup->path_changed) return; setup = domain->setup; - if (setup->application_base) - npaths++; + if (!setup->application_base) + return; /* Must set application base to get private path working */ + npaths++; if (setup->private_bin_path) { utf8 = mono_string_to_utf8 (setup->private_bin_path); pvt_split = g_strsplit (utf8, G_SEARCHPATH_SEPARATOR_S, 1000); @@ -579,49 +603,59 @@ set_domain_search_path (MonoDomain *domain) domain->search_path = tmp = g_malloc ((npaths + 1) * sizeof (gchar *)); tmp [npaths] = NULL; - if (setup->application_base) { - *tmp = mono_string_to_utf8 (setup->application_base); - - /* FIXME: is this needed? */ - if (strncmp (*tmp, "file://", 7) == 0) { - gchar *file = *tmp; - gchar *uri = *tmp; - gchar *tmpuri; - - if (uri [7] != '/') - uri = g_strdup_printf ("file:///%s", uri + 7); - - tmpuri = uri; - uri = mono_escape_uri_string (tmpuri); - *tmp = g_filename_from_uri (uri, NULL, &error); - g_free (uri); - - if (tmpuri != file) - g_free (tmpuri); - - if (error != NULL) { - g_warning ("%s\n", error->message); - g_error_free (error); - *tmp = file; - } else { - g_free (file); - } + + *tmp = mono_string_to_utf8 (setup->application_base); + + /* FIXME: is this needed? */ + if (strncmp (*tmp, "file://", 7) == 0) { + gchar *file = *tmp; + gchar *uri = *tmp; + gchar *tmpuri; + + if (uri [7] != '/') + uri = g_strdup_printf ("file:///%s", uri + 7); + + tmpuri = uri; + uri = mono_escape_uri_string (tmpuri); + *tmp = g_filename_from_uri (uri, NULL, &error); + g_free (uri); + + if (tmpuri != file) + g_free (tmpuri); + + if (error != NULL) { + g_warning ("%s\n", error->message); + g_error_free (error); + *tmp = file; + } else { + g_free (file); } - - } else { - *tmp = g_strdup (""); } for (i = 1; pvt_split && i < npaths; i++) { - if (*tmp [0] == '\0' || g_path_is_absolute (pvt_split [i - 1])) { - tmp [i] = g_strdup (pvt_split [i - 1]); - continue; - } - tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL); + if (strchr (tmp [i], '.')) { + gchar *reduced; + gchar *freeme; + + reduced = reduce_path (tmp [i]); + if (appbaselen == -1) + appbaselen = strlen (tmp [0]); + + if (strncmp (tmp [0], reduced, appbaselen)) { + g_free (reduced); + g_free (tmp [i]); + tmp [i] = g_strdup (""); + continue; + } + + freeme = tmp [i]; + tmp [i] = reduced; + g_free (freeme); + } } - if (setup->private_bin_path_probe != NULL && setup->application_base) { + if (setup->private_bin_path_probe != NULL) { g_free (tmp [0]); tmp [0] = g_strdup (""); } @@ -631,29 +665,67 @@ set_domain_search_path (MonoDomain *domain) g_strfreev (pvt_split); } +static gboolean +try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2, + const gchar *path3, const gchar *path4) +{ + gchar *fullpath; + + *assembly = NULL; + fullpath = g_build_filename (path1, path2, path3, path4, NULL); + if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR)) + *assembly = mono_assembly_open (fullpath, NULL); + + g_free (fullpath); + return (*assembly != NULL); +} + static MonoAssembly * -real_load (gchar **search_path, const gchar *culture, gchar *filename) +real_load (gchar **search_path, const gchar *culture, const gchar *name) { - MonoAssembly *result; + MonoAssembly *result = NULL; gchar **path; - gchar *fullpath; + gchar *filename; + const gchar *local_culture; + gint len; + + if (!culture || *culture == '\0') { + local_culture = ""; + } else { + local_culture = culture; + } + + filename = g_strconcat (name, ".dll", NULL); + len = strlen (filename); for (path = search_path; *path; path++) { if (**path == '\0') continue; /* Ignore empty ApplicationBase */ - if (culture && g_strcasecmp (culture, "neutral")) - fullpath = g_build_filename (*path, culture, filename, NULL); - else - fullpath = g_build_filename (*path, filename, NULL); - - result = mono_assembly_open (fullpath, NULL); - g_free (fullpath); - if (result) - return result; + /* See test cases in bug #58992 and bug #57710 */ + /* 1st try: [culture]/[name].dll (culture may be empty) */ + strcpy (filename + len - 4, ".dll"); + if (try_load_from (&result, *path, local_culture, "", filename)) + break; + + /* 2nd try: [culture]/[name].exe (culture may be empty) */ + strcpy (filename + len - 4, ".exe"); + if (try_load_from (&result, *path, local_culture, "", filename)) + break; + + /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */ + strcpy (filename + len - 4, ".dll"); + if (try_load_from (&result, *path, local_culture, name, filename)) + break; + + /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */ + strcpy (filename + len - 4, ".exe"); + if (try_load_from (&result, *path, local_culture, name, filename)) + break; } - return NULL; + g_free (filename); + return result; } /* @@ -666,50 +738,18 @@ mono_domain_assembly_preload (MonoAssemblyName *aname, gpointer user_data) { MonoDomain *domain = mono_domain_get (); - MonoAssembly *result; - gchar *dll, *exe; + MonoAssembly *result = NULL; set_domain_search_path (domain); - dll = g_strconcat (aname->name, ".dll", NULL); - exe = g_strdup (dll); - strcpy (exe + strlen (exe) - 4, ".exe"); - if (domain->search_path && domain->search_path [0] != NULL) { - /* TODO: should also search in name/name.dll and name/name.exe from appbase */ - result = real_load (domain->search_path, aname->culture, dll); - if (result) { - g_free (dll); - g_free (exe); - return result; - } - - result = real_load (domain->search_path, aname->culture, exe); - if (result) { - g_free (dll); - g_free (exe); - return result; - } + result = real_load (domain->search_path, aname->culture, aname->name); } - if (assemblies_path && assemblies_path [0] != NULL) { - result = real_load (assemblies_path, aname->culture, dll); - if (result) { - g_free (dll); - g_free (exe); - return result; - } - - result = real_load (assemblies_path, aname->culture, exe); - if (result) { - g_free (dll); - g_free (exe); - return result; - } + if (result == NULL && assemblies_path && assemblies_path [0] != NULL) { + result = real_load (assemblies_path, aname->culture, aname->name); } - - g_free (dll); - g_free (exe); + return NULL; } @@ -783,7 +823,7 @@ get_info_from_assembly_name (MonoString *assRef, MonoAssemblyName *aname) while (*tmp) { value = g_strstrip (*tmp); - if (!strncmp (value, "Version=", 8)) { + if (!g_ascii_strncasecmp (value, "Version=", 8)) { if (sscanf (value + 8, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4) { g_strfreev (parts); @@ -798,62 +838,33 @@ get_info_from_assembly_name (MonoString *assRef, MonoAssemblyName *aname) continue; } - if (!strncmp (value, "Culture=", 8)) { - /* g_print ("Culture: %s\n", aname->culture); */ - aname->culture = g_strstrip (g_strdup (value + 8)); + if (!g_ascii_strncasecmp (value, "Culture=", 8)) { + gchar *t = g_strdup (value + 8); + g_strchug (t); + aname->culture = g_strdup (g_strchomp (t)); tmp++; + g_free (t); + if (g_strcasecmp (aname->culture, "neutral") == 0) { + g_free ((void *) aname->culture); + aname->culture = g_strdup (""); + } continue; } - if (!strncmp (value, "PublicKeyToken=", 15)) { + if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) { tmp++; value += 15; - if (*value && strcmp (value, "null")) { - gint i, len; - gchar h, l; - gchar *result; - - value = g_strstrip (g_strdup (value)); - len = strlen (value); - if (len % 2) { - g_free (value); - g_strfreev (parts); - return FALSE; - } - - aname->hash_len = len / 2; - aname->hash_value = g_malloc0 (aname->hash_len); - result = (gchar *) aname->hash_value; - - for (i = 0; i < len; i++) { - if (i % 2) { - l = g_ascii_xdigit_value (value [i]); - if (l == -1) { - g_free (value); - g_strfreev (parts); - return FALSE; - } - result [i / 2] = (h * 16) + l; - } else { - h = g_ascii_xdigit_value (value [i]); - if (h == -1) { - g_free (value); - g_strfreev (parts); - return FALSE; - } - } - } - g_free (value); - - /* - g_print ("PublicKeyToken: "); - for (i = 0; i < aname->hash_len; i++) { - g_print ("%x", 0x00FF & aname->hash_value [i]); - } - g_print ("\n"); - */ + if (*value && strncmp (value, "null", 4)) { + gchar *t = g_strdup (value); + g_strchug (t); + aname->public_tok_value = g_strdup (g_strchomp (value)); + g_free (t); } + continue; } + + g_strfreev (parts); + return FALSE; } g_strfreev (parts); @@ -950,7 +961,7 @@ ves_icall_System_AppDomain_InternalUnload (gint32 domain_id) * Unloading seems to cause problems when running NUnit/NAnt, hence * this workaround. */ - if (getenv ("MONO_NO_UNLOAD")) + if (g_getenv ("MONO_NO_UNLOAD")) return; mono_domain_unload (domain); @@ -985,7 +996,7 @@ ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file, if (!assembly) { mono_raise_exception ((MonoException *)mono_exception_from_name ( - mono_defaults.corlib, "System.IO", "FileNotFoundException")); + mono_defaults.corlib, "System.IO", "FileNotFoundException")); } image = assembly->image; @@ -1164,8 +1175,6 @@ unload_thread_main (void *arg) mono_domain_lock (domain); mono_g_hash_table_foreach (domain->class_vtable_hash, clear_cached_vtable, domain); - mono_g_hash_table_foreach (domain->proxy_vtable_hash, clear_cached_vtable, - domain); mono_domain_unlock (domain); domain->state = MONO_APPDOMAIN_UNLOADED; @@ -1195,7 +1204,6 @@ mono_domain_unload (MonoDomain *domain) { HANDLE thread_handle; guint32 tid; - gboolean ret; MonoAppDomainState prev_state; MonoMethod *method; MonoObject *exc; @@ -1244,10 +1252,13 @@ mono_domain_unload (MonoDomain *domain) #if 0 thread_handle = CreateThread (NULL, 0, unload_thread_main, &thread_data, 0, &tid); #else - thread_handle = CreateThread (NULL, 0, unload_thread_main, &thread_data, CREATE_SUSPENDED, &tid); + thread_handle = CreateThread (NULL, 0, unload_thread_main, &thread_data, CREATE_SUSPENDED, &tid); ResumeThread (thread_handle); #endif - ret = WaitForSingleObject (thread_handle, INFINITE); + + while (WaitForSingleObjectEx (thread_handle, INFINITE, FALSE) == WAIT_IO_COMPLETION) + ; /* wait for the thread */ + if (thread_data.failure_reason) { MonoException *ex;