2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #undef ASSEMBLY_LOAD_DEBUG
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/domain-internals.h>
39 #include "mono/metadata/metadata-internals.h"
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/exception.h>
42 #include <mono/metadata/threads.h>
43 #include <mono/metadata/threadpool-ms.h>
44 #include <mono/metadata/socket-io.h>
45 #include <mono/metadata/tabledefs.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/mono-gc.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/monitor.h>
50 #include <mono/metadata/mono-debug.h>
51 #include <mono/metadata/mono-debug-debugger.h>
52 #include <mono/metadata/attach.h>
53 #include <mono/metadata/file-io.h>
54 #include <mono/metadata/lock-tracer.h>
55 #include <mono/metadata/console-io.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/tokentype.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/utils/mono-uri.h>
61 #include <mono/utils/mono-logger-internals.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-stdlib.h>
64 #include <mono/utils/mono-io-portability.h>
65 #include <mono/utils/mono-error-internals.h>
66 #include <mono/utils/atomic.h>
67 #include <mono/utils/mono-memory-model.h>
68 #include <mono/utils/mono-threads.h>
74 * This is the version number of the corlib-runtime interface. When
75 * making changes to this interface (by changing the layout
76 * of classes the runtime knows about, changing icall signature or
77 * semantics etc), increment this variable. Also increment the
78 * pair of this variable in mscorlib in:
79 * mcs/class/corlib/System/Environment.cs
81 * Changes which are already detected at runtime, like the addition
82 * of icalls, do not require an increment.
84 #define MONO_CORLIB_VERSION 143
89 int assemblybinding_count;
94 static gunichar2 process_guid [36];
95 static gboolean process_guid_set = FALSE;
97 static gboolean no_exec = FALSE;
100 mono_domain_assembly_preload (MonoAssemblyName *aname,
101 gchar **assemblies_path,
104 static MonoAssembly *
105 mono_domain_assembly_search (MonoAssemblyName *aname,
109 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
112 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
114 static MonoAppDomain *
115 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
118 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
120 static MonoLoadFunc load_function = NULL;
122 /* Lazy class loading functions */
123 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
126 mono_install_runtime_load (MonoLoadFunc func)
128 load_function = func;
132 mono_runtime_load (const char *filename, const char *runtime_version)
134 g_assert (load_function);
135 return load_function (filename, runtime_version);
139 * mono_runtime_set_no_exec:
141 * Instructs the runtime to operate in static mode, i.e. avoid/do not
142 * allow managed code execution. This is useful for running the AOT
143 * compiler on platforms which allow full-aot execution only. This
144 * should be called before mono_runtime_init ().
147 mono_runtime_set_no_exec (gboolean val)
153 * mono_runtime_get_no_exec:
155 * If true, then the runtime will not allow managed code execution.
158 mono_runtime_get_no_exec (void)
164 create_domain_objects (MonoDomain *domain)
167 MonoDomain *old_domain = mono_domain_get ();
169 MonoVTable *string_vt;
170 MonoClassField *string_empty_fld;
172 if (domain != old_domain) {
173 mono_thread_push_appdomain_ref (domain);
174 mono_domain_set_internal_with_options (domain, FALSE);
178 * Initialize String.Empty. This enables the removal of
179 * the static cctor of the String class.
181 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
182 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
183 g_assert (string_empty_fld);
184 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
185 mono_error_assert_ok (&error);
186 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
189 * Create an instance early since we can't do it when there is no memory.
191 arg = mono_string_new (domain, "Out of memory");
192 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
195 * These two are needed because the signal handlers might be executing on
196 * an alternate stack, and Boehm GC can't handle that.
198 arg = mono_string_new (domain, "A null value was found where an object instance was required");
199 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
200 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
201 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
203 /*The ephemeron tombstone i*/
204 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
205 mono_error_assert_ok (&error);
207 if (domain != old_domain) {
208 mono_thread_pop_appdomain_ref ();
209 mono_domain_set_internal_with_options (old_domain, FALSE);
213 * This class is used during exception handling, so initialize it here, to prevent
214 * stack overflows while handling stack overflows.
216 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
221 * @domain: domain returned by mono_init ()
223 * Initialize the core AppDomain: this function will run also some
224 * IL initialization code, so it needs the execution engine to be fully
227 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
228 * we know the entry_assembly.
232 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
235 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
236 mono_error_cleanup (&error);
240 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
242 MonoAppDomainSetup *setup;
246 mono_error_init (error);
248 mono_portability_helpers_init ();
250 mono_gc_base_init ();
251 mono_monitor_init ();
252 mono_marshal_init ();
254 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
255 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
256 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
257 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
258 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
259 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
260 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
262 mono_thread_init (start_cb, attach_cb);
264 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
265 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
266 return_if_nok (error);
268 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
270 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
271 return_if_nok (error);
275 domain->setup = setup;
277 mono_thread_attach (domain);
279 mono_type_initialization_init ();
281 if (!mono_runtime_get_no_exec ())
282 create_domain_objects (domain);
284 /* GC init has to happen after thread init */
287 /* contexts use GC handles, so they must be initialized after the GC */
288 mono_context_init_checked (domain, error);
289 return_if_nok (error);
290 mono_context_set (domain->default_context);
292 #ifndef DISABLE_SOCKETS
293 mono_network_init ();
296 mono_console_init ();
299 mono_locks_tracer_init ();
301 /* mscorlib is loaded before we install the load hook */
302 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
308 mono_get_corlib_version (void)
312 MonoClassField *field;
315 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
316 mono_class_init (klass);
317 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
320 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
322 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
323 mono_error_raise_exception (&error); /* FIXME don't raise here */
324 return *(gint32*)((gchar*)value + sizeof (MonoObject));
328 * mono_check_corlib_version
330 * Checks that the corlib that is loaded matches the version of this runtime.
332 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
333 * allocated string with the error otherwise.
336 mono_check_corlib_version (void)
338 int version = mono_get_corlib_version ();
339 if (version != MONO_CORLIB_VERSION)
340 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
347 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
349 * Initializes the @domain's default System.Runtime.Remoting's Context.
352 mono_context_init (MonoDomain *domain)
355 mono_context_init_checked (domain, &error);
356 mono_error_cleanup (&error);
360 mono_context_init_checked (MonoDomain *domain, MonoError *error)
363 MonoAppContext *context;
365 mono_error_init (error);
367 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
368 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
369 return_if_nok (error);
371 context->domain_id = domain->domain_id;
372 context->context_id = 0;
373 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
374 domain->default_context = context;
378 * mono_runtime_cleanup:
383 * This must not be called while there are still running threads executing
387 mono_runtime_cleanup (MonoDomain *domain)
389 mono_attach_cleanup ();
391 /* This ends up calling any pending pending (for at most 2 seconds) */
394 mono_thread_cleanup ();
396 #ifndef DISABLE_SOCKETS
397 mono_network_cleanup ();
399 mono_marshal_cleanup ();
401 mono_type_initialization_cleanup ();
403 mono_monitor_cleanup ();
406 static MonoDomainFunc quit_function = NULL;
409 mono_install_runtime_cleanup (MonoDomainFunc func)
411 quit_function = func;
417 if (quit_function != NULL)
418 quit_function (mono_get_root_domain (), NULL);
422 * mono_domain_create_appdomain:
423 * @friendly_name: The friendly name of the appdomain to create
424 * @configuration_file: The configuration file to initialize the appdomain with
426 * Returns a MonoDomain initialized with the appdomain
429 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
433 MonoAppDomainSetup *setup;
436 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
437 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
438 mono_error_raise_exception (&error); /* FIXME don't raise here */
439 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
441 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
442 mono_error_raise_exception (&error); /* FIXME don't raise here */
444 return mono_domain_from_appdomain (ad);
448 * mono_domain_set_config:
449 * @domain: MonoDomain initialized with the appdomain we want to change
450 * @base_dir: new base directory for the appdomain
451 * @config_file_name: path to the new configuration for the app domain
453 * Used to set the system configuration for an appdomain
455 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
456 * Error Initializing the configuration system. ---> System.ArgumentException:
457 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
460 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
462 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
463 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
466 static MonoAppDomainSetup*
467 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
469 MonoDomain *caller_domain;
470 MonoClass *ads_class;
471 MonoAppDomainSetup *copy;
473 mono_error_init (error);
475 caller_domain = mono_domain_get ();
476 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
478 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
479 return_val_if_nok (error, NULL);
481 mono_domain_set_internal (domain);
483 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
484 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
485 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
486 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
487 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
488 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
489 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
490 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
491 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
492 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
493 copy->publisher_policy = setup->publisher_policy;
494 copy->path_changed = setup->path_changed;
495 copy->loader_optimization = setup->loader_optimization;
496 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
497 copy->disallow_code_downloads = setup->disallow_code_downloads;
498 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
499 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
500 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
501 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
502 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
504 mono_domain_set_internal (caller_domain);
509 static MonoAppDomain *
510 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
515 char *shadow_location;
517 mono_error_init (error);
519 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
521 /* FIXME: pin all those objects */
522 data = mono_domain_create();
524 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
525 return_val_if_nok (error, NULL);
528 data->friendly_name = g_strdup (friendly_name);
530 mono_profiler_appdomain_name (data, data->friendly_name);
532 if (!setup->application_base) {
533 /* Inherit from the root domain since MS.NET does this */
534 MonoDomain *root = mono_get_root_domain ();
535 if (root->setup->application_base) {
536 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
537 mono_error_assert_ok (error); /* FIXME don't swallow the error */
538 MONO_OBJECT_SETREF (setup, application_base, s);
542 mono_context_init_checked (data, error);
543 return_val_if_nok (error, NULL);
545 data->setup = copy_app_domain_setup (data, setup, error);
546 if (!mono_error_ok (error)) {
547 g_free (data->friendly_name);
551 mono_domain_set_options_from_config (data);
552 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
554 #ifndef DISABLE_SHADOW_COPY
555 /*FIXME, guard this for when the debugger is not running */
556 shadow_location = get_shadow_assembly_location_base (data, error);
557 if (!mono_error_ok (error)) {
558 g_free (data->friendly_name);
562 g_free (shadow_location);
565 create_domain_objects (data);
571 * mono_domain_has_type_resolve:
572 * @domain: application domains being looked up
574 * Returns: TRUE if the AppDomain.TypeResolve field has been
578 mono_domain_has_type_resolve (MonoDomain *domain)
580 static MonoClassField *field = NULL;
584 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
588 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
592 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
597 * mono_domain_try_type_resolve:
598 * @domain: application domainwhere the name where the type is going to be resolved
599 * @name: the name of the type to resolve or NULL.
600 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
602 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
603 * the assembly that matches name.
605 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
607 * Returns: A MonoReflectionAssembly or NULL if not found
609 MonoReflectionAssembly *
610 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
613 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
614 mono_error_cleanup (&error);
619 MonoReflectionAssembly *
620 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
622 static MonoMethod *method = NULL;
623 MonoReflectionAssembly *ret;
627 mono_error_init (error);
629 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
631 if (method == NULL) {
632 klass = domain->domain->mbr.obj.vtable->klass;
635 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
636 if (method == NULL) {
637 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
643 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
647 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
648 return_val_if_nok (error, NULL);
654 * mono_domain_owns_vtable_slot:
656 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
659 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
663 mono_domain_lock (domain);
664 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
665 mono_domain_unlock (domain);
672 * @force: force setting.
674 * Set the current appdomain to @domain. If @force is set, set it even
675 * if it is being unloaded.
679 * FALSE if the domain is unloaded
682 mono_domain_set (MonoDomain *domain, gboolean force)
684 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
687 mono_domain_set_internal (domain);
693 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
699 MONO_CHECK_ARG_NULL (name, NULL);
705 str = mono_string_to_utf8 (name);
707 mono_domain_lock (add);
709 if (!strcmp (str, "APPBASE"))
710 o = (MonoObject *)add->setup->application_base;
711 else if (!strcmp (str, "APP_CONFIG_FILE"))
712 o = (MonoObject *)add->setup->configuration_file;
713 else if (!strcmp (str, "DYNAMIC_BASE"))
714 o = (MonoObject *)add->setup->dynamic_base;
715 else if (!strcmp (str, "APP_NAME"))
716 o = (MonoObject *)add->setup->application_name;
717 else if (!strcmp (str, "CACHE_BASE"))
718 o = (MonoObject *)add->setup->cache_path;
719 else if (!strcmp (str, "PRIVATE_BINPATH"))
720 o = (MonoObject *)add->setup->private_bin_path;
721 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
722 o = (MonoObject *)add->setup->private_bin_path_probe;
723 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
724 o = (MonoObject *)add->setup->shadow_copy_directories;
725 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
726 o = (MonoObject *)add->setup->shadow_copy_files;
728 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
730 mono_domain_unlock (add);
740 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
744 MONO_CHECK_ARG_NULL (name,);
750 mono_domain_lock (add);
752 mono_g_hash_table_insert (add->env, name, data);
754 mono_domain_unlock (add);
758 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
763 return ad->data->setup;
767 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
772 return mono_string_new (ad->data, ad->data->friendly_name);
776 ves_icall_System_AppDomain_getCurDomain ()
778 MonoDomain *add = mono_domain_get ();
784 ves_icall_System_AppDomain_getRootDomain ()
786 MonoDomain *root = mono_get_root_domain ();
792 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
794 MonoDomain *domain = mono_domain_get ();
796 return domain->throw_unobserved_task_exceptions;
800 get_attribute_value (const gchar **attribute_names,
801 const gchar **attribute_values,
802 const char *att_name)
805 for (n = 0; attribute_names [n] != NULL; n++) {
806 if (strcmp (attribute_names [n], att_name) == 0)
807 return g_strdup (attribute_values [n]);
813 start_element (GMarkupParseContext *context,
814 const gchar *element_name,
815 const gchar **attribute_names,
816 const gchar **attribute_values,
820 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
822 if (strcmp (element_name, "runtime") == 0) {
823 runtime_config->runtime_count++;
827 if (strcmp (element_name, "assemblyBinding") == 0) {
828 runtime_config->assemblybinding_count++;
832 if (runtime_config->runtime_count != 1)
835 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
836 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
838 if (value && g_ascii_strcasecmp (value, "true") == 0)
839 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
842 if (runtime_config->assemblybinding_count != 1)
845 if (strcmp (element_name, "probing") != 0)
848 g_free (runtime_config->domain->private_bin_path);
849 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
850 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
851 g_free (runtime_config->domain->private_bin_path);
852 runtime_config->domain->private_bin_path = NULL;
858 end_element (GMarkupParseContext *context,
859 const gchar *element_name,
863 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
864 if (strcmp (element_name, "runtime") == 0)
865 runtime_config->runtime_count--;
866 else if (strcmp (element_name, "assemblyBinding") == 0)
867 runtime_config->assemblybinding_count--;
871 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
873 RuntimeConfig *state = (RuntimeConfig *)user_data;
875 const gchar *filename;
877 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
878 msg = error && error->message ? error->message : "";
879 g_warning ("Error parsing %s: %s", filename, msg);
882 static const GMarkupParser
892 mono_domain_set_options_from_config (MonoDomain *domain)
895 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
897 GMarkupParseContext *context;
898 RuntimeConfig runtime_config;
901 if (!domain || !domain->setup || !domain->setup->configuration_file)
904 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
905 if (!mono_error_ok (&error)) {
906 mono_error_cleanup (&error);
910 config_file_path = mono_portability_find_file (config_file_name, TRUE);
911 if (!config_file_path)
912 config_file_path = config_file_name;
914 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
917 runtime_config.runtime_count = 0;
918 runtime_config.assemblybinding_count = 0;
919 runtime_config.domain = domain;
920 runtime_config.filename = config_file_path;
923 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
924 offset = 3; /* Skip UTF-8 BOM */
926 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
927 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
928 g_markup_parse_context_end_parse (context, NULL);
929 g_markup_parse_context_free (context);
933 if (config_file_name != config_file_path)
934 g_free (config_file_name);
935 g_free (config_file_path);
939 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
941 #ifdef DISABLE_APPDOMAINS
942 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
949 fname = mono_string_to_utf8 (friendly_name);
950 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
954 mono_error_raise_exception (&error);
961 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
964 MonoDomain *domain = ad->data;
969 GPtrArray *assemblies;
971 mono_error_init (&error);
974 * Make a copy of the list of assemblies because we can't hold the assemblies
975 * lock while creating objects etc.
977 assemblies = g_ptr_array_new ();
978 /* Need to skip internal assembly builders created by remoting */
979 mono_domain_assemblies_lock (domain);
980 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
981 ass = (MonoAssembly *)tmp->data;
982 if (refonly != ass->ref_only)
984 if (ass->corlib_internal)
986 g_ptr_array_add (assemblies, ass);
988 mono_domain_assemblies_unlock (domain);
990 res = mono_array_new (domain, mono_class_get_assembly_class (), assemblies->len);
991 for (i = 0; i < assemblies->len; ++i) {
992 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
993 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
994 if (!mono_error_ok (&error))
996 mono_array_setref (res, i, ass_obj);
1000 g_ptr_array_free (assemblies, TRUE);
1001 if (!mono_error_ok (&error))
1002 mono_error_set_pending_exception (&error);
1006 MonoReflectionAssembly *
1007 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1009 MonoReflectionAssembly *ret;
1012 MonoBoolean isrefonly;
1013 gpointer params [3];
1015 mono_error_init (error);
1017 if (mono_runtime_get_no_exec ())
1020 g_assert (domain != NULL && fname != NULL);
1022 klass = domain->domain->mbr.obj.vtable->klass;
1025 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1026 if (method == NULL) {
1027 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1031 isrefonly = refonly ? 1 : 0;
1034 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1035 return_val_if_nok (error, NULL);
1038 params [2] = &isrefonly;
1040 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1041 return_val_if_nok (error, NULL);
1047 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1051 MonoReflectionAssembly *assembly;
1052 MonoDomain *domain = mono_domain_get ();
1056 aname_str = mono_stringify_assembly_name (aname);
1058 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1059 str = mono_string_new (domain, aname_str);
1065 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1066 if (!mono_error_ok (&error)) {
1068 mono_error_raise_exception (&error); /* FIXME don't raise here */
1074 return assembly->assembly;
1080 * LOCKING: assumes assemblies_lock in the domain is already locked.
1083 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1087 gboolean destroy_ht = FALSE;
1089 if (!ass->aname.name)
1093 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1097 /* FIXME: handle lazy loaded assemblies */
1098 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1099 g_hash_table_insert (ht, tmp->data, tmp->data);
1101 if (!g_hash_table_lookup (ht, ass)) {
1102 mono_assembly_addref (ass);
1103 g_hash_table_insert (ht, ass, ass);
1104 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1105 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);
1108 if (ass->image->references) {
1109 for (i = 0; ass->image->references [i] != NULL; i++) {
1110 if (ass->image->references [i] != REFERENCE_MISSING)
1111 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1112 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1117 g_hash_table_destroy (ht);
1121 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1123 static MonoClassField *assembly_load_field;
1124 static MonoMethod *assembly_load_method;
1126 MonoDomain *domain = mono_domain_get ();
1127 MonoReflectionAssembly *ref_assembly;
1129 gpointer load_value;
1132 if (!domain->domain)
1133 /* This can happen during startup */
1135 #ifdef ASSEMBLY_LOAD_DEBUG
1136 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1138 klass = domain->domain->mbr.obj.vtable->klass;
1140 mono_domain_assemblies_lock (domain);
1141 add_assemblies_to_domain (domain, assembly, NULL);
1142 mono_domain_assemblies_unlock (domain);
1144 if (assembly_load_field == NULL) {
1145 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1146 g_assert (assembly_load_field);
1149 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1150 if (load_value == NULL) {
1151 /* No events waiting to be triggered */
1155 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1156 mono_error_assert_ok (&error);
1158 if (assembly_load_method == NULL) {
1159 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1160 g_assert (assembly_load_method);
1163 *params = ref_assembly;
1165 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1166 mono_error_raise_exception (&error); /* FIXME don't raise here */
1170 * LOCKING: Acquires the domain assemblies lock.
1173 set_domain_search_path (MonoDomain *domain)
1176 MonoAppDomainSetup *setup;
1178 gchar *search_path = NULL;
1181 gchar **pvt_split = NULL;
1182 GError *gerror = NULL;
1183 gint appbaselen = -1;
1186 * We use the low-level domain assemblies lock, since this is called from
1187 * assembly loads hooks, which means this thread might hold the loader lock.
1189 mono_domain_assemblies_lock (domain);
1191 if (!domain->setup) {
1192 mono_domain_assemblies_unlock (domain);
1196 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1197 mono_domain_assemblies_unlock (domain);
1200 setup = domain->setup;
1201 if (!setup->application_base) {
1202 mono_domain_assemblies_unlock (domain);
1203 return; /* Must set application base to get private path working */
1208 if (setup->private_bin_path) {
1209 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1210 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1211 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1212 mono_error_cleanup (&error);
1213 mono_domain_assemblies_unlock (domain);
1218 if (domain->private_bin_path) {
1219 if (search_path == NULL)
1220 search_path = domain->private_bin_path;
1222 gchar *tmp2 = search_path;
1223 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1230 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1231 * directories relative to ApplicationBase separated by semicolons (see
1232 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1233 * The loop below copes with the fact that some Unix applications may use ':' (or
1234 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1235 * ';' for the subsequent split.
1237 * The issue was reported in bug #81446
1240 #ifndef TARGET_WIN32
1243 slen = strlen (search_path);
1244 for (i = 0; i < slen; i++)
1245 if (search_path [i] == ':')
1246 search_path [i] = ';';
1249 pvt_split = g_strsplit (search_path, ";", 1000);
1250 g_free (search_path);
1251 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1256 g_strfreev (pvt_split);
1258 * Don't do this because the first time is called, the domain
1259 * setup is not finished.
1261 * domain->search_path = g_malloc (sizeof (char *));
1262 * domain->search_path [0] = NULL;
1264 mono_domain_assemblies_unlock (domain);
1268 if (domain->search_path)
1269 g_strfreev (domain->search_path);
1271 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1272 tmp [npaths] = NULL;
1274 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1275 if (!mono_error_ok (&error)) {
1276 mono_error_cleanup (&error);
1277 g_strfreev (pvt_split);
1280 mono_domain_assemblies_unlock (domain);
1284 domain->search_path = tmp;
1286 /* FIXME: is this needed? */
1287 if (strncmp (*tmp, "file://", 7) == 0) {
1293 uri = g_strdup_printf ("file:///%s", uri + 7);
1296 uri = mono_escape_uri_string (tmpuri);
1297 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1303 if (gerror != NULL) {
1304 g_warning ("%s\n", gerror->message);
1305 g_error_free (gerror);
1312 for (i = 1; pvt_split && i < npaths; i++) {
1313 if (g_path_is_absolute (pvt_split [i - 1])) {
1314 tmp [i] = g_strdup (pvt_split [i - 1]);
1316 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1319 if (strchr (tmp [i], '.')) {
1323 reduced = mono_path_canonicalize (tmp [i]);
1324 if (appbaselen == -1)
1325 appbaselen = strlen (tmp [0]);
1327 if (strncmp (tmp [0], reduced, appbaselen)) {
1330 tmp [i] = g_strdup ("");
1340 if (setup->private_bin_path_probe != NULL) {
1342 tmp [0] = g_strdup ("");
1345 domain->setup->path_changed = FALSE;
1347 g_strfreev (pvt_split);
1349 mono_domain_assemblies_unlock (domain);
1352 #ifdef DISABLE_SHADOW_COPY
1354 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1360 mono_make_shadow_copy (const char *filename, MonoError *error)
1362 mono_error_init (error);
1363 return (char *) filename;
1367 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1369 guint16 *orig, *dest;
1370 gboolean copy_result;
1372 strcpy (src + srclen - tail_len, extension);
1374 if (IS_PORTABILITY_CASE) {
1375 gchar *file = mono_portability_find_file (src, TRUE);
1381 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1385 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1387 strcpy (target + targetlen - tail_len, extension);
1388 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1391 copy_result = CopyFile (orig, dest, FALSE);
1393 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1394 * overwritten when updated in their original locations. */
1396 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1405 get_cstring_hash (const char *str)
1411 if (!str || !str [0])
1416 for (i = 0; i < len; i++) {
1417 h = (h << 5) - h + *p;
1425 * Returned memory is malloc'd. Called must free it
1428 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1430 MonoAppDomainSetup *setup;
1431 char *cache_path, *appname;
1435 mono_error_init (error);
1437 setup = domain->setup;
1438 if (setup->cache_path != NULL && setup->application_name != NULL) {
1439 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1440 return_val_if_nok (error, NULL);
1442 #ifndef TARGET_WIN32
1445 for (i = strlen (cache_path) - 1; i >= 0; i--)
1446 if (cache_path [i] == '\\')
1447 cache_path [i] = '/';
1451 appname = mono_string_to_utf8_checked (setup->application_name, error);
1452 if (!mono_error_ok (error)) {
1453 g_free (cache_path);
1457 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1459 g_free (cache_path);
1461 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1462 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1469 get_shadow_assembly_location (const char *filename, MonoError *error)
1471 gint32 hash = 0, hash2 = 0;
1473 char path_hash [30];
1474 char *bname = g_path_get_basename (filename);
1475 char *dirname = g_path_get_dirname (filename);
1476 char *location, *tmploc;
1477 MonoDomain *domain = mono_domain_get ();
1479 mono_error_init (error);
1481 hash = get_cstring_hash (bname);
1482 hash2 = get_cstring_hash (dirname);
1483 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1484 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1485 tmploc = get_shadow_assembly_location_base (domain, error);
1486 if (!mono_error_ok (error)) {
1492 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1500 ensure_directory_exists (const char *filename)
1503 gchar *dir_utf8 = g_path_get_dirname (filename);
1505 gunichar2 *dir_utf16 = NULL;
1508 if (!dir_utf8 || !dir_utf8 [0])
1511 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1519 /* make life easy and only use one directory seperator */
1530 while (*p++ != '\\')
1536 p = wcschr (p, '\\');
1539 retval = _wmkdir (dir_utf16);
1540 if (retval != 0 && errno != EEXIST) {
1553 gchar *dir = g_path_get_dirname (filename);
1557 if (!dir || !dir [0]) {
1562 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1572 p = strchr (p, '/');
1575 retval = mkdir (dir, 0777);
1576 if (retval != 0 && errno != EEXIST) {
1591 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1593 struct stat sbuf_dest;
1595 gchar *real_src = mono_portability_find_file (src, TRUE);
1598 stat_src = (gchar*)src;
1600 stat_src = real_src;
1602 if (stat (stat_src, sbuf_src) == -1) {
1603 time_t tnow = time (NULL);
1608 memset (sbuf_src, 0, sizeof (*sbuf_src));
1609 sbuf_src->st_mtime = tnow;
1610 sbuf_src->st_atime = tnow;
1617 if (stat (dest, &sbuf_dest) == -1)
1620 if (sbuf_src->st_size == sbuf_dest.st_size &&
1621 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1628 shadow_copy_create_ini (const char *shadow, const char *filename)
1638 dir_name = g_path_get_dirname (shadow);
1639 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1641 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1646 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1651 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1652 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1654 if (handle == INVALID_HANDLE_VALUE) {
1658 full_path = mono_path_resolve_symlinks (filename);
1659 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1661 CloseHandle (handle);
1666 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1669 MonoAppDomainSetup *setup;
1672 gchar **directories;
1673 gchar *shadow_status_string;
1675 gboolean shadow_enabled;
1676 gboolean found = FALSE;
1681 setup = domain->setup;
1682 if (setup == NULL || setup->shadow_copy_files == NULL)
1685 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1686 if (!mono_error_ok (&error)) {
1687 mono_error_cleanup (&error);
1690 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1691 g_free (shadow_status_string);
1693 if (!shadow_enabled)
1696 if (setup->shadow_copy_directories == NULL)
1699 /* Is dir_name a shadow_copy destination already? */
1700 base_dir = get_shadow_assembly_location_base (domain, &error);
1701 if (!mono_error_ok (&error)) {
1702 mono_error_cleanup (&error);
1706 if (strstr (dir_name, base_dir)) {
1712 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1713 if (!mono_error_ok (&error)) {
1714 mono_error_cleanup (&error);
1718 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1719 dir_ptr = directories;
1721 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1727 g_strfreev (directories);
1733 This function raises exceptions so it can cause as sorts of nasty stuff if called
1734 while holding a lock.
1735 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1736 or NULL if source file not found.
1737 FIXME bubble up the error instead of raising it here
1740 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1743 gchar *sibling_source, *sibling_target;
1744 gint sibling_source_len, sibling_target_len;
1745 guint16 *orig, *dest;
1748 gboolean copy_result;
1749 struct stat src_sbuf;
1750 struct utimbuf utbuf;
1751 char *dir_name = g_path_get_dirname (filename);
1752 MonoDomain *domain = mono_domain_get ();
1755 mono_error_init (oerror);
1757 set_domain_search_path (domain);
1759 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1761 return (char *) filename;
1764 /* Is dir_name a shadow_copy destination already? */
1765 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1766 if (!mono_error_ok (&error)) {
1767 mono_error_cleanup (&error);
1769 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1773 if (strstr (dir_name, shadow_dir)) {
1774 g_free (shadow_dir);
1776 return (char *) filename;
1778 g_free (shadow_dir);
1781 shadow = get_shadow_assembly_location (filename, &error);
1782 if (!mono_error_ok (&error)) {
1783 mono_error_cleanup (&error);
1784 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1788 if (ensure_directory_exists (shadow) == FALSE) {
1790 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1794 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1795 return (char*) shadow;
1797 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1798 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1801 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1802 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1803 * and not have it runtime error" */
1804 attrs = GetFileAttributes (orig);
1805 if (attrs == INVALID_FILE_ATTRIBUTES) {
1807 return (char *)filename;
1810 copy_result = CopyFile (orig, dest, FALSE);
1812 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1813 * overwritten when updated in their original locations. */
1815 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1820 if (copy_result == FALSE) {
1823 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1824 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1825 return NULL; /* file not found, shadow copy failed */
1827 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1831 /* attempt to copy .mdb, .config if they exist */
1832 sibling_source = g_strconcat (filename, ".config", NULL);
1833 sibling_source_len = strlen (sibling_source);
1834 sibling_target = g_strconcat (shadow, ".config", NULL);
1835 sibling_target_len = strlen (sibling_target);
1837 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1838 if (copy_result == TRUE)
1839 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1841 g_free (sibling_source);
1842 g_free (sibling_target);
1844 if (copy_result == FALSE) {
1846 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1850 /* Create a .ini file containing the original assembly location */
1851 if (!shadow_copy_create_ini (shadow, filename)) {
1853 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1857 utbuf.actime = src_sbuf.st_atime;
1858 utbuf.modtime = src_sbuf.st_mtime;
1859 utime (shadow, &utbuf);
1863 #endif /* DISABLE_SHADOW_COPY */
1866 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1868 if (appdomain == NULL)
1871 return appdomain->data;
1875 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1876 const gchar *path3, const gchar *path4,
1877 gboolean refonly, gboolean is_private)
1880 gboolean found = FALSE;
1883 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1885 if (IS_PORTABILITY_SET) {
1886 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1889 fullpath = new_fullpath;
1893 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1896 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1899 return (*assembly != NULL);
1902 static MonoAssembly *
1903 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1905 MonoAssembly *result = NULL;
1908 const gchar *local_culture;
1910 gboolean is_private = FALSE;
1912 if (!culture || *culture == '\0') {
1915 local_culture = culture;
1918 filename = g_strconcat (name, ".dll", NULL);
1919 len = strlen (filename);
1921 for (path = search_path; *path; path++) {
1922 if (**path == '\0') {
1924 continue; /* Ignore empty ApplicationBase */
1927 /* See test cases in bug #58992 and bug #57710 */
1928 /* 1st try: [culture]/[name].dll (culture may be empty) */
1929 strcpy (filename + len - 4, ".dll");
1930 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1933 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1934 strcpy (filename + len - 4, ".exe");
1935 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1938 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1939 strcpy (filename + len - 4, ".dll");
1940 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1943 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1944 strcpy (filename + len - 4, ".exe");
1945 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1954 * Try loading the assembly from ApplicationBase and PrivateBinPath
1955 * and then from assemblies_path if any.
1956 * LOCKING: This is called from the assembly loading code, which means the caller
1957 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1959 static MonoAssembly *
1960 mono_domain_assembly_preload (MonoAssemblyName *aname,
1961 gchar **assemblies_path,
1964 MonoDomain *domain = mono_domain_get ();
1965 MonoAssembly *result = NULL;
1966 gboolean refonly = GPOINTER_TO_UINT (user_data);
1968 set_domain_search_path (domain);
1970 if (domain->search_path && domain->search_path [0] != NULL) {
1971 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1974 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1975 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1982 * Check whenever a given assembly was already loaded in the current appdomain.
1984 static MonoAssembly *
1985 mono_domain_assembly_search (MonoAssemblyName *aname,
1988 MonoDomain *domain = mono_domain_get ();
1991 gboolean refonly = GPOINTER_TO_UINT (user_data);
1993 mono_domain_assemblies_lock (domain);
1994 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1995 ass = (MonoAssembly *)tmp->data;
1996 /* Dynamic assemblies can't match here in MS.NET */
1997 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2000 mono_domain_assemblies_unlock (domain);
2003 mono_domain_assemblies_unlock (domain);
2008 MonoReflectionAssembly *
2009 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2012 MonoReflectionAssembly *result;
2013 MonoDomain *domain = mono_domain_get ();
2014 char *name, *filename;
2015 MonoImageOpenStatus status = MONO_IMAGE_OK;
2018 if (fname == NULL) {
2019 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2020 mono_set_pending_exception (exc);
2024 name = filename = mono_string_to_utf8 (fname);
2026 ass = mono_assembly_open_full (filename, &status, refOnly);
2031 if (status == MONO_IMAGE_IMAGE_INVALID)
2032 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2034 exc = mono_get_exception_file_not_found2 (NULL, fname);
2036 mono_set_pending_exception (exc);
2042 result = mono_assembly_get_object_checked (domain, ass, &error);
2044 mono_error_set_pending_exception (&error);
2048 MonoReflectionAssembly *
2049 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2050 MonoArray *raw_assembly,
2051 MonoArray *raw_symbol_store, MonoObject *evidence,
2052 MonoBoolean refonly)
2056 MonoReflectionAssembly *refass = NULL;
2057 MonoDomain *domain = ad->data;
2058 MonoImageOpenStatus status;
2059 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2060 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2063 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2067 if (raw_symbol_store != NULL)
2068 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2070 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2074 mono_image_close (image);
2075 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2079 refass = mono_assembly_get_object_checked (domain, ass, &error);
2081 mono_error_set_pending_exception (&error);
2083 MONO_OBJECT_SETREF (refass, evidence, evidence);
2087 MonoReflectionAssembly *
2088 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2091 MonoDomain *domain = ad->data;
2092 MonoImageOpenStatus status = MONO_IMAGE_OK;
2094 MonoAssemblyName aname;
2095 MonoReflectionAssembly *refass = NULL;
2101 name = mono_string_to_utf8 (assRef);
2102 parsed = mono_assembly_name_parse (name, &aname);
2106 /* This is a parse error... */
2108 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2109 if (!mono_error_ok (&error)) {
2110 mono_error_set_pending_exception (&error);
2117 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2118 mono_assembly_name_free (&aname);
2121 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2123 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2124 if (!mono_error_ok (&error)) {
2125 mono_error_set_pending_exception (&error);
2137 refass = mono_assembly_get_object_checked (domain, ass, &error);
2140 mono_error_set_pending_exception (&error);
2142 MONO_OBJECT_SETREF (refass, evidence, evidence);
2147 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2149 MonoException *exc = NULL;
2150 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2152 if (NULL == domain) {
2153 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2154 mono_set_pending_exception (exc);
2158 if (domain == mono_get_root_domain ()) {
2159 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2164 * Unloading seems to cause problems when running NUnit/NAnt, hence
2167 if (g_getenv ("MONO_NO_UNLOAD"))
2169 #ifdef __native_client__
2173 mono_domain_try_unload (domain, (MonoObject**)&exc);
2175 mono_set_pending_exception (exc);
2179 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2181 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2186 return mono_domain_is_unloading (domain);
2190 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2192 mono_unhandled_exception ((MonoObject*) exc);
2196 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2197 MonoReflectionAssembly *refass, MonoArray *args)
2204 image = refass->assembly->image;
2207 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2210 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2213 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2215 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2219 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2221 return ad->data->domain_id;
2225 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2227 MonoDomain *old_domain = mono_domain_get();
2229 if (!mono_domain_set (ad->data, FALSE)) {
2230 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2234 return old_domain->domain;
2238 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2240 MonoDomain *current_domain = mono_domain_get ();
2241 MonoDomain *domain = mono_domain_get_by_id (domainid);
2243 if (!domain || !mono_domain_set (domain, FALSE)) {
2244 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2248 return current_domain->domain;
2252 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2254 mono_thread_push_appdomain_ref (ad->data);
2258 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2260 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2264 * Raise an exception to prevent the managed code from executing a pop
2267 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2271 mono_thread_push_appdomain_ref (domain);
2275 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2277 mono_thread_pop_appdomain_ref ();
2281 ves_icall_System_AppDomain_InternalGetContext ()
2283 return mono_context_get ();
2287 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2289 return mono_domain_get ()->default_context;
2293 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2295 MonoAppContext *old_context = mono_context_get ();
2297 mono_context_set (mc);
2303 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2305 MonoDomain* mono_root_domain = mono_get_root_domain ();
2306 mono_domain_lock (mono_root_domain);
2307 if (process_guid_set) {
2308 mono_domain_unlock (mono_root_domain);
2310 MonoString *res = NULL;
2311 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2312 mono_error_raise_exception (&error);
2315 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2316 process_guid_set = TRUE;
2317 mono_domain_unlock (mono_root_domain);
2322 mono_domain_is_unloading (MonoDomain *domain)
2324 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2331 clear_cached_vtable (MonoVTable *vtable)
2333 MonoClass *klass = vtable->klass;
2334 MonoDomain *domain = vtable->domain;
2335 MonoClassRuntimeInfo *runtime_info;
2338 runtime_info = klass->runtime_info;
2339 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2340 runtime_info->domain_vtables [domain->domain_id] = NULL;
2341 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2342 mono_gc_free_fixed (data);
2345 static G_GNUC_UNUSED void
2346 zero_static_data (MonoVTable *vtable)
2348 MonoClass *klass = vtable->klass;
2351 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2352 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2355 typedef struct unload_data {
2358 char *failure_reason;
2363 unload_data_unref (unload_data *data)
2367 mono_atomic_load_acquire (count, gint32, &data->refcount);
2368 g_assert (count >= 1 && count <= 2);
2373 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2377 deregister_reflection_info_roots_from_list (MonoImage *image)
2379 GSList *list = image->reflection_info_unregister_classes;
2382 MonoClass *klass = (MonoClass *)list->data;
2384 mono_class_free_ref_info (klass);
2389 image->reflection_info_unregister_classes = NULL;
2393 deregister_reflection_info_roots (MonoDomain *domain)
2397 mono_domain_assemblies_lock (domain);
2398 for (list = domain->domain_assemblies; list; list = list->next) {
2399 MonoAssembly *assembly = (MonoAssembly *)list->data;
2400 MonoImage *image = assembly->image;
2404 * No need to take the image lock here since dynamic images are appdomain bound and
2405 * at this point the mutator is gone. Taking the image lock here would mean
2406 * promoting it from a simple lock to a complex lock, which we better avoid if
2409 if (image_is_dynamic (image))
2410 deregister_reflection_info_roots_from_list (image);
2412 for (i = 0; i < image->module_count; ++i) {
2413 MonoImage *module = image->modules [i];
2414 if (module && image_is_dynamic (module))
2415 deregister_reflection_info_roots_from_list (module);
2418 mono_domain_assemblies_unlock (domain);
2421 static guint32 WINAPI
2422 unload_thread_main (void *arg)
2425 unload_data *data = (unload_data*)arg;
2426 MonoDomain *domain = data->domain;
2430 /* Have to attach to the runtime so shutdown can wait for this thread */
2431 /* Force it to be attached to avoid racing during shutdown. */
2432 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2433 mono_error_raise_exception (&error); /* FIXME don't raise here */
2436 * FIXME: Abort our parent thread last, so we can return a failure
2437 * indication if aborting times out.
2439 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2440 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2444 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2445 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2449 /* Finalize all finalizable objects in the doomed appdomain */
2450 if (!mono_domain_finalize (domain, -1)) {
2451 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2455 /* Clear references to our vtables in class->runtime_info.
2456 * We also hold the loader lock because we're going to change
2457 * class->runtime_info.
2460 mono_loader_lock (); //FIXME why do we need the loader lock here?
2461 mono_domain_lock (domain);
2464 * We need to make sure that we don't have any remsets
2465 * pointing into static data of the to-be-freed domain because
2466 * at the next collections they would be invalid. So what we
2467 * do is we first zero all static data and then do a minor
2468 * collection. Because all references in the static data will
2469 * now be null we won't do any unnecessary copies and after
2470 * the collection there won't be any more remsets.
2472 for (i = 0; i < domain->class_vtable_array->len; ++i)
2473 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2474 mono_gc_collect (0);
2476 for (i = 0; i < domain->class_vtable_array->len; ++i)
2477 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2478 deregister_reflection_info_roots (domain);
2480 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2482 mono_domain_unlock (domain);
2483 mono_loader_unlock ();
2485 mono_threads_clear_cached_culture (domain);
2487 domain->state = MONO_APPDOMAIN_UNLOADED;
2489 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2491 /* remove from the handle table the items related to this domain */
2492 mono_gchandle_free_domain (domain);
2494 mono_domain_free (domain, FALSE);
2496 mono_gc_collect (mono_gc_max_generation ());
2498 mono_atomic_store_release (&data->done, TRUE);
2499 unload_data_unref (data);
2500 mono_thread_detach (thread);
2504 mono_atomic_store_release (&data->done, TRUE);
2505 unload_data_unref (data);
2506 mono_thread_detach (thread);
2511 * mono_domain_unload:
2512 * @domain: The domain to unload
2514 * Unloads an appdomain. Follows the process outlined in the comment
2515 * for mono_domain_try_unload.
2518 mono_domain_unload (MonoDomain *domain)
2520 MonoObject *exc = NULL;
2521 mono_domain_try_unload (domain, &exc);
2525 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2529 MONO_PREPARE_BLOCKING;
2530 result = WaitForSingleObjectEx (handle, timeout, alertable);
2531 MONO_FINISH_BLOCKING;
2537 * mono_domain_unload:
2538 * @domain: The domain to unload
2539 * @exc: Exception information
2541 * Unloads an appdomain. Follows the process outlined in:
2542 * http://blogs.gotdotnet.com/cbrumme
2544 * If doing things the 'right' way is too hard or complex, we do it the
2545 * 'simple' way, which means do everything needed to avoid crashes and
2546 * memory leaks, but not much else.
2548 * It is required to pass a valid reference to the exc argument, upon return
2549 * from this function *exc will be set to the exception thrown, if any.
2551 * If this method is not called from an icall (embedded scenario for instance),
2552 * it must not be called with any managed frames on the stack, since the unload
2553 * process could end up trying to abort the current thread.
2556 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2559 HANDLE thread_handle;
2560 MonoAppDomainState prev_state;
2562 unload_data *thread_data;
2563 MonoNativeThreadId tid;
2564 MonoDomain *caller_domain = mono_domain_get ();
2567 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2569 /* Atomically change our state to UNLOADING */
2570 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2571 MONO_APPDOMAIN_UNLOADING_START,
2572 MONO_APPDOMAIN_CREATED);
2573 if (prev_state != MONO_APPDOMAIN_CREATED) {
2574 switch (prev_state) {
2575 case MONO_APPDOMAIN_UNLOADING_START:
2576 case MONO_APPDOMAIN_UNLOADING:
2577 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2579 case MONO_APPDOMAIN_UNLOADED:
2580 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2583 g_warning ("Invalid appdomain state %d", prev_state);
2584 g_assert_not_reached ();
2588 mono_domain_set (domain, FALSE);
2589 /* Notify OnDomainUnload listeners */
2590 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2593 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2595 if (!mono_error_ok (&error)) {
2597 mono_error_cleanup (&error);
2599 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2603 /* Roll back the state change */
2604 domain->state = MONO_APPDOMAIN_CREATED;
2605 mono_domain_set (caller_domain, FALSE);
2608 mono_domain_set (caller_domain, FALSE);
2610 thread_data = g_new0 (unload_data, 1);
2611 thread_data->domain = domain;
2612 thread_data->failure_reason = NULL;
2613 thread_data->done = FALSE;
2614 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2616 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2617 domain->state = MONO_APPDOMAIN_UNLOADING;
2619 * First we create a separate thread for unloading, since
2620 * we might have to abort some threads, including the current one.
2622 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2623 if (thread_handle == NULL)
2625 name = g_strdup_printf ("Unload thread for domain %x", domain);
2626 mono_thread_info_set_name (tid, name);
2627 mono_thread_info_resume (tid);
2630 /* Wait for the thread */
2631 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2632 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2633 /* The unload thread tries to abort us */
2634 /* The icall wrapper will execute the abort */
2635 CloseHandle (thread_handle);
2636 unload_data_unref (thread_data);
2640 CloseHandle (thread_handle);
2642 if (thread_data->failure_reason) {
2643 /* Roll back the state change */
2644 domain->state = MONO_APPDOMAIN_CREATED;
2646 g_warning ("%s", thread_data->failure_reason);
2648 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2650 g_free (thread_data->failure_reason);
2651 thread_data->failure_reason = NULL;
2654 unload_data_unref (thread_data);