2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
13 #undef ASSEMBLY_LOAD_DEBUG
19 #include <sys/types.h>
21 #ifdef HAVE_SYS_TIME_H
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
35 #include <mono/metadata/gc-internals.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/threadpool-ms.h>
43 #include <mono/metadata/socket-io.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/gc-internals.h>
46 #include <mono/metadata/mono-gc.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/monitor.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/reflection-internals.h>
59 #include <mono/utils/mono-uri.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-path.h>
62 #include <mono/utils/mono-stdlib.h>
63 #include <mono/utils/mono-io-portability.h>
64 #include <mono/utils/mono-error-internals.h>
65 #include <mono/utils/atomic.h>
66 #include <mono/utils/mono-memory-model.h>
67 #include <mono/utils/mono-threads.h>
73 * This is the version number of the corlib-runtime interface. When
74 * making changes to this interface (by changing the layout
75 * of classes the runtime knows about, changing icall signature or
76 * semantics etc), increment this variable. Also increment the
77 * pair of this variable in mscorlib in:
78 * mcs/class/corlib/System/Environment.cs
80 * Changes which are already detected at runtime, like the addition
81 * of icalls, do not require an increment.
83 #define MONO_CORLIB_VERSION 142
88 int assemblybinding_count;
93 static gunichar2 process_guid [36];
94 static gboolean process_guid_set = FALSE;
96 static gboolean no_exec = FALSE;
99 mono_domain_assembly_preload (MonoAssemblyName *aname,
100 gchar **assemblies_path,
103 static MonoAssembly *
104 mono_domain_assembly_search (MonoAssemblyName *aname,
108 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
111 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
113 static MonoAppDomain *
114 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
117 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
119 static MonoLoadFunc load_function = NULL;
121 /* Lazy class loading functions */
122 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
125 mono_install_runtime_load (MonoLoadFunc func)
127 load_function = func;
131 mono_runtime_load (const char *filename, const char *runtime_version)
133 g_assert (load_function);
134 return load_function (filename, runtime_version);
138 * mono_runtime_set_no_exec:
140 * Instructs the runtime to operate in static mode, i.e. avoid/do not
141 * allow managed code execution. This is useful for running the AOT
142 * compiler on platforms which allow full-aot execution only. This
143 * should be called before mono_runtime_init ().
146 mono_runtime_set_no_exec (gboolean val)
152 * mono_runtime_get_no_exec:
154 * If true, then the runtime will not allow managed code execution.
157 mono_runtime_get_no_exec (void)
163 create_domain_objects (MonoDomain *domain)
166 MonoDomain *old_domain = mono_domain_get ();
168 MonoVTable *string_vt;
169 MonoClassField *string_empty_fld;
171 if (domain != old_domain) {
172 mono_thread_push_appdomain_ref (domain);
173 mono_domain_set_internal_with_options (domain, FALSE);
177 * Initialize String.Empty. This enables the removal of
178 * the static cctor of the String class.
180 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
181 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
182 g_assert (string_empty_fld);
183 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
186 * Create an instance early since we can't do it when there is no memory.
188 arg = mono_string_new (domain, "Out of memory");
189 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
192 * These two are needed because the signal handlers might be executing on
193 * an alternate stack, and Boehm GC can't handle that.
195 arg = mono_string_new (domain, "A null value was found where an object instance was required");
196 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
197 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
198 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
200 /*The ephemeron tombstone i*/
201 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
202 mono_error_assert_ok (&error);
204 if (domain != old_domain) {
205 mono_thread_pop_appdomain_ref ();
206 mono_domain_set_internal_with_options (old_domain, FALSE);
210 * This class is used during exception handling, so initialize it here, to prevent
211 * stack overflows while handling stack overflows.
213 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
218 * @domain: domain returned by mono_init ()
220 * Initialize the core AppDomain: this function will run also some
221 * IL initialization code, so it needs the execution engine to be fully
224 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
225 * we know the entry_assembly.
229 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
232 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
233 mono_error_cleanup (&error);
237 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
239 MonoAppDomainSetup *setup;
243 mono_error_init (error);
245 mono_portability_helpers_init ();
247 mono_gc_base_init ();
248 mono_monitor_init ();
249 mono_marshal_init ();
251 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
252 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
253 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
254 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
255 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
256 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
257 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
258 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
260 mono_thread_init (start_cb, attach_cb);
262 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
263 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
264 return_if_nok (error);
266 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
268 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
269 return_if_nok (error);
273 domain->setup = setup;
275 mono_thread_attach (domain);
277 mono_type_initialization_init ();
279 if (!mono_runtime_get_no_exec ())
280 create_domain_objects (domain);
282 /* GC init has to happen after thread init */
285 /* contexts use GC handles, so they must be initialized after the GC */
286 mono_context_init_checked (domain, error);
287 return_if_nok (error);
288 mono_context_set (domain->default_context);
290 #ifndef DISABLE_SOCKETS
291 mono_network_init ();
294 mono_console_init ();
297 mono_locks_tracer_init ();
299 /* mscorlib is loaded before we install the load hook */
300 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
306 mono_get_corlib_version (void)
309 MonoClassField *field;
312 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
313 mono_class_init (klass);
314 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
317 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
319 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
320 return *(gint32*)((gchar*)value + sizeof (MonoObject));
324 * mono_check_corlib_version
326 * Checks that the corlib that is loaded matches the version of this runtime.
328 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
329 * allocated string with the error otherwise.
332 mono_check_corlib_version (void)
334 int version = mono_get_corlib_version ();
335 if (version != MONO_CORLIB_VERSION)
336 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
343 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
345 * Initializes the @domain's default System.Runtime.Remoting's Context.
348 mono_context_init (MonoDomain *domain)
351 mono_context_init_checked (domain, &error);
352 mono_error_cleanup (&error);
356 mono_context_init_checked (MonoDomain *domain, MonoError *error)
359 MonoAppContext *context;
361 mono_error_init (error);
363 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
364 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
365 return_if_nok (error);
367 context->domain_id = domain->domain_id;
368 context->context_id = 0;
369 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
370 domain->default_context = context;
374 * mono_runtime_cleanup:
379 * This must not be called while there are still running threads executing
383 mono_runtime_cleanup (MonoDomain *domain)
385 mono_attach_cleanup ();
387 /* This ends up calling any pending pending (for at most 2 seconds) */
390 mono_thread_cleanup ();
392 #ifndef DISABLE_SOCKETS
393 mono_network_cleanup ();
395 mono_marshal_cleanup ();
397 mono_type_initialization_cleanup ();
399 mono_monitor_cleanup ();
402 static MonoDomainFunc quit_function = NULL;
405 mono_install_runtime_cleanup (MonoDomainFunc func)
407 quit_function = func;
413 if (quit_function != NULL)
414 quit_function (mono_get_root_domain (), NULL);
418 * mono_domain_create_appdomain:
419 * @friendly_name: The friendly name of the appdomain to create
420 * @configuration_file: The configuration file to initialize the appdomain with
422 * Returns a MonoDomain initialized with the appdomain
425 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
429 MonoAppDomainSetup *setup;
432 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
433 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
434 mono_error_raise_exception (&error); /* FIXME don't raise here */
435 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
437 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
438 mono_error_raise_exception (&error); /* FIXME don't raise here */
440 return mono_domain_from_appdomain (ad);
444 * mono_domain_set_config:
445 * @domain: MonoDomain initialized with the appdomain we want to change
446 * @base_dir: new base directory for the appdomain
447 * @config_file_name: path to the new configuration for the app domain
449 * Used to set the system configuration for an appdomain
451 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
452 * Error Initializing the configuration system. ---> System.ArgumentException:
453 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
456 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
458 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
459 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
462 static MonoAppDomainSetup*
463 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
465 MonoDomain *caller_domain;
466 MonoClass *ads_class;
467 MonoAppDomainSetup *copy;
469 mono_error_init (error);
471 caller_domain = mono_domain_get ();
472 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
474 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
475 return_val_if_nok (error, NULL);
477 mono_domain_set_internal (domain);
479 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
480 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
481 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
482 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
483 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
484 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
485 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
486 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
487 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
488 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
489 copy->publisher_policy = setup->publisher_policy;
490 copy->path_changed = setup->path_changed;
491 copy->loader_optimization = setup->loader_optimization;
492 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
493 copy->disallow_code_downloads = setup->disallow_code_downloads;
494 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
495 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
496 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
497 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
498 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
500 mono_domain_set_internal (caller_domain);
505 static MonoAppDomain *
506 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
511 char *shadow_location;
513 mono_error_init (error);
515 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
517 /* FIXME: pin all those objects */
518 data = mono_domain_create();
520 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
521 return_val_if_nok (error, NULL);
524 data->friendly_name = g_strdup (friendly_name);
526 mono_profiler_appdomain_name (data, data->friendly_name);
528 if (!setup->application_base) {
529 /* Inherit from the root domain since MS.NET does this */
530 MonoDomain *root = mono_get_root_domain ();
531 if (root->setup->application_base) {
532 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
533 mono_error_assert_ok (error); /* FIXME don't swallow the error */
534 MONO_OBJECT_SETREF (setup, application_base, s);
538 mono_context_init_checked (data, error);
539 return_val_if_nok (error, NULL);
541 data->setup = copy_app_domain_setup (data, setup, error);
542 if (!mono_error_ok (error)) {
543 g_free (data->friendly_name);
547 mono_domain_set_options_from_config (data);
548 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
550 #ifndef DISABLE_SHADOW_COPY
551 /*FIXME, guard this for when the debugger is not running */
552 shadow_location = get_shadow_assembly_location_base (data, error);
553 if (!mono_error_ok (error)) {
554 g_free (data->friendly_name);
558 g_free (shadow_location);
561 create_domain_objects (data);
567 * mono_domain_has_type_resolve:
568 * @domain: application domains being looked up
570 * Returns: TRUE if the AppDomain.TypeResolve field has been
574 mono_domain_has_type_resolve (MonoDomain *domain)
576 static MonoClassField *field = NULL;
580 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
584 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
588 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
593 * mono_domain_try_type_resolve:
594 * @domain: application domainwhere the name where the type is going to be resolved
595 * @name: the name of the type to resolve or NULL.
596 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
598 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
599 * the assembly that matches name.
601 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
603 * Returns: A MonoReflectionAssembly or NULL if not found
605 MonoReflectionAssembly *
606 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
609 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
610 mono_error_cleanup (&error);
615 MonoReflectionAssembly *
616 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
618 static MonoMethod *method = NULL;
619 MonoReflectionAssembly *ret;
623 mono_error_init (error);
625 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
627 if (method == NULL) {
628 klass = domain->domain->mbr.obj.vtable->klass;
631 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
632 if (method == NULL) {
633 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
639 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
643 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
644 return_val_if_nok (error, NULL);
650 * mono_domain_owns_vtable_slot:
652 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
655 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
659 mono_domain_lock (domain);
660 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
661 mono_domain_unlock (domain);
668 * @force: force setting.
670 * Set the current appdomain to @domain. If @force is set, set it even
671 * if it is being unloaded.
675 * FALSE if the domain is unloaded
678 mono_domain_set (MonoDomain *domain, gboolean force)
680 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
683 mono_domain_set_internal (domain);
689 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
695 MONO_CHECK_ARG_NULL (name, NULL);
701 str = mono_string_to_utf8 (name);
703 mono_domain_lock (add);
705 if (!strcmp (str, "APPBASE"))
706 o = (MonoObject *)add->setup->application_base;
707 else if (!strcmp (str, "APP_CONFIG_FILE"))
708 o = (MonoObject *)add->setup->configuration_file;
709 else if (!strcmp (str, "DYNAMIC_BASE"))
710 o = (MonoObject *)add->setup->dynamic_base;
711 else if (!strcmp (str, "APP_NAME"))
712 o = (MonoObject *)add->setup->application_name;
713 else if (!strcmp (str, "CACHE_BASE"))
714 o = (MonoObject *)add->setup->cache_path;
715 else if (!strcmp (str, "PRIVATE_BINPATH"))
716 o = (MonoObject *)add->setup->private_bin_path;
717 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
718 o = (MonoObject *)add->setup->private_bin_path_probe;
719 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
720 o = (MonoObject *)add->setup->shadow_copy_directories;
721 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
722 o = (MonoObject *)add->setup->shadow_copy_files;
724 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
726 mono_domain_unlock (add);
736 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
740 MONO_CHECK_ARG_NULL (name,);
746 mono_domain_lock (add);
748 mono_g_hash_table_insert (add->env, name, data);
750 mono_domain_unlock (add);
754 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
759 return ad->data->setup;
763 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
768 return mono_string_new (ad->data, ad->data->friendly_name);
772 ves_icall_System_AppDomain_getCurDomain ()
774 MonoDomain *add = mono_domain_get ();
780 ves_icall_System_AppDomain_getRootDomain ()
782 MonoDomain *root = mono_get_root_domain ();
788 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
790 MonoDomain *domain = mono_domain_get ();
792 return domain->throw_unobserved_task_exceptions;
796 get_attribute_value (const gchar **attribute_names,
797 const gchar **attribute_values,
798 const char *att_name)
801 for (n = 0; attribute_names [n] != NULL; n++) {
802 if (strcmp (attribute_names [n], att_name) == 0)
803 return g_strdup (attribute_values [n]);
809 start_element (GMarkupParseContext *context,
810 const gchar *element_name,
811 const gchar **attribute_names,
812 const gchar **attribute_values,
816 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
818 if (strcmp (element_name, "runtime") == 0) {
819 runtime_config->runtime_count++;
823 if (strcmp (element_name, "assemblyBinding") == 0) {
824 runtime_config->assemblybinding_count++;
828 if (runtime_config->runtime_count != 1)
831 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
832 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
834 if (value && g_ascii_strcasecmp (value, "true") == 0)
835 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
838 if (runtime_config->assemblybinding_count != 1)
841 if (strcmp (element_name, "probing") != 0)
844 g_free (runtime_config->domain->private_bin_path);
845 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
846 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
847 g_free (runtime_config->domain->private_bin_path);
848 runtime_config->domain->private_bin_path = NULL;
854 end_element (GMarkupParseContext *context,
855 const gchar *element_name,
859 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
860 if (strcmp (element_name, "runtime") == 0)
861 runtime_config->runtime_count--;
862 else if (strcmp (element_name, "assemblyBinding") == 0)
863 runtime_config->assemblybinding_count--;
867 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
869 RuntimeConfig *state = (RuntimeConfig *)user_data;
871 const gchar *filename;
873 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
874 msg = error && error->message ? error->message : "";
875 g_warning ("Error parsing %s: %s", filename, msg);
878 static const GMarkupParser
888 mono_domain_set_options_from_config (MonoDomain *domain)
891 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
893 GMarkupParseContext *context;
894 RuntimeConfig runtime_config;
897 if (!domain || !domain->setup || !domain->setup->configuration_file)
900 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
901 if (!mono_error_ok (&error)) {
902 mono_error_cleanup (&error);
906 config_file_path = mono_portability_find_file (config_file_name, TRUE);
907 if (!config_file_path)
908 config_file_path = config_file_name;
910 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
913 runtime_config.runtime_count = 0;
914 runtime_config.assemblybinding_count = 0;
915 runtime_config.domain = domain;
916 runtime_config.filename = config_file_path;
919 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
920 offset = 3; /* Skip UTF-8 BOM */
922 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
923 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
924 g_markup_parse_context_end_parse (context, NULL);
925 g_markup_parse_context_free (context);
929 if (config_file_name != config_file_path)
930 g_free (config_file_name);
931 g_free (config_file_path);
935 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
937 #ifdef DISABLE_APPDOMAINS
938 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
945 fname = mono_string_to_utf8 (friendly_name);
946 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
950 mono_error_raise_exception (&error);
957 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
960 MonoDomain *domain = ad->data;
965 GPtrArray *assemblies;
967 mono_error_init (&error);
970 * Make a copy of the list of assemblies because we can't hold the assemblies
971 * lock while creating objects etc.
973 assemblies = g_ptr_array_new ();
974 /* Need to skip internal assembly builders created by remoting */
975 mono_domain_assemblies_lock (domain);
976 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
977 ass = (MonoAssembly *)tmp->data;
978 if (refonly != ass->ref_only)
980 if (ass->corlib_internal)
982 g_ptr_array_add (assemblies, ass);
984 mono_domain_assemblies_unlock (domain);
986 res = mono_array_new (domain, mono_class_get_assembly_class (), assemblies->len);
987 for (i = 0; i < assemblies->len; ++i) {
988 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
989 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
990 if (!mono_error_ok (&error))
992 mono_array_setref (res, i, ass_obj);
996 g_ptr_array_free (assemblies, TRUE);
997 if (!mono_error_ok (&error))
998 mono_error_set_pending_exception (&error);
1002 MonoReflectionAssembly *
1003 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1005 MonoReflectionAssembly *ret;
1008 MonoBoolean isrefonly;
1009 gpointer params [3];
1011 mono_error_init (error);
1013 if (mono_runtime_get_no_exec ())
1016 g_assert (domain != NULL && fname != NULL);
1018 klass = domain->domain->mbr.obj.vtable->klass;
1021 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1022 if (method == NULL) {
1023 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1027 isrefonly = refonly ? 1 : 0;
1030 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1031 return_val_if_nok (error, NULL);
1034 params [2] = &isrefonly;
1036 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1037 return_val_if_nok (error, NULL);
1043 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1047 MonoReflectionAssembly *assembly;
1048 MonoDomain *domain = mono_domain_get ();
1052 aname_str = mono_stringify_assembly_name (aname);
1054 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1055 str = mono_string_new (domain, aname_str);
1061 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1062 if (!mono_error_ok (&error)) {
1064 mono_error_raise_exception (&error); /* FIXME don't raise here */
1070 return assembly->assembly;
1076 * LOCKING: assumes assemblies_lock in the domain is already locked.
1079 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1083 gboolean destroy_ht = FALSE;
1085 if (!ass->aname.name)
1089 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1093 /* FIXME: handle lazy loaded assemblies */
1094 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1095 g_hash_table_insert (ht, tmp->data, tmp->data);
1097 if (!g_hash_table_lookup (ht, ass)) {
1098 mono_assembly_addref (ass);
1099 g_hash_table_insert (ht, ass, ass);
1100 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1101 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);
1104 if (ass->image->references) {
1105 for (i = 0; ass->image->references [i] != NULL; i++) {
1106 if (ass->image->references [i] != REFERENCE_MISSING)
1107 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1108 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1113 g_hash_table_destroy (ht);
1117 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1119 static MonoClassField *assembly_load_field;
1120 static MonoMethod *assembly_load_method;
1122 MonoDomain *domain = mono_domain_get ();
1123 MonoReflectionAssembly *ref_assembly;
1125 gpointer load_value;
1128 if (!domain->domain)
1129 /* This can happen during startup */
1131 #ifdef ASSEMBLY_LOAD_DEBUG
1132 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1134 klass = domain->domain->mbr.obj.vtable->klass;
1136 mono_domain_assemblies_lock (domain);
1137 add_assemblies_to_domain (domain, assembly, NULL);
1138 mono_domain_assemblies_unlock (domain);
1140 if (assembly_load_field == NULL) {
1141 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1142 g_assert (assembly_load_field);
1145 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1146 if (load_value == NULL) {
1147 /* No events waiting to be triggered */
1151 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1152 mono_error_assert_ok (&error);
1154 if (assembly_load_method == NULL) {
1155 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1156 g_assert (assembly_load_method);
1159 *params = ref_assembly;
1161 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1162 mono_error_raise_exception (&error); /* FIXME don't raise here */
1166 * LOCKING: Acquires the domain assemblies lock.
1169 set_domain_search_path (MonoDomain *domain)
1172 MonoAppDomainSetup *setup;
1174 gchar *search_path = NULL;
1177 gchar **pvt_split = NULL;
1178 GError *gerror = NULL;
1179 gint appbaselen = -1;
1182 * We use the low-level domain assemblies lock, since this is called from
1183 * assembly loads hooks, which means this thread might hold the loader lock.
1185 mono_domain_assemblies_lock (domain);
1187 if (!domain->setup) {
1188 mono_domain_assemblies_unlock (domain);
1192 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1193 mono_domain_assemblies_unlock (domain);
1196 setup = domain->setup;
1197 if (!setup->application_base) {
1198 mono_domain_assemblies_unlock (domain);
1199 return; /* Must set application base to get private path working */
1204 if (setup->private_bin_path) {
1205 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1206 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1207 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1208 mono_error_cleanup (&error);
1209 mono_domain_assemblies_unlock (domain);
1214 if (domain->private_bin_path) {
1215 if (search_path == NULL)
1216 search_path = domain->private_bin_path;
1218 gchar *tmp2 = search_path;
1219 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1226 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1227 * directories relative to ApplicationBase separated by semicolons (see
1228 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1229 * The loop below copes with the fact that some Unix applications may use ':' (or
1230 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1231 * ';' for the subsequent split.
1233 * The issue was reported in bug #81446
1236 #ifndef TARGET_WIN32
1239 slen = strlen (search_path);
1240 for (i = 0; i < slen; i++)
1241 if (search_path [i] == ':')
1242 search_path [i] = ';';
1245 pvt_split = g_strsplit (search_path, ";", 1000);
1246 g_free (search_path);
1247 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1252 g_strfreev (pvt_split);
1254 * Don't do this because the first time is called, the domain
1255 * setup is not finished.
1257 * domain->search_path = g_malloc (sizeof (char *));
1258 * domain->search_path [0] = NULL;
1260 mono_domain_assemblies_unlock (domain);
1264 if (domain->search_path)
1265 g_strfreev (domain->search_path);
1267 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1268 tmp [npaths] = NULL;
1270 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1271 if (!mono_error_ok (&error)) {
1272 mono_error_cleanup (&error);
1273 g_strfreev (pvt_split);
1276 mono_domain_assemblies_unlock (domain);
1280 domain->search_path = tmp;
1282 /* FIXME: is this needed? */
1283 if (strncmp (*tmp, "file://", 7) == 0) {
1289 uri = g_strdup_printf ("file:///%s", uri + 7);
1292 uri = mono_escape_uri_string (tmpuri);
1293 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1299 if (gerror != NULL) {
1300 g_warning ("%s\n", gerror->message);
1301 g_error_free (gerror);
1308 for (i = 1; pvt_split && i < npaths; i++) {
1309 if (g_path_is_absolute (pvt_split [i - 1])) {
1310 tmp [i] = g_strdup (pvt_split [i - 1]);
1312 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1315 if (strchr (tmp [i], '.')) {
1319 reduced = mono_path_canonicalize (tmp [i]);
1320 if (appbaselen == -1)
1321 appbaselen = strlen (tmp [0]);
1323 if (strncmp (tmp [0], reduced, appbaselen)) {
1326 tmp [i] = g_strdup ("");
1336 if (setup->private_bin_path_probe != NULL) {
1338 tmp [0] = g_strdup ("");
1341 domain->setup->path_changed = FALSE;
1343 g_strfreev (pvt_split);
1345 mono_domain_assemblies_unlock (domain);
1348 #ifdef DISABLE_SHADOW_COPY
1350 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1356 mono_make_shadow_copy (const char *filename, MonoError *error)
1358 mono_error_init (error);
1359 return (char *) filename;
1363 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1365 guint16 *orig, *dest;
1366 gboolean copy_result;
1368 strcpy (src + srclen - tail_len, extension);
1370 if (IS_PORTABILITY_CASE) {
1371 gchar *file = mono_portability_find_file (src, TRUE);
1377 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1381 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1383 strcpy (target + targetlen - tail_len, extension);
1384 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1387 copy_result = CopyFile (orig, dest, FALSE);
1389 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1390 * overwritten when updated in their original locations. */
1392 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1401 get_cstring_hash (const char *str)
1407 if (!str || !str [0])
1412 for (i = 0; i < len; i++) {
1413 h = (h << 5) - h + *p;
1421 * Returned memory is malloc'd. Called must free it
1424 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1426 MonoAppDomainSetup *setup;
1427 char *cache_path, *appname;
1431 mono_error_init (error);
1433 setup = domain->setup;
1434 if (setup->cache_path != NULL && setup->application_name != NULL) {
1435 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1436 return_val_if_nok (error, NULL);
1438 #ifndef TARGET_WIN32
1441 for (i = strlen (cache_path) - 1; i >= 0; i--)
1442 if (cache_path [i] == '\\')
1443 cache_path [i] = '/';
1447 appname = mono_string_to_utf8_checked (setup->application_name, error);
1448 if (!mono_error_ok (error)) {
1449 g_free (cache_path);
1453 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1455 g_free (cache_path);
1457 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1458 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1465 get_shadow_assembly_location (const char *filename, MonoError *error)
1467 gint32 hash = 0, hash2 = 0;
1469 char path_hash [30];
1470 char *bname = g_path_get_basename (filename);
1471 char *dirname = g_path_get_dirname (filename);
1472 char *location, *tmploc;
1473 MonoDomain *domain = mono_domain_get ();
1475 mono_error_init (error);
1477 hash = get_cstring_hash (bname);
1478 hash2 = get_cstring_hash (dirname);
1479 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1480 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1481 tmploc = get_shadow_assembly_location_base (domain, error);
1482 if (!mono_error_ok (error)) {
1488 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1496 ensure_directory_exists (const char *filename)
1499 gchar *dir_utf8 = g_path_get_dirname (filename);
1501 gunichar2 *dir_utf16 = NULL;
1504 if (!dir_utf8 || !dir_utf8 [0])
1507 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1515 /* make life easy and only use one directory seperator */
1526 while (*p++ != '\\')
1532 p = wcschr (p, '\\');
1535 retval = _wmkdir (dir_utf16);
1536 if (retval != 0 && errno != EEXIST) {
1549 gchar *dir = g_path_get_dirname (filename);
1553 if (!dir || !dir [0]) {
1558 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1568 p = strchr (p, '/');
1571 retval = mkdir (dir, 0777);
1572 if (retval != 0 && errno != EEXIST) {
1587 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1589 struct stat sbuf_dest;
1591 gchar *real_src = mono_portability_find_file (src, TRUE);
1594 stat_src = (gchar*)src;
1596 stat_src = real_src;
1598 if (stat (stat_src, sbuf_src) == -1) {
1599 time_t tnow = time (NULL);
1604 memset (sbuf_src, 0, sizeof (*sbuf_src));
1605 sbuf_src->st_mtime = tnow;
1606 sbuf_src->st_atime = tnow;
1613 if (stat (dest, &sbuf_dest) == -1)
1616 if (sbuf_src->st_size == sbuf_dest.st_size &&
1617 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1624 shadow_copy_create_ini (const char *shadow, const char *filename)
1634 dir_name = g_path_get_dirname (shadow);
1635 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1637 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1642 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1647 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1648 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1650 if (handle == INVALID_HANDLE_VALUE) {
1654 full_path = mono_path_resolve_symlinks (filename);
1655 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1657 CloseHandle (handle);
1662 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1665 MonoAppDomainSetup *setup;
1668 gchar **directories;
1669 gchar *shadow_status_string;
1671 gboolean shadow_enabled;
1672 gboolean found = FALSE;
1677 setup = domain->setup;
1678 if (setup == NULL || setup->shadow_copy_files == NULL)
1681 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1682 if (!mono_error_ok (&error)) {
1683 mono_error_cleanup (&error);
1686 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1687 g_free (shadow_status_string);
1689 if (!shadow_enabled)
1692 if (setup->shadow_copy_directories == NULL)
1695 /* Is dir_name a shadow_copy destination already? */
1696 base_dir = get_shadow_assembly_location_base (domain, &error);
1697 if (!mono_error_ok (&error)) {
1698 mono_error_cleanup (&error);
1702 if (strstr (dir_name, base_dir)) {
1708 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1709 if (!mono_error_ok (&error)) {
1710 mono_error_cleanup (&error);
1714 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1715 dir_ptr = directories;
1717 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1723 g_strfreev (directories);
1729 This function raises exceptions so it can cause as sorts of nasty stuff if called
1730 while holding a lock.
1731 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1732 or NULL if source file not found.
1733 FIXME bubble up the error instead of raising it here
1736 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1739 gchar *sibling_source, *sibling_target;
1740 gint sibling_source_len, sibling_target_len;
1741 guint16 *orig, *dest;
1744 gboolean copy_result;
1745 struct stat src_sbuf;
1746 struct utimbuf utbuf;
1747 char *dir_name = g_path_get_dirname (filename);
1748 MonoDomain *domain = mono_domain_get ();
1751 mono_error_init (oerror);
1753 set_domain_search_path (domain);
1755 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1757 return (char *) filename;
1760 /* Is dir_name a shadow_copy destination already? */
1761 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1762 if (!mono_error_ok (&error)) {
1763 mono_error_cleanup (&error);
1765 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1769 if (strstr (dir_name, shadow_dir)) {
1770 g_free (shadow_dir);
1772 return (char *) filename;
1774 g_free (shadow_dir);
1777 shadow = get_shadow_assembly_location (filename, &error);
1778 if (!mono_error_ok (&error)) {
1779 mono_error_cleanup (&error);
1780 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1784 if (ensure_directory_exists (shadow) == FALSE) {
1786 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1790 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1791 return (char*) shadow;
1793 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1794 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1797 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1798 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1799 * and not have it runtime error" */
1800 attrs = GetFileAttributes (orig);
1801 if (attrs == INVALID_FILE_ATTRIBUTES) {
1803 return (char *)filename;
1806 copy_result = CopyFile (orig, dest, FALSE);
1808 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1809 * overwritten when updated in their original locations. */
1811 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1816 if (copy_result == FALSE) {
1819 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1820 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1821 return NULL; /* file not found, shadow copy failed */
1823 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1827 /* attempt to copy .mdb, .config if they exist */
1828 sibling_source = g_strconcat (filename, ".config", NULL);
1829 sibling_source_len = strlen (sibling_source);
1830 sibling_target = g_strconcat (shadow, ".config", NULL);
1831 sibling_target_len = strlen (sibling_target);
1833 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1834 if (copy_result == TRUE)
1835 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1837 g_free (sibling_source);
1838 g_free (sibling_target);
1840 if (copy_result == FALSE) {
1842 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1846 /* Create a .ini file containing the original assembly location */
1847 if (!shadow_copy_create_ini (shadow, filename)) {
1849 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1853 utbuf.actime = src_sbuf.st_atime;
1854 utbuf.modtime = src_sbuf.st_mtime;
1855 utime (shadow, &utbuf);
1859 #endif /* DISABLE_SHADOW_COPY */
1862 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1864 if (appdomain == NULL)
1867 return appdomain->data;
1871 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1872 const gchar *path3, const gchar *path4,
1873 gboolean refonly, gboolean is_private)
1876 gboolean found = FALSE;
1879 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1881 if (IS_PORTABILITY_SET) {
1882 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1885 fullpath = new_fullpath;
1889 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1892 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1895 return (*assembly != NULL);
1898 static MonoAssembly *
1899 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1901 MonoAssembly *result = NULL;
1904 const gchar *local_culture;
1906 gboolean is_private = FALSE;
1908 if (!culture || *culture == '\0') {
1911 local_culture = culture;
1914 filename = g_strconcat (name, ".dll", NULL);
1915 len = strlen (filename);
1917 for (path = search_path; *path; path++) {
1918 if (**path == '\0') {
1920 continue; /* Ignore empty ApplicationBase */
1923 /* See test cases in bug #58992 and bug #57710 */
1924 /* 1st try: [culture]/[name].dll (culture may be empty) */
1925 strcpy (filename + len - 4, ".dll");
1926 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1929 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1930 strcpy (filename + len - 4, ".exe");
1931 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1934 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1935 strcpy (filename + len - 4, ".dll");
1936 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1939 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1940 strcpy (filename + len - 4, ".exe");
1941 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1950 * Try loading the assembly from ApplicationBase and PrivateBinPath
1951 * and then from assemblies_path if any.
1952 * LOCKING: This is called from the assembly loading code, which means the caller
1953 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1955 static MonoAssembly *
1956 mono_domain_assembly_preload (MonoAssemblyName *aname,
1957 gchar **assemblies_path,
1960 MonoDomain *domain = mono_domain_get ();
1961 MonoAssembly *result = NULL;
1962 gboolean refonly = GPOINTER_TO_UINT (user_data);
1964 set_domain_search_path (domain);
1966 if (domain->search_path && domain->search_path [0] != NULL) {
1967 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1970 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1971 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1978 * Check whenever a given assembly was already loaded in the current appdomain.
1980 static MonoAssembly *
1981 mono_domain_assembly_search (MonoAssemblyName *aname,
1984 MonoDomain *domain = mono_domain_get ();
1987 gboolean refonly = GPOINTER_TO_UINT (user_data);
1989 mono_domain_assemblies_lock (domain);
1990 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1991 ass = (MonoAssembly *)tmp->data;
1992 /* Dynamic assemblies can't match here in MS.NET */
1993 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1996 mono_domain_assemblies_unlock (domain);
1999 mono_domain_assemblies_unlock (domain);
2004 MonoReflectionAssembly *
2005 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2008 MonoReflectionAssembly *result;
2009 MonoDomain *domain = mono_domain_get ();
2010 char *name, *filename;
2011 MonoImageOpenStatus status = MONO_IMAGE_OK;
2014 if (fname == NULL) {
2015 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2016 mono_set_pending_exception (exc);
2020 name = filename = mono_string_to_utf8 (fname);
2022 ass = mono_assembly_open_full (filename, &status, refOnly);
2027 if (status == MONO_IMAGE_IMAGE_INVALID)
2028 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2030 exc = mono_get_exception_file_not_found2 (NULL, fname);
2032 mono_set_pending_exception (exc);
2038 result = mono_assembly_get_object_checked (domain, ass, &error);
2040 mono_error_set_pending_exception (&error);
2044 MonoReflectionAssembly *
2045 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2046 MonoArray *raw_assembly,
2047 MonoArray *raw_symbol_store, MonoObject *evidence,
2048 MonoBoolean refonly)
2052 MonoReflectionAssembly *refass = NULL;
2053 MonoDomain *domain = ad->data;
2054 MonoImageOpenStatus status;
2055 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2056 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2059 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2063 if (raw_symbol_store != NULL)
2064 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2066 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2070 mono_image_close (image);
2071 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2075 refass = mono_assembly_get_object_checked (domain, ass, &error);
2077 mono_error_set_pending_exception (&error);
2079 MONO_OBJECT_SETREF (refass, evidence, evidence);
2083 MonoReflectionAssembly *
2084 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2087 MonoDomain *domain = ad->data;
2088 MonoImageOpenStatus status = MONO_IMAGE_OK;
2090 MonoAssemblyName aname;
2091 MonoReflectionAssembly *refass = NULL;
2097 name = mono_string_to_utf8 (assRef);
2098 parsed = mono_assembly_name_parse (name, &aname);
2102 /* This is a parse error... */
2104 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2105 if (!mono_error_ok (&error)) {
2106 mono_error_set_pending_exception (&error);
2113 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2114 mono_assembly_name_free (&aname);
2117 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2119 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2120 if (!mono_error_ok (&error)) {
2121 mono_error_set_pending_exception (&error);
2133 refass = mono_assembly_get_object_checked (domain, ass, &error);
2136 mono_error_set_pending_exception (&error);
2138 MONO_OBJECT_SETREF (refass, evidence, evidence);
2143 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2145 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2147 if (NULL == domain) {
2148 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2149 mono_set_pending_exception (exc);
2153 if (domain == mono_get_root_domain ()) {
2154 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2159 * Unloading seems to cause problems when running NUnit/NAnt, hence
2162 if (g_getenv ("MONO_NO_UNLOAD"))
2164 #ifdef __native_client__
2168 mono_domain_unload (domain);
2172 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2174 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2179 return mono_domain_is_unloading (domain);
2183 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2185 mono_unhandled_exception ((MonoObject*) exc);
2189 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2190 MonoReflectionAssembly *refass, MonoArray *args)
2197 image = refass->assembly->image;
2200 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2203 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2206 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2208 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2212 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2214 return ad->data->domain_id;
2218 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2220 MonoDomain *old_domain = mono_domain_get();
2222 if (!mono_domain_set (ad->data, FALSE)) {
2223 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2227 return old_domain->domain;
2231 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2233 MonoDomain *current_domain = mono_domain_get ();
2234 MonoDomain *domain = mono_domain_get_by_id (domainid);
2236 if (!domain || !mono_domain_set (domain, FALSE)) {
2237 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2241 return current_domain->domain;
2245 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2247 mono_thread_push_appdomain_ref (ad->data);
2251 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2253 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2257 * Raise an exception to prevent the managed code from executing a pop
2260 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2264 mono_thread_push_appdomain_ref (domain);
2268 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2270 mono_thread_pop_appdomain_ref ();
2274 ves_icall_System_AppDomain_InternalGetContext ()
2276 return mono_context_get ();
2280 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2282 return mono_domain_get ()->default_context;
2286 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2288 MonoAppContext *old_context = mono_context_get ();
2290 mono_context_set (mc);
2296 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2298 MonoDomain* mono_root_domain = mono_get_root_domain ();
2299 mono_domain_lock (mono_root_domain);
2300 if (process_guid_set) {
2301 mono_domain_unlock (mono_root_domain);
2303 MonoString *res = NULL;
2304 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2305 mono_error_raise_exception (&error);
2308 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2309 process_guid_set = TRUE;
2310 mono_domain_unlock (mono_root_domain);
2315 mono_domain_is_unloading (MonoDomain *domain)
2317 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2324 clear_cached_vtable (MonoVTable *vtable)
2326 MonoClass *klass = vtable->klass;
2327 MonoDomain *domain = vtable->domain;
2328 MonoClassRuntimeInfo *runtime_info;
2331 runtime_info = klass->runtime_info;
2332 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2333 runtime_info->domain_vtables [domain->domain_id] = NULL;
2334 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2335 mono_gc_free_fixed (data);
2338 static G_GNUC_UNUSED void
2339 zero_static_data (MonoVTable *vtable)
2341 MonoClass *klass = vtable->klass;
2344 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2345 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2348 typedef struct unload_data {
2351 char *failure_reason;
2356 unload_data_unref (unload_data *data)
2360 mono_atomic_load_acquire (count, gint32, &data->refcount);
2361 g_assert (count >= 1 && count <= 2);
2366 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2370 deregister_reflection_info_roots_from_list (MonoImage *image)
2372 GSList *list = image->reflection_info_unregister_classes;
2375 MonoClass *klass = (MonoClass *)list->data;
2377 mono_class_free_ref_info (klass);
2382 image->reflection_info_unregister_classes = NULL;
2386 deregister_reflection_info_roots (MonoDomain *domain)
2390 mono_domain_assemblies_lock (domain);
2391 for (list = domain->domain_assemblies; list; list = list->next) {
2392 MonoAssembly *assembly = (MonoAssembly *)list->data;
2393 MonoImage *image = assembly->image;
2397 * No need to take the image lock here since dynamic images are appdomain bound and
2398 * at this point the mutator is gone. Taking the image lock here would mean
2399 * promoting it from a simple lock to a complex lock, which we better avoid if
2402 if (image_is_dynamic (image))
2403 deregister_reflection_info_roots_from_list (image);
2405 for (i = 0; i < image->module_count; ++i) {
2406 MonoImage *module = image->modules [i];
2407 if (module && image_is_dynamic (module))
2408 deregister_reflection_info_roots_from_list (module);
2411 mono_domain_assemblies_unlock (domain);
2414 static guint32 WINAPI
2415 unload_thread_main (void *arg)
2418 unload_data *data = (unload_data*)arg;
2419 MonoDomain *domain = data->domain;
2423 /* Have to attach to the runtime so shutdown can wait for this thread */
2424 /* Force it to be attached to avoid racing during shutdown. */
2425 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2426 mono_error_raise_exception (&error); /* FIXME don't raise here */
2429 * FIXME: Abort our parent thread last, so we can return a failure
2430 * indication if aborting times out.
2432 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2433 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2437 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2438 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2442 /* Finalize all finalizable objects in the doomed appdomain */
2443 if (!mono_domain_finalize (domain, -1)) {
2444 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2448 /* Clear references to our vtables in class->runtime_info.
2449 * We also hold the loader lock because we're going to change
2450 * class->runtime_info.
2453 mono_loader_lock (); //FIXME why do we need the loader lock here?
2454 mono_domain_lock (domain);
2457 * We need to make sure that we don't have any remsets
2458 * pointing into static data of the to-be-freed domain because
2459 * at the next collections they would be invalid. So what we
2460 * do is we first zero all static data and then do a minor
2461 * collection. Because all references in the static data will
2462 * now be null we won't do any unnecessary copies and after
2463 * the collection there won't be any more remsets.
2465 for (i = 0; i < domain->class_vtable_array->len; ++i)
2466 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2467 mono_gc_collect (0);
2469 for (i = 0; i < domain->class_vtable_array->len; ++i)
2470 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2471 deregister_reflection_info_roots (domain);
2473 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2475 mono_domain_unlock (domain);
2476 mono_loader_unlock ();
2478 mono_threads_clear_cached_culture (domain);
2480 domain->state = MONO_APPDOMAIN_UNLOADED;
2482 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2484 /* remove from the handle table the items related to this domain */
2485 mono_gchandle_free_domain (domain);
2487 mono_domain_free (domain, FALSE);
2489 mono_gc_collect (mono_gc_max_generation ());
2491 mono_atomic_store_release (&data->done, TRUE);
2492 unload_data_unref (data);
2493 mono_thread_detach (thread);
2497 mono_atomic_store_release (&data->done, TRUE);
2498 unload_data_unref (data);
2499 mono_thread_detach (thread);
2504 * mono_domain_unload:
2505 * @domain: The domain to unload
2507 * Unloads an appdomain. Follows the process outlined in the comment
2508 * for mono_domain_try_unload.
2511 mono_domain_unload (MonoDomain *domain)
2513 MonoObject *exc = NULL;
2514 mono_domain_try_unload (domain, &exc);
2516 mono_raise_exception ((MonoException*)exc);
2520 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2524 MONO_PREPARE_BLOCKING;
2525 result = WaitForSingleObjectEx (handle, timeout, alertable);
2526 MONO_FINISH_BLOCKING;
2532 * mono_domain_unload:
2533 * @domain: The domain to unload
2534 * @exc: Exception information
2536 * Unloads an appdomain. Follows the process outlined in:
2537 * http://blogs.gotdotnet.com/cbrumme
2539 * If doing things the 'right' way is too hard or complex, we do it the
2540 * 'simple' way, which means do everything needed to avoid crashes and
2541 * memory leaks, but not much else.
2543 * It is required to pass a valid reference to the exc argument, upon return
2544 * from this function *exc will be set to the exception thrown, if any.
2546 * If this method is not called from an icall (embedded scenario for instance),
2547 * it must not be called with any managed frames on the stack, since the unload
2548 * process could end up trying to abort the current thread.
2551 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2554 HANDLE thread_handle;
2555 MonoAppDomainState prev_state;
2557 unload_data *thread_data;
2558 MonoNativeThreadId tid;
2559 MonoDomain *caller_domain = mono_domain_get ();
2562 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2564 /* Atomically change our state to UNLOADING */
2565 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2566 MONO_APPDOMAIN_UNLOADING_START,
2567 MONO_APPDOMAIN_CREATED);
2568 if (prev_state != MONO_APPDOMAIN_CREATED) {
2569 switch (prev_state) {
2570 case MONO_APPDOMAIN_UNLOADING_START:
2571 case MONO_APPDOMAIN_UNLOADING:
2572 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2574 case MONO_APPDOMAIN_UNLOADED:
2575 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2578 g_warning ("Invalid appdomain state %d", prev_state);
2579 g_assert_not_reached ();
2583 mono_domain_set (domain, FALSE);
2584 /* Notify OnDomainUnload listeners */
2585 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2588 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2590 if (!mono_error_ok (&error)) {
2592 mono_error_cleanup (&error);
2594 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2598 /* Roll back the state change */
2599 domain->state = MONO_APPDOMAIN_CREATED;
2600 mono_domain_set (caller_domain, FALSE);
2603 mono_domain_set (caller_domain, FALSE);
2605 thread_data = g_new0 (unload_data, 1);
2606 thread_data->domain = domain;
2607 thread_data->failure_reason = NULL;
2608 thread_data->done = FALSE;
2609 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2611 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2612 domain->state = MONO_APPDOMAIN_UNLOADING;
2614 * First we create a separate thread for unloading, since
2615 * we might have to abort some threads, including the current one.
2617 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2618 if (thread_handle == NULL)
2620 name = g_strdup_printf ("Unload thread for domain %x", domain);
2621 mono_thread_info_set_name (tid, name);
2622 mono_thread_info_resume (tid);
2625 /* Wait for the thread */
2626 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2627 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2628 /* The unload thread tries to abort us */
2629 /* The icall wrapper will execute the abort */
2630 CloseHandle (thread_handle);
2631 unload_data_unref (thread_data);
2635 CloseHandle (thread_handle);
2637 if (thread_data->failure_reason) {
2638 /* Roll back the state change */
2639 domain->state = MONO_APPDOMAIN_CREATED;
2641 g_warning ("%s", thread_data->failure_reason);
2643 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2645 g_free (thread_data->failure_reason);
2646 thread_data->failure_reason = NULL;
2649 unload_data_unref (thread_data);