2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
13 #undef ASSEMBLY_LOAD_DEBUG
19 #include <sys/types.h>
21 #ifdef HAVE_SYS_TIME_H
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
35 #include <mono/metadata/gc-internals.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/threadpool-ms.h>
43 #include <mono/metadata/socket-io.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/gc-internals.h>
46 #include <mono/metadata/mono-gc.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/monitor.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/reflection-internals.h>
59 #include <mono/utils/mono-uri.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-path.h>
62 #include <mono/utils/mono-stdlib.h>
63 #include <mono/utils/mono-io-portability.h>
64 #include <mono/utils/mono-error-internals.h>
65 #include <mono/utils/atomic.h>
66 #include <mono/utils/mono-memory-model.h>
67 #include <mono/utils/mono-threads.h>
73 * This is the version number of the corlib-runtime interface. When
74 * making changes to this interface (by changing the layout
75 * of classes the runtime knows about, changing icall signature or
76 * semantics etc), increment this variable. Also increment the
77 * pair of this variable in mscorlib in:
78 * mcs/class/corlib/System/Environment.cs
80 * Changes which are already detected at runtime, like the addition
81 * of icalls, do not require an increment.
83 #define MONO_CORLIB_VERSION 140
88 int assemblybinding_count;
93 static gunichar2 process_guid [36];
94 static gboolean process_guid_set = FALSE;
96 static gboolean no_exec = FALSE;
99 mono_domain_assembly_preload (MonoAssemblyName *aname,
100 gchar **assemblies_path,
103 static MonoAssembly *
104 mono_domain_assembly_search (MonoAssemblyName *aname,
108 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
111 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
113 static MonoAppDomain *
114 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
117 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
119 static MonoLoadFunc load_function = NULL;
122 mono_install_runtime_load (MonoLoadFunc func)
124 load_function = func;
128 mono_runtime_load (const char *filename, const char *runtime_version)
130 g_assert (load_function);
131 return load_function (filename, runtime_version);
135 * mono_runtime_set_no_exec:
137 * Instructs the runtime to operate in static mode, i.e. avoid/do not
138 * allow managed code execution. This is useful for running the AOT
139 * compiler on platforms which allow full-aot execution only. This
140 * should be called before mono_runtime_init ().
143 mono_runtime_set_no_exec (gboolean val)
149 * mono_runtime_get_no_exec:
151 * If true, then the runtime will not allow managed code execution.
154 mono_runtime_get_no_exec (void)
160 create_domain_objects (MonoDomain *domain)
163 MonoDomain *old_domain = mono_domain_get ();
165 MonoVTable *string_vt;
166 MonoClassField *string_empty_fld;
168 if (domain != old_domain) {
169 mono_thread_push_appdomain_ref (domain);
170 mono_domain_set_internal_with_options (domain, FALSE);
174 * Initialize String.Empty. This enables the removal of
175 * the static cctor of the String class.
177 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
178 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
179 g_assert (string_empty_fld);
180 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
183 * Create an instance early since we can't do it when there is no memory.
185 arg = mono_string_new (domain, "Out of memory");
186 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
189 * These two are needed because the signal handlers might be executing on
190 * an alternate stack, and Boehm GC can't handle that.
192 arg = mono_string_new (domain, "A null value was found where an object instance was required");
193 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
194 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
195 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
197 /*The ephemeron tombstone i*/
198 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
199 mono_error_assert_ok (&error);
201 if (domain != old_domain) {
202 mono_thread_pop_appdomain_ref ();
203 mono_domain_set_internal_with_options (old_domain, FALSE);
207 * This class is used during exception handling, so initialize it here, to prevent
208 * stack overflows while handling stack overflows.
210 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
215 * @domain: domain returned by mono_init ()
217 * Initialize the core AppDomain: this function will run also some
218 * IL initialization code, so it needs the execution engine to be fully
221 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
222 * we know the entry_assembly.
226 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
227 MonoThreadAttachCB attach_cb)
230 MonoAppDomainSetup *setup;
234 mono_portability_helpers_init ();
236 mono_gc_base_init ();
237 mono_monitor_init ();
238 mono_marshal_init ();
240 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
241 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
242 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
243 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
244 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
245 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
246 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
247 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
249 mono_thread_init (start_cb, attach_cb);
251 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
252 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, &error);
253 mono_error_raise_exception (&error); /* FIXME don't raise here */
255 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
256 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, &error);
257 mono_error_raise_exception (&error); /* FIXME don't raise here */
260 domain->setup = setup;
262 mono_thread_attach (domain);
264 mono_type_initialization_init ();
266 if (!mono_runtime_get_no_exec ())
267 create_domain_objects (domain);
269 /* GC init has to happen after thread init */
272 /* contexts use GC handles, so they must be initialized after the GC */
273 mono_context_init (domain);
274 mono_context_set (domain->default_context);
276 #ifndef DISABLE_SOCKETS
277 mono_network_init ();
280 mono_console_init ();
283 mono_locks_tracer_init ();
285 /* mscorlib is loaded before we install the load hook */
286 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
292 mono_get_corlib_version (void)
295 MonoClassField *field;
298 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
299 mono_class_init (klass);
300 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
303 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
305 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
306 return *(gint32*)((gchar*)value + sizeof (MonoObject));
310 * mono_check_corlib_version
312 * Checks that the corlib that is loaded matches the version of this runtime.
314 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
315 * allocated string with the error otherwise.
318 mono_check_corlib_version (void)
320 int version = mono_get_corlib_version ();
321 if (version != MONO_CORLIB_VERSION)
322 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
329 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
331 * Initializes the @domain's default System.Runtime.Remoting's Context.
334 mono_context_init (MonoDomain *domain)
338 MonoAppContext *context;
340 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
341 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, &error);
342 mono_error_raise_exception (&error); /* FIXME don't raise here */
343 context->domain_id = domain->domain_id;
344 context->context_id = 0;
345 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
346 domain->default_context = context;
350 * mono_runtime_cleanup:
355 * This must not be called while there are still running threads executing
359 mono_runtime_cleanup (MonoDomain *domain)
361 mono_attach_cleanup ();
363 /* This ends up calling any pending pending (for at most 2 seconds) */
366 mono_thread_cleanup ();
368 #ifndef DISABLE_SOCKETS
369 mono_network_cleanup ();
371 mono_marshal_cleanup ();
373 mono_type_initialization_cleanup ();
375 mono_monitor_cleanup ();
378 static MonoDomainFunc quit_function = NULL;
381 mono_install_runtime_cleanup (MonoDomainFunc func)
383 quit_function = func;
389 if (quit_function != NULL)
390 quit_function (mono_get_root_domain (), NULL);
394 * mono_domain_create_appdomain:
395 * @friendly_name: The friendly name of the appdomain to create
396 * @configuration_file: The configuration file to initialize the appdomain with
398 * Returns a MonoDomain initialized with the appdomain
401 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
405 MonoAppDomainSetup *setup;
408 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
409 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
410 mono_error_raise_exception (&error); /* FIXME don't raise here */
411 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
413 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
414 mono_error_raise_exception (&error); /* FIXME don't raise here */
416 return mono_domain_from_appdomain (ad);
420 * mono_domain_set_config:
421 * @domain: MonoDomain initialized with the appdomain we want to change
422 * @base_dir: new base directory for the appdomain
423 * @config_file_name: path to the new configuration for the app domain
425 * Used to set the system configuration for an appdomain
427 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
428 * Error Initializing the configuration system. ---> System.ArgumentException:
429 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
432 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
434 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
435 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
438 static MonoAppDomainSetup*
439 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
442 MonoDomain *caller_domain = mono_domain_get ();
443 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
444 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, &error);
445 mono_error_raise_exception (&error); /* FIXME don't raise here */
447 mono_domain_set_internal (domain);
449 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
450 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
451 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
452 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
453 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
454 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
455 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
456 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
457 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
458 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
459 copy->publisher_policy = setup->publisher_policy;
460 copy->path_changed = setup->path_changed;
461 copy->loader_optimization = setup->loader_optimization;
462 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
463 copy->disallow_code_downloads = setup->disallow_code_downloads;
464 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
465 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
466 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
467 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
468 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
470 mono_domain_set_internal (caller_domain);
475 static MonoAppDomain *
476 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
481 char *shadow_location;
483 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
485 /* FIXME: pin all those objects */
486 data = mono_domain_create();
488 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
489 if (!mono_error_ok (error)) return NULL;
492 data->friendly_name = g_strdup (friendly_name);
494 mono_profiler_appdomain_name (data, data->friendly_name);
496 if (!setup->application_base) {
497 /* Inherit from the root domain since MS.NET does this */
498 MonoDomain *root = mono_get_root_domain ();
499 if (root->setup->application_base) {
500 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
501 mono_error_assert_ok (error); /* FIXME don't swallow the error */
502 MONO_OBJECT_SETREF (setup, application_base, s);
506 mono_context_init (data);
508 data->setup = copy_app_domain_setup (data, setup);
509 mono_domain_set_options_from_config (data);
510 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
512 #ifndef DISABLE_SHADOW_COPY
513 /*FIXME, guard this for when the debugger is not running */
514 shadow_location = get_shadow_assembly_location_base (data, error);
515 if (!mono_error_ok (error))
518 g_free (shadow_location);
521 create_domain_objects (data);
527 * mono_domain_has_type_resolve:
528 * @domain: application domains being looked up
530 * Returns: TRUE if the AppDomain.TypeResolve field has been
534 mono_domain_has_type_resolve (MonoDomain *domain)
536 static MonoClassField *field = NULL;
540 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
544 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
548 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
553 * mono_domain_try_type_resolve:
554 * @domain: application domainwhere the name where the type is going to be resolved
555 * @name: the name of the type to resolve or NULL.
556 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
558 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
559 * the assembly that matches name.
561 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
563 * Returns: A MonoReflectionAssembly or NULL if not found
565 MonoReflectionAssembly *
566 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
569 MonoReflectionAssembly *ret;
572 static MonoMethod *method = NULL;
574 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
576 if (method == NULL) {
577 klass = domain->domain->mbr.obj.vtable->klass;
580 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
581 if (method == NULL) {
582 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
588 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
592 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, &error);
593 mono_error_raise_exception (&error); /* FIXME don't raise here */
599 * mono_domain_owns_vtable_slot:
601 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
604 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
608 mono_domain_lock (domain);
609 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
610 mono_domain_unlock (domain);
617 * @force: force setting.
619 * Set the current appdomain to @domain. If @force is set, set it even
620 * if it is being unloaded.
624 * FALSE if the domain is unloaded
627 mono_domain_set (MonoDomain *domain, gboolean force)
629 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
632 mono_domain_set_internal (domain);
638 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
644 MONO_CHECK_ARG_NULL (name, NULL);
650 str = mono_string_to_utf8 (name);
652 mono_domain_lock (add);
654 if (!strcmp (str, "APPBASE"))
655 o = (MonoObject *)add->setup->application_base;
656 else if (!strcmp (str, "APP_CONFIG_FILE"))
657 o = (MonoObject *)add->setup->configuration_file;
658 else if (!strcmp (str, "DYNAMIC_BASE"))
659 o = (MonoObject *)add->setup->dynamic_base;
660 else if (!strcmp (str, "APP_NAME"))
661 o = (MonoObject *)add->setup->application_name;
662 else if (!strcmp (str, "CACHE_BASE"))
663 o = (MonoObject *)add->setup->cache_path;
664 else if (!strcmp (str, "PRIVATE_BINPATH"))
665 o = (MonoObject *)add->setup->private_bin_path;
666 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
667 o = (MonoObject *)add->setup->private_bin_path_probe;
668 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
669 o = (MonoObject *)add->setup->shadow_copy_directories;
670 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
671 o = (MonoObject *)add->setup->shadow_copy_files;
673 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
675 mono_domain_unlock (add);
685 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
689 MONO_CHECK_ARG_NULL (name,);
695 mono_domain_lock (add);
697 mono_g_hash_table_insert (add->env, name, data);
699 mono_domain_unlock (add);
703 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
708 return ad->data->setup;
712 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
717 return mono_string_new (ad->data, ad->data->friendly_name);
721 ves_icall_System_AppDomain_getCurDomain ()
723 MonoDomain *add = mono_domain_get ();
729 ves_icall_System_AppDomain_getRootDomain ()
731 MonoDomain *root = mono_get_root_domain ();
737 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
739 MonoDomain *domain = mono_domain_get ();
741 return domain->throw_unobserved_task_exceptions;
745 get_attribute_value (const gchar **attribute_names,
746 const gchar **attribute_values,
747 const char *att_name)
750 for (n = 0; attribute_names [n] != NULL; n++) {
751 if (strcmp (attribute_names [n], att_name) == 0)
752 return g_strdup (attribute_values [n]);
758 start_element (GMarkupParseContext *context,
759 const gchar *element_name,
760 const gchar **attribute_names,
761 const gchar **attribute_values,
765 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
767 if (strcmp (element_name, "runtime") == 0) {
768 runtime_config->runtime_count++;
772 if (strcmp (element_name, "assemblyBinding") == 0) {
773 runtime_config->assemblybinding_count++;
777 if (runtime_config->runtime_count != 1)
780 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
781 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
783 if (value && g_ascii_strcasecmp (value, "true") == 0)
784 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
787 if (runtime_config->assemblybinding_count != 1)
790 if (strcmp (element_name, "probing") != 0)
793 g_free (runtime_config->domain->private_bin_path);
794 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
795 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
796 g_free (runtime_config->domain->private_bin_path);
797 runtime_config->domain->private_bin_path = NULL;
803 end_element (GMarkupParseContext *context,
804 const gchar *element_name,
808 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
809 if (strcmp (element_name, "runtime") == 0)
810 runtime_config->runtime_count--;
811 else if (strcmp (element_name, "assemblyBinding") == 0)
812 runtime_config->assemblybinding_count--;
816 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
818 RuntimeConfig *state = (RuntimeConfig *)user_data;
820 const gchar *filename;
822 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
823 msg = error && error->message ? error->message : "";
824 g_warning ("Error parsing %s: %s", filename, msg);
827 static const GMarkupParser
837 mono_domain_set_options_from_config (MonoDomain *domain)
840 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
842 GMarkupParseContext *context;
843 RuntimeConfig runtime_config;
846 if (!domain || !domain->setup || !domain->setup->configuration_file)
849 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
850 if (!mono_error_ok (&error)) {
851 mono_error_cleanup (&error);
855 config_file_path = mono_portability_find_file (config_file_name, TRUE);
856 if (!config_file_path)
857 config_file_path = config_file_name;
859 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
862 runtime_config.runtime_count = 0;
863 runtime_config.assemblybinding_count = 0;
864 runtime_config.domain = domain;
865 runtime_config.filename = config_file_path;
868 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
869 offset = 3; /* Skip UTF-8 BOM */
871 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
872 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
873 g_markup_parse_context_end_parse (context, NULL);
874 g_markup_parse_context_free (context);
878 if (config_file_name != config_file_path)
879 g_free (config_file_name);
880 g_free (config_file_path);
884 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
886 #ifdef DISABLE_APPDOMAINS
887 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
894 fname = mono_string_to_utf8 (friendly_name);
895 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
899 mono_error_raise_exception (&error);
906 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
909 MonoDomain *domain = ad->data;
911 static MonoClass *System_Reflection_Assembly;
915 GPtrArray *assemblies;
917 mono_error_init (&error);
919 if (!System_Reflection_Assembly)
920 System_Reflection_Assembly = mono_class_from_name (
921 mono_defaults.corlib, "System.Reflection", "Assembly");
924 * Make a copy of the list of assemblies because we can't hold the assemblies
925 * lock while creating objects etc.
927 assemblies = g_ptr_array_new ();
928 /* Need to skip internal assembly builders created by remoting */
929 mono_domain_assemblies_lock (domain);
930 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
931 ass = (MonoAssembly *)tmp->data;
932 if (refonly != ass->ref_only)
934 if (ass->corlib_internal)
936 g_ptr_array_add (assemblies, ass);
938 mono_domain_assemblies_unlock (domain);
940 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
941 for (i = 0; i < assemblies->len; ++i) {
942 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
943 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
944 if (!mono_error_ok (&error))
946 mono_array_setref (res, i, ass_obj);
950 g_ptr_array_free (assemblies, TRUE);
951 if (!mono_error_ok (&error))
952 mono_error_set_pending_exception (&error);
956 MonoReflectionAssembly *
957 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
960 MonoReflectionAssembly *ret;
963 MonoBoolean isrefonly;
966 if (mono_runtime_get_no_exec ())
969 g_assert (domain != NULL && fname != NULL);
971 klass = domain->domain->mbr.obj.vtable->klass;
974 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
975 if (method == NULL) {
976 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
980 isrefonly = refonly ? 1 : 0;
983 params[1] = mono_assembly_get_object_checked (domain, requesting, &error);
984 if (!mono_error_ok (&error))
985 mono_error_raise_exception (&error); /* FIXME don't raise here */
988 params [2] = &isrefonly;
990 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, &error);
991 mono_error_raise_exception (&error); /* FIXME don't raise here */
997 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1000 MonoReflectionAssembly *assembly;
1001 MonoDomain *domain = mono_domain_get ();
1005 aname_str = mono_stringify_assembly_name (aname);
1007 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1008 str = mono_string_new (domain, aname_str);
1013 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
1017 return assembly->assembly;
1023 * LOCKING: assumes assemblies_lock in the domain is already locked.
1026 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1030 gboolean destroy_ht = FALSE;
1032 if (!ass->aname.name)
1036 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1040 /* FIXME: handle lazy loaded assemblies */
1041 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1042 g_hash_table_insert (ht, tmp->data, tmp->data);
1044 if (!g_hash_table_lookup (ht, ass)) {
1045 mono_assembly_addref (ass);
1046 g_hash_table_insert (ht, ass, ass);
1047 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1048 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to domain %s, ref_count=%d", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
1051 if (ass->image->references) {
1052 for (i = 0; ass->image->references [i] != NULL; i++) {
1053 if (ass->image->references [i] != REFERENCE_MISSING)
1054 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1055 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1060 g_hash_table_destroy (ht);
1064 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1066 static MonoClassField *assembly_load_field;
1067 static MonoMethod *assembly_load_method;
1069 MonoDomain *domain = mono_domain_get ();
1070 MonoReflectionAssembly *ref_assembly;
1072 gpointer load_value;
1075 if (!domain->domain)
1076 /* This can happen during startup */
1078 #ifdef ASSEMBLY_LOAD_DEBUG
1079 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1081 klass = domain->domain->mbr.obj.vtable->klass;
1083 mono_domain_assemblies_lock (domain);
1084 add_assemblies_to_domain (domain, assembly, NULL);
1085 mono_domain_assemblies_unlock (domain);
1087 if (assembly_load_field == NULL) {
1088 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1089 g_assert (assembly_load_field);
1092 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1093 if (load_value == NULL) {
1094 /* No events waiting to be triggered */
1098 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1099 mono_error_assert_ok (&error);
1101 if (assembly_load_method == NULL) {
1102 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1103 g_assert (assembly_load_method);
1106 *params = ref_assembly;
1108 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1109 mono_error_raise_exception (&error); /* FIXME don't raise here */
1113 * LOCKING: Acquires the domain assemblies lock.
1116 set_domain_search_path (MonoDomain *domain)
1119 MonoAppDomainSetup *setup;
1121 gchar *search_path = NULL;
1124 gchar **pvt_split = NULL;
1125 GError *gerror = NULL;
1126 gint appbaselen = -1;
1129 * We use the low-level domain assemblies lock, since this is called from
1130 * assembly loads hooks, which means this thread might hold the loader lock.
1132 mono_domain_assemblies_lock (domain);
1134 if (!domain->setup) {
1135 mono_domain_assemblies_unlock (domain);
1139 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1140 mono_domain_assemblies_unlock (domain);
1143 setup = domain->setup;
1144 if (!setup->application_base) {
1145 mono_domain_assemblies_unlock (domain);
1146 return; /* Must set application base to get private path working */
1151 if (setup->private_bin_path) {
1152 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1153 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1154 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1155 mono_error_cleanup (&error);
1156 mono_domain_assemblies_unlock (domain);
1161 if (domain->private_bin_path) {
1162 if (search_path == NULL)
1163 search_path = domain->private_bin_path;
1165 gchar *tmp2 = search_path;
1166 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1173 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1174 * directories relative to ApplicationBase separated by semicolons (see
1175 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1176 * The loop below copes with the fact that some Unix applications may use ':' (or
1177 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1178 * ';' for the subsequent split.
1180 * The issue was reported in bug #81446
1183 #ifndef TARGET_WIN32
1186 slen = strlen (search_path);
1187 for (i = 0; i < slen; i++)
1188 if (search_path [i] == ':')
1189 search_path [i] = ';';
1192 pvt_split = g_strsplit (search_path, ";", 1000);
1193 g_free (search_path);
1194 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1199 g_strfreev (pvt_split);
1201 * Don't do this because the first time is called, the domain
1202 * setup is not finished.
1204 * domain->search_path = g_malloc (sizeof (char *));
1205 * domain->search_path [0] = NULL;
1207 mono_domain_assemblies_unlock (domain);
1211 if (domain->search_path)
1212 g_strfreev (domain->search_path);
1214 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1215 tmp [npaths] = NULL;
1217 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1218 if (!mono_error_ok (&error)) {
1219 mono_error_cleanup (&error);
1220 g_strfreev (pvt_split);
1223 mono_domain_assemblies_unlock (domain);
1227 domain->search_path = tmp;
1229 /* FIXME: is this needed? */
1230 if (strncmp (*tmp, "file://", 7) == 0) {
1236 uri = g_strdup_printf ("file:///%s", uri + 7);
1239 uri = mono_escape_uri_string (tmpuri);
1240 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1246 if (gerror != NULL) {
1247 g_warning ("%s\n", gerror->message);
1248 g_error_free (gerror);
1255 for (i = 1; pvt_split && i < npaths; i++) {
1256 if (g_path_is_absolute (pvt_split [i - 1])) {
1257 tmp [i] = g_strdup (pvt_split [i - 1]);
1259 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1262 if (strchr (tmp [i], '.')) {
1266 reduced = mono_path_canonicalize (tmp [i]);
1267 if (appbaselen == -1)
1268 appbaselen = strlen (tmp [0]);
1270 if (strncmp (tmp [0], reduced, appbaselen)) {
1273 tmp [i] = g_strdup ("");
1283 if (setup->private_bin_path_probe != NULL) {
1285 tmp [0] = g_strdup ("");
1288 domain->setup->path_changed = FALSE;
1290 g_strfreev (pvt_split);
1292 mono_domain_assemblies_unlock (domain);
1295 #ifdef DISABLE_SHADOW_COPY
1297 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1303 mono_make_shadow_copy (const char *filename, MonoError *error)
1305 mono_error_init (error);
1306 return (char *) filename;
1310 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1312 guint16 *orig, *dest;
1313 gboolean copy_result;
1315 strcpy (src + srclen - tail_len, extension);
1317 if (IS_PORTABILITY_CASE) {
1318 gchar *file = mono_portability_find_file (src, TRUE);
1324 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1328 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1330 strcpy (target + targetlen - tail_len, extension);
1331 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1334 copy_result = CopyFile (orig, dest, FALSE);
1336 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1337 * overwritten when updated in their original locations. */
1339 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1348 get_cstring_hash (const char *str)
1354 if (!str || !str [0])
1359 for (i = 0; i < len; i++) {
1360 h = (h << 5) - h + *p;
1368 * Returned memory is malloc'd. Called must free it
1371 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1373 MonoAppDomainSetup *setup;
1374 char *cache_path, *appname;
1378 mono_error_init (error);
1380 setup = domain->setup;
1381 if (setup->cache_path != NULL && setup->application_name != NULL) {
1382 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1383 return_val_if_nok (error, NULL);
1385 #ifndef TARGET_WIN32
1388 for (i = strlen (cache_path) - 1; i >= 0; i--)
1389 if (cache_path [i] == '\\')
1390 cache_path [i] = '/';
1394 appname = mono_string_to_utf8_checked (setup->application_name, error);
1395 if (!mono_error_ok (error)) {
1396 g_free (cache_path);
1400 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1402 g_free (cache_path);
1404 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1405 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1412 get_shadow_assembly_location (const char *filename, MonoError *error)
1414 gint32 hash = 0, hash2 = 0;
1416 char path_hash [30];
1417 char *bname = g_path_get_basename (filename);
1418 char *dirname = g_path_get_dirname (filename);
1419 char *location, *tmploc;
1420 MonoDomain *domain = mono_domain_get ();
1422 mono_error_init (error);
1424 hash = get_cstring_hash (bname);
1425 hash2 = get_cstring_hash (dirname);
1426 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1427 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1428 tmploc = get_shadow_assembly_location_base (domain, error);
1429 if (!mono_error_ok (error)) {
1435 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1443 ensure_directory_exists (const char *filename)
1446 gchar *dir_utf8 = g_path_get_dirname (filename);
1448 gunichar2 *dir_utf16 = NULL;
1451 if (!dir_utf8 || !dir_utf8 [0])
1454 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1462 /* make life easy and only use one directory seperator */
1473 while (*p++ != '\\')
1479 p = wcschr (p, '\\');
1482 retval = _wmkdir (dir_utf16);
1483 if (retval != 0 && errno != EEXIST) {
1496 gchar *dir = g_path_get_dirname (filename);
1500 if (!dir || !dir [0]) {
1505 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1515 p = strchr (p, '/');
1518 retval = mkdir (dir, 0777);
1519 if (retval != 0 && errno != EEXIST) {
1534 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1536 struct stat sbuf_dest;
1538 gchar *real_src = mono_portability_find_file (src, TRUE);
1541 stat_src = (gchar*)src;
1543 stat_src = real_src;
1545 if (stat (stat_src, sbuf_src) == -1) {
1546 time_t tnow = time (NULL);
1551 memset (sbuf_src, 0, sizeof (*sbuf_src));
1552 sbuf_src->st_mtime = tnow;
1553 sbuf_src->st_atime = tnow;
1560 if (stat (dest, &sbuf_dest) == -1)
1563 if (sbuf_src->st_size == sbuf_dest.st_size &&
1564 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1571 shadow_copy_create_ini (const char *shadow, const char *filename)
1581 dir_name = g_path_get_dirname (shadow);
1582 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1584 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1589 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1594 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1595 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1597 if (handle == INVALID_HANDLE_VALUE) {
1601 full_path = mono_path_resolve_symlinks (filename);
1602 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1604 CloseHandle (handle);
1609 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1612 MonoAppDomainSetup *setup;
1615 gchar **directories;
1616 gchar *shadow_status_string;
1618 gboolean shadow_enabled;
1619 gboolean found = FALSE;
1624 setup = domain->setup;
1625 if (setup == NULL || setup->shadow_copy_files == NULL)
1628 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1629 if (!mono_error_ok (&error)) {
1630 mono_error_cleanup (&error);
1633 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1634 g_free (shadow_status_string);
1636 if (!shadow_enabled)
1639 if (setup->shadow_copy_directories == NULL)
1642 /* Is dir_name a shadow_copy destination already? */
1643 base_dir = get_shadow_assembly_location_base (domain, &error);
1644 if (!mono_error_ok (&error)) {
1645 mono_error_cleanup (&error);
1649 if (strstr (dir_name, base_dir)) {
1655 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1656 if (!mono_error_ok (&error)) {
1657 mono_error_cleanup (&error);
1661 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1662 dir_ptr = directories;
1664 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1670 g_strfreev (directories);
1676 This function raises exceptions so it can cause as sorts of nasty stuff if called
1677 while holding a lock.
1678 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1679 or NULL if source file not found.
1680 FIXME bubble up the error instead of raising it here
1683 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1686 gchar *sibling_source, *sibling_target;
1687 gint sibling_source_len, sibling_target_len;
1688 guint16 *orig, *dest;
1691 gboolean copy_result;
1692 struct stat src_sbuf;
1693 struct utimbuf utbuf;
1694 char *dir_name = g_path_get_dirname (filename);
1695 MonoDomain *domain = mono_domain_get ();
1698 mono_error_init (oerror);
1700 set_domain_search_path (domain);
1702 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1704 return (char *) filename;
1707 /* Is dir_name a shadow_copy destination already? */
1708 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1709 if (!mono_error_ok (&error)) {
1710 mono_error_cleanup (&error);
1712 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1716 if (strstr (dir_name, shadow_dir)) {
1717 g_free (shadow_dir);
1719 return (char *) filename;
1721 g_free (shadow_dir);
1724 shadow = get_shadow_assembly_location (filename, &error);
1725 if (!mono_error_ok (&error)) {
1726 mono_error_cleanup (&error);
1727 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1731 if (ensure_directory_exists (shadow) == FALSE) {
1733 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1737 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1738 return (char*) shadow;
1740 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1741 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1744 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1745 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1746 * and not have it runtime error" */
1747 attrs = GetFileAttributes (orig);
1748 if (attrs == INVALID_FILE_ATTRIBUTES) {
1750 return (char *)filename;
1753 copy_result = CopyFile (orig, dest, FALSE);
1755 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1756 * overwritten when updated in their original locations. */
1758 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1763 if (copy_result == FALSE) {
1766 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1767 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1768 return NULL; /* file not found, shadow copy failed */
1770 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1774 /* attempt to copy .mdb, .config if they exist */
1775 sibling_source = g_strconcat (filename, ".config", NULL);
1776 sibling_source_len = strlen (sibling_source);
1777 sibling_target = g_strconcat (shadow, ".config", NULL);
1778 sibling_target_len = strlen (sibling_target);
1780 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1781 if (copy_result == TRUE)
1782 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1784 g_free (sibling_source);
1785 g_free (sibling_target);
1787 if (copy_result == FALSE) {
1789 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1793 /* Create a .ini file containing the original assembly location */
1794 if (!shadow_copy_create_ini (shadow, filename)) {
1796 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1800 utbuf.actime = src_sbuf.st_atime;
1801 utbuf.modtime = src_sbuf.st_mtime;
1802 utime (shadow, &utbuf);
1806 #endif /* DISABLE_SHADOW_COPY */
1809 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1811 if (appdomain == NULL)
1814 return appdomain->data;
1818 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1819 const gchar *path3, const gchar *path4,
1820 gboolean refonly, gboolean is_private)
1823 gboolean found = FALSE;
1826 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1828 if (IS_PORTABILITY_SET) {
1829 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1832 fullpath = new_fullpath;
1836 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1839 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1842 return (*assembly != NULL);
1845 static MonoAssembly *
1846 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1848 MonoAssembly *result = NULL;
1851 const gchar *local_culture;
1853 gboolean is_private = FALSE;
1855 if (!culture || *culture == '\0') {
1858 local_culture = culture;
1861 filename = g_strconcat (name, ".dll", NULL);
1862 len = strlen (filename);
1864 for (path = search_path; *path; path++) {
1865 if (**path == '\0') {
1867 continue; /* Ignore empty ApplicationBase */
1870 /* See test cases in bug #58992 and bug #57710 */
1871 /* 1st try: [culture]/[name].dll (culture may be empty) */
1872 strcpy (filename + len - 4, ".dll");
1873 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1876 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1877 strcpy (filename + len - 4, ".exe");
1878 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1881 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1882 strcpy (filename + len - 4, ".dll");
1883 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1886 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1887 strcpy (filename + len - 4, ".exe");
1888 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1897 * Try loading the assembly from ApplicationBase and PrivateBinPath
1898 * and then from assemblies_path if any.
1899 * LOCKING: This is called from the assembly loading code, which means the caller
1900 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1902 static MonoAssembly *
1903 mono_domain_assembly_preload (MonoAssemblyName *aname,
1904 gchar **assemblies_path,
1907 MonoDomain *domain = mono_domain_get ();
1908 MonoAssembly *result = NULL;
1909 gboolean refonly = GPOINTER_TO_UINT (user_data);
1911 set_domain_search_path (domain);
1913 if (domain->search_path && domain->search_path [0] != NULL) {
1914 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1917 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1918 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1925 * Check whenever a given assembly was already loaded in the current appdomain.
1927 static MonoAssembly *
1928 mono_domain_assembly_search (MonoAssemblyName *aname,
1931 MonoDomain *domain = mono_domain_get ();
1934 gboolean refonly = GPOINTER_TO_UINT (user_data);
1936 mono_domain_assemblies_lock (domain);
1937 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1938 ass = (MonoAssembly *)tmp->data;
1939 /* Dynamic assemblies can't match here in MS.NET */
1940 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1943 mono_domain_assemblies_unlock (domain);
1946 mono_domain_assemblies_unlock (domain);
1951 MonoReflectionAssembly *
1952 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1955 MonoReflectionAssembly *result;
1956 MonoDomain *domain = mono_domain_get ();
1957 char *name, *filename;
1958 MonoImageOpenStatus status = MONO_IMAGE_OK;
1961 if (fname == NULL) {
1962 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1963 mono_set_pending_exception (exc);
1967 name = filename = mono_string_to_utf8 (fname);
1969 ass = mono_assembly_open_full (filename, &status, refOnly);
1974 if (status == MONO_IMAGE_IMAGE_INVALID)
1975 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1977 exc = mono_get_exception_file_not_found2 (NULL, fname);
1979 mono_set_pending_exception (exc);
1985 result = mono_assembly_get_object_checked (domain, ass, &error);
1987 mono_error_set_pending_exception (&error);
1991 MonoReflectionAssembly *
1992 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1993 MonoArray *raw_assembly,
1994 MonoArray *raw_symbol_store, MonoObject *evidence,
1995 MonoBoolean refonly)
1999 MonoReflectionAssembly *refass = NULL;
2000 MonoDomain *domain = ad->data;
2001 MonoImageOpenStatus status;
2002 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2003 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2006 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2010 if (raw_symbol_store != NULL)
2011 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2013 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2017 mono_image_close (image);
2018 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2022 refass = mono_assembly_get_object_checked (domain, ass, &error);
2024 mono_error_set_pending_exception (&error);
2026 MONO_OBJECT_SETREF (refass, evidence, evidence);
2030 MonoReflectionAssembly *
2031 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2034 MonoDomain *domain = ad->data;
2035 MonoImageOpenStatus status = MONO_IMAGE_OK;
2037 MonoAssemblyName aname;
2038 MonoReflectionAssembly *refass = NULL;
2044 name = mono_string_to_utf8 (assRef);
2045 parsed = mono_assembly_name_parse (name, &aname);
2049 /* This is a parse error... */
2051 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2055 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2056 mono_assembly_name_free (&aname);
2059 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2061 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2070 refass = mono_assembly_get_object_checked (domain, ass, &error);
2073 mono_error_set_pending_exception (&error);
2075 MONO_OBJECT_SETREF (refass, evidence, evidence);
2080 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2082 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2084 if (NULL == domain) {
2085 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2086 mono_set_pending_exception (exc);
2090 if (domain == mono_get_root_domain ()) {
2091 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2096 * Unloading seems to cause problems when running NUnit/NAnt, hence
2099 if (g_getenv ("MONO_NO_UNLOAD"))
2101 #ifdef __native_client__
2105 mono_domain_unload (domain);
2109 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2111 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2116 return mono_domain_is_unloading (domain);
2120 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2122 mono_unhandled_exception ((MonoObject*) exc);
2126 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2127 MonoReflectionAssembly *refass, MonoArray *args)
2134 image = refass->assembly->image;
2137 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2140 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2143 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2145 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2149 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2151 return ad->data->domain_id;
2155 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2157 MonoDomain *old_domain = mono_domain_get();
2159 if (!mono_domain_set (ad->data, FALSE)) {
2160 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2164 return old_domain->domain;
2168 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2170 MonoDomain *current_domain = mono_domain_get ();
2171 MonoDomain *domain = mono_domain_get_by_id (domainid);
2173 if (!domain || !mono_domain_set (domain, FALSE)) {
2174 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2178 return current_domain->domain;
2182 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2184 mono_thread_push_appdomain_ref (ad->data);
2188 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2190 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2194 * Raise an exception to prevent the managed code from executing a pop
2197 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2201 mono_thread_push_appdomain_ref (domain);
2205 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2207 mono_thread_pop_appdomain_ref ();
2211 ves_icall_System_AppDomain_InternalGetContext ()
2213 return mono_context_get ();
2217 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2219 return mono_domain_get ()->default_context;
2223 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2225 MonoAppContext *old_context = mono_context_get ();
2227 mono_context_set (mc);
2233 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2235 MonoDomain* mono_root_domain = mono_get_root_domain ();
2236 mono_domain_lock (mono_root_domain);
2237 if (process_guid_set) {
2238 mono_domain_unlock (mono_root_domain);
2240 MonoString *res = NULL;
2241 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2242 mono_error_raise_exception (&error);
2245 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2246 process_guid_set = TRUE;
2247 mono_domain_unlock (mono_root_domain);
2252 mono_domain_is_unloading (MonoDomain *domain)
2254 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2261 clear_cached_vtable (MonoVTable *vtable)
2263 MonoClass *klass = vtable->klass;
2264 MonoDomain *domain = vtable->domain;
2265 MonoClassRuntimeInfo *runtime_info;
2268 runtime_info = klass->runtime_info;
2269 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2270 runtime_info->domain_vtables [domain->domain_id] = NULL;
2271 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2272 mono_gc_free_fixed (data);
2275 static G_GNUC_UNUSED void
2276 zero_static_data (MonoVTable *vtable)
2278 MonoClass *klass = vtable->klass;
2281 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2282 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2285 typedef struct unload_data {
2288 char *failure_reason;
2293 unload_data_unref (unload_data *data)
2297 mono_atomic_load_acquire (count, gint32, &data->refcount);
2298 g_assert (count >= 1 && count <= 2);
2303 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2307 deregister_reflection_info_roots_from_list (MonoImage *image)
2309 GSList *list = image->reflection_info_unregister_classes;
2312 MonoClass *klass = (MonoClass *)list->data;
2314 mono_class_free_ref_info (klass);
2319 image->reflection_info_unregister_classes = NULL;
2323 deregister_reflection_info_roots (MonoDomain *domain)
2327 mono_domain_assemblies_lock (domain);
2328 for (list = domain->domain_assemblies; list; list = list->next) {
2329 MonoAssembly *assembly = (MonoAssembly *)list->data;
2330 MonoImage *image = assembly->image;
2334 * No need to take the image lock here since dynamic images are appdomain bound and
2335 * at this point the mutator is gone. Taking the image lock here would mean
2336 * promoting it from a simple lock to a complex lock, which we better avoid if
2339 if (image_is_dynamic (image))
2340 deregister_reflection_info_roots_from_list (image);
2342 for (i = 0; i < image->module_count; ++i) {
2343 MonoImage *module = image->modules [i];
2344 if (module && image_is_dynamic (module))
2345 deregister_reflection_info_roots_from_list (module);
2348 mono_domain_assemblies_unlock (domain);
2351 static guint32 WINAPI
2352 unload_thread_main (void *arg)
2355 unload_data *data = (unload_data*)arg;
2356 MonoDomain *domain = data->domain;
2360 /* Have to attach to the runtime so shutdown can wait for this thread */
2361 /* Force it to be attached to avoid racing during shutdown. */
2362 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2363 mono_error_raise_exception (&error); /* FIXME don't raise here */
2366 * FIXME: Abort our parent thread last, so we can return a failure
2367 * indication if aborting times out.
2369 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2370 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2374 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2375 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2379 /* Finalize all finalizable objects in the doomed appdomain */
2380 if (!mono_domain_finalize (domain, -1)) {
2381 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2385 /* Clear references to our vtables in class->runtime_info.
2386 * We also hold the loader lock because we're going to change
2387 * class->runtime_info.
2390 mono_loader_lock (); //FIXME why do we need the loader lock here?
2391 mono_domain_lock (domain);
2394 * We need to make sure that we don't have any remsets
2395 * pointing into static data of the to-be-freed domain because
2396 * at the next collections they would be invalid. So what we
2397 * do is we first zero all static data and then do a minor
2398 * collection. Because all references in the static data will
2399 * now be null we won't do any unnecessary copies and after
2400 * the collection there won't be any more remsets.
2402 for (i = 0; i < domain->class_vtable_array->len; ++i)
2403 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2404 mono_gc_collect (0);
2406 for (i = 0; i < domain->class_vtable_array->len; ++i)
2407 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2408 deregister_reflection_info_roots (domain);
2410 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2412 mono_domain_unlock (domain);
2413 mono_loader_unlock ();
2415 mono_threads_clear_cached_culture (domain);
2417 domain->state = MONO_APPDOMAIN_UNLOADED;
2419 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2421 /* remove from the handle table the items related to this domain */
2422 mono_gchandle_free_domain (domain);
2424 mono_domain_free (domain, FALSE);
2426 mono_gc_collect (mono_gc_max_generation ());
2428 mono_atomic_store_release (&data->done, TRUE);
2429 unload_data_unref (data);
2430 mono_thread_detach (thread);
2434 mono_atomic_store_release (&data->done, TRUE);
2435 unload_data_unref (data);
2436 mono_thread_detach (thread);
2441 * mono_domain_unload:
2442 * @domain: The domain to unload
2444 * Unloads an appdomain. Follows the process outlined in the comment
2445 * for mono_domain_try_unload.
2448 mono_domain_unload (MonoDomain *domain)
2450 MonoObject *exc = NULL;
2451 mono_domain_try_unload (domain, &exc);
2453 mono_raise_exception ((MonoException*)exc);
2457 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2461 MONO_PREPARE_BLOCKING;
2462 result = WaitForSingleObjectEx (handle, timeout, alertable);
2463 MONO_FINISH_BLOCKING;
2469 * mono_domain_unload:
2470 * @domain: The domain to unload
2471 * @exc: Exception information
2473 * Unloads an appdomain. Follows the process outlined in:
2474 * http://blogs.gotdotnet.com/cbrumme
2476 * If doing things the 'right' way is too hard or complex, we do it the
2477 * 'simple' way, which means do everything needed to avoid crashes and
2478 * memory leaks, but not much else.
2480 * It is required to pass a valid reference to the exc argument, upon return
2481 * from this function *exc will be set to the exception thrown, if any.
2483 * If this method is not called from an icall (embedded scenario for instance),
2484 * it must not be called with any managed frames on the stack, since the unload
2485 * process could end up trying to abort the current thread.
2488 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2491 HANDLE thread_handle;
2492 MonoAppDomainState prev_state;
2494 unload_data *thread_data;
2495 MonoNativeThreadId tid;
2496 MonoDomain *caller_domain = mono_domain_get ();
2499 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2501 /* Atomically change our state to UNLOADING */
2502 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2503 MONO_APPDOMAIN_UNLOADING_START,
2504 MONO_APPDOMAIN_CREATED);
2505 if (prev_state != MONO_APPDOMAIN_CREATED) {
2506 switch (prev_state) {
2507 case MONO_APPDOMAIN_UNLOADING_START:
2508 case MONO_APPDOMAIN_UNLOADING:
2509 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2511 case MONO_APPDOMAIN_UNLOADED:
2512 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2515 g_warning ("Invalid appdomain state %d", prev_state);
2516 g_assert_not_reached ();
2520 mono_domain_set (domain, FALSE);
2521 /* Notify OnDomainUnload listeners */
2522 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2525 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2527 if (!mono_error_ok (&error)) {
2529 mono_error_cleanup (&error);
2531 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2535 /* Roll back the state change */
2536 domain->state = MONO_APPDOMAIN_CREATED;
2537 mono_domain_set (caller_domain, FALSE);
2540 mono_domain_set (caller_domain, FALSE);
2542 thread_data = g_new0 (unload_data, 1);
2543 thread_data->domain = domain;
2544 thread_data->failure_reason = NULL;
2545 thread_data->done = FALSE;
2546 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2548 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2549 domain->state = MONO_APPDOMAIN_UNLOADING;
2551 * First we create a separate thread for unloading, since
2552 * we might have to abort some threads, including the current one.
2554 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2555 if (thread_handle == NULL)
2557 name = g_strdup_printf ("Unload thread for domain %x", domain);
2558 mono_thread_info_set_name (tid, name);
2559 mono_thread_info_resume (tid);
2562 /* Wait for the thread */
2563 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2564 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2565 /* The unload thread tries to abort us */
2566 /* The icall wrapper will execute the abort */
2567 CloseHandle (thread_handle);
2568 unload_data_unref (thread_data);
2572 CloseHandle (thread_handle);
2574 if (thread_data->failure_reason) {
2575 /* Roll back the state change */
2576 domain->state = MONO_APPDOMAIN_CREATED;
2578 g_warning ("%s", thread_data->failure_reason);
2580 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2582 g_free (thread_data->failure_reason);
2583 thread_data->failure_reason = NULL;
2586 unload_data_unref (thread_data);