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/metadata/abi-details.h>
62 #include <mono/utils/mono-uri.h>
63 #include <mono/utils/mono-logger-internals.h>
64 #include <mono/utils/mono-path.h>
65 #include <mono/utils/mono-stdlib.h>
66 #include <mono/utils/mono-io-portability.h>
67 #include <mono/utils/mono-error-internals.h>
68 #include <mono/utils/atomic.h>
69 #include <mono/utils/mono-memory-model.h>
70 #include <mono/utils/mono-threads.h>
71 #include <mono/utils/w32handle.h>
77 * This is the version number of the corlib-runtime interface. When
78 * making changes to this interface (by changing the layout
79 * of classes the runtime knows about, changing icall signature or
80 * semantics etc), increment this variable. Also increment the
81 * pair of this variable in mscorlib in:
82 * mcs/class/corlib/System/Environment.cs
84 * Changes which are already detected at runtime, like the addition
85 * of icalls, do not require an increment.
87 #define MONO_CORLIB_VERSION 158
92 int assemblybinding_count;
97 static gunichar2 process_guid [36];
98 static gboolean process_guid_set = FALSE;
100 static gboolean no_exec = FALSE;
102 static MonoAssembly *
103 mono_domain_assembly_preload (MonoAssemblyName *aname,
104 gchar **assemblies_path,
107 static MonoAssembly *
108 mono_domain_assembly_search (MonoAssemblyName *aname,
112 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
115 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
117 static MonoAppDomain *
118 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
121 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
123 static MonoLoadFunc load_function = NULL;
125 /* Lazy class loading functions */
126 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
129 mono_install_runtime_load (MonoLoadFunc func)
131 load_function = func;
135 mono_runtime_load (const char *filename, const char *runtime_version)
137 g_assert (load_function);
138 return load_function (filename, runtime_version);
142 * mono_runtime_set_no_exec:
144 * Instructs the runtime to operate in static mode, i.e. avoid/do not
145 * allow managed code execution. This is useful for running the AOT
146 * compiler on platforms which allow full-aot execution only. This
147 * should be called before mono_runtime_init ().
150 mono_runtime_set_no_exec (gboolean val)
156 * mono_runtime_get_no_exec:
158 * If true, then the runtime will not allow managed code execution.
161 mono_runtime_get_no_exec (void)
167 create_domain_objects (MonoDomain *domain)
170 MonoDomain *old_domain = mono_domain_get ();
172 MonoVTable *string_vt;
173 MonoClassField *string_empty_fld;
175 if (domain != old_domain) {
176 mono_thread_push_appdomain_ref (domain);
177 mono_domain_set_internal_with_options (domain, FALSE);
181 * Initialize String.Empty. This enables the removal of
182 * the static cctor of the String class.
184 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
185 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
186 g_assert (string_empty_fld);
187 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
188 mono_error_assert_ok (&error);
189 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
192 * Create an instance early since we can't do it when there is no memory.
194 arg = mono_string_new (domain, "Out of memory");
195 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
196 mono_error_assert_ok (&error);
199 * These two are needed because the signal handlers might be executing on
200 * an alternate stack, and Boehm GC can't handle that.
202 arg = mono_string_new (domain, "A null value was found where an object instance was required");
203 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
204 mono_error_assert_ok (&error);
205 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
206 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
207 mono_error_assert_ok (&error);
209 /*The ephemeron tombstone i*/
210 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
211 mono_error_assert_ok (&error);
213 if (domain != old_domain) {
214 mono_thread_pop_appdomain_ref ();
215 mono_domain_set_internal_with_options (old_domain, FALSE);
219 * This class is used during exception handling, so initialize it here, to prevent
220 * stack overflows while handling stack overflows.
222 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
227 * @domain: domain returned by mono_init ()
229 * Initialize the core AppDomain: this function will run also some
230 * IL initialization code, so it needs the execution engine to be fully
233 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
234 * we know the entry_assembly.
238 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
241 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
242 mono_error_cleanup (&error);
246 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
248 MonoAppDomainSetup *setup;
252 mono_error_init (error);
254 mono_portability_helpers_init ();
256 mono_gc_base_init ();
257 mono_monitor_init ();
258 mono_marshal_init ();
260 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
261 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
262 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
263 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
264 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
265 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
266 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
268 mono_thread_init (start_cb, attach_cb);
270 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
271 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
272 return_if_nok (error);
274 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
276 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
277 return_if_nok (error);
281 domain->setup = setup;
283 mono_thread_attach (domain);
285 mono_type_initialization_init ();
287 if (!mono_runtime_get_no_exec ())
288 create_domain_objects (domain);
290 /* GC init has to happen after thread init */
293 /* contexts use GC handles, so they must be initialized after the GC */
294 mono_context_init_checked (domain, error);
295 return_if_nok (error);
296 mono_context_set (domain->default_context);
298 #ifndef DISABLE_SOCKETS
299 mono_network_init ();
302 mono_console_init ();
305 mono_locks_tracer_init ();
307 /* mscorlib is loaded before we install the load hook */
308 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
314 mono_get_corlib_version (void)
318 MonoClassField *field;
321 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
322 mono_class_init (klass);
323 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
326 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
328 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
329 mono_error_assert_ok (&error);
330 return *(gint32*)((gchar*)value + sizeof (MonoObject));
334 * mono_check_corlib_version
336 * Checks that the corlib that is loaded matches the version of this runtime.
338 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
339 * allocated string with the error otherwise.
342 mono_check_corlib_version (void)
344 int version = mono_get_corlib_version ();
345 if (version != MONO_CORLIB_VERSION)
346 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
348 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
349 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
350 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
351 if (native_offset != managed_offset)
352 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
359 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
361 * Initializes the @domain's default System.Runtime.Remoting's Context.
364 mono_context_init (MonoDomain *domain)
367 mono_context_init_checked (domain, &error);
368 mono_error_cleanup (&error);
372 mono_context_init_checked (MonoDomain *domain, MonoError *error)
375 MonoAppContext *context;
377 mono_error_init (error);
379 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
380 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
381 return_if_nok (error);
383 context->domain_id = domain->domain_id;
384 context->context_id = 0;
385 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
386 domain->default_context = context;
390 * mono_runtime_cleanup:
395 * This must not be called while there are still running threads executing
399 mono_runtime_cleanup (MonoDomain *domain)
401 mono_attach_cleanup ();
403 /* This ends up calling any pending pending (for at most 2 seconds) */
406 mono_thread_cleanup ();
408 #ifndef DISABLE_SOCKETS
409 mono_network_cleanup ();
411 mono_marshal_cleanup ();
413 mono_type_initialization_cleanup ();
415 mono_monitor_cleanup ();
418 static MonoDomainFunc quit_function = NULL;
421 mono_install_runtime_cleanup (MonoDomainFunc func)
423 quit_function = func;
429 if (quit_function != NULL)
430 quit_function (mono_get_root_domain (), NULL);
434 * mono_domain_create_appdomain:
435 * @friendly_name: The friendly name of the appdomain to create
436 * @configuration_file: The configuration file to initialize the appdomain with
438 * Returns a MonoDomain initialized with the appdomain
441 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
445 MonoAppDomainSetup *setup;
448 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
449 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
452 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
454 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
458 return mono_domain_from_appdomain (ad);
460 mono_error_cleanup (&error);
465 * mono_domain_set_config:
466 * @domain: MonoDomain initialized with the appdomain we want to change
467 * @base_dir: new base directory for the appdomain
468 * @config_file_name: path to the new configuration for the app domain
470 * Used to set the system configuration for an appdomain
472 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
473 * Error Initializing the configuration system. ---> System.ArgumentException:
474 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
477 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
479 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
480 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
483 static MonoAppDomainSetup*
484 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
486 MonoDomain *caller_domain;
487 MonoClass *ads_class;
488 MonoAppDomainSetup *copy;
490 mono_error_init (error);
492 caller_domain = mono_domain_get ();
493 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
495 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
496 return_val_if_nok (error, NULL);
498 mono_domain_set_internal (domain);
500 #define XCOPY_FIELD(dst,field,src,error) \
502 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
503 return_val_if_nok (error, NULL); \
504 MONO_OBJECT_SETREF ((dst),field,copied_val); \
507 XCOPY_FIELD (copy, application_base, setup->application_base, error);
508 XCOPY_FIELD (copy, application_name, setup->application_name, error);
509 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
510 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
511 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
512 XCOPY_FIELD (copy, license_file, setup->license_file, error);
513 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
514 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
515 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
516 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
517 copy->publisher_policy = setup->publisher_policy;
518 copy->path_changed = setup->path_changed;
519 copy->loader_optimization = setup->loader_optimization;
520 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
521 copy->disallow_code_downloads = setup->disallow_code_downloads;
522 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
523 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
524 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
525 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
526 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
530 mono_domain_set_internal (caller_domain);
535 static MonoAppDomain *
536 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
541 char *shadow_location;
543 mono_error_init (error);
545 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
547 /* FIXME: pin all those objects */
548 data = mono_domain_create();
550 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
551 return_val_if_nok (error, NULL);
554 data->friendly_name = g_strdup (friendly_name);
556 mono_profiler_appdomain_name (data, data->friendly_name);
558 if (!setup->application_base) {
559 /* Inherit from the root domain since MS.NET does this */
560 MonoDomain *root = mono_get_root_domain ();
561 if (root->setup->application_base) {
562 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
563 mono_error_assert_ok (error); /* FIXME don't swallow the error */
564 MONO_OBJECT_SETREF (setup, application_base, s);
568 mono_context_init_checked (data, error);
569 return_val_if_nok (error, NULL);
571 data->setup = copy_app_domain_setup (data, setup, error);
572 if (!mono_error_ok (error)) {
573 g_free (data->friendly_name);
577 mono_domain_set_options_from_config (data);
578 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
580 #ifndef DISABLE_SHADOW_COPY
581 /*FIXME, guard this for when the debugger is not running */
582 shadow_location = get_shadow_assembly_location_base (data, error);
583 if (!mono_error_ok (error)) {
584 g_free (data->friendly_name);
588 g_free (shadow_location);
591 create_domain_objects (data);
597 * mono_domain_has_type_resolve:
598 * @domain: application domains being looked up
600 * Returns: TRUE if the AppDomain.TypeResolve field has been
604 mono_domain_has_type_resolve (MonoDomain *domain)
606 static MonoClassField *field = NULL;
610 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
614 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
618 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
623 * mono_domain_try_type_resolve:
624 * @domain: application domainwhere the name where the type is going to be resolved
625 * @name: the name of the type to resolve or NULL.
626 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
628 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
629 * the assembly that matches name.
631 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
633 * Returns: A MonoReflectionAssembly or NULL if not found
635 MonoReflectionAssembly *
636 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
639 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
640 mono_error_cleanup (&error);
645 MonoReflectionAssembly *
646 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
648 static MonoMethod *method = NULL;
649 MonoReflectionAssembly *ret;
653 mono_error_init (error);
655 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
657 if (method == NULL) {
658 klass = domain->domain->mbr.obj.vtable->klass;
661 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
662 if (method == NULL) {
663 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
669 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
673 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
674 return_val_if_nok (error, NULL);
680 * mono_domain_owns_vtable_slot:
682 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
685 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
689 mono_domain_lock (domain);
690 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
691 mono_domain_unlock (domain);
698 * @force: force setting.
700 * Set the current appdomain to @domain. If @force is set, set it even
701 * if it is being unloaded.
705 * FALSE if the domain is unloaded
708 mono_domain_set (MonoDomain *domain, gboolean force)
710 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
713 mono_domain_set_internal (domain);
719 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
726 MONO_CHECK_ARG_NULL (name, NULL);
732 str = mono_string_to_utf8_checked (name, &error);
733 if (mono_error_set_pending_exception (&error))
736 mono_domain_lock (add);
738 if (!strcmp (str, "APPBASE"))
739 o = (MonoObject *)add->setup->application_base;
740 else if (!strcmp (str, "APP_CONFIG_FILE"))
741 o = (MonoObject *)add->setup->configuration_file;
742 else if (!strcmp (str, "DYNAMIC_BASE"))
743 o = (MonoObject *)add->setup->dynamic_base;
744 else if (!strcmp (str, "APP_NAME"))
745 o = (MonoObject *)add->setup->application_name;
746 else if (!strcmp (str, "CACHE_BASE"))
747 o = (MonoObject *)add->setup->cache_path;
748 else if (!strcmp (str, "PRIVATE_BINPATH"))
749 o = (MonoObject *)add->setup->private_bin_path;
750 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
751 o = (MonoObject *)add->setup->private_bin_path_probe;
752 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
753 o = (MonoObject *)add->setup->shadow_copy_directories;
754 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
755 o = (MonoObject *)add->setup->shadow_copy_files;
757 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
759 mono_domain_unlock (add);
769 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
773 MONO_CHECK_ARG_NULL (name,);
779 mono_domain_lock (add);
781 mono_g_hash_table_insert (add->env, name, data);
783 mono_domain_unlock (add);
787 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
792 return ad->data->setup;
796 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
801 return mono_string_new (ad->data, ad->data->friendly_name);
805 ves_icall_System_AppDomain_getCurDomain ()
807 MonoDomain *add = mono_domain_get ();
813 ves_icall_System_AppDomain_getRootDomain ()
815 MonoDomain *root = mono_get_root_domain ();
821 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
823 MonoDomain *domain = mono_domain_get ();
825 return domain->throw_unobserved_task_exceptions;
829 get_attribute_value (const gchar **attribute_names,
830 const gchar **attribute_values,
831 const char *att_name)
834 for (n = 0; attribute_names [n] != NULL; n++) {
835 if (strcmp (attribute_names [n], att_name) == 0)
836 return g_strdup (attribute_values [n]);
842 start_element (GMarkupParseContext *context,
843 const gchar *element_name,
844 const gchar **attribute_names,
845 const gchar **attribute_values,
849 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
851 if (strcmp (element_name, "runtime") == 0) {
852 runtime_config->runtime_count++;
856 if (strcmp (element_name, "assemblyBinding") == 0) {
857 runtime_config->assemblybinding_count++;
861 if (runtime_config->runtime_count != 1)
864 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
865 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
867 if (value && g_ascii_strcasecmp (value, "true") == 0)
868 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
871 if (runtime_config->assemblybinding_count != 1)
874 if (strcmp (element_name, "probing") != 0)
877 g_free (runtime_config->domain->private_bin_path);
878 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
879 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
880 g_free (runtime_config->domain->private_bin_path);
881 runtime_config->domain->private_bin_path = NULL;
887 end_element (GMarkupParseContext *context,
888 const gchar *element_name,
892 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
893 if (strcmp (element_name, "runtime") == 0)
894 runtime_config->runtime_count--;
895 else if (strcmp (element_name, "assemblyBinding") == 0)
896 runtime_config->assemblybinding_count--;
900 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
902 RuntimeConfig *state = (RuntimeConfig *)user_data;
904 const gchar *filename;
906 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
907 msg = error && error->message ? error->message : "";
908 g_warning ("Error parsing %s: %s", filename, msg);
911 static const GMarkupParser
921 mono_domain_set_options_from_config (MonoDomain *domain)
924 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
926 GMarkupParseContext *context;
927 RuntimeConfig runtime_config;
930 if (!domain || !domain->setup || !domain->setup->configuration_file)
933 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
934 if (!mono_error_ok (&error)) {
935 mono_error_cleanup (&error);
939 config_file_path = mono_portability_find_file (config_file_name, TRUE);
940 if (!config_file_path)
941 config_file_path = config_file_name;
943 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
946 runtime_config.runtime_count = 0;
947 runtime_config.assemblybinding_count = 0;
948 runtime_config.domain = domain;
949 runtime_config.filename = config_file_path;
952 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
953 offset = 3; /* Skip UTF-8 BOM */
955 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
956 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
957 g_markup_parse_context_end_parse (context, NULL);
958 g_markup_parse_context_free (context);
962 if (config_file_name != config_file_path)
963 g_free (config_file_name);
964 g_free (config_file_path);
968 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
971 MonoAppDomain *ad = NULL;
973 #ifdef DISABLE_APPDOMAINS
974 mono_error_init (&error);
975 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
979 fname = mono_string_to_utf8_checked (friendly_name, &error);
980 if (mono_error_set_pending_exception (&error))
982 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
986 mono_error_set_pending_exception (&error);
991 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
994 MonoDomain *domain = ad->data;
999 GPtrArray *assemblies;
1001 mono_error_init (&error);
1004 * Make a copy of the list of assemblies because we can't hold the assemblies
1005 * lock while creating objects etc.
1007 assemblies = g_ptr_array_new ();
1008 /* Need to skip internal assembly builders created by remoting */
1009 mono_domain_assemblies_lock (domain);
1010 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1011 ass = (MonoAssembly *)tmp->data;
1012 if (refonly != ass->ref_only)
1014 if (ass->corlib_internal)
1016 g_ptr_array_add (assemblies, ass);
1018 mono_domain_assemblies_unlock (domain);
1020 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1021 if (!is_ok (&error))
1023 for (i = 0; i < assemblies->len; ++i) {
1024 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1025 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1026 if (!mono_error_ok (&error))
1028 mono_array_setref (res, i, ass_obj);
1032 g_ptr_array_free (assemblies, TRUE);
1033 if (!mono_error_ok (&error))
1034 mono_error_set_pending_exception (&error);
1038 MonoReflectionAssembly *
1039 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1041 MonoReflectionAssembly *ret;
1044 MonoBoolean isrefonly;
1045 gpointer params [3];
1047 mono_error_init (error);
1049 if (mono_runtime_get_no_exec ())
1052 g_assert (domain != NULL && fname != NULL);
1054 klass = domain->domain->mbr.obj.vtable->klass;
1057 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1058 if (method == NULL) {
1059 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1063 isrefonly = refonly ? 1 : 0;
1066 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1067 return_val_if_nok (error, NULL);
1070 params [2] = &isrefonly;
1072 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1073 return_val_if_nok (error, NULL);
1079 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1083 MonoReflectionAssembly *assembly;
1084 MonoDomain *domain = mono_domain_get ();
1088 aname_str = mono_stringify_assembly_name (aname);
1090 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1091 str = mono_string_new (domain, aname_str);
1097 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1098 mono_error_cleanup (&error);
1101 return assembly->assembly;
1107 * LOCKING: assumes assemblies_lock in the domain is already locked.
1110 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1114 gboolean destroy_ht = FALSE;
1116 if (!ass->aname.name)
1120 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1124 /* FIXME: handle lazy loaded assemblies */
1125 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1126 g_hash_table_insert (ht, tmp->data, tmp->data);
1128 if (!g_hash_table_lookup (ht, ass)) {
1129 mono_assembly_addref (ass);
1130 g_hash_table_insert (ht, ass, ass);
1131 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1132 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);
1135 if (ass->image->references) {
1136 for (i = 0; ass->image->references [i] != NULL; i++) {
1137 if (ass->image->references [i] != REFERENCE_MISSING)
1138 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1139 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1144 g_hash_table_destroy (ht);
1148 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1150 static MonoClassField *assembly_load_field;
1151 static MonoMethod *assembly_load_method;
1153 MonoDomain *domain = mono_domain_get ();
1154 MonoReflectionAssembly *ref_assembly;
1156 gpointer load_value;
1159 if (!domain->domain)
1160 /* This can happen during startup */
1162 #ifdef ASSEMBLY_LOAD_DEBUG
1163 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1165 klass = domain->domain->mbr.obj.vtable->klass;
1167 mono_domain_assemblies_lock (domain);
1168 add_assemblies_to_domain (domain, assembly, NULL);
1169 mono_domain_assemblies_unlock (domain);
1171 if (assembly_load_field == NULL) {
1172 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1173 g_assert (assembly_load_field);
1176 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1177 if (load_value == NULL) {
1178 /* No events waiting to be triggered */
1182 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1183 mono_error_assert_ok (&error);
1185 if (assembly_load_method == NULL) {
1186 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1187 g_assert (assembly_load_method);
1190 *params = ref_assembly;
1192 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1193 mono_error_cleanup (&error);
1197 * LOCKING: Acquires the domain assemblies lock.
1200 set_domain_search_path (MonoDomain *domain)
1203 MonoAppDomainSetup *setup;
1205 gchar *search_path = NULL;
1208 gchar **pvt_split = NULL;
1209 GError *gerror = NULL;
1210 gint appbaselen = -1;
1213 * We use the low-level domain assemblies lock, since this is called from
1214 * assembly loads hooks, which means this thread might hold the loader lock.
1216 mono_domain_assemblies_lock (domain);
1218 if (!domain->setup) {
1219 mono_domain_assemblies_unlock (domain);
1223 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1224 mono_domain_assemblies_unlock (domain);
1227 setup = domain->setup;
1228 if (!setup->application_base) {
1229 mono_domain_assemblies_unlock (domain);
1230 return; /* Must set application base to get private path working */
1235 if (setup->private_bin_path) {
1236 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1237 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1238 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1239 mono_error_cleanup (&error);
1240 mono_domain_assemblies_unlock (domain);
1245 if (domain->private_bin_path) {
1246 if (search_path == NULL)
1247 search_path = domain->private_bin_path;
1249 gchar *tmp2 = search_path;
1250 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1257 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1258 * directories relative to ApplicationBase separated by semicolons (see
1259 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1260 * The loop below copes with the fact that some Unix applications may use ':' (or
1261 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1262 * ';' for the subsequent split.
1264 * The issue was reported in bug #81446
1267 #ifndef TARGET_WIN32
1270 slen = strlen (search_path);
1271 for (i = 0; i < slen; i++)
1272 if (search_path [i] == ':')
1273 search_path [i] = ';';
1276 pvt_split = g_strsplit (search_path, ";", 1000);
1277 g_free (search_path);
1278 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1283 g_strfreev (pvt_split);
1285 * Don't do this because the first time is called, the domain
1286 * setup is not finished.
1288 * domain->search_path = g_malloc (sizeof (char *));
1289 * domain->search_path [0] = NULL;
1291 mono_domain_assemblies_unlock (domain);
1295 if (domain->search_path)
1296 g_strfreev (domain->search_path);
1298 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1299 tmp [npaths] = NULL;
1301 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1302 if (!mono_error_ok (&error)) {
1303 mono_error_cleanup (&error);
1304 g_strfreev (pvt_split);
1307 mono_domain_assemblies_unlock (domain);
1311 domain->search_path = tmp;
1313 /* FIXME: is this needed? */
1314 if (strncmp (*tmp, "file://", 7) == 0) {
1320 uri = g_strdup_printf ("file:///%s", uri + 7);
1323 uri = mono_escape_uri_string (tmpuri);
1324 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1330 if (gerror != NULL) {
1331 g_warning ("%s\n", gerror->message);
1332 g_error_free (gerror);
1339 for (i = 1; pvt_split && i < npaths; i++) {
1340 if (g_path_is_absolute (pvt_split [i - 1])) {
1341 tmp [i] = g_strdup (pvt_split [i - 1]);
1343 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1346 if (strchr (tmp [i], '.')) {
1350 reduced = mono_path_canonicalize (tmp [i]);
1351 if (appbaselen == -1)
1352 appbaselen = strlen (tmp [0]);
1354 if (strncmp (tmp [0], reduced, appbaselen)) {
1357 tmp [i] = g_strdup ("");
1367 if (setup->private_bin_path_probe != NULL) {
1369 tmp [0] = g_strdup ("");
1372 domain->setup->path_changed = FALSE;
1374 g_strfreev (pvt_split);
1376 mono_domain_assemblies_unlock (domain);
1379 #ifdef DISABLE_SHADOW_COPY
1381 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1387 mono_make_shadow_copy (const char *filename, MonoError *error)
1389 mono_error_init (error);
1390 return (char *) filename;
1394 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1396 guint16 *orig, *dest;
1397 gboolean copy_result;
1399 strcpy (src + srclen - tail_len, extension);
1401 if (IS_PORTABILITY_CASE) {
1402 gchar *file = mono_portability_find_file (src, TRUE);
1408 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1412 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1414 strcpy (target + targetlen - tail_len, extension);
1415 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1418 copy_result = CopyFile (orig, dest, FALSE);
1420 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1421 * overwritten when updated in their original locations. */
1423 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1432 get_cstring_hash (const char *str)
1438 if (!str || !str [0])
1443 for (i = 0; i < len; i++) {
1444 h = (h << 5) - h + *p;
1452 * Returned memory is malloc'd. Called must free it
1455 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1457 MonoAppDomainSetup *setup;
1458 char *cache_path, *appname;
1462 mono_error_init (error);
1464 setup = domain->setup;
1465 if (setup->cache_path != NULL && setup->application_name != NULL) {
1466 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1467 return_val_if_nok (error, NULL);
1469 #ifndef TARGET_WIN32
1472 for (i = strlen (cache_path) - 1; i >= 0; i--)
1473 if (cache_path [i] == '\\')
1474 cache_path [i] = '/';
1478 appname = mono_string_to_utf8_checked (setup->application_name, error);
1479 if (!mono_error_ok (error)) {
1480 g_free (cache_path);
1484 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1486 g_free (cache_path);
1488 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1489 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1496 get_shadow_assembly_location (const char *filename, MonoError *error)
1498 gint32 hash = 0, hash2 = 0;
1500 char path_hash [30];
1501 char *bname = g_path_get_basename (filename);
1502 char *dirname = g_path_get_dirname (filename);
1503 char *location, *tmploc;
1504 MonoDomain *domain = mono_domain_get ();
1506 mono_error_init (error);
1508 hash = get_cstring_hash (bname);
1509 hash2 = get_cstring_hash (dirname);
1510 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1511 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1512 tmploc = get_shadow_assembly_location_base (domain, error);
1513 if (!mono_error_ok (error)) {
1519 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1527 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1529 struct stat sbuf_dest;
1531 gchar *real_src = mono_portability_find_file (src, TRUE);
1534 stat_src = (gchar*)src;
1536 stat_src = real_src;
1538 if (stat (stat_src, sbuf_src) == -1) {
1539 time_t tnow = time (NULL);
1544 memset (sbuf_src, 0, sizeof (*sbuf_src));
1545 sbuf_src->st_mtime = tnow;
1546 sbuf_src->st_atime = tnow;
1553 if (stat (dest, &sbuf_dest) == -1)
1556 if (sbuf_src->st_size == sbuf_dest.st_size &&
1557 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1564 shadow_copy_create_ini (const char *shadow, const char *filename)
1574 dir_name = g_path_get_dirname (shadow);
1575 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1577 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1582 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1587 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1588 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1590 if (handle == INVALID_HANDLE_VALUE) {
1594 full_path = mono_path_resolve_symlinks (filename);
1595 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1597 CloseHandle (handle);
1602 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1605 MonoAppDomainSetup *setup;
1608 gchar **directories;
1609 gchar *shadow_status_string;
1611 gboolean shadow_enabled;
1612 gboolean found = FALSE;
1617 setup = domain->setup;
1618 if (setup == NULL || setup->shadow_copy_files == NULL)
1621 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1622 if (!mono_error_ok (&error)) {
1623 mono_error_cleanup (&error);
1626 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1627 g_free (shadow_status_string);
1629 if (!shadow_enabled)
1632 if (setup->shadow_copy_directories == NULL)
1635 /* Is dir_name a shadow_copy destination already? */
1636 base_dir = get_shadow_assembly_location_base (domain, &error);
1637 if (!mono_error_ok (&error)) {
1638 mono_error_cleanup (&error);
1642 if (strstr (dir_name, base_dir)) {
1648 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1649 if (!mono_error_ok (&error)) {
1650 mono_error_cleanup (&error);
1654 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1655 dir_ptr = directories;
1657 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1663 g_strfreev (directories);
1669 This function raises exceptions so it can cause as sorts of nasty stuff if called
1670 while holding a lock.
1671 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1672 or NULL if source file not found.
1673 FIXME bubble up the error instead of raising it here
1676 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1679 gchar *sibling_source, *sibling_target;
1680 gint sibling_source_len, sibling_target_len;
1681 guint16 *orig, *dest;
1684 gboolean copy_result;
1685 struct stat src_sbuf;
1686 struct utimbuf utbuf;
1687 char *dir_name = g_path_get_dirname (filename);
1688 MonoDomain *domain = mono_domain_get ();
1691 mono_error_init (oerror);
1693 set_domain_search_path (domain);
1695 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1697 return (char *) filename;
1700 /* Is dir_name a shadow_copy destination already? */
1701 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1702 if (!mono_error_ok (&error)) {
1703 mono_error_cleanup (&error);
1705 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1709 if (strstr (dir_name, shadow_dir)) {
1710 g_free (shadow_dir);
1712 return (char *) filename;
1714 g_free (shadow_dir);
1717 shadow = get_shadow_assembly_location (filename, &error);
1718 if (!mono_error_ok (&error)) {
1719 mono_error_cleanup (&error);
1720 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1724 if (g_ensure_directory_exists (shadow) == FALSE) {
1726 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1730 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1731 return (char*) shadow;
1733 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1734 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1737 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1738 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1739 * and not have it runtime error" */
1740 attrs = GetFileAttributes (orig);
1741 if (attrs == INVALID_FILE_ATTRIBUTES) {
1743 return (char *)filename;
1746 copy_result = CopyFile (orig, dest, FALSE);
1748 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1749 * overwritten when updated in their original locations. */
1751 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1756 if (copy_result == FALSE) {
1759 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1760 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1761 return NULL; /* file not found, shadow copy failed */
1763 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1767 /* attempt to copy .mdb, .config if they exist */
1768 sibling_source = g_strconcat (filename, ".config", NULL);
1769 sibling_source_len = strlen (sibling_source);
1770 sibling_target = g_strconcat (shadow, ".config", NULL);
1771 sibling_target_len = strlen (sibling_target);
1773 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1775 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1777 g_free (sibling_source);
1778 g_free (sibling_target);
1782 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1786 /* Create a .ini file containing the original assembly location */
1787 if (!shadow_copy_create_ini (shadow, filename)) {
1789 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1793 utbuf.actime = src_sbuf.st_atime;
1794 utbuf.modtime = src_sbuf.st_mtime;
1795 utime (shadow, &utbuf);
1799 #endif /* DISABLE_SHADOW_COPY */
1802 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1804 if (appdomain == NULL)
1807 return appdomain->data;
1811 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1812 const gchar *path3, const gchar *path4,
1813 gboolean refonly, gboolean is_private)
1816 gboolean found = FALSE;
1819 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1821 if (IS_PORTABILITY_SET) {
1822 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1825 fullpath = new_fullpath;
1829 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1832 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1835 return (*assembly != NULL);
1838 static MonoAssembly *
1839 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1841 MonoAssembly *result = NULL;
1844 const gchar *local_culture;
1846 gboolean is_private = FALSE;
1848 if (!culture || *culture == '\0') {
1851 local_culture = culture;
1854 filename = g_strconcat (name, ".dll", NULL);
1855 len = strlen (filename);
1857 for (path = search_path; *path; path++) {
1858 if (**path == '\0') {
1860 continue; /* Ignore empty ApplicationBase */
1863 /* See test cases in bug #58992 and bug #57710 */
1864 /* 1st try: [culture]/[name].dll (culture may be empty) */
1865 strcpy (filename + len - 4, ".dll");
1866 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1869 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1870 strcpy (filename + len - 4, ".exe");
1871 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1874 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1875 strcpy (filename + len - 4, ".dll");
1876 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1879 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1880 strcpy (filename + len - 4, ".exe");
1881 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1890 * Try loading the assembly from ApplicationBase and PrivateBinPath
1891 * and then from assemblies_path if any.
1892 * LOCKING: This is called from the assembly loading code, which means the caller
1893 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1895 static MonoAssembly *
1896 mono_domain_assembly_preload (MonoAssemblyName *aname,
1897 gchar **assemblies_path,
1900 MonoDomain *domain = mono_domain_get ();
1901 MonoAssembly *result = NULL;
1902 gboolean refonly = GPOINTER_TO_UINT (user_data);
1904 set_domain_search_path (domain);
1906 if (domain->search_path && domain->search_path [0] != NULL) {
1907 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1910 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1911 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1918 * Check whenever a given assembly was already loaded in the current appdomain.
1920 static MonoAssembly *
1921 mono_domain_assembly_search (MonoAssemblyName *aname,
1924 MonoDomain *domain = mono_domain_get ();
1927 gboolean refonly = GPOINTER_TO_UINT (user_data);
1929 mono_domain_assemblies_lock (domain);
1930 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1931 ass = (MonoAssembly *)tmp->data;
1932 /* Dynamic assemblies can't match here in MS.NET */
1933 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1936 mono_domain_assemblies_unlock (domain);
1939 mono_domain_assemblies_unlock (domain);
1944 MonoReflectionAssembly *
1945 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1948 MonoReflectionAssembly *result;
1949 MonoDomain *domain = mono_domain_get ();
1950 char *name, *filename;
1951 MonoImageOpenStatus status = MONO_IMAGE_OK;
1954 if (fname == NULL) {
1955 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1956 mono_set_pending_exception (exc);
1960 name = filename = mono_string_to_utf8_checked (fname, &error);
1961 if (mono_error_set_pending_exception (&error))
1964 ass = mono_assembly_open_full (filename, &status, refOnly);
1969 if (status == MONO_IMAGE_IMAGE_INVALID)
1970 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1972 exc = mono_get_exception_file_not_found2 (NULL, fname);
1974 mono_set_pending_exception (exc);
1980 result = mono_assembly_get_object_checked (domain, ass, &error);
1982 mono_error_set_pending_exception (&error);
1986 MonoReflectionAssembly *
1987 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1988 MonoArray *raw_assembly,
1989 MonoArray *raw_symbol_store, MonoObject *evidence,
1990 MonoBoolean refonly)
1994 MonoReflectionAssembly *refass = NULL;
1995 MonoDomain *domain = ad->data;
1996 MonoImageOpenStatus status;
1997 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1998 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2001 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2005 if (raw_symbol_store != NULL)
2006 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2008 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2012 mono_image_close (image);
2013 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2017 refass = mono_assembly_get_object_checked (domain, ass, &error);
2019 mono_error_set_pending_exception (&error);
2021 MONO_OBJECT_SETREF (refass, evidence, evidence);
2025 MonoReflectionAssembly *
2026 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2029 MonoDomain *domain = ad->data;
2030 MonoImageOpenStatus status = MONO_IMAGE_OK;
2032 MonoAssemblyName aname;
2033 MonoReflectionAssembly *refass = NULL;
2039 name = mono_string_to_utf8_checked (assRef, &error);
2040 if (mono_error_set_pending_exception (&error))
2042 parsed = mono_assembly_name_parse (name, &aname);
2046 /* This is a parse error... */
2048 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2049 if (!mono_error_ok (&error)) {
2050 mono_error_set_pending_exception (&error);
2057 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2058 mono_assembly_name_free (&aname);
2061 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2063 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2064 if (!mono_error_ok (&error)) {
2065 mono_error_set_pending_exception (&error);
2077 refass = mono_assembly_get_object_checked (domain, ass, &error);
2080 mono_error_set_pending_exception (&error);
2082 MONO_OBJECT_SETREF (refass, evidence, evidence);
2087 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2089 MonoException *exc = NULL;
2090 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2092 if (NULL == domain) {
2093 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2094 mono_set_pending_exception (exc);
2098 if (domain == mono_get_root_domain ()) {
2099 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2104 * Unloading seems to cause problems when running NUnit/NAnt, hence
2107 if (g_getenv ("MONO_NO_UNLOAD"))
2109 #ifdef __native_client__
2113 mono_domain_try_unload (domain, (MonoObject**)&exc);
2115 mono_set_pending_exception (exc);
2119 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2121 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2126 return mono_domain_is_unloading (domain);
2130 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2132 mono_unhandled_exception ((MonoObject*) exc);
2136 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2137 MonoReflectionAssembly *refass, MonoArray *args)
2144 image = refass->assembly->image;
2147 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2150 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2153 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2154 mono_error_assert_ok (&error);
2157 int res = mono_runtime_exec_main_checked (method, (MonoArray *)args, &error);
2158 mono_error_set_pending_exception (&error);
2163 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2165 return ad->data->domain_id;
2169 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2171 MonoDomain *old_domain = mono_domain_get();
2173 if (!mono_domain_set (ad->data, FALSE)) {
2174 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2178 return old_domain->domain;
2182 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2184 MonoDomain *current_domain = mono_domain_get ();
2185 MonoDomain *domain = mono_domain_get_by_id (domainid);
2187 if (!domain || !mono_domain_set (domain, FALSE)) {
2188 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2192 return current_domain->domain;
2196 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2198 mono_thread_push_appdomain_ref (ad->data);
2202 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2204 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2208 * Raise an exception to prevent the managed code from executing a pop
2211 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2215 mono_thread_push_appdomain_ref (domain);
2219 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2221 mono_thread_pop_appdomain_ref ();
2225 ves_icall_System_AppDomain_InternalGetContext ()
2227 return mono_context_get ();
2231 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2233 return mono_domain_get ()->default_context;
2237 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2239 MonoAppContext *old_context = mono_context_get ();
2241 mono_context_set (mc);
2247 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2249 MonoDomain* mono_root_domain = mono_get_root_domain ();
2250 mono_domain_lock (mono_root_domain);
2251 if (process_guid_set) {
2252 mono_domain_unlock (mono_root_domain);
2254 MonoString *res = NULL;
2255 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2256 mono_error_set_pending_exception (&error);
2259 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2260 process_guid_set = TRUE;
2261 mono_domain_unlock (mono_root_domain);
2266 mono_domain_is_unloading (MonoDomain *domain)
2268 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2275 clear_cached_vtable (MonoVTable *vtable)
2277 MonoClass *klass = vtable->klass;
2278 MonoDomain *domain = vtable->domain;
2279 MonoClassRuntimeInfo *runtime_info;
2282 runtime_info = klass->runtime_info;
2283 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2284 runtime_info->domain_vtables [domain->domain_id] = NULL;
2285 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2286 mono_gc_free_fixed (data);
2289 static G_GNUC_UNUSED void
2290 zero_static_data (MonoVTable *vtable)
2292 MonoClass *klass = vtable->klass;
2295 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2296 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2299 typedef struct unload_data {
2302 char *failure_reason;
2307 unload_data_unref (unload_data *data)
2311 mono_atomic_load_acquire (count, gint32, &data->refcount);
2312 g_assert (count >= 1 && count <= 2);
2317 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2321 deregister_reflection_info_roots_from_list (MonoImage *image)
2323 GSList *list = image->reflection_info_unregister_classes;
2326 MonoClass *klass = (MonoClass *)list->data;
2328 mono_class_free_ref_info (klass);
2333 image->reflection_info_unregister_classes = NULL;
2337 deregister_reflection_info_roots (MonoDomain *domain)
2341 mono_domain_assemblies_lock (domain);
2342 for (list = domain->domain_assemblies; list; list = list->next) {
2343 MonoAssembly *assembly = (MonoAssembly *)list->data;
2344 MonoImage *image = assembly->image;
2348 * No need to take the image lock here since dynamic images are appdomain bound and
2349 * at this point the mutator is gone. Taking the image lock here would mean
2350 * promoting it from a simple lock to a complex lock, which we better avoid if
2353 if (image_is_dynamic (image))
2354 deregister_reflection_info_roots_from_list (image);
2356 for (i = 0; i < image->module_count; ++i) {
2357 MonoImage *module = image->modules [i];
2358 if (module && image_is_dynamic (module))
2359 deregister_reflection_info_roots_from_list (module);
2362 mono_domain_assemblies_unlock (domain);
2366 unload_thread_main (void *arg)
2369 unload_data *data = (unload_data*)arg;
2370 MonoDomain *domain = data->domain;
2374 /* Have to attach to the runtime so shutdown can wait for this thread */
2375 /* Force it to be attached to avoid racing during shutdown. */
2376 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2378 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2379 if (!is_ok (&error)) {
2380 data->failure_reason = g_strdup (mono_error_get_message (&error));
2381 mono_error_cleanup (&error);
2386 * FIXME: Abort our parent thread last, so we can return a failure
2387 * indication if aborting times out.
2389 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2390 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2394 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2395 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2399 /* Finalize all finalizable objects in the doomed appdomain */
2400 if (!mono_domain_finalize (domain, -1)) {
2401 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2405 /* Clear references to our vtables in class->runtime_info.
2406 * We also hold the loader lock because we're going to change
2407 * class->runtime_info.
2410 mono_loader_lock (); //FIXME why do we need the loader lock here?
2411 mono_domain_lock (domain);
2414 * We need to make sure that we don't have any remsets
2415 * pointing into static data of the to-be-freed domain because
2416 * at the next collections they would be invalid. So what we
2417 * do is we first zero all static data and then do a minor
2418 * collection. Because all references in the static data will
2419 * now be null we won't do any unnecessary copies and after
2420 * the collection there won't be any more remsets.
2422 for (i = 0; i < domain->class_vtable_array->len; ++i)
2423 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2424 mono_gc_collect (0);
2426 for (i = 0; i < domain->class_vtable_array->len; ++i)
2427 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2428 deregister_reflection_info_roots (domain);
2430 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2432 mono_domain_unlock (domain);
2433 mono_loader_unlock ();
2435 mono_threads_clear_cached_culture (domain);
2437 domain->state = MONO_APPDOMAIN_UNLOADED;
2439 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2441 /* remove from the handle table the items related to this domain */
2442 mono_gchandle_free_domain (domain);
2444 mono_domain_free (domain, FALSE);
2446 mono_gc_collect (mono_gc_max_generation ());
2448 mono_atomic_store_release (&data->done, TRUE);
2449 unload_data_unref (data);
2450 mono_thread_detach (thread);
2454 mono_atomic_store_release (&data->done, TRUE);
2455 unload_data_unref (data);
2456 mono_thread_detach (thread);
2461 * mono_domain_unload:
2462 * @domain: The domain to unload
2464 * Unloads an appdomain. Follows the process outlined in the comment
2465 * for mono_domain_try_unload.
2468 mono_domain_unload (MonoDomain *domain)
2470 MonoObject *exc = NULL;
2471 mono_domain_try_unload (domain, &exc);
2475 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2480 result = WaitForSingleObjectEx (handle, timeout, alertable);
2487 * mono_domain_unload:
2488 * @domain: The domain to unload
2489 * @exc: Exception information
2491 * Unloads an appdomain. Follows the process outlined in:
2492 * http://blogs.gotdotnet.com/cbrumme
2494 * If doing things the 'right' way is too hard or complex, we do it the
2495 * 'simple' way, which means do everything needed to avoid crashes and
2496 * memory leaks, but not much else.
2498 * It is required to pass a valid reference to the exc argument, upon return
2499 * from this function *exc will be set to the exception thrown, if any.
2501 * If this method is not called from an icall (embedded scenario for instance),
2502 * it must not be called with any managed frames on the stack, since the unload
2503 * process could end up trying to abort the current thread.
2506 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2509 HANDLE thread_handle;
2510 MonoAppDomainState prev_state;
2512 unload_data *thread_data;
2513 MonoNativeThreadId tid;
2514 MonoDomain *caller_domain = mono_domain_get ();
2516 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2518 /* Atomically change our state to UNLOADING */
2519 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2520 MONO_APPDOMAIN_UNLOADING_START,
2521 MONO_APPDOMAIN_CREATED);
2522 if (prev_state != MONO_APPDOMAIN_CREATED) {
2523 switch (prev_state) {
2524 case MONO_APPDOMAIN_UNLOADING_START:
2525 case MONO_APPDOMAIN_UNLOADING:
2526 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2528 case MONO_APPDOMAIN_UNLOADED:
2529 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2532 g_warning ("Invalid appdomain state %d", prev_state);
2533 g_assert_not_reached ();
2537 mono_domain_set (domain, FALSE);
2538 /* Notify OnDomainUnload listeners */
2539 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2542 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2544 if (!mono_error_ok (&error)) {
2546 mono_error_cleanup (&error);
2548 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2552 /* Roll back the state change */
2553 domain->state = MONO_APPDOMAIN_CREATED;
2554 mono_domain_set (caller_domain, FALSE);
2557 mono_domain_set (caller_domain, FALSE);
2559 thread_data = g_new0 (unload_data, 1);
2560 thread_data->domain = domain;
2561 thread_data->failure_reason = NULL;
2562 thread_data->done = FALSE;
2563 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2565 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2566 domain->state = MONO_APPDOMAIN_UNLOADING;
2568 * First we create a separate thread for unloading, since
2569 * we might have to abort some threads, including the current one.
2571 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, 0, &tid);
2572 if (thread_handle == NULL)
2575 /* Wait for the thread */
2576 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2577 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2578 /* The unload thread tries to abort us */
2579 /* The icall wrapper will execute the abort */
2580 mono_threads_close_thread_handle (thread_handle);
2581 unload_data_unref (thread_data);
2586 mono_threads_close_thread_handle (thread_handle);
2588 if (thread_data->failure_reason) {
2589 /* Roll back the state change */
2590 domain->state = MONO_APPDOMAIN_CREATED;
2592 g_warning ("%s", thread_data->failure_reason);
2594 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2596 g_free (thread_data->failure_reason);
2597 thread_data->failure_reason = NULL;
2600 unload_data_unref (thread_data);