*
* (c) 2001-2003 Ximian, Inc. (http://www.ximian.com)
*/
-
+#undef ASSEMBLY_LOAD_DEBUG
#include <config.h>
#include <glib.h>
#include <string.h>
+#include <unistd.h>
#include <mono/os/gc_wrapper.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/monitor.h>
#include <mono/metadata/threadpool.h>
+#include <mono/metadata/mono-debug.h>
#include <mono/utils/mono-uri.h>
+#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-path.h>
+#include <mono/utils/mono-stdlib.h>
-#define MONO_CORLIB_VERSION 36
+#define MONO_CORLIB_VERSION 54
CRITICAL_SECTION mono_delegate_section;
mono_domain_assembly_search (MonoAssemblyName *aname,
gpointer user_data);
+static MonoAssembly *
+mono_domain_assembly_postload_search (MonoAssemblyName *aname,
+ gpointer user_data);
+
static void
mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
+ mono_install_assembly_postload_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
+ mono_install_assembly_postload_refonly_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
domain->default_context = context;
}
-/* This must not be called while there are still running threads executing
+/**
+ * mono_runtime_cleanup:
+ * @domain: unused.
+ *
+ * Internal routine.
+ *
+ * This must not be called while there are still running threads executing
* managed code.
*/
void
/* This ends up calling any pending pending (for at most 2 seconds) */
mono_gc_cleanup ();
+ mono_thread_cleanup ();
+
mono_network_cleanup ();
+
+ mono_marshal_cleanup ();
+
+ mono_type_initialization_cleanup ();
+
+ mono_monitor_cleanup ();
}
static MonoDomainFunc quit_function = NULL;
quit_function (mono_get_root_domain (), NULL);
}
+/**
+ * mono_runtime_set_shutting_down:
+ *
+ * Invoked by System.Environment.Exit to flag that the runtime
+ * is shutting down.
+ */
void
mono_runtime_set_shutting_down (void)
{
shutting_down = TRUE;
}
+/**
+ * mono_runtime_is_shutting_down:
+ *
+ * Returns whether the runtime has been flagged for shutdown.
+ *
+ * This is consumed by the P:System.Environment.HasShutdownStarted
+ * property.
+ *
+ */
gboolean
mono_runtime_is_shutting_down (void)
{
return shutting_down;
}
+/**
+ * mono_domain_has_type_resolve:
+ * @domain: application domains being looked up
+ *
+ * Returns true if the AppDomain.TypeResolve field has been
+ * set.
+ */
gboolean
mono_domain_has_type_resolve (MonoDomain *domain)
{
return o != NULL;
}
+/**
+ * mono_domain_try_type_resolve:
+ * @domain: application domainwhere the name where the type is going to be resolved
+ * @name: the name of the type to resolve or NULL.
+ * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
+ *
+ * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
+ * the assembly that matches name.
+ *
+ * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
+ *
+ * Returns: A MonoReflectionAssembly or NULL if not found
+ */
MonoReflectionAssembly *
mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
{
/**
* mono_domain_owns_vtable_slot:
*
- * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
+ * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
*/
gboolean
mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
* @domain: domain
* @force: force setting.
*
- * Set the current appdomain to @domain. If @force is set, set it even
+ * Set the current appdomain to @domain. If @force is set, set it even
* if it is being unloaded.
*
* Returns:
MonoObject *
ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
{
- MonoDomain *add = ad->data;
+ MonoDomain *add;
MonoObject *o;
char *str;
MONO_ARCH_SAVE_REGS;
g_assert (ad != NULL);
+ add = ad->data;
+ g_assert (add != NULL);
if (name == NULL)
mono_raise_exception (mono_get_exception_argument_null ("name"));
void
ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
{
- MonoDomain *add = ad->data;
+ MonoDomain *add;
MONO_ARCH_SAVE_REGS;
g_assert (ad != NULL);
+ add = ad->data;
+ g_assert (add != NULL);
if (name == NULL)
mono_raise_exception (mono_get_exception_argument_null ("name"));
MonoAppDomain *
ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
{
- MonoDomain *domain = mono_domain_get ();
MonoClass *adclass;
MonoAppDomain *ad;
MonoDomain *data;
- GSList *tmp;
MONO_ARCH_SAVE_REGS;
if (!setup->application_base) {
/* Inherit from the root domain since MS.NET does this */
MonoDomain *root = mono_get_root_domain ();
- setup->application_base = mono_string_new_utf16 (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base));
+ if (root->setup->application_base)
+ MONO_OBJECT_SETREF (setup, application_base, mono_string_new_utf16 (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base)));
}
mono_context_init (data);
- /* The new appdomain should have all assemblies loaded */
- mono_domain_lock (domain);
- /*g_print ("copy assemblies from domain %p (%s)\n", domain, domain->friendly_name);*/
- for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next)
- add_assemblies_to_domain (data, tmp->data, NULL);
- mono_domain_unlock (domain);
+ add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
return ad;
}
count = 0;
/* Need to skip internal assembly builders created by remoting */
- mono_domain_lock (domain);
+ mono_domain_assemblies_lock (domain);
for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
ass = tmp->data;
if (refonly && !ass->ref_only)
continue;
if (ass->corlib_internal)
continue;
- mono_array_set (res, gpointer, i, mono_assembly_get_object (domain, ass));
+ mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
++i;
}
- mono_domain_unlock (domain);
+ mono_domain_assemblies_unlock (domain);
return res;
}
return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
}
+static MonoAssembly *
+mono_domain_assembly_postload_search (MonoAssemblyName *aname,
+ gpointer user_data)
+{
+ gboolean refonly = GPOINTER_TO_UINT (user_data);
+ MonoReflectionAssembly *assembly;
+ MonoDomain *domain = mono_domain_get ();
+ char *aname_str;
+
+ aname_str = mono_stringify_assembly_name (aname);
+
+ /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
+ assembly = try_assembly_resolve (domain, mono_string_new (domain, aname_str), refonly);
+
+ g_free (aname_str);
+
+ if (assembly)
+ return assembly->assembly;
+ else
+ return NULL;
+}
+
/*
- * LOCKING: assumes domain is already locked.
+ * LOCKING: assumes assemblies_lock in the domain is already locked.
*/
static void
add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
mono_assembly_addref (ass);
g_hash_table_insert (ht, ass, ass);
domain->domain_assemblies = g_slist_prepend (domain->domain_assemblies, ass);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s %p added to domain %s, ref_count=%d\n", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
}
if (ass->image->references) {
static void
mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
{
+ static MonoClassField *assembly_load_field;
+ static MonoMethod *assembly_load_method;
MonoDomain *domain = mono_domain_get ();
MonoReflectionAssembly *ref_assembly;
MonoClass *klass;
- MonoMethod *method;
+ gpointer load_value;
void *params [1];
if (!domain->domain)
/* This can happen during startup */
return;
-
+#ifdef ASSEMBLY_LOAD_DEBUG
+ fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
+#endif
klass = domain->domain->mbr.obj.vtable->klass;
- method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
- if (method == NULL) {
- g_warning ("Method AppDomain.DoAssemblyLoad not found.\n");
- return;
+ mono_domain_assemblies_lock (domain);
+ add_assemblies_to_domain (domain, assembly, NULL);
+ mono_domain_assemblies_unlock (domain);
+
+ if (assembly_load_field == NULL) {
+ assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
+ g_assert (assembly_load_field);
}
- mono_domain_lock (domain);
- add_assemblies_to_domain (domain, assembly, NULL);
- mono_domain_unlock (domain);
+ mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
+ if (load_value == NULL) {
+ /* No events waiting to be triggered */
+ return;
+ }
ref_assembly = mono_assembly_get_object (domain, assembly);
g_assert (ref_assembly);
- *params = ref_assembly;
- 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);
- }
+ if (assembly_load_method == NULL) {
+ assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
+ g_assert (assembly_load_method);
}
- result = g_string_new ("");
- list = g_list_reverse (list);
-
- for (tmp = list; tmp; tmp = tmp->next) {
- gchar *data = (gchar *) tmp->data;
-
- if (data && *data) {
-#ifdef PLATFORM_WIN32
- if (result->len == 0)
- g_string_append_printf (result, "%s\\", data);
- else if (result->str [result->len - 1] == '\\')
- g_string_append_printf (result, "%s", data);
- else
-#endif
- g_string_append_printf (result, "%c%s",
- G_DIR_SEPARATOR, data);
- }
- }
-
- res = result->str;
- g_string_free (result, FALSE);
- g_list_free (list);
- g_strfreev (parts);
- return res;
+ *params = ref_assembly;
+ mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
}
static void
gchar *reduced;
gchar *freeme;
- reduced = reduce_path (tmp [i]);
+ reduced = mono_path_canonicalize (tmp [i]);
if (appbaselen == -1)
appbaselen = strlen (tmp [0]);
g_strfreev (pvt_split);
}
+static char *
+make_shadow_copy (const char *filename)
+{
+ gchar *tmp;
+ guint16 *orig, *dest;
+ MonoDomain *domain = mono_domain_get ();
+ char *db;
+ int fd;
+ gboolean copy_result;
+ MonoException *exc;
+
+ db = mono_string_to_utf8 (domain->setup->dynamic_base);
+ tmp = g_build_filename (db, "shadow-XXXXXX", NULL);
+ fd = mono_mkstemp (tmp);
+ if (fd == -1) {
+ exc = mono_get_exception_execution_engine ("Failed to create shadow copy (mkstemp).");
+ g_free (tmp);
+ g_free (db);
+ mono_raise_exception (exc);
+ }
+ close (fd);
+ remove (tmp);
+ orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
+ dest = g_utf8_to_utf16 (tmp, strlen (tmp), NULL, NULL, NULL);
+ copy_result = CopyFile (orig, dest, TRUE);
+ g_free (dest);
+ g_free (orig);
+ g_free (db);
+
+ if (copy_result == FALSE) {
+ g_free (tmp);
+ exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
+ mono_raise_exception (exc);
+ }
+ return tmp;
+}
+
static gboolean
try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
- const gchar *path3, const gchar *path4, gboolean refonly)
+ const gchar *path3, const gchar *path4,
+ gboolean refonly, gboolean is_private)
{
+
gchar *fullpath;
*assembly = NULL;
fullpath = g_build_filename (path1, path2, path3, path4, NULL);
- if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
+ if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR)) {
+ if (is_private) {
+ char *new_path = make_shadow_copy (fullpath);
+ g_free (fullpath);
+ fullpath = new_path;
+ }
+
*assembly = mono_assembly_open_full (fullpath, NULL, refonly);
+ }
g_free (fullpath);
return (*assembly != NULL);
gchar *filename;
const gchar *local_culture;
gint len;
+ gboolean is_private = FALSE;
if (!culture || *culture == '\0') {
local_culture = "";
len = strlen (filename);
for (path = search_path; *path; path++) {
- if (**path == '\0')
+ if (**path == '\0') {
+ is_private = TRUE;
continue; /* Ignore empty ApplicationBase */
+ }
/* 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, refonly))
+ if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
break;
/* 2nd try: [culture]/[name].exe (culture may be empty) */
strcpy (filename + len - 4, ".exe");
- if (try_load_from (&result, *path, local_culture, "", filename, refonly))
+ if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
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, refonly))
+ if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
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, refonly))
+ if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
break;
}
MonoAssembly *ass;
gboolean refonly = GPOINTER_TO_UINT (user_data);
- mono_domain_lock (domain);
+ mono_domain_assemblies_lock (domain);
for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
ass = tmp->data;
/* Dynamic assemblies can't match here in MS.NET */
if (ass->dynamic || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
continue;
- mono_domain_unlock (domain);
+ mono_domain_assemblies_unlock (domain);
return ass;
}
- mono_domain_unlock (domain);
+ mono_domain_assemblies_unlock (domain);
return NULL;
}
ass = mono_assembly_open_full (filename, &status, refOnly);
- g_free (name);
-
if (!ass){
- MonoException *exc = mono_get_exception_file_not_found (fname);
+ MonoException *exc;
+
+ if (status == MONO_IMAGE_IMAGE_INVALID)
+ exc = mono_get_exception_bad_image_format (name);
+ else
+ exc = mono_get_exception_file_not_found (fname);
+ g_free (name);
mono_raise_exception (exc);
}
+ g_free (name);
+
return mono_assembly_get_object (domain, ass);
}
MonoDomain *domain = ad->data;
MonoImageOpenStatus status;
guint32 raw_assembly_len = mono_array_length (raw_assembly);
- MonoImage *image = mono_image_open_from_data (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL);
+ MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
- if (raw_symbol_store)
- 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 (""));
return NULL;
}
+ if (raw_symbol_store != NULL)
+ mono_debug_init_2_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
+
ass = mono_assembly_load_from_full (image, "", &status, refonly);
+
if (!ass) {
mono_image_close (image);
mono_raise_exception (mono_get_exception_bad_image_format (""));
}
refass = mono_assembly_get_object (domain, ass);
- refass->evidence = evidence;
+ MONO_OBJECT_SETREF (refass, evidence, evidence);
return refass;
}
if (refass == NULL)
refass = mono_assembly_get_object (domain, ass);
- refass->evidence = evidence;
+ MONO_OBJECT_SETREF (refass, evidence, evidence);
return refass;
}
args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
refass = mono_assembly_get_object (ad->data, assembly);
- refass->evidence = evidence;
+ MONO_OBJECT_SETREF (refass, evidence, evidence);
res = mono_runtime_exec_main (method, (MonoArray *)args, NULL);
char *failure_reason;
} unload_data;
-static guint32
+static guint32 WINAPI
unload_thread_main (void *arg)
{
unload_data *data = (unload_data*)arg;
/* printf ("UNLOADED %s.\n", domain->friendly_name); */
+ /* remove from the handle table the items related to this domain */
+ mono_gchandle_free_domain (domain);
+
mono_domain_free (domain, FALSE);
mono_gc_collect (mono_gc_max_generation ());
/*
* mono_domain_unload:
+ * @domain: The domain to unload
*
* Unloads an appdomain. Follows the process outlined in:
* http://blogs.gotdotnet.com/cbrumme
+ *
* If doing things the 'right' way is too hard or complex, we do it the
* 'simple' way, which means do everything needed to avoid crashes and
* memory leaks, but not much else.
mono_domain_unload (MonoDomain *domain)
{
HANDLE thread_handle;
- guint32 tid, res;
+ gsize tid;
+ guint32 res;
MonoAppDomainState prev_state;
MonoMethod *method;
MonoObject *exc;
if (mono_thread_has_appdomain_ref (mono_thread_current (), domain) && (mono_thread_interruption_requested ()))
/* The unload thread tries to abort us */
/* The icall wrapper will execute the abort */
+ CloseHandle (thread_handle);
return;
}
+ CloseHandle (thread_handle);
mono_domain_set (caller_domain, FALSE);
g_warning (thread_data.failure_reason);
+ ex = mono_get_exception_cannot_unload_appdomain (thread_data.failure_reason);
+
g_free (thread_data.failure_reason);
thread_data.failure_reason = NULL;
- ex = mono_get_exception_cannot_unload_appdomain (thread_data.failure_reason);
-
mono_raise_exception (ex);
}
}