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_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_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_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_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
365 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
366 return_if_nok (error);
368 context->domain_id = domain->domain_id;
369 context->context_id = 0;
370 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
371 domain->default_context = context;
375 * mono_runtime_cleanup:
380 * This must not be called while there are still running threads executing
384 mono_runtime_cleanup (MonoDomain *domain)
386 mono_attach_cleanup ();
388 /* This ends up calling any pending pending (for at most 2 seconds) */
391 mono_thread_cleanup ();
393 #ifndef DISABLE_SOCKETS
394 mono_network_cleanup ();
396 mono_marshal_cleanup ();
398 mono_type_initialization_cleanup ();
400 mono_monitor_cleanup ();
403 static MonoDomainFunc quit_function = NULL;
406 mono_install_runtime_cleanup (MonoDomainFunc func)
408 quit_function = func;
414 if (quit_function != NULL)
415 quit_function (mono_get_root_domain (), NULL);
419 * mono_domain_create_appdomain:
420 * @friendly_name: The friendly name of the appdomain to create
421 * @configuration_file: The configuration file to initialize the appdomain with
423 * Returns a MonoDomain initialized with the appdomain
426 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
430 MonoAppDomainSetup *setup;
433 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
434 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
435 mono_error_raise_exception (&error); /* FIXME don't raise here */
436 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
438 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
439 mono_error_raise_exception (&error); /* FIXME don't raise here */
441 return mono_domain_from_appdomain (ad);
445 * mono_domain_set_config:
446 * @domain: MonoDomain initialized with the appdomain we want to change
447 * @base_dir: new base directory for the appdomain
448 * @config_file_name: path to the new configuration for the app domain
450 * Used to set the system configuration for an appdomain
452 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
453 * Error Initializing the configuration system. ---> System.ArgumentException:
454 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
457 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
459 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
460 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
463 static MonoAppDomainSetup*
464 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
466 MonoDomain *caller_domain;
467 MonoClass *ads_class;
468 MonoAppDomainSetup *copy;
470 mono_error_init (error);
472 caller_domain = mono_domain_get ();
473 ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
475 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
476 return_val_if_nok (error, NULL);
478 mono_domain_set_internal (domain);
480 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
481 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
482 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
483 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
484 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
485 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
486 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
487 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
488 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
489 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
490 copy->publisher_policy = setup->publisher_policy;
491 copy->path_changed = setup->path_changed;
492 copy->loader_optimization = setup->loader_optimization;
493 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
494 copy->disallow_code_downloads = setup->disallow_code_downloads;
495 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
496 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
497 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
498 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
499 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
501 mono_domain_set_internal (caller_domain);
506 static MonoAppDomain *
507 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
512 char *shadow_location;
514 mono_error_init (error);
516 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
518 /* FIXME: pin all those objects */
519 data = mono_domain_create();
521 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
522 return_val_if_nok (error, NULL);
525 data->friendly_name = g_strdup (friendly_name);
527 mono_profiler_appdomain_name (data, data->friendly_name);
529 if (!setup->application_base) {
530 /* Inherit from the root domain since MS.NET does this */
531 MonoDomain *root = mono_get_root_domain ();
532 if (root->setup->application_base) {
533 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
534 mono_error_assert_ok (error); /* FIXME don't swallow the error */
535 MONO_OBJECT_SETREF (setup, application_base, s);
539 mono_context_init_checked (data, error);
540 return_val_if_nok (error, NULL);
542 data->setup = copy_app_domain_setup (data, setup, error);
543 if (!mono_error_ok (error)) {
544 g_free (data->friendly_name);
548 mono_domain_set_options_from_config (data);
549 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
551 #ifndef DISABLE_SHADOW_COPY
552 /*FIXME, guard this for when the debugger is not running */
553 shadow_location = get_shadow_assembly_location_base (data, error);
554 if (!mono_error_ok (error)) {
555 g_free (data->friendly_name);
559 g_free (shadow_location);
562 create_domain_objects (data);
568 * mono_domain_has_type_resolve:
569 * @domain: application domains being looked up
571 * Returns: TRUE if the AppDomain.TypeResolve field has been
575 mono_domain_has_type_resolve (MonoDomain *domain)
577 static MonoClassField *field = NULL;
581 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
585 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
589 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
594 * mono_domain_try_type_resolve:
595 * @domain: application domainwhere the name where the type is going to be resolved
596 * @name: the name of the type to resolve or NULL.
597 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
599 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
600 * the assembly that matches name.
602 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
604 * Returns: A MonoReflectionAssembly or NULL if not found
606 MonoReflectionAssembly *
607 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
610 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
611 mono_error_cleanup (&error);
616 MonoReflectionAssembly *
617 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
619 static MonoMethod *method = NULL;
620 MonoReflectionAssembly *ret;
624 mono_error_init (error);
626 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
628 if (method == NULL) {
629 klass = domain->domain->mbr.obj.vtable->klass;
632 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
633 if (method == NULL) {
634 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
640 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
644 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
645 return_val_if_nok (error, NULL);
651 * mono_domain_owns_vtable_slot:
653 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
656 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
660 mono_domain_lock (domain);
661 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
662 mono_domain_unlock (domain);
669 * @force: force setting.
671 * Set the current appdomain to @domain. If @force is set, set it even
672 * if it is being unloaded.
676 * FALSE if the domain is unloaded
679 mono_domain_set (MonoDomain *domain, gboolean force)
681 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
684 mono_domain_set_internal (domain);
690 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
696 MONO_CHECK_ARG_NULL (name, NULL);
702 str = mono_string_to_utf8 (name);
704 mono_domain_lock (add);
706 if (!strcmp (str, "APPBASE"))
707 o = (MonoObject *)add->setup->application_base;
708 else if (!strcmp (str, "APP_CONFIG_FILE"))
709 o = (MonoObject *)add->setup->configuration_file;
710 else if (!strcmp (str, "DYNAMIC_BASE"))
711 o = (MonoObject *)add->setup->dynamic_base;
712 else if (!strcmp (str, "APP_NAME"))
713 o = (MonoObject *)add->setup->application_name;
714 else if (!strcmp (str, "CACHE_BASE"))
715 o = (MonoObject *)add->setup->cache_path;
716 else if (!strcmp (str, "PRIVATE_BINPATH"))
717 o = (MonoObject *)add->setup->private_bin_path;
718 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
719 o = (MonoObject *)add->setup->private_bin_path_probe;
720 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
721 o = (MonoObject *)add->setup->shadow_copy_directories;
722 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
723 o = (MonoObject *)add->setup->shadow_copy_files;
725 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
727 mono_domain_unlock (add);
737 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
741 MONO_CHECK_ARG_NULL (name,);
747 mono_domain_lock (add);
749 mono_g_hash_table_insert (add->env, name, data);
751 mono_domain_unlock (add);
755 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
760 return ad->data->setup;
764 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
769 return mono_string_new (ad->data, ad->data->friendly_name);
773 ves_icall_System_AppDomain_getCurDomain ()
775 MonoDomain *add = mono_domain_get ();
781 ves_icall_System_AppDomain_getRootDomain ()
783 MonoDomain *root = mono_get_root_domain ();
789 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
791 MonoDomain *domain = mono_domain_get ();
793 return domain->throw_unobserved_task_exceptions;
797 get_attribute_value (const gchar **attribute_names,
798 const gchar **attribute_values,
799 const char *att_name)
802 for (n = 0; attribute_names [n] != NULL; n++) {
803 if (strcmp (attribute_names [n], att_name) == 0)
804 return g_strdup (attribute_values [n]);
810 start_element (GMarkupParseContext *context,
811 const gchar *element_name,
812 const gchar **attribute_names,
813 const gchar **attribute_values,
817 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
819 if (strcmp (element_name, "runtime") == 0) {
820 runtime_config->runtime_count++;
824 if (strcmp (element_name, "assemblyBinding") == 0) {
825 runtime_config->assemblybinding_count++;
829 if (runtime_config->runtime_count != 1)
832 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
833 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
835 if (value && g_ascii_strcasecmp (value, "true") == 0)
836 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
839 if (runtime_config->assemblybinding_count != 1)
842 if (strcmp (element_name, "probing") != 0)
845 g_free (runtime_config->domain->private_bin_path);
846 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
847 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
848 g_free (runtime_config->domain->private_bin_path);
849 runtime_config->domain->private_bin_path = NULL;
855 end_element (GMarkupParseContext *context,
856 const gchar *element_name,
860 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
861 if (strcmp (element_name, "runtime") == 0)
862 runtime_config->runtime_count--;
863 else if (strcmp (element_name, "assemblyBinding") == 0)
864 runtime_config->assemblybinding_count--;
868 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
870 RuntimeConfig *state = (RuntimeConfig *)user_data;
872 const gchar *filename;
874 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
875 msg = error && error->message ? error->message : "";
876 g_warning ("Error parsing %s: %s", filename, msg);
879 static const GMarkupParser
889 mono_domain_set_options_from_config (MonoDomain *domain)
892 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
894 GMarkupParseContext *context;
895 RuntimeConfig runtime_config;
898 if (!domain || !domain->setup || !domain->setup->configuration_file)
901 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
902 if (!mono_error_ok (&error)) {
903 mono_error_cleanup (&error);
907 config_file_path = mono_portability_find_file (config_file_name, TRUE);
908 if (!config_file_path)
909 config_file_path = config_file_name;
911 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
914 runtime_config.runtime_count = 0;
915 runtime_config.assemblybinding_count = 0;
916 runtime_config.domain = domain;
917 runtime_config.filename = config_file_path;
920 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
921 offset = 3; /* Skip UTF-8 BOM */
923 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
924 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
925 g_markup_parse_context_end_parse (context, NULL);
926 g_markup_parse_context_free (context);
930 if (config_file_name != config_file_path)
931 g_free (config_file_name);
932 g_free (config_file_path);
936 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
938 #ifdef DISABLE_APPDOMAINS
939 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
946 fname = mono_string_to_utf8 (friendly_name);
947 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
951 mono_error_raise_exception (&error);
958 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
961 MonoDomain *domain = ad->data;
966 GPtrArray *assemblies;
968 mono_error_init (&error);
971 * Make a copy of the list of assemblies because we can't hold the assemblies
972 * lock while creating objects etc.
974 assemblies = g_ptr_array_new ();
975 /* Need to skip internal assembly builders created by remoting */
976 mono_domain_assemblies_lock (domain);
977 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
978 ass = (MonoAssembly *)tmp->data;
979 if (refonly != ass->ref_only)
981 if (ass->corlib_internal)
983 g_ptr_array_add (assemblies, ass);
985 mono_domain_assemblies_unlock (domain);
987 res = mono_array_new (domain, mono_class_get_assembly_class (), assemblies->len);
988 for (i = 0; i < assemblies->len; ++i) {
989 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
990 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
991 if (!mono_error_ok (&error))
993 mono_array_setref (res, i, ass_obj);
997 g_ptr_array_free (assemblies, TRUE);
998 if (!mono_error_ok (&error))
999 mono_error_set_pending_exception (&error);
1003 MonoReflectionAssembly *
1004 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1006 MonoReflectionAssembly *ret;
1009 MonoBoolean isrefonly;
1010 gpointer params [3];
1012 mono_error_init (error);
1014 if (mono_runtime_get_no_exec ())
1017 g_assert (domain != NULL && fname != NULL);
1019 klass = domain->domain->mbr.obj.vtable->klass;
1022 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1023 if (method == NULL) {
1024 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1028 isrefonly = refonly ? 1 : 0;
1031 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1032 return_val_if_nok (error, NULL);
1035 params [2] = &isrefonly;
1037 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1038 return_val_if_nok (error, NULL);
1044 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1048 MonoReflectionAssembly *assembly;
1049 MonoDomain *domain = mono_domain_get ();
1053 aname_str = mono_stringify_assembly_name (aname);
1055 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1056 str = mono_string_new (domain, aname_str);
1062 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1063 if (!mono_error_ok (&error)) {
1065 mono_error_raise_exception (&error); /* FIXME don't raise here */
1071 return assembly->assembly;
1077 * LOCKING: assumes assemblies_lock in the domain is already locked.
1080 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1084 gboolean destroy_ht = FALSE;
1086 if (!ass->aname.name)
1090 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1094 /* FIXME: handle lazy loaded assemblies */
1095 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1096 g_hash_table_insert (ht, tmp->data, tmp->data);
1098 if (!g_hash_table_lookup (ht, ass)) {
1099 mono_assembly_addref (ass);
1100 g_hash_table_insert (ht, ass, ass);
1101 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1102 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);
1105 if (ass->image->references) {
1106 for (i = 0; ass->image->references [i] != NULL; i++) {
1107 if (ass->image->references [i] != REFERENCE_MISSING)
1108 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1109 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1114 g_hash_table_destroy (ht);
1118 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1120 static MonoClassField *assembly_load_field;
1121 static MonoMethod *assembly_load_method;
1123 MonoDomain *domain = mono_domain_get ();
1124 MonoReflectionAssembly *ref_assembly;
1126 gpointer load_value;
1129 if (!domain->domain)
1130 /* This can happen during startup */
1132 #ifdef ASSEMBLY_LOAD_DEBUG
1133 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1135 klass = domain->domain->mbr.obj.vtable->klass;
1137 mono_domain_assemblies_lock (domain);
1138 add_assemblies_to_domain (domain, assembly, NULL);
1139 mono_domain_assemblies_unlock (domain);
1141 if (assembly_load_field == NULL) {
1142 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1143 g_assert (assembly_load_field);
1146 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1147 if (load_value == NULL) {
1148 /* No events waiting to be triggered */
1152 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1153 mono_error_assert_ok (&error);
1155 if (assembly_load_method == NULL) {
1156 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1157 g_assert (assembly_load_method);
1160 *params = ref_assembly;
1162 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1163 mono_error_raise_exception (&error); /* FIXME don't raise here */
1167 * LOCKING: Acquires the domain assemblies lock.
1170 set_domain_search_path (MonoDomain *domain)
1173 MonoAppDomainSetup *setup;
1175 gchar *search_path = NULL;
1178 gchar **pvt_split = NULL;
1179 GError *gerror = NULL;
1180 gint appbaselen = -1;
1183 * We use the low-level domain assemblies lock, since this is called from
1184 * assembly loads hooks, which means this thread might hold the loader lock.
1186 mono_domain_assemblies_lock (domain);
1188 if (!domain->setup) {
1189 mono_domain_assemblies_unlock (domain);
1193 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1194 mono_domain_assemblies_unlock (domain);
1197 setup = domain->setup;
1198 if (!setup->application_base) {
1199 mono_domain_assemblies_unlock (domain);
1200 return; /* Must set application base to get private path working */
1205 if (setup->private_bin_path) {
1206 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1207 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1208 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1209 mono_error_cleanup (&error);
1210 mono_domain_assemblies_unlock (domain);
1215 if (domain->private_bin_path) {
1216 if (search_path == NULL)
1217 search_path = domain->private_bin_path;
1219 gchar *tmp2 = search_path;
1220 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1227 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1228 * directories relative to ApplicationBase separated by semicolons (see
1229 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1230 * The loop below copes with the fact that some Unix applications may use ':' (or
1231 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1232 * ';' for the subsequent split.
1234 * The issue was reported in bug #81446
1237 #ifndef TARGET_WIN32
1240 slen = strlen (search_path);
1241 for (i = 0; i < slen; i++)
1242 if (search_path [i] == ':')
1243 search_path [i] = ';';
1246 pvt_split = g_strsplit (search_path, ";", 1000);
1247 g_free (search_path);
1248 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1253 g_strfreev (pvt_split);
1255 * Don't do this because the first time is called, the domain
1256 * setup is not finished.
1258 * domain->search_path = g_malloc (sizeof (char *));
1259 * domain->search_path [0] = NULL;
1261 mono_domain_assemblies_unlock (domain);
1265 if (domain->search_path)
1266 g_strfreev (domain->search_path);
1268 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1269 tmp [npaths] = NULL;
1271 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1272 if (!mono_error_ok (&error)) {
1273 mono_error_cleanup (&error);
1274 g_strfreev (pvt_split);
1277 mono_domain_assemblies_unlock (domain);
1281 domain->search_path = tmp;
1283 /* FIXME: is this needed? */
1284 if (strncmp (*tmp, "file://", 7) == 0) {
1290 uri = g_strdup_printf ("file:///%s", uri + 7);
1293 uri = mono_escape_uri_string (tmpuri);
1294 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1300 if (gerror != NULL) {
1301 g_warning ("%s\n", gerror->message);
1302 g_error_free (gerror);
1309 for (i = 1; pvt_split && i < npaths; i++) {
1310 if (g_path_is_absolute (pvt_split [i - 1])) {
1311 tmp [i] = g_strdup (pvt_split [i - 1]);
1313 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1316 if (strchr (tmp [i], '.')) {
1320 reduced = mono_path_canonicalize (tmp [i]);
1321 if (appbaselen == -1)
1322 appbaselen = strlen (tmp [0]);
1324 if (strncmp (tmp [0], reduced, appbaselen)) {
1327 tmp [i] = g_strdup ("");
1337 if (setup->private_bin_path_probe != NULL) {
1339 tmp [0] = g_strdup ("");
1342 domain->setup->path_changed = FALSE;
1344 g_strfreev (pvt_split);
1346 mono_domain_assemblies_unlock (domain);
1349 #ifdef DISABLE_SHADOW_COPY
1351 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1357 mono_make_shadow_copy (const char *filename, MonoError *error)
1359 mono_error_init (error);
1360 return (char *) filename;
1364 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1366 guint16 *orig, *dest;
1367 gboolean copy_result;
1369 strcpy (src + srclen - tail_len, extension);
1371 if (IS_PORTABILITY_CASE) {
1372 gchar *file = mono_portability_find_file (src, TRUE);
1378 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1382 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1384 strcpy (target + targetlen - tail_len, extension);
1385 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1388 copy_result = CopyFile (orig, dest, FALSE);
1390 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1391 * overwritten when updated in their original locations. */
1393 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1402 get_cstring_hash (const char *str)
1408 if (!str || !str [0])
1413 for (i = 0; i < len; i++) {
1414 h = (h << 5) - h + *p;
1422 * Returned memory is malloc'd. Called must free it
1425 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1427 MonoAppDomainSetup *setup;
1428 char *cache_path, *appname;
1432 mono_error_init (error);
1434 setup = domain->setup;
1435 if (setup->cache_path != NULL && setup->application_name != NULL) {
1436 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1437 return_val_if_nok (error, NULL);
1439 #ifndef TARGET_WIN32
1442 for (i = strlen (cache_path) - 1; i >= 0; i--)
1443 if (cache_path [i] == '\\')
1444 cache_path [i] = '/';
1448 appname = mono_string_to_utf8_checked (setup->application_name, error);
1449 if (!mono_error_ok (error)) {
1450 g_free (cache_path);
1454 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1456 g_free (cache_path);
1458 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1459 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1466 get_shadow_assembly_location (const char *filename, MonoError *error)
1468 gint32 hash = 0, hash2 = 0;
1470 char path_hash [30];
1471 char *bname = g_path_get_basename (filename);
1472 char *dirname = g_path_get_dirname (filename);
1473 char *location, *tmploc;
1474 MonoDomain *domain = mono_domain_get ();
1476 mono_error_init (error);
1478 hash = get_cstring_hash (bname);
1479 hash2 = get_cstring_hash (dirname);
1480 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1481 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1482 tmploc = get_shadow_assembly_location_base (domain, error);
1483 if (!mono_error_ok (error)) {
1489 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1497 ensure_directory_exists (const char *filename)
1500 gchar *dir_utf8 = g_path_get_dirname (filename);
1502 gunichar2 *dir_utf16 = NULL;
1505 if (!dir_utf8 || !dir_utf8 [0])
1508 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1516 /* make life easy and only use one directory seperator */
1527 while (*p++ != '\\')
1533 p = wcschr (p, '\\');
1536 retval = _wmkdir (dir_utf16);
1537 if (retval != 0 && errno != EEXIST) {
1550 gchar *dir = g_path_get_dirname (filename);
1554 if (!dir || !dir [0]) {
1559 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1569 p = strchr (p, '/');
1572 retval = mkdir (dir, 0777);
1573 if (retval != 0 && errno != EEXIST) {
1588 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1590 struct stat sbuf_dest;
1592 gchar *real_src = mono_portability_find_file (src, TRUE);
1595 stat_src = (gchar*)src;
1597 stat_src = real_src;
1599 if (stat (stat_src, sbuf_src) == -1) {
1600 time_t tnow = time (NULL);
1605 memset (sbuf_src, 0, sizeof (*sbuf_src));
1606 sbuf_src->st_mtime = tnow;
1607 sbuf_src->st_atime = tnow;
1614 if (stat (dest, &sbuf_dest) == -1)
1617 if (sbuf_src->st_size == sbuf_dest.st_size &&
1618 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1625 shadow_copy_create_ini (const char *shadow, const char *filename)
1635 dir_name = g_path_get_dirname (shadow);
1636 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1638 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1643 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1648 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1649 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1651 if (handle == INVALID_HANDLE_VALUE) {
1655 full_path = mono_path_resolve_symlinks (filename);
1656 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1658 CloseHandle (handle);
1663 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1666 MonoAppDomainSetup *setup;
1669 gchar **directories;
1670 gchar *shadow_status_string;
1672 gboolean shadow_enabled;
1673 gboolean found = FALSE;
1678 setup = domain->setup;
1679 if (setup == NULL || setup->shadow_copy_files == NULL)
1682 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1683 if (!mono_error_ok (&error)) {
1684 mono_error_cleanup (&error);
1687 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1688 g_free (shadow_status_string);
1690 if (!shadow_enabled)
1693 if (setup->shadow_copy_directories == NULL)
1696 /* Is dir_name a shadow_copy destination already? */
1697 base_dir = get_shadow_assembly_location_base (domain, &error);
1698 if (!mono_error_ok (&error)) {
1699 mono_error_cleanup (&error);
1703 if (strstr (dir_name, base_dir)) {
1709 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1710 if (!mono_error_ok (&error)) {
1711 mono_error_cleanup (&error);
1715 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1716 dir_ptr = directories;
1718 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1724 g_strfreev (directories);
1730 This function raises exceptions so it can cause as sorts of nasty stuff if called
1731 while holding a lock.
1732 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1733 or NULL if source file not found.
1734 FIXME bubble up the error instead of raising it here
1737 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1740 gchar *sibling_source, *sibling_target;
1741 gint sibling_source_len, sibling_target_len;
1742 guint16 *orig, *dest;
1745 gboolean copy_result;
1746 struct stat src_sbuf;
1747 struct utimbuf utbuf;
1748 char *dir_name = g_path_get_dirname (filename);
1749 MonoDomain *domain = mono_domain_get ();
1752 mono_error_init (oerror);
1754 set_domain_search_path (domain);
1756 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1758 return (char *) filename;
1761 /* Is dir_name a shadow_copy destination already? */
1762 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1763 if (!mono_error_ok (&error)) {
1764 mono_error_cleanup (&error);
1766 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1770 if (strstr (dir_name, shadow_dir)) {
1771 g_free (shadow_dir);
1773 return (char *) filename;
1775 g_free (shadow_dir);
1778 shadow = get_shadow_assembly_location (filename, &error);
1779 if (!mono_error_ok (&error)) {
1780 mono_error_cleanup (&error);
1781 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1785 if (ensure_directory_exists (shadow) == FALSE) {
1787 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1791 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1792 return (char*) shadow;
1794 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1795 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1798 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1799 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1800 * and not have it runtime error" */
1801 attrs = GetFileAttributes (orig);
1802 if (attrs == INVALID_FILE_ATTRIBUTES) {
1804 return (char *)filename;
1807 copy_result = CopyFile (orig, dest, FALSE);
1809 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1810 * overwritten when updated in their original locations. */
1812 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1817 if (copy_result == FALSE) {
1820 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1821 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1822 return NULL; /* file not found, shadow copy failed */
1824 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1828 /* attempt to copy .mdb, .config if they exist */
1829 sibling_source = g_strconcat (filename, ".config", NULL);
1830 sibling_source_len = strlen (sibling_source);
1831 sibling_target = g_strconcat (shadow, ".config", NULL);
1832 sibling_target_len = strlen (sibling_target);
1834 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1835 if (copy_result == TRUE)
1836 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1838 g_free (sibling_source);
1839 g_free (sibling_target);
1841 if (copy_result == FALSE) {
1843 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1847 /* Create a .ini file containing the original assembly location */
1848 if (!shadow_copy_create_ini (shadow, filename)) {
1850 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1854 utbuf.actime = src_sbuf.st_atime;
1855 utbuf.modtime = src_sbuf.st_mtime;
1856 utime (shadow, &utbuf);
1860 #endif /* DISABLE_SHADOW_COPY */
1863 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1865 if (appdomain == NULL)
1868 return appdomain->data;
1872 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1873 const gchar *path3, const gchar *path4,
1874 gboolean refonly, gboolean is_private)
1877 gboolean found = FALSE;
1880 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1882 if (IS_PORTABILITY_SET) {
1883 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1886 fullpath = new_fullpath;
1890 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1893 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1896 return (*assembly != NULL);
1899 static MonoAssembly *
1900 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1902 MonoAssembly *result = NULL;
1905 const gchar *local_culture;
1907 gboolean is_private = FALSE;
1909 if (!culture || *culture == '\0') {
1912 local_culture = culture;
1915 filename = g_strconcat (name, ".dll", NULL);
1916 len = strlen (filename);
1918 for (path = search_path; *path; path++) {
1919 if (**path == '\0') {
1921 continue; /* Ignore empty ApplicationBase */
1924 /* See test cases in bug #58992 and bug #57710 */
1925 /* 1st try: [culture]/[name].dll (culture may be empty) */
1926 strcpy (filename + len - 4, ".dll");
1927 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1930 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1931 strcpy (filename + len - 4, ".exe");
1932 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1935 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1936 strcpy (filename + len - 4, ".dll");
1937 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1940 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1941 strcpy (filename + len - 4, ".exe");
1942 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1951 * Try loading the assembly from ApplicationBase and PrivateBinPath
1952 * and then from assemblies_path if any.
1953 * LOCKING: This is called from the assembly loading code, which means the caller
1954 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1956 static MonoAssembly *
1957 mono_domain_assembly_preload (MonoAssemblyName *aname,
1958 gchar **assemblies_path,
1961 MonoDomain *domain = mono_domain_get ();
1962 MonoAssembly *result = NULL;
1963 gboolean refonly = GPOINTER_TO_UINT (user_data);
1965 set_domain_search_path (domain);
1967 if (domain->search_path && domain->search_path [0] != NULL) {
1968 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1971 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1972 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1979 * Check whenever a given assembly was already loaded in the current appdomain.
1981 static MonoAssembly *
1982 mono_domain_assembly_search (MonoAssemblyName *aname,
1985 MonoDomain *domain = mono_domain_get ();
1988 gboolean refonly = GPOINTER_TO_UINT (user_data);
1990 mono_domain_assemblies_lock (domain);
1991 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1992 ass = (MonoAssembly *)tmp->data;
1993 /* Dynamic assemblies can't match here in MS.NET */
1994 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1997 mono_domain_assemblies_unlock (domain);
2000 mono_domain_assemblies_unlock (domain);
2005 MonoReflectionAssembly *
2006 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2009 MonoReflectionAssembly *result;
2010 MonoDomain *domain = mono_domain_get ();
2011 char *name, *filename;
2012 MonoImageOpenStatus status = MONO_IMAGE_OK;
2015 if (fname == NULL) {
2016 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2017 mono_set_pending_exception (exc);
2021 name = filename = mono_string_to_utf8 (fname);
2023 ass = mono_assembly_open_full (filename, &status, refOnly);
2028 if (status == MONO_IMAGE_IMAGE_INVALID)
2029 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2031 exc = mono_get_exception_file_not_found2 (NULL, fname);
2033 mono_set_pending_exception (exc);
2039 result = mono_assembly_get_object_checked (domain, ass, &error);
2041 mono_error_set_pending_exception (&error);
2045 MonoReflectionAssembly *
2046 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2047 MonoArray *raw_assembly,
2048 MonoArray *raw_symbol_store, MonoObject *evidence,
2049 MonoBoolean refonly)
2053 MonoReflectionAssembly *refass = NULL;
2054 MonoDomain *domain = ad->data;
2055 MonoImageOpenStatus status;
2056 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2057 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2060 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2064 if (raw_symbol_store != NULL)
2065 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2067 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2071 mono_image_close (image);
2072 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2076 refass = mono_assembly_get_object_checked (domain, ass, &error);
2078 mono_error_set_pending_exception (&error);
2080 MONO_OBJECT_SETREF (refass, evidence, evidence);
2084 MonoReflectionAssembly *
2085 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2088 MonoDomain *domain = ad->data;
2089 MonoImageOpenStatus status = MONO_IMAGE_OK;
2091 MonoAssemblyName aname;
2092 MonoReflectionAssembly *refass = NULL;
2098 name = mono_string_to_utf8 (assRef);
2099 parsed = mono_assembly_name_parse (name, &aname);
2103 /* This is a parse error... */
2105 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2106 if (!mono_error_ok (&error)) {
2107 mono_error_set_pending_exception (&error);
2114 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2115 mono_assembly_name_free (&aname);
2118 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2120 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2121 if (!mono_error_ok (&error)) {
2122 mono_error_set_pending_exception (&error);
2134 refass = mono_assembly_get_object_checked (domain, ass, &error);
2137 mono_error_set_pending_exception (&error);
2139 MONO_OBJECT_SETREF (refass, evidence, evidence);
2144 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2146 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2148 if (NULL == domain) {
2149 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2150 mono_set_pending_exception (exc);
2154 if (domain == mono_get_root_domain ()) {
2155 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2160 * Unloading seems to cause problems when running NUnit/NAnt, hence
2163 if (g_getenv ("MONO_NO_UNLOAD"))
2165 #ifdef __native_client__
2169 mono_domain_unload (domain);
2173 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2175 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2180 return mono_domain_is_unloading (domain);
2184 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2186 mono_unhandled_exception ((MonoObject*) exc);
2190 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2191 MonoReflectionAssembly *refass, MonoArray *args)
2198 image = refass->assembly->image;
2201 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2204 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2207 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2209 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2213 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2215 return ad->data->domain_id;
2219 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2221 MonoDomain *old_domain = mono_domain_get();
2223 if (!mono_domain_set (ad->data, FALSE)) {
2224 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2228 return old_domain->domain;
2232 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2234 MonoDomain *current_domain = mono_domain_get ();
2235 MonoDomain *domain = mono_domain_get_by_id (domainid);
2237 if (!domain || !mono_domain_set (domain, FALSE)) {
2238 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2242 return current_domain->domain;
2246 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2248 mono_thread_push_appdomain_ref (ad->data);
2252 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2254 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2258 * Raise an exception to prevent the managed code from executing a pop
2261 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2265 mono_thread_push_appdomain_ref (domain);
2269 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2271 mono_thread_pop_appdomain_ref ();
2275 ves_icall_System_AppDomain_InternalGetContext ()
2277 return mono_context_get ();
2281 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2283 return mono_domain_get ()->default_context;
2287 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2289 MonoAppContext *old_context = mono_context_get ();
2291 mono_context_set (mc);
2297 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2299 MonoDomain* mono_root_domain = mono_get_root_domain ();
2300 mono_domain_lock (mono_root_domain);
2301 if (process_guid_set) {
2302 mono_domain_unlock (mono_root_domain);
2304 MonoString *res = NULL;
2305 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2306 mono_error_raise_exception (&error);
2309 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2310 process_guid_set = TRUE;
2311 mono_domain_unlock (mono_root_domain);
2316 mono_domain_is_unloading (MonoDomain *domain)
2318 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2325 clear_cached_vtable (MonoVTable *vtable)
2327 MonoClass *klass = vtable->klass;
2328 MonoDomain *domain = vtable->domain;
2329 MonoClassRuntimeInfo *runtime_info;
2332 runtime_info = klass->runtime_info;
2333 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2334 runtime_info->domain_vtables [domain->domain_id] = NULL;
2335 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2336 mono_gc_free_fixed (data);
2339 static G_GNUC_UNUSED void
2340 zero_static_data (MonoVTable *vtable)
2342 MonoClass *klass = vtable->klass;
2345 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2346 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2349 typedef struct unload_data {
2352 char *failure_reason;
2357 unload_data_unref (unload_data *data)
2361 mono_atomic_load_acquire (count, gint32, &data->refcount);
2362 g_assert (count >= 1 && count <= 2);
2367 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2371 deregister_reflection_info_roots_from_list (MonoImage *image)
2373 GSList *list = image->reflection_info_unregister_classes;
2376 MonoClass *klass = (MonoClass *)list->data;
2378 mono_class_free_ref_info (klass);
2383 image->reflection_info_unregister_classes = NULL;
2387 deregister_reflection_info_roots (MonoDomain *domain)
2391 mono_domain_assemblies_lock (domain);
2392 for (list = domain->domain_assemblies; list; list = list->next) {
2393 MonoAssembly *assembly = (MonoAssembly *)list->data;
2394 MonoImage *image = assembly->image;
2398 * No need to take the image lock here since dynamic images are appdomain bound and
2399 * at this point the mutator is gone. Taking the image lock here would mean
2400 * promoting it from a simple lock to a complex lock, which we better avoid if
2403 if (image_is_dynamic (image))
2404 deregister_reflection_info_roots_from_list (image);
2406 for (i = 0; i < image->module_count; ++i) {
2407 MonoImage *module = image->modules [i];
2408 if (module && image_is_dynamic (module))
2409 deregister_reflection_info_roots_from_list (module);
2412 mono_domain_assemblies_unlock (domain);
2415 static guint32 WINAPI
2416 unload_thread_main (void *arg)
2419 unload_data *data = (unload_data*)arg;
2420 MonoDomain *domain = data->domain;
2424 /* Have to attach to the runtime so shutdown can wait for this thread */
2425 /* Force it to be attached to avoid racing during shutdown. */
2426 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2427 mono_error_raise_exception (&error); /* FIXME don't raise here */
2430 * FIXME: Abort our parent thread last, so we can return a failure
2431 * indication if aborting times out.
2433 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2434 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2438 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2439 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2443 /* Finalize all finalizable objects in the doomed appdomain */
2444 if (!mono_domain_finalize (domain, -1)) {
2445 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2449 /* Clear references to our vtables in class->runtime_info.
2450 * We also hold the loader lock because we're going to change
2451 * class->runtime_info.
2454 mono_loader_lock (); //FIXME why do we need the loader lock here?
2455 mono_domain_lock (domain);
2458 * We need to make sure that we don't have any remsets
2459 * pointing into static data of the to-be-freed domain because
2460 * at the next collections they would be invalid. So what we
2461 * do is we first zero all static data and then do a minor
2462 * collection. Because all references in the static data will
2463 * now be null we won't do any unnecessary copies and after
2464 * the collection there won't be any more remsets.
2466 for (i = 0; i < domain->class_vtable_array->len; ++i)
2467 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2468 mono_gc_collect (0);
2470 for (i = 0; i < domain->class_vtable_array->len; ++i)
2471 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2472 deregister_reflection_info_roots (domain);
2474 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2476 mono_domain_unlock (domain);
2477 mono_loader_unlock ();
2479 mono_threads_clear_cached_culture (domain);
2481 domain->state = MONO_APPDOMAIN_UNLOADED;
2483 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2485 /* remove from the handle table the items related to this domain */
2486 mono_gchandle_free_domain (domain);
2488 mono_domain_free (domain, FALSE);
2490 mono_gc_collect (mono_gc_max_generation ());
2492 mono_atomic_store_release (&data->done, TRUE);
2493 unload_data_unref (data);
2494 mono_thread_detach (thread);
2498 mono_atomic_store_release (&data->done, TRUE);
2499 unload_data_unref (data);
2500 mono_thread_detach (thread);
2505 * mono_domain_unload:
2506 * @domain: The domain to unload
2508 * Unloads an appdomain. Follows the process outlined in the comment
2509 * for mono_domain_try_unload.
2512 mono_domain_unload (MonoDomain *domain)
2514 MonoObject *exc = NULL;
2515 mono_domain_try_unload (domain, &exc);
2517 mono_raise_exception ((MonoException*)exc);
2521 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2525 MONO_PREPARE_BLOCKING;
2526 result = WaitForSingleObjectEx (handle, timeout, alertable);
2527 MONO_FINISH_BLOCKING;
2533 * mono_domain_unload:
2534 * @domain: The domain to unload
2535 * @exc: Exception information
2537 * Unloads an appdomain. Follows the process outlined in:
2538 * http://blogs.gotdotnet.com/cbrumme
2540 * If doing things the 'right' way is too hard or complex, we do it the
2541 * 'simple' way, which means do everything needed to avoid crashes and
2542 * memory leaks, but not much else.
2544 * It is required to pass a valid reference to the exc argument, upon return
2545 * from this function *exc will be set to the exception thrown, if any.
2547 * If this method is not called from an icall (embedded scenario for instance),
2548 * it must not be called with any managed frames on the stack, since the unload
2549 * process could end up trying to abort the current thread.
2552 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2555 HANDLE thread_handle;
2556 MonoAppDomainState prev_state;
2558 unload_data *thread_data;
2559 MonoNativeThreadId tid;
2560 MonoDomain *caller_domain = mono_domain_get ();
2563 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2565 /* Atomically change our state to UNLOADING */
2566 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2567 MONO_APPDOMAIN_UNLOADING_START,
2568 MONO_APPDOMAIN_CREATED);
2569 if (prev_state != MONO_APPDOMAIN_CREATED) {
2570 switch (prev_state) {
2571 case MONO_APPDOMAIN_UNLOADING_START:
2572 case MONO_APPDOMAIN_UNLOADING:
2573 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2575 case MONO_APPDOMAIN_UNLOADED:
2576 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2579 g_warning ("Invalid appdomain state %d", prev_state);
2580 g_assert_not_reached ();
2584 mono_domain_set (domain, FALSE);
2585 /* Notify OnDomainUnload listeners */
2586 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2589 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2591 if (!mono_error_ok (&error)) {
2593 mono_error_cleanup (&error);
2595 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2599 /* Roll back the state change */
2600 domain->state = MONO_APPDOMAIN_CREATED;
2601 mono_domain_set (caller_domain, FALSE);
2604 mono_domain_set (caller_domain, FALSE);
2606 thread_data = g_new0 (unload_data, 1);
2607 thread_data->domain = domain;
2608 thread_data->failure_reason = NULL;
2609 thread_data->done = FALSE;
2610 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2612 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2613 domain->state = MONO_APPDOMAIN_UNLOADING;
2615 * First we create a separate thread for unloading, since
2616 * we might have to abort some threads, including the current one.
2618 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2619 if (thread_handle == NULL)
2621 name = g_strdup_printf ("Unload thread for domain %x", domain);
2622 mono_thread_info_set_name (tid, name);
2623 mono_thread_info_resume (tid);
2626 /* Wait for the thread */
2627 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2628 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2629 /* The unload thread tries to abort us */
2630 /* The icall wrapper will execute the abort */
2631 CloseHandle (thread_handle);
2632 unload_data_unref (thread_data);
2636 CloseHandle (thread_handle);
2638 if (thread_data->failure_reason) {
2639 /* Roll back the state change */
2640 domain->state = MONO_APPDOMAIN_CREATED;
2642 g_warning ("%s", thread_data->failure_reason);
2644 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2646 g_free (thread_data->failure_reason);
2647 thread_data->failure_reason = NULL;
2650 unload_data_unref (thread_data);