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
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #undef ASSEMBLY_LOAD_DEBUG
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/domain-internals.h>
39 #include "mono/metadata/metadata-internals.h"
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/exception.h>
42 #include <mono/metadata/exception-internals.h>
43 #include <mono/metadata/threads.h>
44 #include <mono/metadata/threadpool-ms.h>
45 #include <mono/metadata/socket-io.h>
46 #include <mono/metadata/tabledefs.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/monitor.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/file-io.h>
55 #include <mono/metadata/lock-tracer.h>
56 #include <mono/metadata/console-io.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/tokentype.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/reflection-internals.h>
61 #include <mono/utils/mono-uri.h>
62 #include <mono/utils/mono-logger-internals.h>
63 #include <mono/utils/mono-path.h>
64 #include <mono/utils/mono-stdlib.h>
65 #include <mono/utils/mono-io-portability.h>
66 #include <mono/utils/mono-error-internals.h>
67 #include <mono/utils/atomic.h>
68 #include <mono/utils/mono-memory-model.h>
69 #include <mono/utils/mono-threads.h>
70 #include <mono/utils/w32handle.h>
76 * This is the version number of the corlib-runtime interface. When
77 * making changes to this interface (by changing the layout
78 * of classes the runtime knows about, changing icall signature or
79 * semantics etc), increment this variable. Also increment the
80 * pair of this variable in mscorlib in:
81 * mcs/class/corlib/System/Environment.cs
83 * Changes which are already detected at runtime, like the addition
84 * of icalls, do not require an increment.
86 #define MONO_CORLIB_VERSION 151
91 int assemblybinding_count;
96 static gunichar2 process_guid [36];
97 static gboolean process_guid_set = FALSE;
99 static gboolean no_exec = FALSE;
101 static MonoAssembly *
102 mono_domain_assembly_preload (MonoAssemblyName *aname,
103 gchar **assemblies_path,
106 static MonoAssembly *
107 mono_domain_assembly_search (MonoAssemblyName *aname,
111 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
114 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
116 static MonoAppDomain *
117 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
120 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
122 static MonoLoadFunc load_function = NULL;
124 /* Lazy class loading functions */
125 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
128 mono_install_runtime_load (MonoLoadFunc func)
130 load_function = func;
134 mono_runtime_load (const char *filename, const char *runtime_version)
136 g_assert (load_function);
137 return load_function (filename, runtime_version);
141 * mono_runtime_set_no_exec:
143 * Instructs the runtime to operate in static mode, i.e. avoid/do not
144 * allow managed code execution. This is useful for running the AOT
145 * compiler on platforms which allow full-aot execution only. This
146 * should be called before mono_runtime_init ().
149 mono_runtime_set_no_exec (gboolean val)
155 * mono_runtime_get_no_exec:
157 * If true, then the runtime will not allow managed code execution.
160 mono_runtime_get_no_exec (void)
166 create_domain_objects (MonoDomain *domain)
169 MonoDomain *old_domain = mono_domain_get ();
171 MonoVTable *string_vt;
172 MonoClassField *string_empty_fld;
174 if (domain != old_domain) {
175 mono_thread_push_appdomain_ref (domain);
176 mono_domain_set_internal_with_options (domain, FALSE);
180 * Initialize String.Empty. This enables the removal of
181 * the static cctor of the String class.
183 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
184 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
185 g_assert (string_empty_fld);
186 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
187 mono_error_assert_ok (&error);
188 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
191 * Create an instance early since we can't do it when there is no memory.
193 arg = mono_string_new (domain, "Out of memory");
194 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
195 mono_error_assert_ok (&error);
198 * These two are needed because the signal handlers might be executing on
199 * an alternate stack, and Boehm GC can't handle that.
201 arg = mono_string_new (domain, "A null value was found where an object instance was required");
202 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
203 mono_error_assert_ok (&error);
204 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
205 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
206 mono_error_assert_ok (&error);
208 /*The ephemeron tombstone i*/
209 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
210 mono_error_assert_ok (&error);
212 if (domain != old_domain) {
213 mono_thread_pop_appdomain_ref ();
214 mono_domain_set_internal_with_options (old_domain, FALSE);
218 * This class is used during exception handling, so initialize it here, to prevent
219 * stack overflows while handling stack overflows.
221 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
226 * @domain: domain returned by mono_init ()
228 * Initialize the core AppDomain: this function will run also some
229 * IL initialization code, so it needs the execution engine to be fully
232 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
233 * we know the entry_assembly.
237 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
240 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
241 mono_error_cleanup (&error);
245 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
247 MonoAppDomainSetup *setup;
251 mono_error_init (error);
253 mono_portability_helpers_init ();
255 mono_gc_base_init ();
256 mono_monitor_init ();
257 mono_marshal_init ();
259 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
260 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
261 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
262 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
263 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
264 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
265 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
267 mono_thread_init (start_cb, attach_cb);
269 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
270 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
271 return_if_nok (error);
273 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
275 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
276 return_if_nok (error);
280 domain->setup = setup;
282 mono_thread_attach (domain);
284 mono_type_initialization_init ();
286 if (!mono_runtime_get_no_exec ())
287 create_domain_objects (domain);
289 /* GC init has to happen after thread init */
292 /* contexts use GC handles, so they must be initialized after the GC */
293 mono_context_init_checked (domain, error);
294 return_if_nok (error);
295 mono_context_set (domain->default_context);
297 #ifndef DISABLE_SOCKETS
298 mono_network_init ();
301 mono_console_init ();
304 mono_locks_tracer_init ();
306 /* mscorlib is loaded before we install the load hook */
307 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
313 mono_get_corlib_version (void)
317 MonoClassField *field;
320 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
321 mono_class_init (klass);
322 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
325 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
327 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
328 mono_error_assert_ok (&error);
329 return *(gint32*)((gchar*)value + sizeof (MonoObject));
333 * mono_check_corlib_version
335 * Checks that the corlib that is loaded matches the version of this runtime.
337 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
338 * allocated string with the error otherwise.
341 mono_check_corlib_version (void)
343 int version = mono_get_corlib_version ();
344 if (version != MONO_CORLIB_VERSION)
345 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
352 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
354 * Initializes the @domain's default System.Runtime.Remoting's Context.
357 mono_context_init (MonoDomain *domain)
360 mono_context_init_checked (domain, &error);
361 mono_error_cleanup (&error);
365 mono_context_init_checked (MonoDomain *domain, MonoError *error)
368 MonoAppContext *context;
370 mono_error_init (error);
372 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
373 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
374 return_if_nok (error);
376 context->domain_id = domain->domain_id;
377 context->context_id = 0;
378 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
379 domain->default_context = context;
383 * mono_runtime_cleanup:
388 * This must not be called while there are still running threads executing
392 mono_runtime_cleanup (MonoDomain *domain)
394 mono_attach_cleanup ();
396 /* This ends up calling any pending pending (for at most 2 seconds) */
399 mono_thread_cleanup ();
401 #ifndef DISABLE_SOCKETS
402 mono_network_cleanup ();
404 mono_marshal_cleanup ();
406 mono_type_initialization_cleanup ();
408 mono_monitor_cleanup ();
411 static MonoDomainFunc quit_function = NULL;
414 mono_install_runtime_cleanup (MonoDomainFunc func)
416 quit_function = func;
422 if (quit_function != NULL)
423 quit_function (mono_get_root_domain (), NULL);
427 * mono_domain_create_appdomain:
428 * @friendly_name: The friendly name of the appdomain to create
429 * @configuration_file: The configuration file to initialize the appdomain with
431 * Returns a MonoDomain initialized with the appdomain
434 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
438 MonoAppDomainSetup *setup;
441 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
442 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
445 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
447 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
451 return mono_domain_from_appdomain (ad);
453 mono_error_cleanup (&error);
458 * mono_domain_set_config:
459 * @domain: MonoDomain initialized with the appdomain we want to change
460 * @base_dir: new base directory for the appdomain
461 * @config_file_name: path to the new configuration for the app domain
463 * Used to set the system configuration for an appdomain
465 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
466 * Error Initializing the configuration system. ---> System.ArgumentException:
467 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
470 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
472 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
473 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
476 static MonoAppDomainSetup*
477 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
479 MonoDomain *caller_domain;
480 MonoClass *ads_class;
481 MonoAppDomainSetup *copy;
483 mono_error_init (error);
485 caller_domain = mono_domain_get ();
486 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
488 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
489 return_val_if_nok (error, NULL);
491 mono_domain_set_internal (domain);
493 #define XCOPY_FIELD(dst,field,src,error) \
495 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
496 return_val_if_nok (error, NULL); \
497 MONO_OBJECT_SETREF ((dst),field,copied_val); \
500 XCOPY_FIELD (copy, application_base, setup->application_base, error);
501 XCOPY_FIELD (copy, application_name, setup->application_name, error);
502 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
503 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
504 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
505 XCOPY_FIELD (copy, license_file, setup->license_file, error);
506 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
507 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
508 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
509 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
510 copy->publisher_policy = setup->publisher_policy;
511 copy->path_changed = setup->path_changed;
512 copy->loader_optimization = setup->loader_optimization;
513 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
514 copy->disallow_code_downloads = setup->disallow_code_downloads;
515 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
516 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
517 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
518 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
519 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
523 mono_domain_set_internal (caller_domain);
528 static MonoAppDomain *
529 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
534 char *shadow_location;
536 mono_error_init (error);
538 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
540 /* FIXME: pin all those objects */
541 data = mono_domain_create();
543 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
544 return_val_if_nok (error, NULL);
547 data->friendly_name = g_strdup (friendly_name);
549 mono_profiler_appdomain_name (data, data->friendly_name);
551 if (!setup->application_base) {
552 /* Inherit from the root domain since MS.NET does this */
553 MonoDomain *root = mono_get_root_domain ();
554 if (root->setup->application_base) {
555 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
556 mono_error_assert_ok (error); /* FIXME don't swallow the error */
557 MONO_OBJECT_SETREF (setup, application_base, s);
561 mono_context_init_checked (data, error);
562 return_val_if_nok (error, NULL);
564 data->setup = copy_app_domain_setup (data, setup, error);
565 if (!mono_error_ok (error)) {
566 g_free (data->friendly_name);
570 mono_domain_set_options_from_config (data);
571 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
573 #ifndef DISABLE_SHADOW_COPY
574 /*FIXME, guard this for when the debugger is not running */
575 shadow_location = get_shadow_assembly_location_base (data, error);
576 if (!mono_error_ok (error)) {
577 g_free (data->friendly_name);
581 g_free (shadow_location);
584 create_domain_objects (data);
590 * mono_domain_has_type_resolve:
591 * @domain: application domains being looked up
593 * Returns: TRUE if the AppDomain.TypeResolve field has been
597 mono_domain_has_type_resolve (MonoDomain *domain)
599 static MonoClassField *field = NULL;
603 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
607 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
611 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
616 * mono_domain_try_type_resolve:
617 * @domain: application domainwhere the name where the type is going to be resolved
618 * @name: the name of the type to resolve or NULL.
619 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
621 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
622 * the assembly that matches name.
624 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
626 * Returns: A MonoReflectionAssembly or NULL if not found
628 MonoReflectionAssembly *
629 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
632 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
633 mono_error_cleanup (&error);
638 MonoReflectionAssembly *
639 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
641 static MonoMethod *method = NULL;
642 MonoReflectionAssembly *ret;
646 mono_error_init (error);
648 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
650 if (method == NULL) {
651 klass = domain->domain->mbr.obj.vtable->klass;
654 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
655 if (method == NULL) {
656 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
662 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
666 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
667 return_val_if_nok (error, NULL);
673 * mono_domain_owns_vtable_slot:
675 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
678 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
682 mono_domain_lock (domain);
683 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
684 mono_domain_unlock (domain);
691 * @force: force setting.
693 * Set the current appdomain to @domain. If @force is set, set it even
694 * if it is being unloaded.
698 * FALSE if the domain is unloaded
701 mono_domain_set (MonoDomain *domain, gboolean force)
703 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
706 mono_domain_set_internal (domain);
712 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
719 MONO_CHECK_ARG_NULL (name, NULL);
725 str = mono_string_to_utf8_checked (name, &error);
726 if (mono_error_set_pending_exception (&error))
729 mono_domain_lock (add);
731 if (!strcmp (str, "APPBASE"))
732 o = (MonoObject *)add->setup->application_base;
733 else if (!strcmp (str, "APP_CONFIG_FILE"))
734 o = (MonoObject *)add->setup->configuration_file;
735 else if (!strcmp (str, "DYNAMIC_BASE"))
736 o = (MonoObject *)add->setup->dynamic_base;
737 else if (!strcmp (str, "APP_NAME"))
738 o = (MonoObject *)add->setup->application_name;
739 else if (!strcmp (str, "CACHE_BASE"))
740 o = (MonoObject *)add->setup->cache_path;
741 else if (!strcmp (str, "PRIVATE_BINPATH"))
742 o = (MonoObject *)add->setup->private_bin_path;
743 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
744 o = (MonoObject *)add->setup->private_bin_path_probe;
745 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
746 o = (MonoObject *)add->setup->shadow_copy_directories;
747 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
748 o = (MonoObject *)add->setup->shadow_copy_files;
750 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
752 mono_domain_unlock (add);
762 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
766 MONO_CHECK_ARG_NULL (name,);
772 mono_domain_lock (add);
774 mono_g_hash_table_insert (add->env, name, data);
776 mono_domain_unlock (add);
780 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
785 return ad->data->setup;
789 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
794 return mono_string_new (ad->data, ad->data->friendly_name);
798 ves_icall_System_AppDomain_getCurDomain ()
800 MonoDomain *add = mono_domain_get ();
806 ves_icall_System_AppDomain_getRootDomain ()
808 MonoDomain *root = mono_get_root_domain ();
814 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
816 MonoDomain *domain = mono_domain_get ();
818 return domain->throw_unobserved_task_exceptions;
822 get_attribute_value (const gchar **attribute_names,
823 const gchar **attribute_values,
824 const char *att_name)
827 for (n = 0; attribute_names [n] != NULL; n++) {
828 if (strcmp (attribute_names [n], att_name) == 0)
829 return g_strdup (attribute_values [n]);
835 start_element (GMarkupParseContext *context,
836 const gchar *element_name,
837 const gchar **attribute_names,
838 const gchar **attribute_values,
842 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
844 if (strcmp (element_name, "runtime") == 0) {
845 runtime_config->runtime_count++;
849 if (strcmp (element_name, "assemblyBinding") == 0) {
850 runtime_config->assemblybinding_count++;
854 if (runtime_config->runtime_count != 1)
857 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
858 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
860 if (value && g_ascii_strcasecmp (value, "true") == 0)
861 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
864 if (runtime_config->assemblybinding_count != 1)
867 if (strcmp (element_name, "probing") != 0)
870 g_free (runtime_config->domain->private_bin_path);
871 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
872 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
873 g_free (runtime_config->domain->private_bin_path);
874 runtime_config->domain->private_bin_path = NULL;
880 end_element (GMarkupParseContext *context,
881 const gchar *element_name,
885 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
886 if (strcmp (element_name, "runtime") == 0)
887 runtime_config->runtime_count--;
888 else if (strcmp (element_name, "assemblyBinding") == 0)
889 runtime_config->assemblybinding_count--;
893 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
895 RuntimeConfig *state = (RuntimeConfig *)user_data;
897 const gchar *filename;
899 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
900 msg = error && error->message ? error->message : "";
901 g_warning ("Error parsing %s: %s", filename, msg);
904 static const GMarkupParser
914 mono_domain_set_options_from_config (MonoDomain *domain)
917 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
919 GMarkupParseContext *context;
920 RuntimeConfig runtime_config;
923 if (!domain || !domain->setup || !domain->setup->configuration_file)
926 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
927 if (!mono_error_ok (&error)) {
928 mono_error_cleanup (&error);
932 config_file_path = mono_portability_find_file (config_file_name, TRUE);
933 if (!config_file_path)
934 config_file_path = config_file_name;
936 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
939 runtime_config.runtime_count = 0;
940 runtime_config.assemblybinding_count = 0;
941 runtime_config.domain = domain;
942 runtime_config.filename = config_file_path;
945 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
946 offset = 3; /* Skip UTF-8 BOM */
948 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
949 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
950 g_markup_parse_context_end_parse (context, NULL);
951 g_markup_parse_context_free (context);
955 if (config_file_name != config_file_path)
956 g_free (config_file_name);
957 g_free (config_file_path);
961 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
964 MonoAppDomain *ad = NULL;
965 #ifdef DISABLE_APPDOMAINS
966 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
970 fname = mono_string_to_utf8_checked (friendly_name, &error);
971 if (mono_error_set_pending_exception (&error))
973 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
977 mono_error_set_pending_exception (&error);
982 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
985 MonoDomain *domain = ad->data;
990 GPtrArray *assemblies;
992 mono_error_init (&error);
995 * Make a copy of the list of assemblies because we can't hold the assemblies
996 * lock while creating objects etc.
998 assemblies = g_ptr_array_new ();
999 /* Need to skip internal assembly builders created by remoting */
1000 mono_domain_assemblies_lock (domain);
1001 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1002 ass = (MonoAssembly *)tmp->data;
1003 if (refonly != ass->ref_only)
1005 if (ass->corlib_internal)
1007 g_ptr_array_add (assemblies, ass);
1009 mono_domain_assemblies_unlock (domain);
1011 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1012 if (!is_ok (&error))
1014 for (i = 0; i < assemblies->len; ++i) {
1015 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1016 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1017 if (!mono_error_ok (&error))
1019 mono_array_setref (res, i, ass_obj);
1023 g_ptr_array_free (assemblies, TRUE);
1024 if (!mono_error_ok (&error))
1025 mono_error_set_pending_exception (&error);
1029 MonoReflectionAssembly *
1030 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1032 MonoReflectionAssembly *ret;
1035 MonoBoolean isrefonly;
1036 gpointer params [3];
1038 mono_error_init (error);
1040 if (mono_runtime_get_no_exec ())
1043 g_assert (domain != NULL && fname != NULL);
1045 klass = domain->domain->mbr.obj.vtable->klass;
1048 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1049 if (method == NULL) {
1050 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1054 isrefonly = refonly ? 1 : 0;
1057 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1058 return_val_if_nok (error, NULL);
1061 params [2] = &isrefonly;
1063 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1064 return_val_if_nok (error, NULL);
1070 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1074 MonoReflectionAssembly *assembly;
1075 MonoDomain *domain = mono_domain_get ();
1079 aname_str = mono_stringify_assembly_name (aname);
1081 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1082 str = mono_string_new (domain, aname_str);
1088 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1089 mono_error_cleanup (&error);
1092 return assembly->assembly;
1098 * LOCKING: assumes assemblies_lock in the domain is already locked.
1101 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1105 gboolean destroy_ht = FALSE;
1107 if (!ass->aname.name)
1111 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1115 /* FIXME: handle lazy loaded assemblies */
1116 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1117 g_hash_table_insert (ht, tmp->data, tmp->data);
1119 if (!g_hash_table_lookup (ht, ass)) {
1120 mono_assembly_addref (ass);
1121 g_hash_table_insert (ht, ass, ass);
1122 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1123 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);
1126 if (ass->image->references) {
1127 for (i = 0; ass->image->references [i] != NULL; i++) {
1128 if (ass->image->references [i] != REFERENCE_MISSING)
1129 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1130 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1135 g_hash_table_destroy (ht);
1139 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1141 static MonoClassField *assembly_load_field;
1142 static MonoMethod *assembly_load_method;
1144 MonoDomain *domain = mono_domain_get ();
1145 MonoReflectionAssembly *ref_assembly;
1147 gpointer load_value;
1150 if (!domain->domain)
1151 /* This can happen during startup */
1153 #ifdef ASSEMBLY_LOAD_DEBUG
1154 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1156 klass = domain->domain->mbr.obj.vtable->klass;
1158 mono_domain_assemblies_lock (domain);
1159 add_assemblies_to_domain (domain, assembly, NULL);
1160 mono_domain_assemblies_unlock (domain);
1162 if (assembly_load_field == NULL) {
1163 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1164 g_assert (assembly_load_field);
1167 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1168 if (load_value == NULL) {
1169 /* No events waiting to be triggered */
1173 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1174 mono_error_assert_ok (&error);
1176 if (assembly_load_method == NULL) {
1177 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1178 g_assert (assembly_load_method);
1181 *params = ref_assembly;
1183 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1184 mono_error_cleanup (&error);
1188 * LOCKING: Acquires the domain assemblies lock.
1191 set_domain_search_path (MonoDomain *domain)
1194 MonoAppDomainSetup *setup;
1196 gchar *search_path = NULL;
1199 gchar **pvt_split = NULL;
1200 GError *gerror = NULL;
1201 gint appbaselen = -1;
1204 * We use the low-level domain assemblies lock, since this is called from
1205 * assembly loads hooks, which means this thread might hold the loader lock.
1207 mono_domain_assemblies_lock (domain);
1209 if (!domain->setup) {
1210 mono_domain_assemblies_unlock (domain);
1214 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1215 mono_domain_assemblies_unlock (domain);
1218 setup = domain->setup;
1219 if (!setup->application_base) {
1220 mono_domain_assemblies_unlock (domain);
1221 return; /* Must set application base to get private path working */
1226 if (setup->private_bin_path) {
1227 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1228 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1229 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1230 mono_error_cleanup (&error);
1231 mono_domain_assemblies_unlock (domain);
1236 if (domain->private_bin_path) {
1237 if (search_path == NULL)
1238 search_path = domain->private_bin_path;
1240 gchar *tmp2 = search_path;
1241 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1248 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1249 * directories relative to ApplicationBase separated by semicolons (see
1250 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1251 * The loop below copes with the fact that some Unix applications may use ':' (or
1252 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1253 * ';' for the subsequent split.
1255 * The issue was reported in bug #81446
1258 #ifndef TARGET_WIN32
1261 slen = strlen (search_path);
1262 for (i = 0; i < slen; i++)
1263 if (search_path [i] == ':')
1264 search_path [i] = ';';
1267 pvt_split = g_strsplit (search_path, ";", 1000);
1268 g_free (search_path);
1269 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1274 g_strfreev (pvt_split);
1276 * Don't do this because the first time is called, the domain
1277 * setup is not finished.
1279 * domain->search_path = g_malloc (sizeof (char *));
1280 * domain->search_path [0] = NULL;
1282 mono_domain_assemblies_unlock (domain);
1286 if (domain->search_path)
1287 g_strfreev (domain->search_path);
1289 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1290 tmp [npaths] = NULL;
1292 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1293 if (!mono_error_ok (&error)) {
1294 mono_error_cleanup (&error);
1295 g_strfreev (pvt_split);
1298 mono_domain_assemblies_unlock (domain);
1302 domain->search_path = tmp;
1304 /* FIXME: is this needed? */
1305 if (strncmp (*tmp, "file://", 7) == 0) {
1311 uri = g_strdup_printf ("file:///%s", uri + 7);
1314 uri = mono_escape_uri_string (tmpuri);
1315 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1321 if (gerror != NULL) {
1322 g_warning ("%s\n", gerror->message);
1323 g_error_free (gerror);
1330 for (i = 1; pvt_split && i < npaths; i++) {
1331 if (g_path_is_absolute (pvt_split [i - 1])) {
1332 tmp [i] = g_strdup (pvt_split [i - 1]);
1334 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1337 if (strchr (tmp [i], '.')) {
1341 reduced = mono_path_canonicalize (tmp [i]);
1342 if (appbaselen == -1)
1343 appbaselen = strlen (tmp [0]);
1345 if (strncmp (tmp [0], reduced, appbaselen)) {
1348 tmp [i] = g_strdup ("");
1358 if (setup->private_bin_path_probe != NULL) {
1360 tmp [0] = g_strdup ("");
1363 domain->setup->path_changed = FALSE;
1365 g_strfreev (pvt_split);
1367 mono_domain_assemblies_unlock (domain);
1370 #ifdef DISABLE_SHADOW_COPY
1372 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1378 mono_make_shadow_copy (const char *filename, MonoError *error)
1380 mono_error_init (error);
1381 return (char *) filename;
1385 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1387 guint16 *orig, *dest;
1388 gboolean copy_result;
1390 strcpy (src + srclen - tail_len, extension);
1392 if (IS_PORTABILITY_CASE) {
1393 gchar *file = mono_portability_find_file (src, TRUE);
1399 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1403 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1405 strcpy (target + targetlen - tail_len, extension);
1406 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1409 copy_result = CopyFile (orig, dest, FALSE);
1411 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1412 * overwritten when updated in their original locations. */
1414 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1423 get_cstring_hash (const char *str)
1429 if (!str || !str [0])
1434 for (i = 0; i < len; i++) {
1435 h = (h << 5) - h + *p;
1443 * Returned memory is malloc'd. Called must free it
1446 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1448 MonoAppDomainSetup *setup;
1449 char *cache_path, *appname;
1453 mono_error_init (error);
1455 setup = domain->setup;
1456 if (setup->cache_path != NULL && setup->application_name != NULL) {
1457 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1458 return_val_if_nok (error, NULL);
1460 #ifndef TARGET_WIN32
1463 for (i = strlen (cache_path) - 1; i >= 0; i--)
1464 if (cache_path [i] == '\\')
1465 cache_path [i] = '/';
1469 appname = mono_string_to_utf8_checked (setup->application_name, error);
1470 if (!mono_error_ok (error)) {
1471 g_free (cache_path);
1475 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1477 g_free (cache_path);
1479 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1480 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1487 get_shadow_assembly_location (const char *filename, MonoError *error)
1489 gint32 hash = 0, hash2 = 0;
1491 char path_hash [30];
1492 char *bname = g_path_get_basename (filename);
1493 char *dirname = g_path_get_dirname (filename);
1494 char *location, *tmploc;
1495 MonoDomain *domain = mono_domain_get ();
1497 mono_error_init (error);
1499 hash = get_cstring_hash (bname);
1500 hash2 = get_cstring_hash (dirname);
1501 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1502 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1503 tmploc = get_shadow_assembly_location_base (domain, error);
1504 if (!mono_error_ok (error)) {
1510 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1518 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1520 struct stat sbuf_dest;
1522 gchar *real_src = mono_portability_find_file (src, TRUE);
1525 stat_src = (gchar*)src;
1527 stat_src = real_src;
1529 if (stat (stat_src, sbuf_src) == -1) {
1530 time_t tnow = time (NULL);
1535 memset (sbuf_src, 0, sizeof (*sbuf_src));
1536 sbuf_src->st_mtime = tnow;
1537 sbuf_src->st_atime = tnow;
1544 if (stat (dest, &sbuf_dest) == -1)
1547 if (sbuf_src->st_size == sbuf_dest.st_size &&
1548 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1555 shadow_copy_create_ini (const char *shadow, const char *filename)
1565 dir_name = g_path_get_dirname (shadow);
1566 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1568 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1573 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1578 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1579 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1581 if (handle == INVALID_HANDLE_VALUE) {
1585 full_path = mono_path_resolve_symlinks (filename);
1586 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1588 CloseHandle (handle);
1593 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1596 MonoAppDomainSetup *setup;
1599 gchar **directories;
1600 gchar *shadow_status_string;
1602 gboolean shadow_enabled;
1603 gboolean found = FALSE;
1608 setup = domain->setup;
1609 if (setup == NULL || setup->shadow_copy_files == NULL)
1612 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1613 if (!mono_error_ok (&error)) {
1614 mono_error_cleanup (&error);
1617 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1618 g_free (shadow_status_string);
1620 if (!shadow_enabled)
1623 if (setup->shadow_copy_directories == NULL)
1626 /* Is dir_name a shadow_copy destination already? */
1627 base_dir = get_shadow_assembly_location_base (domain, &error);
1628 if (!mono_error_ok (&error)) {
1629 mono_error_cleanup (&error);
1633 if (strstr (dir_name, base_dir)) {
1639 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1640 if (!mono_error_ok (&error)) {
1641 mono_error_cleanup (&error);
1645 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1646 dir_ptr = directories;
1648 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1654 g_strfreev (directories);
1660 This function raises exceptions so it can cause as sorts of nasty stuff if called
1661 while holding a lock.
1662 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1663 or NULL if source file not found.
1664 FIXME bubble up the error instead of raising it here
1667 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1670 gchar *sibling_source, *sibling_target;
1671 gint sibling_source_len, sibling_target_len;
1672 guint16 *orig, *dest;
1675 gboolean copy_result;
1676 struct stat src_sbuf;
1677 struct utimbuf utbuf;
1678 char *dir_name = g_path_get_dirname (filename);
1679 MonoDomain *domain = mono_domain_get ();
1682 mono_error_init (oerror);
1684 set_domain_search_path (domain);
1686 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1688 return (char *) filename;
1691 /* Is dir_name a shadow_copy destination already? */
1692 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1693 if (!mono_error_ok (&error)) {
1694 mono_error_cleanup (&error);
1696 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1700 if (strstr (dir_name, shadow_dir)) {
1701 g_free (shadow_dir);
1703 return (char *) filename;
1705 g_free (shadow_dir);
1708 shadow = get_shadow_assembly_location (filename, &error);
1709 if (!mono_error_ok (&error)) {
1710 mono_error_cleanup (&error);
1711 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1715 if (g_ensure_directory_exists (shadow) == FALSE) {
1717 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1721 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1722 return (char*) shadow;
1724 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1725 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1728 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1729 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1730 * and not have it runtime error" */
1731 attrs = GetFileAttributes (orig);
1732 if (attrs == INVALID_FILE_ATTRIBUTES) {
1734 return (char *)filename;
1737 copy_result = CopyFile (orig, dest, FALSE);
1739 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1740 * overwritten when updated in their original locations. */
1742 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1747 if (copy_result == FALSE) {
1750 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1751 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1752 return NULL; /* file not found, shadow copy failed */
1754 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1758 /* attempt to copy .mdb, .config if they exist */
1759 sibling_source = g_strconcat (filename, ".config", NULL);
1760 sibling_source_len = strlen (sibling_source);
1761 sibling_target = g_strconcat (shadow, ".config", NULL);
1762 sibling_target_len = strlen (sibling_target);
1764 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1766 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1768 g_free (sibling_source);
1769 g_free (sibling_target);
1773 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1777 /* Create a .ini file containing the original assembly location */
1778 if (!shadow_copy_create_ini (shadow, filename)) {
1780 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1784 utbuf.actime = src_sbuf.st_atime;
1785 utbuf.modtime = src_sbuf.st_mtime;
1786 utime (shadow, &utbuf);
1790 #endif /* DISABLE_SHADOW_COPY */
1793 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1795 if (appdomain == NULL)
1798 return appdomain->data;
1802 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1803 const gchar *path3, const gchar *path4,
1804 gboolean refonly, gboolean is_private)
1807 gboolean found = FALSE;
1810 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1812 if (IS_PORTABILITY_SET) {
1813 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1816 fullpath = new_fullpath;
1820 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1823 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1826 return (*assembly != NULL);
1829 static MonoAssembly *
1830 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1832 MonoAssembly *result = NULL;
1835 const gchar *local_culture;
1837 gboolean is_private = FALSE;
1839 if (!culture || *culture == '\0') {
1842 local_culture = culture;
1845 filename = g_strconcat (name, ".dll", NULL);
1846 len = strlen (filename);
1848 for (path = search_path; *path; path++) {
1849 if (**path == '\0') {
1851 continue; /* Ignore empty ApplicationBase */
1854 /* See test cases in bug #58992 and bug #57710 */
1855 /* 1st try: [culture]/[name].dll (culture may be empty) */
1856 strcpy (filename + len - 4, ".dll");
1857 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1860 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1861 strcpy (filename + len - 4, ".exe");
1862 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1865 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1866 strcpy (filename + len - 4, ".dll");
1867 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1870 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1871 strcpy (filename + len - 4, ".exe");
1872 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1881 * Try loading the assembly from ApplicationBase and PrivateBinPath
1882 * and then from assemblies_path if any.
1883 * LOCKING: This is called from the assembly loading code, which means the caller
1884 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1886 static MonoAssembly *
1887 mono_domain_assembly_preload (MonoAssemblyName *aname,
1888 gchar **assemblies_path,
1891 MonoDomain *domain = mono_domain_get ();
1892 MonoAssembly *result = NULL;
1893 gboolean refonly = GPOINTER_TO_UINT (user_data);
1895 set_domain_search_path (domain);
1897 if (domain->search_path && domain->search_path [0] != NULL) {
1898 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1901 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1902 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1909 * Check whenever a given assembly was already loaded in the current appdomain.
1911 static MonoAssembly *
1912 mono_domain_assembly_search (MonoAssemblyName *aname,
1915 MonoDomain *domain = mono_domain_get ();
1918 gboolean refonly = GPOINTER_TO_UINT (user_data);
1920 mono_domain_assemblies_lock (domain);
1921 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1922 ass = (MonoAssembly *)tmp->data;
1923 /* Dynamic assemblies can't match here in MS.NET */
1924 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1927 mono_domain_assemblies_unlock (domain);
1930 mono_domain_assemblies_unlock (domain);
1935 MonoReflectionAssembly *
1936 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1939 MonoReflectionAssembly *result;
1940 MonoDomain *domain = mono_domain_get ();
1941 char *name, *filename;
1942 MonoImageOpenStatus status = MONO_IMAGE_OK;
1945 if (fname == NULL) {
1946 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1947 mono_set_pending_exception (exc);
1951 name = filename = mono_string_to_utf8_checked (fname, &error);
1952 if (mono_error_set_pending_exception (&error))
1955 ass = mono_assembly_open_full (filename, &status, refOnly);
1960 if (status == MONO_IMAGE_IMAGE_INVALID)
1961 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1963 exc = mono_get_exception_file_not_found2 (NULL, fname);
1965 mono_set_pending_exception (exc);
1971 result = mono_assembly_get_object_checked (domain, ass, &error);
1973 mono_error_set_pending_exception (&error);
1977 MonoReflectionAssembly *
1978 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1979 MonoArray *raw_assembly,
1980 MonoArray *raw_symbol_store, MonoObject *evidence,
1981 MonoBoolean refonly)
1985 MonoReflectionAssembly *refass = NULL;
1986 MonoDomain *domain = ad->data;
1987 MonoImageOpenStatus status;
1988 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1989 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1992 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1996 if (raw_symbol_store != NULL)
1997 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1999 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2003 mono_image_close (image);
2004 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2008 refass = mono_assembly_get_object_checked (domain, ass, &error);
2010 mono_error_set_pending_exception (&error);
2012 MONO_OBJECT_SETREF (refass, evidence, evidence);
2016 MonoReflectionAssembly *
2017 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2020 MonoDomain *domain = ad->data;
2021 MonoImageOpenStatus status = MONO_IMAGE_OK;
2023 MonoAssemblyName aname;
2024 MonoReflectionAssembly *refass = NULL;
2030 name = mono_string_to_utf8_checked (assRef, &error);
2031 if (mono_error_set_pending_exception (&error))
2033 parsed = mono_assembly_name_parse (name, &aname);
2037 /* This is a parse error... */
2039 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2040 if (!mono_error_ok (&error)) {
2041 mono_error_set_pending_exception (&error);
2048 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2049 mono_assembly_name_free (&aname);
2052 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2054 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2055 if (!mono_error_ok (&error)) {
2056 mono_error_set_pending_exception (&error);
2068 refass = mono_assembly_get_object_checked (domain, ass, &error);
2071 mono_error_set_pending_exception (&error);
2073 MONO_OBJECT_SETREF (refass, evidence, evidence);
2078 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2080 MonoException *exc = NULL;
2081 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2083 if (NULL == domain) {
2084 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2085 mono_set_pending_exception (exc);
2089 if (domain == mono_get_root_domain ()) {
2090 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2095 * Unloading seems to cause problems when running NUnit/NAnt, hence
2098 if (g_getenv ("MONO_NO_UNLOAD"))
2100 #ifdef __native_client__
2104 mono_domain_try_unload (domain, (MonoObject**)&exc);
2106 mono_set_pending_exception (exc);
2110 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2112 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2117 return mono_domain_is_unloading (domain);
2121 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2123 mono_unhandled_exception ((MonoObject*) exc);
2127 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2128 MonoReflectionAssembly *refass, MonoArray *args)
2135 image = refass->assembly->image;
2138 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2141 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2144 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2145 mono_error_assert_ok (&error);
2148 int res = mono_runtime_exec_main_checked (method, (MonoArray *)args, &error);
2149 mono_error_set_pending_exception (&error);
2154 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2156 return ad->data->domain_id;
2160 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2162 MonoDomain *old_domain = mono_domain_get();
2164 if (!mono_domain_set (ad->data, FALSE)) {
2165 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2169 return old_domain->domain;
2173 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2175 MonoDomain *current_domain = mono_domain_get ();
2176 MonoDomain *domain = mono_domain_get_by_id (domainid);
2178 if (!domain || !mono_domain_set (domain, FALSE)) {
2179 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2183 return current_domain->domain;
2187 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2189 mono_thread_push_appdomain_ref (ad->data);
2193 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2195 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2199 * Raise an exception to prevent the managed code from executing a pop
2202 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2206 mono_thread_push_appdomain_ref (domain);
2210 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2212 mono_thread_pop_appdomain_ref ();
2216 ves_icall_System_AppDomain_InternalGetContext ()
2218 return mono_context_get ();
2222 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2224 return mono_domain_get ()->default_context;
2228 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2230 MonoAppContext *old_context = mono_context_get ();
2232 mono_context_set (mc);
2238 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2240 MonoDomain* mono_root_domain = mono_get_root_domain ();
2241 mono_domain_lock (mono_root_domain);
2242 if (process_guid_set) {
2243 mono_domain_unlock (mono_root_domain);
2245 MonoString *res = NULL;
2246 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2247 mono_error_set_pending_exception (&error);
2250 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2251 process_guid_set = TRUE;
2252 mono_domain_unlock (mono_root_domain);
2257 mono_domain_is_unloading (MonoDomain *domain)
2259 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2266 clear_cached_vtable (MonoVTable *vtable)
2268 MonoClass *klass = vtable->klass;
2269 MonoDomain *domain = vtable->domain;
2270 MonoClassRuntimeInfo *runtime_info;
2273 runtime_info = klass->runtime_info;
2274 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2275 runtime_info->domain_vtables [domain->domain_id] = NULL;
2276 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2277 mono_gc_free_fixed (data);
2280 static G_GNUC_UNUSED void
2281 zero_static_data (MonoVTable *vtable)
2283 MonoClass *klass = vtable->klass;
2286 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2287 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2290 typedef struct unload_data {
2293 char *failure_reason;
2298 unload_data_unref (unload_data *data)
2302 mono_atomic_load_acquire (count, gint32, &data->refcount);
2303 g_assert (count >= 1 && count <= 2);
2308 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2312 deregister_reflection_info_roots_from_list (MonoImage *image)
2314 GSList *list = image->reflection_info_unregister_classes;
2317 MonoClass *klass = (MonoClass *)list->data;
2319 mono_class_free_ref_info (klass);
2324 image->reflection_info_unregister_classes = NULL;
2328 deregister_reflection_info_roots (MonoDomain *domain)
2332 mono_domain_assemblies_lock (domain);
2333 for (list = domain->domain_assemblies; list; list = list->next) {
2334 MonoAssembly *assembly = (MonoAssembly *)list->data;
2335 MonoImage *image = assembly->image;
2339 * No need to take the image lock here since dynamic images are appdomain bound and
2340 * at this point the mutator is gone. Taking the image lock here would mean
2341 * promoting it from a simple lock to a complex lock, which we better avoid if
2344 if (image_is_dynamic (image))
2345 deregister_reflection_info_roots_from_list (image);
2347 for (i = 0; i < image->module_count; ++i) {
2348 MonoImage *module = image->modules [i];
2349 if (module && image_is_dynamic (module))
2350 deregister_reflection_info_roots_from_list (module);
2353 mono_domain_assemblies_unlock (domain);
2356 static guint32 WINAPI
2357 unload_thread_main (void *arg)
2360 unload_data *data = (unload_data*)arg;
2361 MonoDomain *domain = data->domain;
2365 /* Have to attach to the runtime so shutdown can wait for this thread */
2366 /* Force it to be attached to avoid racing during shutdown. */
2367 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2369 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2370 if (!is_ok (&error)) {
2371 data->failure_reason = g_strdup (mono_error_get_message (&error));
2372 mono_error_cleanup (&error);
2377 * FIXME: Abort our parent thread last, so we can return a failure
2378 * indication if aborting times out.
2380 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2381 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2385 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2386 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2390 /* Finalize all finalizable objects in the doomed appdomain */
2391 if (!mono_domain_finalize (domain, -1)) {
2392 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2396 /* Clear references to our vtables in class->runtime_info.
2397 * We also hold the loader lock because we're going to change
2398 * class->runtime_info.
2401 mono_loader_lock (); //FIXME why do we need the loader lock here?
2402 mono_domain_lock (domain);
2405 * We need to make sure that we don't have any remsets
2406 * pointing into static data of the to-be-freed domain because
2407 * at the next collections they would be invalid. So what we
2408 * do is we first zero all static data and then do a minor
2409 * collection. Because all references in the static data will
2410 * now be null we won't do any unnecessary copies and after
2411 * the collection there won't be any more remsets.
2413 for (i = 0; i < domain->class_vtable_array->len; ++i)
2414 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2415 mono_gc_collect (0);
2417 for (i = 0; i < domain->class_vtable_array->len; ++i)
2418 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2419 deregister_reflection_info_roots (domain);
2421 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2423 mono_domain_unlock (domain);
2424 mono_loader_unlock ();
2426 mono_threads_clear_cached_culture (domain);
2428 domain->state = MONO_APPDOMAIN_UNLOADED;
2430 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2432 /* remove from the handle table the items related to this domain */
2433 mono_gchandle_free_domain (domain);
2435 mono_domain_free (domain, FALSE);
2437 mono_gc_collect (mono_gc_max_generation ());
2439 mono_atomic_store_release (&data->done, TRUE);
2440 unload_data_unref (data);
2441 mono_thread_detach (thread);
2445 mono_atomic_store_release (&data->done, TRUE);
2446 unload_data_unref (data);
2447 mono_thread_detach (thread);
2452 * mono_domain_unload:
2453 * @domain: The domain to unload
2455 * Unloads an appdomain. Follows the process outlined in the comment
2456 * for mono_domain_try_unload.
2459 mono_domain_unload (MonoDomain *domain)
2461 MonoObject *exc = NULL;
2462 mono_domain_try_unload (domain, &exc);
2466 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2471 result = WaitForSingleObjectEx (handle, timeout, alertable);
2478 * mono_domain_unload:
2479 * @domain: The domain to unload
2480 * @exc: Exception information
2482 * Unloads an appdomain. Follows the process outlined in:
2483 * http://blogs.gotdotnet.com/cbrumme
2485 * If doing things the 'right' way is too hard or complex, we do it the
2486 * 'simple' way, which means do everything needed to avoid crashes and
2487 * memory leaks, but not much else.
2489 * It is required to pass a valid reference to the exc argument, upon return
2490 * from this function *exc will be set to the exception thrown, if any.
2492 * If this method is not called from an icall (embedded scenario for instance),
2493 * it must not be called with any managed frames on the stack, since the unload
2494 * process could end up trying to abort the current thread.
2497 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2500 HANDLE thread_handle;
2501 MonoAppDomainState prev_state;
2503 unload_data *thread_data;
2504 MonoNativeThreadId tid;
2505 MonoDomain *caller_domain = mono_domain_get ();
2508 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2510 /* Atomically change our state to UNLOADING */
2511 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2512 MONO_APPDOMAIN_UNLOADING_START,
2513 MONO_APPDOMAIN_CREATED);
2514 if (prev_state != MONO_APPDOMAIN_CREATED) {
2515 switch (prev_state) {
2516 case MONO_APPDOMAIN_UNLOADING_START:
2517 case MONO_APPDOMAIN_UNLOADING:
2518 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2520 case MONO_APPDOMAIN_UNLOADED:
2521 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2524 g_warning ("Invalid appdomain state %d", prev_state);
2525 g_assert_not_reached ();
2529 mono_domain_set (domain, FALSE);
2530 /* Notify OnDomainUnload listeners */
2531 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2534 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2536 if (!mono_error_ok (&error)) {
2538 mono_error_cleanup (&error);
2540 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2544 /* Roll back the state change */
2545 domain->state = MONO_APPDOMAIN_CREATED;
2546 mono_domain_set (caller_domain, FALSE);
2549 mono_domain_set (caller_domain, FALSE);
2551 thread_data = g_new0 (unload_data, 1);
2552 thread_data->domain = domain;
2553 thread_data->failure_reason = NULL;
2554 thread_data->done = FALSE;
2555 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2557 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2558 domain->state = MONO_APPDOMAIN_UNLOADING;
2560 * First we create a separate thread for unloading, since
2561 * we might have to abort some threads, including the current one.
2565 tp.creation_flags = CREATE_SUSPENDED;
2566 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, &tp, &tid);
2567 if (thread_handle == NULL)
2569 mono_thread_info_resume (tid);
2571 /* Wait for the thread */
2572 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2573 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2574 /* The unload thread tries to abort us */
2575 /* The icall wrapper will execute the abort */
2576 CloseHandle (thread_handle);
2577 unload_data_unref (thread_data);
2581 CloseHandle (thread_handle);
2583 if (thread_data->failure_reason) {
2584 /* Roll back the state change */
2585 domain->state = MONO_APPDOMAIN_CREATED;
2587 g_warning ("%s", thread_data->failure_reason);
2589 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2591 g_free (thread_data->failure_reason);
2592 thread_data->failure_reason = NULL;
2595 unload_data_unref (thread_data);