X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fappdomain.c;h=80e36207fca72b4966be7dc13211de6a2fe1a623;hb=ccf4e0f3ad38270a2b31ec5df9569bcc8c1ca2b4;hp=b5b5bc63502614e6f0c3de8a4272788fadbf471f;hpb=4bb899324182abd6195b9ad7d49eb29346e3eb56;p=mono.git diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index b5b5bc63502..80e36207fca 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -24,14 +24,17 @@ #include #include #include +#include -#define MONO_CORLIB_VERSION 3 +#define MONO_CORLIB_VERSION 20 CRITICAL_SECTION mono_delegate_section; static gunichar2 process_guid [36]; static gboolean process_guid_set = FALSE; +static gboolean shutting_down = FALSE; + static MonoAssembly * mono_domain_assembly_preload (MonoAssemblyName *aname, gchar **assemblies_path, @@ -65,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); @@ -86,12 +92,23 @@ mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, mono_context_init (domain); mono_context_set (domain->default_context); - mono_thread_init (start_cb, attach_cb); + mono_type_initialization_init (); + /* * 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. + */ + 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 (); @@ -148,9 +165,11 @@ mono_context_init (MonoDomain *domain) void mono_runtime_cleanup (MonoDomain *domain) { + shutting_down = TRUE; + /* This ends up calling any pending pending (for at most 2 seconds) */ mono_gc_cleanup (); - + mono_network_cleanup (); } @@ -169,6 +188,12 @@ mono_runtime_quit () quit_function (mono_root_domain, NULL); } +gboolean +mono_runtime_is_shutting_down (void) +{ + return shutting_down; +} + gboolean mono_domain_has_type_resolve (MonoDomain *domain) { @@ -236,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) { @@ -517,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) { @@ -527,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); @@ -560,44 +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; - - if (uri [7] != '/') - uri = g_strdup_printf ("file:///%s", uri + 7); - - *tmp = g_filename_from_uri (uri, NULL, &error); - if (uri != file) - g_free (uri); - - 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 (""); } @@ -607,24 +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, 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 */ - 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; } /* @@ -637,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, dll); - if (result) { - g_free (dll); - g_free (exe); - return result; - } - - result = real_load (domain->search_path, 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, dll); - if (result) { - g_free (dll); - g_free (exe); - return result; - } - - result = real_load (assemblies_path, 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; } @@ -725,7 +794,7 @@ free_assembly_name (MonoAssemblyName *aname) } static gboolean -get_info_from_assembly_name (MonoReflectionAssemblyName *assRef, MonoAssemblyName *aname) +get_info_from_assembly_name (MonoString *assRef, MonoAssemblyName *aname) { gchar *name; gchar *value; @@ -735,7 +804,7 @@ get_info_from_assembly_name (MonoReflectionAssemblyName *assRef, MonoAssemblyNam memset (aname, 0, sizeof (MonoAssemblyName)); - name = mono_string_to_utf8 (assRef->name); + name = mono_string_to_utf8 (assRef); parts = tmp = g_strsplit (name, ",", 4); g_free (name); if (!tmp || !*tmp) { @@ -754,7 +823,7 @@ get_info_from_assembly_name (MonoReflectionAssemblyName *assRef, MonoAssemblyNam 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); @@ -769,62 +838,33 @@ get_info_from_assembly_name (MonoReflectionAssemblyName *assRef, MonoAssemblyNam 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); @@ -843,7 +883,7 @@ ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, MonoImage *image = mono_image_open_from_data (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL); if (raw_symbol_store) - mono_raise_exception (mono_get_exception_not_implemented ()); + mono_raise_exception (mono_get_exception_not_implemented ("LoadAssemblyRaw: Raw Symbol Store not Implemented")); if (!image) { mono_raise_exception (mono_get_exception_bad_image_format ("")); @@ -862,7 +902,7 @@ ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, } MonoReflectionAssembly * -ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoReflectionAssemblyName *assRef, MonoObject *evidence) +ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence) { MonoDomain *domain = ad->data; MonoImageOpenStatus status = MONO_IMAGE_OK; @@ -872,28 +912,25 @@ ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoReflectionAssem MONO_ARCH_SAVE_REGS; - memset (&aname, 0, sizeof (aname)); - /* FIXME : examine evidence? */ g_assert (assRef != NULL); - g_assert (assRef->name != NULL); if (!get_info_from_assembly_name (assRef, &aname)) { MonoException *exc; free_assembly_name (&aname); /* This is a parse error... */ - exc = mono_get_exception_file_not_found (assRef->name); + exc = mono_get_exception_file_not_found (assRef); mono_raise_exception (exc); } ass = mono_assembly_load (&aname, NULL, &status); free_assembly_name (&aname); - if (!ass && (refass = try_assembly_resolve (domain, assRef->name)) == NULL){ + if (!ass && (refass = try_assembly_resolve (domain, assRef)) == NULL){ /* FIXME: it doesn't make much sense since we really don't have a filename ... */ - MonoException *exc = mono_get_exception_file_not_found (assRef->name); + MonoException *exc = mono_get_exception_file_not_found (assRef); mono_raise_exception (exc); } @@ -920,6 +957,13 @@ ves_icall_System_AppDomain_InternalUnload (gint32 domain_id) return; } + /* + * Unloading seems to cause problems when running NUnit/NAnt, hence + * this workaround. + */ + if (g_getenv ("MONO_NO_UNLOAD")) + return; + mono_domain_unload (domain); } @@ -952,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; @@ -999,7 +1043,7 @@ ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid) MONO_ARCH_SAVE_REGS; - if (!mono_domain_set (domain, FALSE)) + if (!domain || !mono_domain_set (domain, FALSE)) mono_raise_exception (mono_get_exception_appdomain_unloaded ()); return current_domain->domain; @@ -1020,8 +1064,14 @@ ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id) MONO_ARCH_SAVE_REGS; - if (domain) - mono_thread_push_appdomain_ref (domain); + if (!domain) + /* + * Raise an exception to prevent the managed code from executing a pop + * later. + */ + mono_raise_exception (mono_get_exception_appdomain_unloaded ()); + + mono_thread_push_appdomain_ref (domain); } void @@ -1110,13 +1160,13 @@ unload_thread_main (void *arg) * FIXME: Abort our parent thread last, so we can return a failure * indication if aborting times out. */ - if (!mono_threads_abort_appdomain_threads (domain, 1000)) { + if (!mono_threads_abort_appdomain_threads (domain, 10000)) { data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name); return 1; } /* Finalize all finalizable objects in the doomed appdomain */ - if (!mono_domain_finalize (domain, 1000)) { + if (!mono_domain_finalize (domain, 10000)) { data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name); return 1; } @@ -1125,12 +1175,12 @@ 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; + //printf ("UNLOADED %s.\n", domain->friendly_name); + mono_domain_free (domain, FALSE); #ifdef HAVE_BOEHM_GC @@ -1154,7 +1204,6 @@ mono_domain_unload (MonoDomain *domain) { HANDLE thread_handle; guint32 tid; - gboolean ret; MonoAppDomainState prev_state; MonoMethod *method; MonoObject *exc; @@ -1203,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;