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 152
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;
966 #ifdef DISABLE_APPDOMAINS
967 mono_error_init (&error);
968 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
972 fname = mono_string_to_utf8_checked (friendly_name, &error);
973 if (mono_error_set_pending_exception (&error))
975 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
979 mono_error_set_pending_exception (&error);
984 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
987 MonoDomain *domain = ad->data;
992 GPtrArray *assemblies;
994 mono_error_init (&error);
997 * Make a copy of the list of assemblies because we can't hold the assemblies
998 * lock while creating objects etc.
1000 assemblies = g_ptr_array_new ();
1001 /* Need to skip internal assembly builders created by remoting */
1002 mono_domain_assemblies_lock (domain);
1003 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1004 ass = (MonoAssembly *)tmp->data;
1005 if (refonly != ass->ref_only)
1007 if (ass->corlib_internal)
1009 g_ptr_array_add (assemblies, ass);
1011 mono_domain_assemblies_unlock (domain);
1013 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1014 if (!is_ok (&error))
1016 for (i = 0; i < assemblies->len; ++i) {
1017 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1018 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1019 if (!mono_error_ok (&error))
1021 mono_array_setref (res, i, ass_obj);
1025 g_ptr_array_free (assemblies, TRUE);
1026 if (!mono_error_ok (&error))
1027 mono_error_set_pending_exception (&error);
1031 MonoReflectionAssembly *
1032 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1034 MonoReflectionAssembly *ret;
1037 MonoBoolean isrefonly;
1038 gpointer params [3];
1040 mono_error_init (error);
1042 if (mono_runtime_get_no_exec ())
1045 g_assert (domain != NULL && fname != NULL);
1047 klass = domain->domain->mbr.obj.vtable->klass;
1050 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1051 if (method == NULL) {
1052 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1056 isrefonly = refonly ? 1 : 0;
1059 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1060 return_val_if_nok (error, NULL);
1063 params [2] = &isrefonly;
1065 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1066 return_val_if_nok (error, NULL);
1072 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1076 MonoReflectionAssembly *assembly;
1077 MonoDomain *domain = mono_domain_get ();
1081 aname_str = mono_stringify_assembly_name (aname);
1083 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1084 str = mono_string_new (domain, aname_str);
1090 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1091 mono_error_cleanup (&error);
1094 return assembly->assembly;
1100 * LOCKING: assumes assemblies_lock in the domain is already locked.
1103 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1107 gboolean destroy_ht = FALSE;
1109 if (!ass->aname.name)
1113 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1117 /* FIXME: handle lazy loaded assemblies */
1118 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1119 g_hash_table_insert (ht, tmp->data, tmp->data);
1121 if (!g_hash_table_lookup (ht, ass)) {
1122 mono_assembly_addref (ass);
1123 g_hash_table_insert (ht, ass, ass);
1124 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1125 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);
1128 if (ass->image->references) {
1129 for (i = 0; ass->image->references [i] != NULL; i++) {
1130 if (ass->image->references [i] != REFERENCE_MISSING)
1131 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1132 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1137 g_hash_table_destroy (ht);
1141 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1143 static MonoClassField *assembly_load_field;
1144 static MonoMethod *assembly_load_method;
1146 MonoDomain *domain = mono_domain_get ();
1147 MonoReflectionAssembly *ref_assembly;
1149 gpointer load_value;
1152 if (!domain->domain)
1153 /* This can happen during startup */
1155 #ifdef ASSEMBLY_LOAD_DEBUG
1156 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1158 klass = domain->domain->mbr.obj.vtable->klass;
1160 mono_domain_assemblies_lock (domain);
1161 add_assemblies_to_domain (domain, assembly, NULL);
1162 mono_domain_assemblies_unlock (domain);
1164 if (assembly_load_field == NULL) {
1165 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1166 g_assert (assembly_load_field);
1169 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1170 if (load_value == NULL) {
1171 /* No events waiting to be triggered */
1175 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1176 mono_error_assert_ok (&error);
1178 if (assembly_load_method == NULL) {
1179 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1180 g_assert (assembly_load_method);
1183 *params = ref_assembly;
1185 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1186 mono_error_cleanup (&error);
1190 * LOCKING: Acquires the domain assemblies lock.
1193 set_domain_search_path (MonoDomain *domain)
1196 MonoAppDomainSetup *setup;
1198 gchar *search_path = NULL;
1201 gchar **pvt_split = NULL;
1202 GError *gerror = NULL;
1203 gint appbaselen = -1;
1206 * We use the low-level domain assemblies lock, since this is called from
1207 * assembly loads hooks, which means this thread might hold the loader lock.
1209 mono_domain_assemblies_lock (domain);
1211 if (!domain->setup) {
1212 mono_domain_assemblies_unlock (domain);
1216 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1217 mono_domain_assemblies_unlock (domain);
1220 setup = domain->setup;
1221 if (!setup->application_base) {
1222 mono_domain_assemblies_unlock (domain);
1223 return; /* Must set application base to get private path working */
1228 if (setup->private_bin_path) {
1229 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1230 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1231 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1232 mono_error_cleanup (&error);
1233 mono_domain_assemblies_unlock (domain);
1238 if (domain->private_bin_path) {
1239 if (search_path == NULL)
1240 search_path = domain->private_bin_path;
1242 gchar *tmp2 = search_path;
1243 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1250 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1251 * directories relative to ApplicationBase separated by semicolons (see
1252 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1253 * The loop below copes with the fact that some Unix applications may use ':' (or
1254 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1255 * ';' for the subsequent split.
1257 * The issue was reported in bug #81446
1260 #ifndef TARGET_WIN32
1263 slen = strlen (search_path);
1264 for (i = 0; i < slen; i++)
1265 if (search_path [i] == ':')
1266 search_path [i] = ';';
1269 pvt_split = g_strsplit (search_path, ";", 1000);
1270 g_free (search_path);
1271 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1276 g_strfreev (pvt_split);
1278 * Don't do this because the first time is called, the domain
1279 * setup is not finished.
1281 * domain->search_path = g_malloc (sizeof (char *));
1282 * domain->search_path [0] = NULL;
1284 mono_domain_assemblies_unlock (domain);
1288 if (domain->search_path)
1289 g_strfreev (domain->search_path);
1291 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1292 tmp [npaths] = NULL;
1294 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1295 if (!mono_error_ok (&error)) {
1296 mono_error_cleanup (&error);
1297 g_strfreev (pvt_split);
1300 mono_domain_assemblies_unlock (domain);
1304 domain->search_path = tmp;
1306 /* FIXME: is this needed? */
1307 if (strncmp (*tmp, "file://", 7) == 0) {
1313 uri = g_strdup_printf ("file:///%s", uri + 7);
1316 uri = mono_escape_uri_string (tmpuri);
1317 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1323 if (gerror != NULL) {
1324 g_warning ("%s\n", gerror->message);
1325 g_error_free (gerror);
1332 for (i = 1; pvt_split && i < npaths; i++) {
1333 if (g_path_is_absolute (pvt_split [i - 1])) {
1334 tmp [i] = g_strdup (pvt_split [i - 1]);
1336 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1339 if (strchr (tmp [i], '.')) {
1343 reduced = mono_path_canonicalize (tmp [i]);
1344 if (appbaselen == -1)
1345 appbaselen = strlen (tmp [0]);
1347 if (strncmp (tmp [0], reduced, appbaselen)) {
1350 tmp [i] = g_strdup ("");
1360 if (setup->private_bin_path_probe != NULL) {
1362 tmp [0] = g_strdup ("");
1365 domain->setup->path_changed = FALSE;
1367 g_strfreev (pvt_split);
1369 mono_domain_assemblies_unlock (domain);
1372 #ifdef DISABLE_SHADOW_COPY
1374 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1380 mono_make_shadow_copy (const char *filename, MonoError *error)
1382 mono_error_init (error);
1383 return (char *) filename;
1387 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1389 guint16 *orig, *dest;
1390 gboolean copy_result;
1392 strcpy (src + srclen - tail_len, extension);
1394 if (IS_PORTABILITY_CASE) {
1395 gchar *file = mono_portability_find_file (src, TRUE);
1401 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1405 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1407 strcpy (target + targetlen - tail_len, extension);
1408 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1411 copy_result = CopyFile (orig, dest, FALSE);
1413 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1414 * overwritten when updated in their original locations. */
1416 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1425 get_cstring_hash (const char *str)
1431 if (!str || !str [0])
1436 for (i = 0; i < len; i++) {
1437 h = (h << 5) - h + *p;
1445 * Returned memory is malloc'd. Called must free it
1448 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1450 MonoAppDomainSetup *setup;
1451 char *cache_path, *appname;
1455 mono_error_init (error);
1457 setup = domain->setup;
1458 if (setup->cache_path != NULL && setup->application_name != NULL) {
1459 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1460 return_val_if_nok (error, NULL);
1462 #ifndef TARGET_WIN32
1465 for (i = strlen (cache_path) - 1; i >= 0; i--)
1466 if (cache_path [i] == '\\')
1467 cache_path [i] = '/';
1471 appname = mono_string_to_utf8_checked (setup->application_name, error);
1472 if (!mono_error_ok (error)) {
1473 g_free (cache_path);
1477 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1479 g_free (cache_path);
1481 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1482 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1489 get_shadow_assembly_location (const char *filename, MonoError *error)
1491 gint32 hash = 0, hash2 = 0;
1493 char path_hash [30];
1494 char *bname = g_path_get_basename (filename);
1495 char *dirname = g_path_get_dirname (filename);
1496 char *location, *tmploc;
1497 MonoDomain *domain = mono_domain_get ();
1499 mono_error_init (error);
1501 hash = get_cstring_hash (bname);
1502 hash2 = get_cstring_hash (dirname);
1503 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1504 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1505 tmploc = get_shadow_assembly_location_base (domain, error);
1506 if (!mono_error_ok (error)) {
1512 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1520 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1522 struct stat sbuf_dest;
1524 gchar *real_src = mono_portability_find_file (src, TRUE);
1527 stat_src = (gchar*)src;
1529 stat_src = real_src;
1531 if (stat (stat_src, sbuf_src) == -1) {
1532 time_t tnow = time (NULL);
1537 memset (sbuf_src, 0, sizeof (*sbuf_src));
1538 sbuf_src->st_mtime = tnow;
1539 sbuf_src->st_atime = tnow;
1546 if (stat (dest, &sbuf_dest) == -1)
1549 if (sbuf_src->st_size == sbuf_dest.st_size &&
1550 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1557 shadow_copy_create_ini (const char *shadow, const char *filename)
1567 dir_name = g_path_get_dirname (shadow);
1568 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1570 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1575 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1580 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1581 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1583 if (handle == INVALID_HANDLE_VALUE) {
1587 full_path = mono_path_resolve_symlinks (filename);
1588 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1590 CloseHandle (handle);
1595 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1598 MonoAppDomainSetup *setup;
1601 gchar **directories;
1602 gchar *shadow_status_string;
1604 gboolean shadow_enabled;
1605 gboolean found = FALSE;
1610 setup = domain->setup;
1611 if (setup == NULL || setup->shadow_copy_files == NULL)
1614 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1615 if (!mono_error_ok (&error)) {
1616 mono_error_cleanup (&error);
1619 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1620 g_free (shadow_status_string);
1622 if (!shadow_enabled)
1625 if (setup->shadow_copy_directories == NULL)
1628 /* Is dir_name a shadow_copy destination already? */
1629 base_dir = get_shadow_assembly_location_base (domain, &error);
1630 if (!mono_error_ok (&error)) {
1631 mono_error_cleanup (&error);
1635 if (strstr (dir_name, base_dir)) {
1641 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1642 if (!mono_error_ok (&error)) {
1643 mono_error_cleanup (&error);
1647 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1648 dir_ptr = directories;
1650 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1656 g_strfreev (directories);
1662 This function raises exceptions so it can cause as sorts of nasty stuff if called
1663 while holding a lock.
1664 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1665 or NULL if source file not found.
1666 FIXME bubble up the error instead of raising it here
1669 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1672 gchar *sibling_source, *sibling_target;
1673 gint sibling_source_len, sibling_target_len;
1674 guint16 *orig, *dest;
1677 gboolean copy_result;
1678 struct stat src_sbuf;
1679 struct utimbuf utbuf;
1680 char *dir_name = g_path_get_dirname (filename);
1681 MonoDomain *domain = mono_domain_get ();
1684 mono_error_init (oerror);
1686 set_domain_search_path (domain);
1688 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1690 return (char *) filename;
1693 /* Is dir_name a shadow_copy destination already? */
1694 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1695 if (!mono_error_ok (&error)) {
1696 mono_error_cleanup (&error);
1698 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1702 if (strstr (dir_name, shadow_dir)) {
1703 g_free (shadow_dir);
1705 return (char *) filename;
1707 g_free (shadow_dir);
1710 shadow = get_shadow_assembly_location (filename, &error);
1711 if (!mono_error_ok (&error)) {
1712 mono_error_cleanup (&error);
1713 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1717 if (g_ensure_directory_exists (shadow) == FALSE) {
1719 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1723 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1724 return (char*) shadow;
1726 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1727 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1730 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1731 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1732 * and not have it runtime error" */
1733 attrs = GetFileAttributes (orig);
1734 if (attrs == INVALID_FILE_ATTRIBUTES) {
1736 return (char *)filename;
1739 copy_result = CopyFile (orig, dest, FALSE);
1741 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1742 * overwritten when updated in their original locations. */
1744 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1749 if (copy_result == FALSE) {
1752 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1753 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1754 return NULL; /* file not found, shadow copy failed */
1756 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1760 /* attempt to copy .mdb, .config if they exist */
1761 sibling_source = g_strconcat (filename, ".config", NULL);
1762 sibling_source_len = strlen (sibling_source);
1763 sibling_target = g_strconcat (shadow, ".config", NULL);
1764 sibling_target_len = strlen (sibling_target);
1766 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1768 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1770 g_free (sibling_source);
1771 g_free (sibling_target);
1775 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1779 /* Create a .ini file containing the original assembly location */
1780 if (!shadow_copy_create_ini (shadow, filename)) {
1782 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1786 utbuf.actime = src_sbuf.st_atime;
1787 utbuf.modtime = src_sbuf.st_mtime;
1788 utime (shadow, &utbuf);
1792 #endif /* DISABLE_SHADOW_COPY */
1795 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1797 if (appdomain == NULL)
1800 return appdomain->data;
1804 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1805 const gchar *path3, const gchar *path4,
1806 gboolean refonly, gboolean is_private)
1809 gboolean found = FALSE;
1812 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1814 if (IS_PORTABILITY_SET) {
1815 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1818 fullpath = new_fullpath;
1822 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1825 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1828 return (*assembly != NULL);
1831 static MonoAssembly *
1832 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1834 MonoAssembly *result = NULL;
1837 const gchar *local_culture;
1839 gboolean is_private = FALSE;
1841 if (!culture || *culture == '\0') {
1844 local_culture = culture;
1847 filename = g_strconcat (name, ".dll", NULL);
1848 len = strlen (filename);
1850 for (path = search_path; *path; path++) {
1851 if (**path == '\0') {
1853 continue; /* Ignore empty ApplicationBase */
1856 /* See test cases in bug #58992 and bug #57710 */
1857 /* 1st try: [culture]/[name].dll (culture may be empty) */
1858 strcpy (filename + len - 4, ".dll");
1859 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1862 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1863 strcpy (filename + len - 4, ".exe");
1864 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1867 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1868 strcpy (filename + len - 4, ".dll");
1869 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1872 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1873 strcpy (filename + len - 4, ".exe");
1874 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1883 * Try loading the assembly from ApplicationBase and PrivateBinPath
1884 * and then from assemblies_path if any.
1885 * LOCKING: This is called from the assembly loading code, which means the caller
1886 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1888 static MonoAssembly *
1889 mono_domain_assembly_preload (MonoAssemblyName *aname,
1890 gchar **assemblies_path,
1893 MonoDomain *domain = mono_domain_get ();
1894 MonoAssembly *result = NULL;
1895 gboolean refonly = GPOINTER_TO_UINT (user_data);
1897 set_domain_search_path (domain);
1899 if (domain->search_path && domain->search_path [0] != NULL) {
1900 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1903 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1904 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1911 * Check whenever a given assembly was already loaded in the current appdomain.
1913 static MonoAssembly *
1914 mono_domain_assembly_search (MonoAssemblyName *aname,
1917 MonoDomain *domain = mono_domain_get ();
1920 gboolean refonly = GPOINTER_TO_UINT (user_data);
1922 mono_domain_assemblies_lock (domain);
1923 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1924 ass = (MonoAssembly *)tmp->data;
1925 /* Dynamic assemblies can't match here in MS.NET */
1926 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1929 mono_domain_assemblies_unlock (domain);
1932 mono_domain_assemblies_unlock (domain);
1937 MonoReflectionAssembly *
1938 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1941 MonoReflectionAssembly *result;
1942 MonoDomain *domain = mono_domain_get ();
1943 char *name, *filename;
1944 MonoImageOpenStatus status = MONO_IMAGE_OK;
1947 if (fname == NULL) {
1948 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1949 mono_set_pending_exception (exc);
1953 name = filename = mono_string_to_utf8_checked (fname, &error);
1954 if (mono_error_set_pending_exception (&error))
1957 ass = mono_assembly_open_full (filename, &status, refOnly);
1962 if (status == MONO_IMAGE_IMAGE_INVALID)
1963 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1965 exc = mono_get_exception_file_not_found2 (NULL, fname);
1967 mono_set_pending_exception (exc);
1973 result = mono_assembly_get_object_checked (domain, ass, &error);
1975 mono_error_set_pending_exception (&error);
1979 MonoReflectionAssembly *
1980 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1981 MonoArray *raw_assembly,
1982 MonoArray *raw_symbol_store, MonoObject *evidence,
1983 MonoBoolean refonly)
1987 MonoReflectionAssembly *refass = NULL;
1988 MonoDomain *domain = ad->data;
1989 MonoImageOpenStatus status;
1990 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1991 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1994 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1998 if (raw_symbol_store != NULL)
1999 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2001 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2005 mono_image_close (image);
2006 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2010 refass = mono_assembly_get_object_checked (domain, ass, &error);
2012 mono_error_set_pending_exception (&error);
2014 MONO_OBJECT_SETREF (refass, evidence, evidence);
2018 MonoReflectionAssembly *
2019 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2022 MonoDomain *domain = ad->data;
2023 MonoImageOpenStatus status = MONO_IMAGE_OK;
2025 MonoAssemblyName aname;
2026 MonoReflectionAssembly *refass = NULL;
2032 name = mono_string_to_utf8_checked (assRef, &error);
2033 if (mono_error_set_pending_exception (&error))
2035 parsed = mono_assembly_name_parse (name, &aname);
2039 /* This is a parse error... */
2041 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2042 if (!mono_error_ok (&error)) {
2043 mono_error_set_pending_exception (&error);
2050 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2051 mono_assembly_name_free (&aname);
2054 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2056 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2057 if (!mono_error_ok (&error)) {
2058 mono_error_set_pending_exception (&error);
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 MonoException *exc = NULL;
2083 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2085 if (NULL == domain) {
2086 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2087 mono_set_pending_exception (exc);
2091 if (domain == mono_get_root_domain ()) {
2092 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2097 * Unloading seems to cause problems when running NUnit/NAnt, hence
2100 if (g_getenv ("MONO_NO_UNLOAD"))
2102 #ifdef __native_client__
2106 mono_domain_try_unload (domain, (MonoObject**)&exc);
2108 mono_set_pending_exception (exc);
2112 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2114 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2119 return mono_domain_is_unloading (domain);
2123 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2125 mono_unhandled_exception ((MonoObject*) exc);
2129 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2130 MonoReflectionAssembly *refass, MonoArray *args)
2137 image = refass->assembly->image;
2140 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2143 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2146 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2147 mono_error_assert_ok (&error);
2150 int res = mono_runtime_exec_main_checked (method, (MonoArray *)args, &error);
2151 mono_error_set_pending_exception (&error);
2156 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2158 return ad->data->domain_id;
2162 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2164 MonoDomain *old_domain = mono_domain_get();
2166 if (!mono_domain_set (ad->data, FALSE)) {
2167 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2171 return old_domain->domain;
2175 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2177 MonoDomain *current_domain = mono_domain_get ();
2178 MonoDomain *domain = mono_domain_get_by_id (domainid);
2180 if (!domain || !mono_domain_set (domain, FALSE)) {
2181 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2185 return current_domain->domain;
2189 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2191 mono_thread_push_appdomain_ref (ad->data);
2195 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2197 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2201 * Raise an exception to prevent the managed code from executing a pop
2204 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2208 mono_thread_push_appdomain_ref (domain);
2212 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2214 mono_thread_pop_appdomain_ref ();
2218 ves_icall_System_AppDomain_InternalGetContext ()
2220 return mono_context_get ();
2224 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2226 return mono_domain_get ()->default_context;
2230 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2232 MonoAppContext *old_context = mono_context_get ();
2234 mono_context_set (mc);
2240 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2242 MonoDomain* mono_root_domain = mono_get_root_domain ();
2243 mono_domain_lock (mono_root_domain);
2244 if (process_guid_set) {
2245 mono_domain_unlock (mono_root_domain);
2247 MonoString *res = NULL;
2248 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2249 mono_error_set_pending_exception (&error);
2252 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2253 process_guid_set = TRUE;
2254 mono_domain_unlock (mono_root_domain);
2259 mono_domain_is_unloading (MonoDomain *domain)
2261 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2268 clear_cached_vtable (MonoVTable *vtable)
2270 MonoClass *klass = vtable->klass;
2271 MonoDomain *domain = vtable->domain;
2272 MonoClassRuntimeInfo *runtime_info;
2275 runtime_info = klass->runtime_info;
2276 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2277 runtime_info->domain_vtables [domain->domain_id] = NULL;
2278 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2279 mono_gc_free_fixed (data);
2282 static G_GNUC_UNUSED void
2283 zero_static_data (MonoVTable *vtable)
2285 MonoClass *klass = vtable->klass;
2288 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2289 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2292 typedef struct unload_data {
2295 char *failure_reason;
2300 unload_data_unref (unload_data *data)
2304 mono_atomic_load_acquire (count, gint32, &data->refcount);
2305 g_assert (count >= 1 && count <= 2);
2310 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2314 deregister_reflection_info_roots_from_list (MonoImage *image)
2316 GSList *list = image->reflection_info_unregister_classes;
2319 MonoClass *klass = (MonoClass *)list->data;
2321 mono_class_free_ref_info (klass);
2326 image->reflection_info_unregister_classes = NULL;
2330 deregister_reflection_info_roots (MonoDomain *domain)
2334 mono_domain_assemblies_lock (domain);
2335 for (list = domain->domain_assemblies; list; list = list->next) {
2336 MonoAssembly *assembly = (MonoAssembly *)list->data;
2337 MonoImage *image = assembly->image;
2341 * No need to take the image lock here since dynamic images are appdomain bound and
2342 * at this point the mutator is gone. Taking the image lock here would mean
2343 * promoting it from a simple lock to a complex lock, which we better avoid if
2346 if (image_is_dynamic (image))
2347 deregister_reflection_info_roots_from_list (image);
2349 for (i = 0; i < image->module_count; ++i) {
2350 MonoImage *module = image->modules [i];
2351 if (module && image_is_dynamic (module))
2352 deregister_reflection_info_roots_from_list (module);
2355 mono_domain_assemblies_unlock (domain);
2359 unload_thread_main (void *arg)
2362 unload_data *data = (unload_data*)arg;
2363 MonoDomain *domain = data->domain;
2367 /* Have to attach to the runtime so shutdown can wait for this thread */
2368 /* Force it to be attached to avoid racing during shutdown. */
2369 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2371 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2372 if (!is_ok (&error)) {
2373 data->failure_reason = g_strdup (mono_error_get_message (&error));
2374 mono_error_cleanup (&error);
2379 * FIXME: Abort our parent thread last, so we can return a failure
2380 * indication if aborting times out.
2382 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2383 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2387 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2388 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2392 /* Finalize all finalizable objects in the doomed appdomain */
2393 if (!mono_domain_finalize (domain, -1)) {
2394 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2398 /* Clear references to our vtables in class->runtime_info.
2399 * We also hold the loader lock because we're going to change
2400 * class->runtime_info.
2403 mono_loader_lock (); //FIXME why do we need the loader lock here?
2404 mono_domain_lock (domain);
2407 * We need to make sure that we don't have any remsets
2408 * pointing into static data of the to-be-freed domain because
2409 * at the next collections they would be invalid. So what we
2410 * do is we first zero all static data and then do a minor
2411 * collection. Because all references in the static data will
2412 * now be null we won't do any unnecessary copies and after
2413 * the collection there won't be any more remsets.
2415 for (i = 0; i < domain->class_vtable_array->len; ++i)
2416 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2417 mono_gc_collect (0);
2419 for (i = 0; i < domain->class_vtable_array->len; ++i)
2420 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2421 deregister_reflection_info_roots (domain);
2423 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2425 mono_domain_unlock (domain);
2426 mono_loader_unlock ();
2428 mono_threads_clear_cached_culture (domain);
2430 domain->state = MONO_APPDOMAIN_UNLOADED;
2432 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2434 /* remove from the handle table the items related to this domain */
2435 mono_gchandle_free_domain (domain);
2437 mono_domain_free (domain, FALSE);
2439 mono_gc_collect (mono_gc_max_generation ());
2441 mono_atomic_store_release (&data->done, TRUE);
2442 unload_data_unref (data);
2443 mono_thread_detach (thread);
2447 mono_atomic_store_release (&data->done, TRUE);
2448 unload_data_unref (data);
2449 mono_thread_detach (thread);
2454 * mono_domain_unload:
2455 * @domain: The domain to unload
2457 * Unloads an appdomain. Follows the process outlined in the comment
2458 * for mono_domain_try_unload.
2461 mono_domain_unload (MonoDomain *domain)
2463 MonoObject *exc = NULL;
2464 mono_domain_try_unload (domain, &exc);
2468 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2473 result = WaitForSingleObjectEx (handle, timeout, alertable);
2480 * mono_domain_unload:
2481 * @domain: The domain to unload
2482 * @exc: Exception information
2484 * Unloads an appdomain. Follows the process outlined in:
2485 * http://blogs.gotdotnet.com/cbrumme
2487 * If doing things the 'right' way is too hard or complex, we do it the
2488 * 'simple' way, which means do everything needed to avoid crashes and
2489 * memory leaks, but not much else.
2491 * It is required to pass a valid reference to the exc argument, upon return
2492 * from this function *exc will be set to the exception thrown, if any.
2494 * If this method is not called from an icall (embedded scenario for instance),
2495 * it must not be called with any managed frames on the stack, since the unload
2496 * process could end up trying to abort the current thread.
2499 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2502 HANDLE thread_handle;
2503 MonoAppDomainState prev_state;
2505 unload_data *thread_data;
2506 MonoNativeThreadId tid;
2507 MonoDomain *caller_domain = mono_domain_get ();
2510 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2512 /* Atomically change our state to UNLOADING */
2513 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2514 MONO_APPDOMAIN_UNLOADING_START,
2515 MONO_APPDOMAIN_CREATED);
2516 if (prev_state != MONO_APPDOMAIN_CREATED) {
2517 switch (prev_state) {
2518 case MONO_APPDOMAIN_UNLOADING_START:
2519 case MONO_APPDOMAIN_UNLOADING:
2520 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2522 case MONO_APPDOMAIN_UNLOADED:
2523 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2526 g_warning ("Invalid appdomain state %d", prev_state);
2527 g_assert_not_reached ();
2531 mono_domain_set (domain, FALSE);
2532 /* Notify OnDomainUnload listeners */
2533 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2536 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2538 if (!mono_error_ok (&error)) {
2540 mono_error_cleanup (&error);
2542 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2546 /* Roll back the state change */
2547 domain->state = MONO_APPDOMAIN_CREATED;
2548 mono_domain_set (caller_domain, FALSE);
2551 mono_domain_set (caller_domain, FALSE);
2553 thread_data = g_new0 (unload_data, 1);
2554 thread_data->domain = domain;
2555 thread_data->failure_reason = NULL;
2556 thread_data->done = FALSE;
2557 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2559 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2560 domain->state = MONO_APPDOMAIN_UNLOADING;
2562 * First we create a separate thread for unloading, since
2563 * we might have to abort some threads, including the current one.
2565 tp.priority = MONO_THREAD_PRIORITY_NORMAL;
2567 tp.creation_flags = CREATE_SUSPENDED;
2568 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, &tp, &tid);
2569 if (thread_handle == NULL)
2571 mono_thread_info_resume (tid);
2573 /* Wait for the thread */
2574 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2575 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2576 /* The unload thread tries to abort us */
2577 /* The icall wrapper will execute the abort */
2578 CloseHandle (thread_handle);
2579 unload_data_unref (thread_data);
2583 CloseHandle (thread_handle);
2585 if (thread_data->failure_reason) {
2586 /* Roll back the state change */
2587 domain->state = MONO_APPDOMAIN_CREATED;
2589 g_warning ("%s", thread_data->failure_reason);
2591 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2593 g_free (thread_data->failure_reason);
2594 thread_data->failure_reason = NULL;
2597 unload_data_unref (thread_data);