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>
75 * This is the version number of the corlib-runtime interface. When
76 * making changes to this interface (by changing the layout
77 * of classes the runtime knows about, changing icall signature or
78 * semantics etc), increment this variable. Also increment the
79 * pair of this variable in mscorlib in:
80 * mcs/class/corlib/System/Environment.cs
82 * Changes which are already detected at runtime, like the addition
83 * of icalls, do not require an increment.
85 #define MONO_CORLIB_VERSION 150
90 int assemblybinding_count;
95 static gunichar2 process_guid [36];
96 static gboolean process_guid_set = FALSE;
98 static gboolean no_exec = FALSE;
100 static MonoAssembly *
101 mono_domain_assembly_preload (MonoAssemblyName *aname,
102 gchar **assemblies_path,
105 static MonoAssembly *
106 mono_domain_assembly_search (MonoAssemblyName *aname,
110 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
113 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
115 static MonoAppDomain *
116 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
119 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
121 static MonoLoadFunc load_function = NULL;
123 /* Lazy class loading functions */
124 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
127 mono_install_runtime_load (MonoLoadFunc func)
129 load_function = func;
133 mono_runtime_load (const char *filename, const char *runtime_version)
135 g_assert (load_function);
136 return load_function (filename, runtime_version);
140 * mono_runtime_set_no_exec:
142 * Instructs the runtime to operate in static mode, i.e. avoid/do not
143 * allow managed code execution. This is useful for running the AOT
144 * compiler on platforms which allow full-aot execution only. This
145 * should be called before mono_runtime_init ().
148 mono_runtime_set_no_exec (gboolean val)
154 * mono_runtime_get_no_exec:
156 * If true, then the runtime will not allow managed code execution.
159 mono_runtime_get_no_exec (void)
165 create_domain_objects (MonoDomain *domain)
168 MonoDomain *old_domain = mono_domain_get ();
170 MonoVTable *string_vt;
171 MonoClassField *string_empty_fld;
173 if (domain != old_domain) {
174 mono_thread_push_appdomain_ref (domain);
175 mono_domain_set_internal_with_options (domain, FALSE);
179 * Initialize String.Empty. This enables the removal of
180 * the static cctor of the String class.
182 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
183 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
184 g_assert (string_empty_fld);
185 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
186 mono_error_assert_ok (&error);
187 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
190 * Create an instance early since we can't do it when there is no memory.
192 arg = mono_string_new (domain, "Out of memory");
193 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
194 mono_error_assert_ok (&error);
197 * These two are needed because the signal handlers might be executing on
198 * an alternate stack, and Boehm GC can't handle that.
200 arg = mono_string_new (domain, "A null value was found where an object instance was required");
201 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
202 mono_error_assert_ok (&error);
203 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
204 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
205 mono_error_assert_ok (&error);
207 /*The ephemeron tombstone i*/
208 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
209 mono_error_assert_ok (&error);
211 if (domain != old_domain) {
212 mono_thread_pop_appdomain_ref ();
213 mono_domain_set_internal_with_options (old_domain, FALSE);
217 * This class is used during exception handling, so initialize it here, to prevent
218 * stack overflows while handling stack overflows.
220 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
225 * @domain: domain returned by mono_init ()
227 * Initialize the core AppDomain: this function will run also some
228 * IL initialization code, so it needs the execution engine to be fully
231 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
232 * we know the entry_assembly.
236 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
239 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
240 mono_error_cleanup (&error);
244 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
246 MonoAppDomainSetup *setup;
250 mono_error_init (error);
252 mono_portability_helpers_init ();
254 mono_gc_base_init ();
255 mono_monitor_init ();
256 mono_marshal_init ();
258 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
259 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
260 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
261 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
262 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
263 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
264 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
266 mono_thread_init (start_cb, attach_cb);
268 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
269 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
270 return_if_nok (error);
272 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
274 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
275 return_if_nok (error);
279 domain->setup = setup;
281 mono_thread_attach (domain);
283 mono_type_initialization_init ();
285 if (!mono_runtime_get_no_exec ())
286 create_domain_objects (domain);
288 /* GC init has to happen after thread init */
291 /* contexts use GC handles, so they must be initialized after the GC */
292 mono_context_init_checked (domain, error);
293 return_if_nok (error);
294 mono_context_set (domain->default_context);
296 #ifndef DISABLE_SOCKETS
297 mono_network_init ();
300 mono_console_init ();
303 mono_locks_tracer_init ();
305 /* mscorlib is loaded before we install the load hook */
306 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
312 mono_get_corlib_version (void)
316 MonoClassField *field;
319 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
320 mono_class_init (klass);
321 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
324 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
326 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
327 mono_error_assert_ok (&error);
328 return *(gint32*)((gchar*)value + sizeof (MonoObject));
332 * mono_check_corlib_version
334 * Checks that the corlib that is loaded matches the version of this runtime.
336 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
337 * allocated string with the error otherwise.
340 mono_check_corlib_version (void)
342 int version = mono_get_corlib_version ();
343 if (version != MONO_CORLIB_VERSION)
344 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
351 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
353 * Initializes the @domain's default System.Runtime.Remoting's Context.
356 mono_context_init (MonoDomain *domain)
359 mono_context_init_checked (domain, &error);
360 mono_error_cleanup (&error);
364 mono_context_init_checked (MonoDomain *domain, MonoError *error)
367 MonoAppContext *context;
369 mono_error_init (error);
371 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
372 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
373 return_if_nok (error);
375 context->domain_id = domain->domain_id;
376 context->context_id = 0;
377 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
378 domain->default_context = context;
382 * mono_runtime_cleanup:
387 * This must not be called while there are still running threads executing
391 mono_runtime_cleanup (MonoDomain *domain)
393 mono_attach_cleanup ();
395 /* This ends up calling any pending pending (for at most 2 seconds) */
398 mono_thread_cleanup ();
400 #ifndef DISABLE_SOCKETS
401 mono_network_cleanup ();
403 mono_marshal_cleanup ();
405 mono_type_initialization_cleanup ();
407 mono_monitor_cleanup ();
410 static MonoDomainFunc quit_function = NULL;
413 mono_install_runtime_cleanup (MonoDomainFunc func)
415 quit_function = func;
421 if (quit_function != NULL)
422 quit_function (mono_get_root_domain (), NULL);
426 * mono_domain_create_appdomain:
427 * @friendly_name: The friendly name of the appdomain to create
428 * @configuration_file: The configuration file to initialize the appdomain with
430 * Returns a MonoDomain initialized with the appdomain
433 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
437 MonoAppDomainSetup *setup;
440 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
441 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
444 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
446 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
450 return mono_domain_from_appdomain (ad);
452 mono_error_cleanup (&error);
457 * mono_domain_set_config:
458 * @domain: MonoDomain initialized with the appdomain we want to change
459 * @base_dir: new base directory for the appdomain
460 * @config_file_name: path to the new configuration for the app domain
462 * Used to set the system configuration for an appdomain
464 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
465 * Error Initializing the configuration system. ---> System.ArgumentException:
466 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
469 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
471 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
472 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
475 static MonoAppDomainSetup*
476 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
478 MonoDomain *caller_domain;
479 MonoClass *ads_class;
480 MonoAppDomainSetup *copy;
482 mono_error_init (error);
484 caller_domain = mono_domain_get ();
485 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
487 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
488 return_val_if_nok (error, NULL);
490 mono_domain_set_internal (domain);
492 #define XCOPY_FIELD(dst,field,src,error) \
494 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
495 return_val_if_nok (error, NULL); \
496 MONO_OBJECT_SETREF ((dst),field,copied_val); \
499 XCOPY_FIELD (copy, application_base, setup->application_base, error);
500 XCOPY_FIELD (copy, application_name, setup->application_name, error);
501 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
502 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
503 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
504 XCOPY_FIELD (copy, license_file, setup->license_file, error);
505 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
506 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
507 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
508 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
509 copy->publisher_policy = setup->publisher_policy;
510 copy->path_changed = setup->path_changed;
511 copy->loader_optimization = setup->loader_optimization;
512 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
513 copy->disallow_code_downloads = setup->disallow_code_downloads;
514 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
515 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
516 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
517 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
518 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
522 mono_domain_set_internal (caller_domain);
527 static MonoAppDomain *
528 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
533 char *shadow_location;
535 mono_error_init (error);
537 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
539 /* FIXME: pin all those objects */
540 data = mono_domain_create();
542 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
543 return_val_if_nok (error, NULL);
546 data->friendly_name = g_strdup (friendly_name);
548 mono_profiler_appdomain_name (data, data->friendly_name);
550 if (!setup->application_base) {
551 /* Inherit from the root domain since MS.NET does this */
552 MonoDomain *root = mono_get_root_domain ();
553 if (root->setup->application_base) {
554 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
555 mono_error_assert_ok (error); /* FIXME don't swallow the error */
556 MONO_OBJECT_SETREF (setup, application_base, s);
560 mono_context_init_checked (data, error);
561 return_val_if_nok (error, NULL);
563 data->setup = copy_app_domain_setup (data, setup, error);
564 if (!mono_error_ok (error)) {
565 g_free (data->friendly_name);
569 mono_domain_set_options_from_config (data);
570 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
572 #ifndef DISABLE_SHADOW_COPY
573 /*FIXME, guard this for when the debugger is not running */
574 shadow_location = get_shadow_assembly_location_base (data, error);
575 if (!mono_error_ok (error)) {
576 g_free (data->friendly_name);
580 g_free (shadow_location);
583 create_domain_objects (data);
589 * mono_domain_has_type_resolve:
590 * @domain: application domains being looked up
592 * Returns: TRUE if the AppDomain.TypeResolve field has been
596 mono_domain_has_type_resolve (MonoDomain *domain)
598 static MonoClassField *field = NULL;
602 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
606 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
610 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
615 * mono_domain_try_type_resolve:
616 * @domain: application domainwhere the name where the type is going to be resolved
617 * @name: the name of the type to resolve or NULL.
618 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
620 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
621 * the assembly that matches name.
623 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
625 * Returns: A MonoReflectionAssembly or NULL if not found
627 MonoReflectionAssembly *
628 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
631 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
632 mono_error_cleanup (&error);
637 MonoReflectionAssembly *
638 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
640 static MonoMethod *method = NULL;
641 MonoReflectionAssembly *ret;
645 mono_error_init (error);
647 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
649 if (method == NULL) {
650 klass = domain->domain->mbr.obj.vtable->klass;
653 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
654 if (method == NULL) {
655 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
661 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
665 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
666 return_val_if_nok (error, NULL);
672 * mono_domain_owns_vtable_slot:
674 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
677 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
681 mono_domain_lock (domain);
682 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
683 mono_domain_unlock (domain);
690 * @force: force setting.
692 * Set the current appdomain to @domain. If @force is set, set it even
693 * if it is being unloaded.
697 * FALSE if the domain is unloaded
700 mono_domain_set (MonoDomain *domain, gboolean force)
702 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
705 mono_domain_set_internal (domain);
711 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
718 MONO_CHECK_ARG_NULL (name, NULL);
724 str = mono_string_to_utf8_checked (name, &error);
725 if (mono_error_set_pending_exception (&error))
728 mono_domain_lock (add);
730 if (!strcmp (str, "APPBASE"))
731 o = (MonoObject *)add->setup->application_base;
732 else if (!strcmp (str, "APP_CONFIG_FILE"))
733 o = (MonoObject *)add->setup->configuration_file;
734 else if (!strcmp (str, "DYNAMIC_BASE"))
735 o = (MonoObject *)add->setup->dynamic_base;
736 else if (!strcmp (str, "APP_NAME"))
737 o = (MonoObject *)add->setup->application_name;
738 else if (!strcmp (str, "CACHE_BASE"))
739 o = (MonoObject *)add->setup->cache_path;
740 else if (!strcmp (str, "PRIVATE_BINPATH"))
741 o = (MonoObject *)add->setup->private_bin_path;
742 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
743 o = (MonoObject *)add->setup->private_bin_path_probe;
744 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
745 o = (MonoObject *)add->setup->shadow_copy_directories;
746 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
747 o = (MonoObject *)add->setup->shadow_copy_files;
749 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
751 mono_domain_unlock (add);
761 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
765 MONO_CHECK_ARG_NULL (name,);
771 mono_domain_lock (add);
773 mono_g_hash_table_insert (add->env, name, data);
775 mono_domain_unlock (add);
779 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
784 return ad->data->setup;
788 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
793 return mono_string_new (ad->data, ad->data->friendly_name);
797 ves_icall_System_AppDomain_getCurDomain ()
799 MonoDomain *add = mono_domain_get ();
805 ves_icall_System_AppDomain_getRootDomain ()
807 MonoDomain *root = mono_get_root_domain ();
813 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
815 MonoDomain *domain = mono_domain_get ();
817 return domain->throw_unobserved_task_exceptions;
821 get_attribute_value (const gchar **attribute_names,
822 const gchar **attribute_values,
823 const char *att_name)
826 for (n = 0; attribute_names [n] != NULL; n++) {
827 if (strcmp (attribute_names [n], att_name) == 0)
828 return g_strdup (attribute_values [n]);
834 start_element (GMarkupParseContext *context,
835 const gchar *element_name,
836 const gchar **attribute_names,
837 const gchar **attribute_values,
841 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
843 if (strcmp (element_name, "runtime") == 0) {
844 runtime_config->runtime_count++;
848 if (strcmp (element_name, "assemblyBinding") == 0) {
849 runtime_config->assemblybinding_count++;
853 if (runtime_config->runtime_count != 1)
856 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
857 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
859 if (value && g_ascii_strcasecmp (value, "true") == 0)
860 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
863 if (runtime_config->assemblybinding_count != 1)
866 if (strcmp (element_name, "probing") != 0)
869 g_free (runtime_config->domain->private_bin_path);
870 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
871 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
872 g_free (runtime_config->domain->private_bin_path);
873 runtime_config->domain->private_bin_path = NULL;
879 end_element (GMarkupParseContext *context,
880 const gchar *element_name,
884 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
885 if (strcmp (element_name, "runtime") == 0)
886 runtime_config->runtime_count--;
887 else if (strcmp (element_name, "assemblyBinding") == 0)
888 runtime_config->assemblybinding_count--;
892 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
894 RuntimeConfig *state = (RuntimeConfig *)user_data;
896 const gchar *filename;
898 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
899 msg = error && error->message ? error->message : "";
900 g_warning ("Error parsing %s: %s", filename, msg);
903 static const GMarkupParser
913 mono_domain_set_options_from_config (MonoDomain *domain)
916 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
918 GMarkupParseContext *context;
919 RuntimeConfig runtime_config;
922 if (!domain || !domain->setup || !domain->setup->configuration_file)
925 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
926 if (!mono_error_ok (&error)) {
927 mono_error_cleanup (&error);
931 config_file_path = mono_portability_find_file (config_file_name, TRUE);
932 if (!config_file_path)
933 config_file_path = config_file_name;
935 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
938 runtime_config.runtime_count = 0;
939 runtime_config.assemblybinding_count = 0;
940 runtime_config.domain = domain;
941 runtime_config.filename = config_file_path;
944 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
945 offset = 3; /* Skip UTF-8 BOM */
947 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
948 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
949 g_markup_parse_context_end_parse (context, NULL);
950 g_markup_parse_context_free (context);
954 if (config_file_name != config_file_path)
955 g_free (config_file_name);
956 g_free (config_file_path);
960 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
963 MonoAppDomain *ad = NULL;
964 #ifdef DISABLE_APPDOMAINS
965 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
969 fname = mono_string_to_utf8_checked (friendly_name, &error);
970 if (mono_error_set_pending_exception (&error))
972 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
976 mono_error_set_pending_exception (&error);
981 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
984 MonoDomain *domain = ad->data;
989 GPtrArray *assemblies;
991 mono_error_init (&error);
994 * Make a copy of the list of assemblies because we can't hold the assemblies
995 * lock while creating objects etc.
997 assemblies = g_ptr_array_new ();
998 /* Need to skip internal assembly builders created by remoting */
999 mono_domain_assemblies_lock (domain);
1000 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1001 ass = (MonoAssembly *)tmp->data;
1002 if (refonly != ass->ref_only)
1004 if (ass->corlib_internal)
1006 g_ptr_array_add (assemblies, ass);
1008 mono_domain_assemblies_unlock (domain);
1010 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1011 if (!is_ok (&error))
1013 for (i = 0; i < assemblies->len; ++i) {
1014 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1015 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1016 if (!mono_error_ok (&error))
1018 mono_array_setref (res, i, ass_obj);
1022 g_ptr_array_free (assemblies, TRUE);
1023 if (!mono_error_ok (&error))
1024 mono_error_set_pending_exception (&error);
1028 MonoReflectionAssembly *
1029 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1031 MonoReflectionAssembly *ret;
1034 MonoBoolean isrefonly;
1035 gpointer params [3];
1037 mono_error_init (error);
1039 if (mono_runtime_get_no_exec ())
1042 g_assert (domain != NULL && fname != NULL);
1044 klass = domain->domain->mbr.obj.vtable->klass;
1047 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1048 if (method == NULL) {
1049 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1053 isrefonly = refonly ? 1 : 0;
1056 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1057 return_val_if_nok (error, NULL);
1060 params [2] = &isrefonly;
1062 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1063 return_val_if_nok (error, NULL);
1069 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1073 MonoReflectionAssembly *assembly;
1074 MonoDomain *domain = mono_domain_get ();
1078 aname_str = mono_stringify_assembly_name (aname);
1080 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1081 str = mono_string_new (domain, aname_str);
1087 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1088 mono_error_cleanup (&error);
1091 return assembly->assembly;
1097 * LOCKING: assumes assemblies_lock in the domain is already locked.
1100 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1104 gboolean destroy_ht = FALSE;
1106 if (!ass->aname.name)
1110 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1114 /* FIXME: handle lazy loaded assemblies */
1115 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1116 g_hash_table_insert (ht, tmp->data, tmp->data);
1118 if (!g_hash_table_lookup (ht, ass)) {
1119 mono_assembly_addref (ass);
1120 g_hash_table_insert (ht, ass, ass);
1121 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1122 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);
1125 if (ass->image->references) {
1126 for (i = 0; ass->image->references [i] != NULL; i++) {
1127 if (ass->image->references [i] != REFERENCE_MISSING)
1128 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1129 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1134 g_hash_table_destroy (ht);
1138 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1140 static MonoClassField *assembly_load_field;
1141 static MonoMethod *assembly_load_method;
1143 MonoDomain *domain = mono_domain_get ();
1144 MonoReflectionAssembly *ref_assembly;
1146 gpointer load_value;
1149 if (!domain->domain)
1150 /* This can happen during startup */
1152 #ifdef ASSEMBLY_LOAD_DEBUG
1153 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1155 klass = domain->domain->mbr.obj.vtable->klass;
1157 mono_domain_assemblies_lock (domain);
1158 add_assemblies_to_domain (domain, assembly, NULL);
1159 mono_domain_assemblies_unlock (domain);
1161 if (assembly_load_field == NULL) {
1162 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1163 g_assert (assembly_load_field);
1166 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1167 if (load_value == NULL) {
1168 /* No events waiting to be triggered */
1172 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1173 mono_error_assert_ok (&error);
1175 if (assembly_load_method == NULL) {
1176 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1177 g_assert (assembly_load_method);
1180 *params = ref_assembly;
1182 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1183 mono_error_cleanup (&error);
1187 * LOCKING: Acquires the domain assemblies lock.
1190 set_domain_search_path (MonoDomain *domain)
1193 MonoAppDomainSetup *setup;
1195 gchar *search_path = NULL;
1198 gchar **pvt_split = NULL;
1199 GError *gerror = NULL;
1200 gint appbaselen = -1;
1203 * We use the low-level domain assemblies lock, since this is called from
1204 * assembly loads hooks, which means this thread might hold the loader lock.
1206 mono_domain_assemblies_lock (domain);
1208 if (!domain->setup) {
1209 mono_domain_assemblies_unlock (domain);
1213 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1214 mono_domain_assemblies_unlock (domain);
1217 setup = domain->setup;
1218 if (!setup->application_base) {
1219 mono_domain_assemblies_unlock (domain);
1220 return; /* Must set application base to get private path working */
1225 if (setup->private_bin_path) {
1226 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1227 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1228 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1229 mono_error_cleanup (&error);
1230 mono_domain_assemblies_unlock (domain);
1235 if (domain->private_bin_path) {
1236 if (search_path == NULL)
1237 search_path = domain->private_bin_path;
1239 gchar *tmp2 = search_path;
1240 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1247 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1248 * directories relative to ApplicationBase separated by semicolons (see
1249 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1250 * The loop below copes with the fact that some Unix applications may use ':' (or
1251 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1252 * ';' for the subsequent split.
1254 * The issue was reported in bug #81446
1257 #ifndef TARGET_WIN32
1260 slen = strlen (search_path);
1261 for (i = 0; i < slen; i++)
1262 if (search_path [i] == ':')
1263 search_path [i] = ';';
1266 pvt_split = g_strsplit (search_path, ";", 1000);
1267 g_free (search_path);
1268 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1273 g_strfreev (pvt_split);
1275 * Don't do this because the first time is called, the domain
1276 * setup is not finished.
1278 * domain->search_path = g_malloc (sizeof (char *));
1279 * domain->search_path [0] = NULL;
1281 mono_domain_assemblies_unlock (domain);
1285 if (domain->search_path)
1286 g_strfreev (domain->search_path);
1288 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1289 tmp [npaths] = NULL;
1291 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1292 if (!mono_error_ok (&error)) {
1293 mono_error_cleanup (&error);
1294 g_strfreev (pvt_split);
1297 mono_domain_assemblies_unlock (domain);
1301 domain->search_path = tmp;
1303 /* FIXME: is this needed? */
1304 if (strncmp (*tmp, "file://", 7) == 0) {
1310 uri = g_strdup_printf ("file:///%s", uri + 7);
1313 uri = mono_escape_uri_string (tmpuri);
1314 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1320 if (gerror != NULL) {
1321 g_warning ("%s\n", gerror->message);
1322 g_error_free (gerror);
1329 for (i = 1; pvt_split && i < npaths; i++) {
1330 if (g_path_is_absolute (pvt_split [i - 1])) {
1331 tmp [i] = g_strdup (pvt_split [i - 1]);
1333 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1336 if (strchr (tmp [i], '.')) {
1340 reduced = mono_path_canonicalize (tmp [i]);
1341 if (appbaselen == -1)
1342 appbaselen = strlen (tmp [0]);
1344 if (strncmp (tmp [0], reduced, appbaselen)) {
1347 tmp [i] = g_strdup ("");
1357 if (setup->private_bin_path_probe != NULL) {
1359 tmp [0] = g_strdup ("");
1362 domain->setup->path_changed = FALSE;
1364 g_strfreev (pvt_split);
1366 mono_domain_assemblies_unlock (domain);
1369 #ifdef DISABLE_SHADOW_COPY
1371 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1377 mono_make_shadow_copy (const char *filename, MonoError *error)
1379 mono_error_init (error);
1380 return (char *) filename;
1384 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1386 guint16 *orig, *dest;
1387 gboolean copy_result;
1389 strcpy (src + srclen - tail_len, extension);
1391 if (IS_PORTABILITY_CASE) {
1392 gchar *file = mono_portability_find_file (src, TRUE);
1398 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1402 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1404 strcpy (target + targetlen - tail_len, extension);
1405 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1408 copy_result = CopyFile (orig, dest, FALSE);
1410 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1411 * overwritten when updated in their original locations. */
1413 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1422 get_cstring_hash (const char *str)
1428 if (!str || !str [0])
1433 for (i = 0; i < len; i++) {
1434 h = (h << 5) - h + *p;
1442 * Returned memory is malloc'd. Called must free it
1445 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1447 MonoAppDomainSetup *setup;
1448 char *cache_path, *appname;
1452 mono_error_init (error);
1454 setup = domain->setup;
1455 if (setup->cache_path != NULL && setup->application_name != NULL) {
1456 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1457 return_val_if_nok (error, NULL);
1459 #ifndef TARGET_WIN32
1462 for (i = strlen (cache_path) - 1; i >= 0; i--)
1463 if (cache_path [i] == '\\')
1464 cache_path [i] = '/';
1468 appname = mono_string_to_utf8_checked (setup->application_name, error);
1469 if (!mono_error_ok (error)) {
1470 g_free (cache_path);
1474 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1476 g_free (cache_path);
1478 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1479 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1486 get_shadow_assembly_location (const char *filename, MonoError *error)
1488 gint32 hash = 0, hash2 = 0;
1490 char path_hash [30];
1491 char *bname = g_path_get_basename (filename);
1492 char *dirname = g_path_get_dirname (filename);
1493 char *location, *tmploc;
1494 MonoDomain *domain = mono_domain_get ();
1496 mono_error_init (error);
1498 hash = get_cstring_hash (bname);
1499 hash2 = get_cstring_hash (dirname);
1500 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1501 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1502 tmploc = get_shadow_assembly_location_base (domain, error);
1503 if (!mono_error_ok (error)) {
1509 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1517 ensure_directory_exists (const char *filename)
1520 gchar *dir_utf8 = g_path_get_dirname (filename);
1522 gunichar2 *dir_utf16 = NULL;
1525 if (!dir_utf8 || !dir_utf8 [0])
1528 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1536 /* make life easy and only use one directory seperator */
1547 while (*p++ != '\\')
1553 p = wcschr (p, '\\');
1556 retval = _wmkdir (dir_utf16);
1557 if (retval != 0 && errno != EEXIST) {
1570 gchar *dir = g_path_get_dirname (filename);
1574 if (!dir || !dir [0]) {
1579 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1589 p = strchr (p, '/');
1592 retval = mkdir (dir, 0777);
1593 if (retval != 0 && errno != EEXIST) {
1608 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1610 struct stat sbuf_dest;
1612 gchar *real_src = mono_portability_find_file (src, TRUE);
1615 stat_src = (gchar*)src;
1617 stat_src = real_src;
1619 if (stat (stat_src, sbuf_src) == -1) {
1620 time_t tnow = time (NULL);
1625 memset (sbuf_src, 0, sizeof (*sbuf_src));
1626 sbuf_src->st_mtime = tnow;
1627 sbuf_src->st_atime = tnow;
1634 if (stat (dest, &sbuf_dest) == -1)
1637 if (sbuf_src->st_size == sbuf_dest.st_size &&
1638 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1645 shadow_copy_create_ini (const char *shadow, const char *filename)
1655 dir_name = g_path_get_dirname (shadow);
1656 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1658 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1663 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1668 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1669 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1671 if (handle == INVALID_HANDLE_VALUE) {
1675 full_path = mono_path_resolve_symlinks (filename);
1676 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1678 CloseHandle (handle);
1683 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1686 MonoAppDomainSetup *setup;
1689 gchar **directories;
1690 gchar *shadow_status_string;
1692 gboolean shadow_enabled;
1693 gboolean found = FALSE;
1698 setup = domain->setup;
1699 if (setup == NULL || setup->shadow_copy_files == NULL)
1702 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1703 if (!mono_error_ok (&error)) {
1704 mono_error_cleanup (&error);
1707 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1708 g_free (shadow_status_string);
1710 if (!shadow_enabled)
1713 if (setup->shadow_copy_directories == NULL)
1716 /* Is dir_name a shadow_copy destination already? */
1717 base_dir = get_shadow_assembly_location_base (domain, &error);
1718 if (!mono_error_ok (&error)) {
1719 mono_error_cleanup (&error);
1723 if (strstr (dir_name, base_dir)) {
1729 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1730 if (!mono_error_ok (&error)) {
1731 mono_error_cleanup (&error);
1735 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1736 dir_ptr = directories;
1738 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1744 g_strfreev (directories);
1750 This function raises exceptions so it can cause as sorts of nasty stuff if called
1751 while holding a lock.
1752 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1753 or NULL if source file not found.
1754 FIXME bubble up the error instead of raising it here
1757 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1760 gchar *sibling_source, *sibling_target;
1761 gint sibling_source_len, sibling_target_len;
1762 guint16 *orig, *dest;
1765 gboolean copy_result;
1766 struct stat src_sbuf;
1767 struct utimbuf utbuf;
1768 char *dir_name = g_path_get_dirname (filename);
1769 MonoDomain *domain = mono_domain_get ();
1772 mono_error_init (oerror);
1774 set_domain_search_path (domain);
1776 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1778 return (char *) filename;
1781 /* Is dir_name a shadow_copy destination already? */
1782 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1783 if (!mono_error_ok (&error)) {
1784 mono_error_cleanup (&error);
1786 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1790 if (strstr (dir_name, shadow_dir)) {
1791 g_free (shadow_dir);
1793 return (char *) filename;
1795 g_free (shadow_dir);
1798 shadow = get_shadow_assembly_location (filename, &error);
1799 if (!mono_error_ok (&error)) {
1800 mono_error_cleanup (&error);
1801 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1805 if (ensure_directory_exists (shadow) == FALSE) {
1807 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1811 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1812 return (char*) shadow;
1814 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1815 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1818 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1819 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1820 * and not have it runtime error" */
1821 attrs = GetFileAttributes (orig);
1822 if (attrs == INVALID_FILE_ATTRIBUTES) {
1824 return (char *)filename;
1827 copy_result = CopyFile (orig, dest, FALSE);
1829 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1830 * overwritten when updated in their original locations. */
1832 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1837 if (copy_result == FALSE) {
1840 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1841 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1842 return NULL; /* file not found, shadow copy failed */
1844 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1848 /* attempt to copy .mdb, .config if they exist */
1849 sibling_source = g_strconcat (filename, ".config", NULL);
1850 sibling_source_len = strlen (sibling_source);
1851 sibling_target = g_strconcat (shadow, ".config", NULL);
1852 sibling_target_len = strlen (sibling_target);
1854 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1855 if (copy_result == TRUE)
1856 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1858 g_free (sibling_source);
1859 g_free (sibling_target);
1861 if (copy_result == FALSE) {
1863 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1867 /* Create a .ini file containing the original assembly location */
1868 if (!shadow_copy_create_ini (shadow, filename)) {
1870 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1874 utbuf.actime = src_sbuf.st_atime;
1875 utbuf.modtime = src_sbuf.st_mtime;
1876 utime (shadow, &utbuf);
1880 #endif /* DISABLE_SHADOW_COPY */
1883 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1885 if (appdomain == NULL)
1888 return appdomain->data;
1892 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1893 const gchar *path3, const gchar *path4,
1894 gboolean refonly, gboolean is_private)
1897 gboolean found = FALSE;
1900 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1902 if (IS_PORTABILITY_SET) {
1903 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1906 fullpath = new_fullpath;
1910 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1913 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1916 return (*assembly != NULL);
1919 static MonoAssembly *
1920 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1922 MonoAssembly *result = NULL;
1925 const gchar *local_culture;
1927 gboolean is_private = FALSE;
1929 if (!culture || *culture == '\0') {
1932 local_culture = culture;
1935 filename = g_strconcat (name, ".dll", NULL);
1936 len = strlen (filename);
1938 for (path = search_path; *path; path++) {
1939 if (**path == '\0') {
1941 continue; /* Ignore empty ApplicationBase */
1944 /* See test cases in bug #58992 and bug #57710 */
1945 /* 1st try: [culture]/[name].dll (culture may be empty) */
1946 strcpy (filename + len - 4, ".dll");
1947 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1950 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1951 strcpy (filename + len - 4, ".exe");
1952 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1955 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1956 strcpy (filename + len - 4, ".dll");
1957 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1960 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1961 strcpy (filename + len - 4, ".exe");
1962 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1971 * Try loading the assembly from ApplicationBase and PrivateBinPath
1972 * and then from assemblies_path if any.
1973 * LOCKING: This is called from the assembly loading code, which means the caller
1974 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1976 static MonoAssembly *
1977 mono_domain_assembly_preload (MonoAssemblyName *aname,
1978 gchar **assemblies_path,
1981 MonoDomain *domain = mono_domain_get ();
1982 MonoAssembly *result = NULL;
1983 gboolean refonly = GPOINTER_TO_UINT (user_data);
1985 set_domain_search_path (domain);
1987 if (domain->search_path && domain->search_path [0] != NULL) {
1988 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1991 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1992 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1999 * Check whenever a given assembly was already loaded in the current appdomain.
2001 static MonoAssembly *
2002 mono_domain_assembly_search (MonoAssemblyName *aname,
2005 MonoDomain *domain = mono_domain_get ();
2008 gboolean refonly = GPOINTER_TO_UINT (user_data);
2010 mono_domain_assemblies_lock (domain);
2011 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2012 ass = (MonoAssembly *)tmp->data;
2013 /* Dynamic assemblies can't match here in MS.NET */
2014 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2017 mono_domain_assemblies_unlock (domain);
2020 mono_domain_assemblies_unlock (domain);
2025 MonoReflectionAssembly *
2026 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2029 MonoReflectionAssembly *result;
2030 MonoDomain *domain = mono_domain_get ();
2031 char *name, *filename;
2032 MonoImageOpenStatus status = MONO_IMAGE_OK;
2035 if (fname == NULL) {
2036 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2037 mono_set_pending_exception (exc);
2041 name = filename = mono_string_to_utf8_checked (fname, &error);
2042 if (mono_error_set_pending_exception (&error))
2045 ass = mono_assembly_open_full (filename, &status, refOnly);
2050 if (status == MONO_IMAGE_IMAGE_INVALID)
2051 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2053 exc = mono_get_exception_file_not_found2 (NULL, fname);
2055 mono_set_pending_exception (exc);
2061 result = mono_assembly_get_object_checked (domain, ass, &error);
2063 mono_error_set_pending_exception (&error);
2067 MonoReflectionAssembly *
2068 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2069 MonoArray *raw_assembly,
2070 MonoArray *raw_symbol_store, MonoObject *evidence,
2071 MonoBoolean refonly)
2075 MonoReflectionAssembly *refass = NULL;
2076 MonoDomain *domain = ad->data;
2077 MonoImageOpenStatus status;
2078 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2079 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2082 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2086 if (raw_symbol_store != NULL)
2087 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2089 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2093 mono_image_close (image);
2094 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2098 refass = mono_assembly_get_object_checked (domain, ass, &error);
2100 mono_error_set_pending_exception (&error);
2102 MONO_OBJECT_SETREF (refass, evidence, evidence);
2106 MonoReflectionAssembly *
2107 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2110 MonoDomain *domain = ad->data;
2111 MonoImageOpenStatus status = MONO_IMAGE_OK;
2113 MonoAssemblyName aname;
2114 MonoReflectionAssembly *refass = NULL;
2120 name = mono_string_to_utf8_checked (assRef, &error);
2121 if (mono_error_set_pending_exception (&error))
2123 parsed = mono_assembly_name_parse (name, &aname);
2127 /* This is a parse error... */
2129 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2130 if (!mono_error_ok (&error)) {
2131 mono_error_set_pending_exception (&error);
2138 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2139 mono_assembly_name_free (&aname);
2142 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2144 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2145 if (!mono_error_ok (&error)) {
2146 mono_error_set_pending_exception (&error);
2158 refass = mono_assembly_get_object_checked (domain, ass, &error);
2161 mono_error_set_pending_exception (&error);
2163 MONO_OBJECT_SETREF (refass, evidence, evidence);
2168 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2170 MonoException *exc = NULL;
2171 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2173 if (NULL == domain) {
2174 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2175 mono_set_pending_exception (exc);
2179 if (domain == mono_get_root_domain ()) {
2180 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2185 * Unloading seems to cause problems when running NUnit/NAnt, hence
2188 if (g_getenv ("MONO_NO_UNLOAD"))
2190 #ifdef __native_client__
2194 mono_domain_try_unload (domain, (MonoObject**)&exc);
2196 mono_set_pending_exception (exc);
2200 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2202 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2207 return mono_domain_is_unloading (domain);
2211 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2213 mono_unhandled_exception ((MonoObject*) exc);
2217 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2218 MonoReflectionAssembly *refass, MonoArray *args)
2225 image = refass->assembly->image;
2228 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2231 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2234 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2235 mono_error_assert_ok (&error);
2238 int res = mono_runtime_exec_main_checked (method, (MonoArray *)args, &error);
2239 mono_error_set_pending_exception (&error);
2244 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2246 return ad->data->domain_id;
2250 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2252 MonoDomain *old_domain = mono_domain_get();
2254 if (!mono_domain_set (ad->data, FALSE)) {
2255 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2259 return old_domain->domain;
2263 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2265 MonoDomain *current_domain = mono_domain_get ();
2266 MonoDomain *domain = mono_domain_get_by_id (domainid);
2268 if (!domain || !mono_domain_set (domain, FALSE)) {
2269 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2273 return current_domain->domain;
2277 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2279 mono_thread_push_appdomain_ref (ad->data);
2283 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2285 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2289 * Raise an exception to prevent the managed code from executing a pop
2292 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2296 mono_thread_push_appdomain_ref (domain);
2300 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2302 mono_thread_pop_appdomain_ref ();
2306 ves_icall_System_AppDomain_InternalGetContext ()
2308 return mono_context_get ();
2312 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2314 return mono_domain_get ()->default_context;
2318 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2320 MonoAppContext *old_context = mono_context_get ();
2322 mono_context_set (mc);
2328 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2330 MonoDomain* mono_root_domain = mono_get_root_domain ();
2331 mono_domain_lock (mono_root_domain);
2332 if (process_guid_set) {
2333 mono_domain_unlock (mono_root_domain);
2335 MonoString *res = NULL;
2336 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2337 mono_error_set_pending_exception (&error);
2340 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2341 process_guid_set = TRUE;
2342 mono_domain_unlock (mono_root_domain);
2347 mono_domain_is_unloading (MonoDomain *domain)
2349 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2356 clear_cached_vtable (MonoVTable *vtable)
2358 MonoClass *klass = vtable->klass;
2359 MonoDomain *domain = vtable->domain;
2360 MonoClassRuntimeInfo *runtime_info;
2363 runtime_info = klass->runtime_info;
2364 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2365 runtime_info->domain_vtables [domain->domain_id] = NULL;
2366 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2367 mono_gc_free_fixed (data);
2370 static G_GNUC_UNUSED void
2371 zero_static_data (MonoVTable *vtable)
2373 MonoClass *klass = vtable->klass;
2376 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2377 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2380 typedef struct unload_data {
2383 char *failure_reason;
2388 unload_data_unref (unload_data *data)
2392 mono_atomic_load_acquire (count, gint32, &data->refcount);
2393 g_assert (count >= 1 && count <= 2);
2398 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2402 deregister_reflection_info_roots_from_list (MonoImage *image)
2404 GSList *list = image->reflection_info_unregister_classes;
2407 MonoClass *klass = (MonoClass *)list->data;
2409 mono_class_free_ref_info (klass);
2414 image->reflection_info_unregister_classes = NULL;
2418 deregister_reflection_info_roots (MonoDomain *domain)
2422 mono_domain_assemblies_lock (domain);
2423 for (list = domain->domain_assemblies; list; list = list->next) {
2424 MonoAssembly *assembly = (MonoAssembly *)list->data;
2425 MonoImage *image = assembly->image;
2429 * No need to take the image lock here since dynamic images are appdomain bound and
2430 * at this point the mutator is gone. Taking the image lock here would mean
2431 * promoting it from a simple lock to a complex lock, which we better avoid if
2434 if (image_is_dynamic (image))
2435 deregister_reflection_info_roots_from_list (image);
2437 for (i = 0; i < image->module_count; ++i) {
2438 MonoImage *module = image->modules [i];
2439 if (module && image_is_dynamic (module))
2440 deregister_reflection_info_roots_from_list (module);
2443 mono_domain_assemblies_unlock (domain);
2446 static guint32 WINAPI
2447 unload_thread_main (void *arg)
2450 unload_data *data = (unload_data*)arg;
2451 MonoDomain *domain = data->domain;
2455 /* Have to attach to the runtime so shutdown can wait for this thread */
2456 /* Force it to be attached to avoid racing during shutdown. */
2457 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2459 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2460 if (!is_ok (&error)) {
2461 data->failure_reason = g_strdup (mono_error_get_message (&error));
2462 mono_error_cleanup (&error);
2467 * FIXME: Abort our parent thread last, so we can return a failure
2468 * indication if aborting times out.
2470 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2471 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2475 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2476 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2480 /* Finalize all finalizable objects in the doomed appdomain */
2481 if (!mono_domain_finalize (domain, -1)) {
2482 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2486 /* Clear references to our vtables in class->runtime_info.
2487 * We also hold the loader lock because we're going to change
2488 * class->runtime_info.
2491 mono_loader_lock (); //FIXME why do we need the loader lock here?
2492 mono_domain_lock (domain);
2495 * We need to make sure that we don't have any remsets
2496 * pointing into static data of the to-be-freed domain because
2497 * at the next collections they would be invalid. So what we
2498 * do is we first zero all static data and then do a minor
2499 * collection. Because all references in the static data will
2500 * now be null we won't do any unnecessary copies and after
2501 * the collection there won't be any more remsets.
2503 for (i = 0; i < domain->class_vtable_array->len; ++i)
2504 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2505 mono_gc_collect (0);
2507 for (i = 0; i < domain->class_vtable_array->len; ++i)
2508 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2509 deregister_reflection_info_roots (domain);
2511 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2513 mono_domain_unlock (domain);
2514 mono_loader_unlock ();
2516 mono_threads_clear_cached_culture (domain);
2518 domain->state = MONO_APPDOMAIN_UNLOADED;
2520 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2522 /* remove from the handle table the items related to this domain */
2523 mono_gchandle_free_domain (domain);
2525 mono_domain_free (domain, FALSE);
2527 mono_gc_collect (mono_gc_max_generation ());
2529 mono_atomic_store_release (&data->done, TRUE);
2530 unload_data_unref (data);
2531 mono_thread_detach (thread);
2535 mono_atomic_store_release (&data->done, TRUE);
2536 unload_data_unref (data);
2537 mono_thread_detach (thread);
2542 * mono_domain_unload:
2543 * @domain: The domain to unload
2545 * Unloads an appdomain. Follows the process outlined in the comment
2546 * for mono_domain_try_unload.
2549 mono_domain_unload (MonoDomain *domain)
2551 MonoObject *exc = NULL;
2552 mono_domain_try_unload (domain, &exc);
2556 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2561 result = WaitForSingleObjectEx (handle, timeout, alertable);
2568 * mono_domain_unload:
2569 * @domain: The domain to unload
2570 * @exc: Exception information
2572 * Unloads an appdomain. Follows the process outlined in:
2573 * http://blogs.gotdotnet.com/cbrumme
2575 * If doing things the 'right' way is too hard or complex, we do it the
2576 * 'simple' way, which means do everything needed to avoid crashes and
2577 * memory leaks, but not much else.
2579 * It is required to pass a valid reference to the exc argument, upon return
2580 * from this function *exc will be set to the exception thrown, if any.
2582 * If this method is not called from an icall (embedded scenario for instance),
2583 * it must not be called with any managed frames on the stack, since the unload
2584 * process could end up trying to abort the current thread.
2587 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2590 HANDLE thread_handle;
2591 MonoAppDomainState prev_state;
2593 unload_data *thread_data;
2594 MonoNativeThreadId tid;
2595 MonoDomain *caller_domain = mono_domain_get ();
2597 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2599 /* Atomically change our state to UNLOADING */
2600 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2601 MONO_APPDOMAIN_UNLOADING_START,
2602 MONO_APPDOMAIN_CREATED);
2603 if (prev_state != MONO_APPDOMAIN_CREATED) {
2604 switch (prev_state) {
2605 case MONO_APPDOMAIN_UNLOADING_START:
2606 case MONO_APPDOMAIN_UNLOADING:
2607 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2609 case MONO_APPDOMAIN_UNLOADED:
2610 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2613 g_warning ("Invalid appdomain state %d", prev_state);
2614 g_assert_not_reached ();
2618 mono_domain_set (domain, FALSE);
2619 /* Notify OnDomainUnload listeners */
2620 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2623 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2625 if (!mono_error_ok (&error)) {
2627 mono_error_cleanup (&error);
2629 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2633 /* Roll back the state change */
2634 domain->state = MONO_APPDOMAIN_CREATED;
2635 mono_domain_set (caller_domain, FALSE);
2638 mono_domain_set (caller_domain, FALSE);
2640 thread_data = g_new0 (unload_data, 1);
2641 thread_data->domain = domain;
2642 thread_data->failure_reason = NULL;
2643 thread_data->done = FALSE;
2644 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2646 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2647 domain->state = MONO_APPDOMAIN_UNLOADING;
2649 * First we create a separate thread for unloading, since
2650 * we might have to abort some threads, including the current one.
2652 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2653 if (thread_handle == NULL)
2655 mono_thread_info_resume (tid);
2657 /* Wait for the thread */
2658 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2659 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2660 /* The unload thread tries to abort us */
2661 /* The icall wrapper will execute the abort */
2662 CloseHandle (thread_handle);
2663 unload_data_unref (thread_data);
2667 CloseHandle (thread_handle);
2669 if (thread_data->failure_reason) {
2670 /* Roll back the state change */
2671 domain->state = MONO_APPDOMAIN_CREATED;
2673 g_warning ("%s", thread_data->failure_reason);
2675 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2677 g_free (thread_data->failure_reason);
2678 thread_data->failure_reason = NULL;
2681 unload_data_unref (thread_data);