2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #undef ASSEMBLY_LOAD_DEBUG
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/domain-internals.h>
39 #include "mono/metadata/metadata-internals.h"
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/exception.h>
42 #include <mono/metadata/exception-internals.h>
43 #include <mono/metadata/threads.h>
44 #include <mono/metadata/threadpool-ms.h>
45 #include <mono/metadata/socket-io.h>
46 #include <mono/metadata/tabledefs.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/monitor.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/file-io.h>
55 #include <mono/metadata/lock-tracer.h>
56 #include <mono/metadata/console-io.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/tokentype.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/reflection-internals.h>
61 #include <mono/metadata/abi-details.h>
62 #include <mono/utils/mono-uri.h>
63 #include <mono/utils/mono-logger-internals.h>
64 #include <mono/utils/mono-path.h>
65 #include <mono/utils/mono-stdlib.h>
66 #include <mono/utils/mono-io-portability.h>
67 #include <mono/utils/mono-error-internals.h>
68 #include <mono/utils/atomic.h>
69 #include <mono/utils/mono-memory-model.h>
70 #include <mono/utils/mono-threads.h>
71 #include <mono/metadata/w32handle.h>
77 * This is the version number of the corlib-runtime interface. When
78 * making changes to this interface (by changing the layout
79 * of classes the runtime knows about, changing icall signature or
80 * semantics etc), increment this variable. Also increment the
81 * pair of this variable in mscorlib in:
82 * mcs/class/corlib/System/Environment.cs
84 * Changes which are already detected at runtime, like the addition
85 * of icalls, do not require an increment.
87 #define MONO_CORLIB_VERSION 164
92 int assemblybinding_count;
97 static gunichar2 process_guid [36];
98 static gboolean process_guid_set = FALSE;
100 static gboolean no_exec = FALSE;
102 static MonoAssembly *
103 mono_domain_assembly_preload (MonoAssemblyName *aname,
104 gchar **assemblies_path,
107 static MonoAssembly *
108 mono_domain_assembly_search (MonoAssemblyName *aname,
112 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
115 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
117 static MonoAppDomain *
118 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
121 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
123 static MonoLoadFunc load_function = NULL;
125 /* Lazy class loading functions */
126 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
129 mono_install_runtime_load (MonoLoadFunc func)
131 load_function = func;
135 mono_runtime_load (const char *filename, const char *runtime_version)
137 g_assert (load_function);
138 return load_function (filename, runtime_version);
142 * mono_runtime_set_no_exec:
144 * Instructs the runtime to operate in static mode, i.e. avoid/do not
145 * allow managed code execution. This is useful for running the AOT
146 * compiler on platforms which allow full-aot execution only. This
147 * should be called before mono_runtime_init ().
150 mono_runtime_set_no_exec (gboolean val)
156 * mono_runtime_get_no_exec:
158 * If true, then the runtime will not allow managed code execution.
161 mono_runtime_get_no_exec (void)
167 create_domain_objects (MonoDomain *domain)
170 MonoDomain *old_domain = mono_domain_get ();
172 MonoVTable *string_vt;
173 MonoClassField *string_empty_fld;
175 if (domain != old_domain) {
176 mono_thread_push_appdomain_ref (domain);
177 mono_domain_set_internal_with_options (domain, FALSE);
181 * Initialize String.Empty. This enables the removal of
182 * the static cctor of the String class.
184 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
185 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
186 g_assert (string_empty_fld);
187 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
188 mono_error_assert_ok (&error);
189 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
190 domain->empty_string = empty_str;
193 * Create an instance early since we can't do it when there is no memory.
195 arg = mono_string_new (domain, "Out of memory");
196 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
197 mono_error_assert_ok (&error);
200 * These two are needed because the signal handlers might be executing on
201 * an alternate stack, and Boehm GC can't handle that.
203 arg = mono_string_new (domain, "A null value was found where an object instance was required");
204 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
205 mono_error_assert_ok (&error);
206 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
207 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
208 mono_error_assert_ok (&error);
210 /*The ephemeron tombstone i*/
211 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
212 mono_error_assert_ok (&error);
214 if (domain != old_domain) {
215 mono_thread_pop_appdomain_ref ();
216 mono_domain_set_internal_with_options (old_domain, FALSE);
220 * This class is used during exception handling, so initialize it here, to prevent
221 * stack overflows while handling stack overflows.
223 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
228 * @domain: domain returned by mono_init ()
230 * Initialize the core AppDomain: this function will run also some
231 * IL initialization code, so it needs the execution engine to be fully
234 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
235 * we know the entry_assembly.
239 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
242 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
243 mono_error_cleanup (&error);
247 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
249 MonoAppDomainSetup *setup;
253 mono_error_init (error);
255 mono_portability_helpers_init ();
257 mono_gc_base_init ();
258 mono_monitor_init ();
259 mono_marshal_init ();
261 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
262 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
263 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
264 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
265 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
266 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
267 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
269 mono_thread_init (start_cb, attach_cb);
271 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
272 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
273 return_if_nok (error);
275 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
277 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
278 return_if_nok (error);
282 domain->setup = setup;
284 mono_thread_attach (domain);
286 mono_type_initialization_init ();
288 if (!mono_runtime_get_no_exec ())
289 create_domain_objects (domain);
291 /* GC init has to happen after thread init */
294 /* contexts use GC handles, so they must be initialized after the GC */
295 mono_context_init_checked (domain, error);
296 return_if_nok (error);
297 mono_context_set (domain->default_context);
299 #ifndef DISABLE_SOCKETS
300 mono_network_init ();
303 mono_console_init ();
306 mono_locks_tracer_init ();
308 /* mscorlib is loaded before we install the load hook */
309 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
315 mono_get_corlib_version (void)
319 MonoClassField *field;
322 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
323 mono_class_init (klass);
324 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
327 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
329 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
330 mono_error_assert_ok (&error);
331 return *(gint32*)((gchar*)value + sizeof (MonoObject));
335 * mono_check_corlib_version
337 * Checks that the corlib that is loaded matches the version of this runtime.
339 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
340 * allocated string with the error otherwise.
343 mono_check_corlib_version (void)
345 int version = mono_get_corlib_version ();
346 if (version != MONO_CORLIB_VERSION)
347 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
349 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
350 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
351 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
352 if (native_offset != managed_offset)
353 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
360 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
362 * Initializes the @domain's default System.Runtime.Remoting's Context.
365 mono_context_init (MonoDomain *domain)
368 mono_context_init_checked (domain, &error);
369 mono_error_cleanup (&error);
373 mono_context_init_checked (MonoDomain *domain, MonoError *error)
376 MonoAppContext *context;
378 mono_error_init (error);
380 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
381 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
382 return_if_nok (error);
384 context->domain_id = domain->domain_id;
385 context->context_id = 0;
386 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
387 domain->default_context = context;
391 * mono_runtime_cleanup:
396 * This must not be called while there are still running threads executing
400 mono_runtime_cleanup (MonoDomain *domain)
402 mono_attach_cleanup ();
404 /* This ends up calling any pending pending (for at most 2 seconds) */
407 mono_thread_cleanup ();
409 #ifndef DISABLE_SOCKETS
410 mono_network_cleanup ();
412 mono_marshal_cleanup ();
414 mono_type_initialization_cleanup ();
416 mono_monitor_cleanup ();
419 static MonoDomainFunc quit_function = NULL;
422 mono_install_runtime_cleanup (MonoDomainFunc func)
424 quit_function = func;
430 if (quit_function != NULL)
431 quit_function (mono_get_root_domain (), NULL);
435 * mono_domain_create_appdomain:
436 * @friendly_name: The friendly name of the appdomain to create
437 * @configuration_file: The configuration file to initialize the appdomain with
439 * Returns a MonoDomain initialized with the appdomain
442 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
446 MonoAppDomainSetup *setup;
449 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
450 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
453 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
455 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
459 return mono_domain_from_appdomain (ad);
461 mono_error_cleanup (&error);
466 * mono_domain_set_config:
467 * @domain: MonoDomain initialized with the appdomain we want to change
468 * @base_dir: new base directory for the appdomain
469 * @config_file_name: path to the new configuration for the app domain
471 * Used to set the system configuration for an appdomain
473 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
474 * Error Initializing the configuration system. ---> System.ArgumentException:
475 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
478 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
480 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
481 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
484 static MonoAppDomainSetup*
485 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
487 MonoDomain *caller_domain;
488 MonoClass *ads_class;
489 MonoAppDomainSetup *copy;
491 mono_error_init (error);
493 caller_domain = mono_domain_get ();
494 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
496 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
497 return_val_if_nok (error, NULL);
499 mono_domain_set_internal (domain);
501 #define XCOPY_FIELD(dst,field,src,error) \
503 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
504 return_val_if_nok (error, NULL); \
505 MONO_OBJECT_SETREF ((dst),field,copied_val); \
508 XCOPY_FIELD (copy, application_base, setup->application_base, error);
509 XCOPY_FIELD (copy, application_name, setup->application_name, error);
510 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
511 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
512 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
513 XCOPY_FIELD (copy, license_file, setup->license_file, error);
514 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
515 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
516 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
517 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
518 copy->publisher_policy = setup->publisher_policy;
519 copy->path_changed = setup->path_changed;
520 copy->loader_optimization = setup->loader_optimization;
521 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
522 copy->disallow_code_downloads = setup->disallow_code_downloads;
523 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
524 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
525 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
526 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
527 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
531 mono_domain_set_internal (caller_domain);
536 static MonoAppDomain *
537 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
542 char *shadow_location;
544 mono_error_init (error);
546 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
548 /* FIXME: pin all those objects */
549 data = mono_domain_create();
551 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
552 return_val_if_nok (error, NULL);
555 data->friendly_name = g_strdup (friendly_name);
557 mono_profiler_appdomain_name (data, data->friendly_name);
559 if (!setup->application_base) {
560 /* Inherit from the root domain since MS.NET does this */
561 MonoDomain *root = mono_get_root_domain ();
562 if (root->setup->application_base) {
563 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
564 mono_error_assert_ok (error); /* FIXME don't swallow the error */
565 MONO_OBJECT_SETREF (setup, application_base, s);
569 mono_context_init_checked (data, error);
570 return_val_if_nok (error, NULL);
572 data->setup = copy_app_domain_setup (data, setup, error);
573 if (!mono_error_ok (error)) {
574 g_free (data->friendly_name);
578 mono_domain_set_options_from_config (data);
579 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
581 #ifndef DISABLE_SHADOW_COPY
582 /*FIXME, guard this for when the debugger is not running */
583 shadow_location = get_shadow_assembly_location_base (data, error);
584 if (!mono_error_ok (error)) {
585 g_free (data->friendly_name);
589 g_free (shadow_location);
592 create_domain_objects (data);
598 * mono_domain_has_type_resolve:
599 * @domain: application domains being looked up
601 * Returns: TRUE if the AppDomain.TypeResolve field has been
605 mono_domain_has_type_resolve (MonoDomain *domain)
607 static MonoClassField *field = NULL;
611 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
615 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
619 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
624 * mono_domain_try_type_resolve:
625 * @domain: application domainwhere the name where the type is going to be resolved
626 * @name: the name of the type to resolve or NULL.
627 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
629 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
630 * the assembly that matches name.
632 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
634 * Returns: A MonoReflectionAssembly or NULL if not found
636 MonoReflectionAssembly *
637 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
640 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
641 mono_error_cleanup (&error);
646 MonoReflectionAssembly *
647 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
649 static MonoMethod *method = NULL;
650 MonoReflectionAssembly *ret;
654 mono_error_init (error);
656 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
658 if (method == NULL) {
659 klass = domain->domain->mbr.obj.vtable->klass;
662 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
663 if (method == NULL) {
664 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
670 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
674 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
675 return_val_if_nok (error, NULL);
681 * mono_domain_owns_vtable_slot:
683 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
686 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
690 mono_domain_lock (domain);
691 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
692 mono_domain_unlock (domain);
699 * @force: force setting.
701 * Set the current appdomain to @domain. If @force is set, set it even
702 * if it is being unloaded.
706 * FALSE if the domain is unloaded
709 mono_domain_set (MonoDomain *domain, gboolean force)
711 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
714 mono_domain_set_internal (domain);
720 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
727 MONO_CHECK_ARG_NULL (name, NULL);
733 str = mono_string_to_utf8_checked (name, &error);
734 if (mono_error_set_pending_exception (&error))
737 mono_domain_lock (add);
739 if (!strcmp (str, "APPBASE"))
740 o = (MonoObject *)add->setup->application_base;
741 else if (!strcmp (str, "APP_CONFIG_FILE"))
742 o = (MonoObject *)add->setup->configuration_file;
743 else if (!strcmp (str, "DYNAMIC_BASE"))
744 o = (MonoObject *)add->setup->dynamic_base;
745 else if (!strcmp (str, "APP_NAME"))
746 o = (MonoObject *)add->setup->application_name;
747 else if (!strcmp (str, "CACHE_BASE"))
748 o = (MonoObject *)add->setup->cache_path;
749 else if (!strcmp (str, "PRIVATE_BINPATH"))
750 o = (MonoObject *)add->setup->private_bin_path;
751 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
752 o = (MonoObject *)add->setup->private_bin_path_probe;
753 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
754 o = (MonoObject *)add->setup->shadow_copy_directories;
755 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
756 o = (MonoObject *)add->setup->shadow_copy_files;
758 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
760 mono_domain_unlock (add);
770 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
774 MONO_CHECK_ARG_NULL (name,);
780 mono_domain_lock (add);
782 mono_g_hash_table_insert (add->env, name, data);
784 mono_domain_unlock (add);
788 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
793 return ad->data->setup;
797 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
802 return mono_string_new (ad->data, ad->data->friendly_name);
806 ves_icall_System_AppDomain_getCurDomain ()
808 MonoDomain *add = mono_domain_get ();
814 ves_icall_System_AppDomain_getRootDomain ()
816 MonoDomain *root = mono_get_root_domain ();
822 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
824 MonoDomain *domain = mono_domain_get ();
826 return domain->throw_unobserved_task_exceptions;
830 get_attribute_value (const gchar **attribute_names,
831 const gchar **attribute_values,
832 const char *att_name)
835 for (n = 0; attribute_names [n] != NULL; n++) {
836 if (strcmp (attribute_names [n], att_name) == 0)
837 return g_strdup (attribute_values [n]);
843 start_element (GMarkupParseContext *context,
844 const gchar *element_name,
845 const gchar **attribute_names,
846 const gchar **attribute_values,
850 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
852 if (strcmp (element_name, "runtime") == 0) {
853 runtime_config->runtime_count++;
857 if (strcmp (element_name, "assemblyBinding") == 0) {
858 runtime_config->assemblybinding_count++;
862 if (runtime_config->runtime_count != 1)
865 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
866 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
868 if (value && g_ascii_strcasecmp (value, "true") == 0)
869 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
872 if (runtime_config->assemblybinding_count != 1)
875 if (strcmp (element_name, "probing") != 0)
878 g_free (runtime_config->domain->private_bin_path);
879 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
880 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
881 g_free (runtime_config->domain->private_bin_path);
882 runtime_config->domain->private_bin_path = NULL;
888 end_element (GMarkupParseContext *context,
889 const gchar *element_name,
893 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
894 if (strcmp (element_name, "runtime") == 0)
895 runtime_config->runtime_count--;
896 else if (strcmp (element_name, "assemblyBinding") == 0)
897 runtime_config->assemblybinding_count--;
901 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
903 RuntimeConfig *state = (RuntimeConfig *)user_data;
905 const gchar *filename;
907 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
908 msg = error && error->message ? error->message : "";
909 g_warning ("Error parsing %s: %s", filename, msg);
912 static const GMarkupParser
922 mono_domain_set_options_from_config (MonoDomain *domain)
925 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
927 GMarkupParseContext *context;
928 RuntimeConfig runtime_config;
931 if (!domain || !domain->setup || !domain->setup->configuration_file)
934 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
935 if (!mono_error_ok (&error)) {
936 mono_error_cleanup (&error);
940 config_file_path = mono_portability_find_file (config_file_name, TRUE);
941 if (!config_file_path)
942 config_file_path = config_file_name;
944 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
947 runtime_config.runtime_count = 0;
948 runtime_config.assemblybinding_count = 0;
949 runtime_config.domain = domain;
950 runtime_config.filename = config_file_path;
953 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
954 offset = 3; /* Skip UTF-8 BOM */
956 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
957 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
958 g_markup_parse_context_end_parse (context, NULL);
959 g_markup_parse_context_free (context);
963 if (config_file_name != config_file_path)
964 g_free (config_file_name);
965 g_free (config_file_path);
969 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
972 MonoAppDomain *ad = NULL;
974 #ifdef DISABLE_APPDOMAINS
975 mono_error_init (&error);
976 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
980 fname = mono_string_to_utf8_checked (friendly_name, &error);
981 if (mono_error_set_pending_exception (&error))
983 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
987 mono_error_set_pending_exception (&error);
992 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
995 MonoDomain *domain = ad->data;
1000 GPtrArray *assemblies;
1002 mono_error_init (&error);
1005 * Make a copy of the list of assemblies because we can't hold the assemblies
1006 * lock while creating objects etc.
1008 assemblies = g_ptr_array_new ();
1009 /* Need to skip internal assembly builders created by remoting */
1010 mono_domain_assemblies_lock (domain);
1011 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1012 ass = (MonoAssembly *)tmp->data;
1013 if (refonly != ass->ref_only)
1015 if (ass->corlib_internal)
1017 g_ptr_array_add (assemblies, ass);
1019 mono_domain_assemblies_unlock (domain);
1021 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1022 if (!is_ok (&error))
1024 for (i = 0; i < assemblies->len; ++i) {
1025 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1026 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1027 if (!mono_error_ok (&error))
1029 mono_array_setref (res, i, ass_obj);
1033 g_ptr_array_free (assemblies, TRUE);
1034 if (!mono_error_ok (&error))
1035 mono_error_set_pending_exception (&error);
1039 MonoReflectionAssembly *
1040 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1042 MonoReflectionAssembly *ret;
1045 MonoBoolean isrefonly;
1046 gpointer params [3];
1048 mono_error_init (error);
1050 if (mono_runtime_get_no_exec ())
1053 g_assert (domain != NULL && fname != NULL);
1055 klass = domain->domain->mbr.obj.vtable->klass;
1058 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1059 if (method == NULL) {
1060 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1064 isrefonly = refonly ? 1 : 0;
1067 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1068 return_val_if_nok (error, NULL);
1071 params [2] = &isrefonly;
1073 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1074 return_val_if_nok (error, NULL);
1080 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1084 MonoReflectionAssembly *assembly;
1085 MonoDomain *domain = mono_domain_get ();
1089 aname_str = mono_stringify_assembly_name (aname);
1091 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1092 str = mono_string_new (domain, aname_str);
1098 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1099 mono_error_cleanup (&error);
1102 return assembly->assembly;
1108 * LOCKING: assumes assemblies_lock in the domain is already locked.
1111 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1115 gboolean destroy_ht = FALSE;
1117 if (!ass->aname.name)
1121 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1125 /* FIXME: handle lazy loaded assemblies */
1126 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1127 g_hash_table_insert (ht, tmp->data, tmp->data);
1129 if (!g_hash_table_lookup (ht, ass)) {
1130 mono_assembly_addref (ass);
1131 g_hash_table_insert (ht, ass, ass);
1132 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1133 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);
1136 if (ass->image->references) {
1137 for (i = 0; ass->image->references [i] != NULL; i++) {
1138 if (ass->image->references [i] != REFERENCE_MISSING)
1139 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1140 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1145 g_hash_table_destroy (ht);
1149 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1151 static MonoClassField *assembly_load_field;
1152 static MonoMethod *assembly_load_method;
1154 MonoDomain *domain = mono_domain_get ();
1155 MonoReflectionAssembly *ref_assembly;
1157 gpointer load_value;
1160 if (!domain->domain)
1161 /* This can happen during startup */
1163 #ifdef ASSEMBLY_LOAD_DEBUG
1164 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1166 klass = domain->domain->mbr.obj.vtable->klass;
1168 mono_domain_assemblies_lock (domain);
1169 add_assemblies_to_domain (domain, assembly, NULL);
1170 mono_domain_assemblies_unlock (domain);
1172 if (assembly_load_field == NULL) {
1173 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1174 g_assert (assembly_load_field);
1177 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1178 if (load_value == NULL) {
1179 /* No events waiting to be triggered */
1183 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1184 mono_error_assert_ok (&error);
1186 if (assembly_load_method == NULL) {
1187 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1188 g_assert (assembly_load_method);
1191 *params = ref_assembly;
1193 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1194 mono_error_cleanup (&error);
1198 * LOCKING: Acquires the domain assemblies lock.
1201 set_domain_search_path (MonoDomain *domain)
1204 MonoAppDomainSetup *setup;
1206 gchar *search_path = NULL;
1209 gchar **pvt_split = NULL;
1210 GError *gerror = NULL;
1211 gint appbaselen = -1;
1214 * We use the low-level domain assemblies lock, since this is called from
1215 * assembly loads hooks, which means this thread might hold the loader lock.
1217 mono_domain_assemblies_lock (domain);
1219 if (!domain->setup) {
1220 mono_domain_assemblies_unlock (domain);
1224 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1225 mono_domain_assemblies_unlock (domain);
1228 setup = domain->setup;
1229 if (!setup->application_base) {
1230 mono_domain_assemblies_unlock (domain);
1231 return; /* Must set application base to get private path working */
1236 if (setup->private_bin_path) {
1237 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1238 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1239 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1240 mono_error_cleanup (&error);
1241 mono_domain_assemblies_unlock (domain);
1246 if (domain->private_bin_path) {
1247 if (search_path == NULL)
1248 search_path = domain->private_bin_path;
1250 gchar *tmp2 = search_path;
1251 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1258 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1259 * directories relative to ApplicationBase separated by semicolons (see
1260 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1261 * The loop below copes with the fact that some Unix applications may use ':' (or
1262 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1263 * ';' for the subsequent split.
1265 * The issue was reported in bug #81446
1268 #ifndef TARGET_WIN32
1271 slen = strlen (search_path);
1272 for (i = 0; i < slen; i++)
1273 if (search_path [i] == ':')
1274 search_path [i] = ';';
1277 pvt_split = g_strsplit (search_path, ";", 1000);
1278 g_free (search_path);
1279 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1284 g_strfreev (pvt_split);
1286 * Don't do this because the first time is called, the domain
1287 * setup is not finished.
1289 * domain->search_path = g_malloc (sizeof (char *));
1290 * domain->search_path [0] = NULL;
1292 mono_domain_assemblies_unlock (domain);
1296 if (domain->search_path)
1297 g_strfreev (domain->search_path);
1299 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1300 tmp [npaths] = NULL;
1302 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1303 if (!mono_error_ok (&error)) {
1304 mono_error_cleanup (&error);
1305 g_strfreev (pvt_split);
1308 mono_domain_assemblies_unlock (domain);
1312 domain->search_path = tmp;
1314 /* FIXME: is this needed? */
1315 if (strncmp (*tmp, "file://", 7) == 0) {
1321 uri = g_strdup_printf ("file:///%s", uri + 7);
1324 uri = mono_escape_uri_string (tmpuri);
1325 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1331 if (gerror != NULL) {
1332 g_warning ("%s\n", gerror->message);
1333 g_error_free (gerror);
1340 for (i = 1; pvt_split && i < npaths; i++) {
1341 if (g_path_is_absolute (pvt_split [i - 1])) {
1342 tmp [i] = g_strdup (pvt_split [i - 1]);
1344 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1347 if (strchr (tmp [i], '.')) {
1351 reduced = mono_path_canonicalize (tmp [i]);
1352 if (appbaselen == -1)
1353 appbaselen = strlen (tmp [0]);
1355 if (strncmp (tmp [0], reduced, appbaselen)) {
1358 tmp [i] = g_strdup ("");
1368 if (setup->private_bin_path_probe != NULL) {
1370 tmp [0] = g_strdup ("");
1373 domain->setup->path_changed = FALSE;
1375 g_strfreev (pvt_split);
1377 mono_domain_assemblies_unlock (domain);
1380 #ifdef DISABLE_SHADOW_COPY
1382 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1388 mono_make_shadow_copy (const char *filename, MonoError *error)
1390 mono_error_init (error);
1391 return (char *) filename;
1395 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1397 guint16 *orig, *dest;
1398 gboolean copy_result;
1400 strcpy (src + srclen - tail_len, extension);
1402 if (IS_PORTABILITY_CASE) {
1403 gchar *file = mono_portability_find_file (src, TRUE);
1409 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1413 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1415 strcpy (target + targetlen - tail_len, extension);
1416 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1420 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1421 copy_result = CopyFile (orig, dest, FALSE);
1423 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1426 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1427 * overwritten when updated in their original locations. */
1429 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1438 get_cstring_hash (const char *str)
1444 if (!str || !str [0])
1449 for (i = 0; i < len; i++) {
1450 h = (h << 5) - h + *p;
1458 * Returned memory is malloc'd. Called must free it
1461 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1463 MonoAppDomainSetup *setup;
1464 char *cache_path, *appname;
1468 mono_error_init (error);
1470 setup = domain->setup;
1471 if (setup->cache_path != NULL && setup->application_name != NULL) {
1472 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1473 return_val_if_nok (error, NULL);
1475 #ifndef TARGET_WIN32
1478 for (i = strlen (cache_path) - 1; i >= 0; i--)
1479 if (cache_path [i] == '\\')
1480 cache_path [i] = '/';
1484 appname = mono_string_to_utf8_checked (setup->application_name, error);
1485 if (!mono_error_ok (error)) {
1486 g_free (cache_path);
1490 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1492 g_free (cache_path);
1494 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1495 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1502 get_shadow_assembly_location (const char *filename, MonoError *error)
1504 gint32 hash = 0, hash2 = 0;
1506 char path_hash [30];
1507 char *bname = g_path_get_basename (filename);
1508 char *dirname = g_path_get_dirname (filename);
1509 char *location, *tmploc;
1510 MonoDomain *domain = mono_domain_get ();
1512 mono_error_init (error);
1514 hash = get_cstring_hash (bname);
1515 hash2 = get_cstring_hash (dirname);
1516 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1517 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1518 tmploc = get_shadow_assembly_location_base (domain, error);
1519 if (!mono_error_ok (error)) {
1525 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1533 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1535 struct stat sbuf_dest;
1537 gchar *real_src = mono_portability_find_file (src, TRUE);
1540 stat_src = (gchar*)src;
1542 stat_src = real_src;
1544 if (stat (stat_src, sbuf_src) == -1) {
1545 time_t tnow = time (NULL);
1550 memset (sbuf_src, 0, sizeof (*sbuf_src));
1551 sbuf_src->st_mtime = tnow;
1552 sbuf_src->st_atime = tnow;
1559 if (stat (dest, &sbuf_dest) == -1)
1562 if (sbuf_src->st_size == sbuf_dest.st_size &&
1563 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1570 shadow_copy_create_ini (const char *shadow, const char *filename)
1580 dir_name = g_path_get_dirname (shadow);
1581 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1583 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1588 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1593 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1594 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1596 if (handle == INVALID_HANDLE_VALUE) {
1600 full_path = mono_path_resolve_symlinks (filename);
1601 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1603 CloseHandle (handle);
1608 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1611 MonoAppDomainSetup *setup;
1614 gchar **directories;
1615 gchar *shadow_status_string;
1617 gboolean shadow_enabled;
1618 gboolean found = FALSE;
1623 setup = domain->setup;
1624 if (setup == NULL || setup->shadow_copy_files == NULL)
1627 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1628 if (!mono_error_ok (&error)) {
1629 mono_error_cleanup (&error);
1632 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1633 g_free (shadow_status_string);
1635 if (!shadow_enabled)
1638 if (setup->shadow_copy_directories == NULL)
1641 /* Is dir_name a shadow_copy destination already? */
1642 base_dir = get_shadow_assembly_location_base (domain, &error);
1643 if (!mono_error_ok (&error)) {
1644 mono_error_cleanup (&error);
1648 if (strstr (dir_name, base_dir)) {
1654 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1655 if (!mono_error_ok (&error)) {
1656 mono_error_cleanup (&error);
1660 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1661 dir_ptr = directories;
1663 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1669 g_strfreev (directories);
1675 This function raises exceptions so it can cause as sorts of nasty stuff if called
1676 while holding a lock.
1677 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1678 or NULL if source file not found.
1679 FIXME bubble up the error instead of raising it here
1682 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1685 gchar *sibling_source, *sibling_target;
1686 gint sibling_source_len, sibling_target_len;
1687 guint16 *orig, *dest;
1690 gboolean copy_result;
1691 struct stat src_sbuf;
1692 struct utimbuf utbuf;
1693 char *dir_name = g_path_get_dirname (filename);
1694 MonoDomain *domain = mono_domain_get ();
1697 mono_error_init (oerror);
1699 set_domain_search_path (domain);
1701 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1703 return (char *) filename;
1706 /* Is dir_name a shadow_copy destination already? */
1707 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1708 if (!mono_error_ok (&error)) {
1709 mono_error_cleanup (&error);
1711 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1715 if (strstr (dir_name, shadow_dir)) {
1716 g_free (shadow_dir);
1718 return (char *) filename;
1720 g_free (shadow_dir);
1723 shadow = get_shadow_assembly_location (filename, &error);
1724 if (!mono_error_ok (&error)) {
1725 mono_error_cleanup (&error);
1726 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1730 if (g_ensure_directory_exists (shadow) == FALSE) {
1732 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1736 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1737 return (char*) shadow;
1739 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1740 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1743 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1744 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1745 * and not have it runtime error" */
1746 attrs = GetFileAttributes (orig);
1747 if (attrs == INVALID_FILE_ATTRIBUTES) {
1749 return (char *)filename;
1752 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1753 copy_result = CopyFile (orig, dest, FALSE);
1755 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1758 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1759 * overwritten when updated in their original locations. */
1761 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1766 if (copy_result == FALSE) {
1769 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1770 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1771 return NULL; /* file not found, shadow copy failed */
1773 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1777 /* attempt to copy .mdb, .config if they exist */
1778 sibling_source = g_strconcat (filename, ".config", NULL);
1779 sibling_source_len = strlen (sibling_source);
1780 sibling_target = g_strconcat (shadow, ".config", NULL);
1781 sibling_target_len = strlen (sibling_target);
1783 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1785 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1787 g_free (sibling_source);
1788 g_free (sibling_target);
1792 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1796 /* Create a .ini file containing the original assembly location */
1797 if (!shadow_copy_create_ini (shadow, filename)) {
1799 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1803 utbuf.actime = src_sbuf.st_atime;
1804 utbuf.modtime = src_sbuf.st_mtime;
1805 utime (shadow, &utbuf);
1809 #endif /* DISABLE_SHADOW_COPY */
1812 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1814 if (appdomain == NULL)
1817 return appdomain->data;
1821 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1822 const gchar *path3, const gchar *path4,
1823 gboolean refonly, gboolean is_private)
1826 gboolean found = FALSE;
1829 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1831 if (IS_PORTABILITY_SET) {
1832 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1835 fullpath = new_fullpath;
1839 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1842 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1845 return (*assembly != NULL);
1848 static MonoAssembly *
1849 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1851 MonoAssembly *result = NULL;
1854 const gchar *local_culture;
1856 gboolean is_private = FALSE;
1858 if (!culture || *culture == '\0') {
1861 local_culture = culture;
1864 filename = g_strconcat (name, ".dll", NULL);
1865 len = strlen (filename);
1867 for (path = search_path; *path; path++) {
1868 if (**path == '\0') {
1870 continue; /* Ignore empty ApplicationBase */
1873 /* See test cases in bug #58992 and bug #57710 */
1874 /* 1st try: [culture]/[name].dll (culture may be empty) */
1875 strcpy (filename + len - 4, ".dll");
1876 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1879 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1880 strcpy (filename + len - 4, ".exe");
1881 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1884 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1885 strcpy (filename + len - 4, ".dll");
1886 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1889 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1890 strcpy (filename + len - 4, ".exe");
1891 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1900 * Try loading the assembly from ApplicationBase and PrivateBinPath
1901 * and then from assemblies_path if any.
1902 * LOCKING: This is called from the assembly loading code, which means the caller
1903 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1905 static MonoAssembly *
1906 mono_domain_assembly_preload (MonoAssemblyName *aname,
1907 gchar **assemblies_path,
1910 MonoDomain *domain = mono_domain_get ();
1911 MonoAssembly *result = NULL;
1912 gboolean refonly = GPOINTER_TO_UINT (user_data);
1914 set_domain_search_path (domain);
1916 if (domain->search_path && domain->search_path [0] != NULL) {
1917 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1920 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1921 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1928 * Check whenever a given assembly was already loaded in the current appdomain.
1930 static MonoAssembly *
1931 mono_domain_assembly_search (MonoAssemblyName *aname,
1934 MonoDomain *domain = mono_domain_get ();
1937 gboolean refonly = GPOINTER_TO_UINT (user_data);
1939 mono_domain_assemblies_lock (domain);
1940 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1941 ass = (MonoAssembly *)tmp->data;
1942 /* Dynamic assemblies can't match here in MS.NET */
1943 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1946 mono_domain_assemblies_unlock (domain);
1949 mono_domain_assemblies_unlock (domain);
1954 MonoReflectionAssembly *
1955 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1958 MonoReflectionAssembly *result;
1959 MonoDomain *domain = mono_domain_get ();
1960 char *name, *filename;
1961 MonoImageOpenStatus status = MONO_IMAGE_OK;
1962 MonoAssembly *ass = NULL;
1967 mono_error_init (&error);
1969 if (fname == NULL) {
1970 mono_error_set_argument_null (&error, "assemblyFile", "");
1974 name = filename = mono_string_to_utf8_checked (fname, &error);
1975 if (!is_ok (&error))
1978 ass = mono_assembly_open_full (filename, &status, refOnly);
1981 if (status == MONO_IMAGE_IMAGE_INVALID)
1982 mono_error_set_bad_image_name (&error, g_strdup (name), "");
1984 mono_error_set_assembly_load (&error, g_strdup (name), "%s", "");
1988 result = mono_assembly_get_object_checked (domain, ass, &error);
1991 mono_error_set_pending_exception (&error);
1996 MonoReflectionAssembly *
1997 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1998 MonoArray *raw_assembly,
1999 MonoArray *raw_symbol_store, MonoObject *evidence,
2000 MonoBoolean refonly)
2004 MonoReflectionAssembly *refass = NULL;
2005 MonoDomain *domain = ad->data;
2006 MonoImageOpenStatus status;
2007 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2008 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2011 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2015 if (raw_symbol_store != NULL)
2016 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2018 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2022 mono_image_close (image);
2023 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2027 refass = mono_assembly_get_object_checked (domain, ass, &error);
2029 mono_error_set_pending_exception (&error);
2031 MONO_OBJECT_SETREF (refass, evidence, evidence);
2035 MonoReflectionAssembly *
2036 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2039 MonoDomain *domain = ad->data;
2040 MonoImageOpenStatus status = MONO_IMAGE_OK;
2042 MonoAssemblyName aname;
2043 MonoReflectionAssembly *refass = NULL;
2049 name = mono_string_to_utf8_checked (assRef, &error);
2050 if (mono_error_set_pending_exception (&error))
2052 parsed = mono_assembly_name_parse (name, &aname);
2055 /* This is a parse error... */
2057 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2058 if (!is_ok (&error))
2064 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2065 mono_assembly_name_free (&aname);
2068 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2070 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2071 if (!is_ok (&error))
2078 ass = refass->assembly;
2082 if (refass == NULL) {
2083 refass = mono_assembly_get_object_checked (domain, ass, &error);
2084 if (!is_ok (&error))
2088 MONO_OBJECT_SETREF (refass, evidence, evidence);
2092 mono_error_set_pending_exception (&error);
2097 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2099 MonoException *exc = NULL;
2100 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2102 if (NULL == domain) {
2103 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2104 mono_set_pending_exception (exc);
2108 if (domain == mono_get_root_domain ()) {
2109 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2114 * Unloading seems to cause problems when running NUnit/NAnt, hence
2117 if (g_getenv ("MONO_NO_UNLOAD"))
2119 #ifdef __native_client__
2123 mono_domain_try_unload (domain, (MonoObject**)&exc);
2125 mono_set_pending_exception (exc);
2129 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2131 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2136 return mono_domain_is_unloading (domain);
2140 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2142 mono_unhandled_exception ((MonoObject*) exc);
2146 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2147 MonoReflectionAssembly *refass, MonoArray *args)
2154 image = refass->assembly->image;
2157 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2160 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2163 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2164 mono_error_assert_ok (&error);
2167 int res = mono_runtime_exec_main_checked (method, (MonoArray *)args, &error);
2168 mono_error_set_pending_exception (&error);
2173 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2175 return ad->data->domain_id;
2179 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2181 MonoDomain *old_domain = mono_domain_get();
2183 if (!mono_domain_set (ad->data, FALSE)) {
2184 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2188 return old_domain->domain;
2192 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2194 MonoDomain *current_domain = mono_domain_get ();
2195 MonoDomain *domain = mono_domain_get_by_id (domainid);
2197 if (!domain || !mono_domain_set (domain, FALSE)) {
2198 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2202 return current_domain->domain;
2206 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2208 mono_thread_push_appdomain_ref (ad->data);
2212 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2214 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2218 * Raise an exception to prevent the managed code from executing a pop
2221 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2225 mono_thread_push_appdomain_ref (domain);
2229 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2231 mono_thread_pop_appdomain_ref ();
2235 ves_icall_System_AppDomain_InternalGetContext ()
2237 return mono_context_get ();
2241 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2243 return mono_domain_get ()->default_context;
2247 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2249 MonoAppContext *old_context = mono_context_get ();
2251 mono_context_set (mc);
2257 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2259 MonoDomain* mono_root_domain = mono_get_root_domain ();
2260 mono_domain_lock (mono_root_domain);
2261 if (process_guid_set) {
2262 mono_domain_unlock (mono_root_domain);
2264 MonoString *res = NULL;
2265 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2266 mono_error_set_pending_exception (&error);
2269 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2270 process_guid_set = TRUE;
2271 mono_domain_unlock (mono_root_domain);
2276 mono_domain_is_unloading (MonoDomain *domain)
2278 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2285 clear_cached_vtable (MonoVTable *vtable)
2287 MonoClass *klass = vtable->klass;
2288 MonoDomain *domain = vtable->domain;
2289 MonoClassRuntimeInfo *runtime_info;
2292 runtime_info = klass->runtime_info;
2293 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2294 runtime_info->domain_vtables [domain->domain_id] = NULL;
2295 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2296 mono_gc_free_fixed (data);
2299 static G_GNUC_UNUSED void
2300 zero_static_data (MonoVTable *vtable)
2302 MonoClass *klass = vtable->klass;
2305 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2306 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2309 typedef struct unload_data {
2312 char *failure_reason;
2317 unload_data_unref (unload_data *data)
2321 mono_atomic_load_acquire (count, gint32, &data->refcount);
2322 g_assert (count >= 1 && count <= 2);
2327 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2331 deregister_reflection_info_roots_from_list (MonoImage *image)
2333 GSList *list = image->reflection_info_unregister_classes;
2336 MonoClass *klass = (MonoClass *)list->data;
2338 mono_class_free_ref_info (klass);
2343 image->reflection_info_unregister_classes = NULL;
2347 deregister_reflection_info_roots (MonoDomain *domain)
2351 mono_domain_assemblies_lock (domain);
2352 for (list = domain->domain_assemblies; list; list = list->next) {
2353 MonoAssembly *assembly = (MonoAssembly *)list->data;
2354 MonoImage *image = assembly->image;
2358 * No need to take the image lock here since dynamic images are appdomain bound and
2359 * at this point the mutator is gone. Taking the image lock here would mean
2360 * promoting it from a simple lock to a complex lock, which we better avoid if
2363 if (image_is_dynamic (image))
2364 deregister_reflection_info_roots_from_list (image);
2366 for (i = 0; i < image->module_count; ++i) {
2367 MonoImage *module = image->modules [i];
2368 if (module && image_is_dynamic (module))
2369 deregister_reflection_info_roots_from_list (module);
2372 mono_domain_assemblies_unlock (domain);
2376 unload_thread_main (void *arg)
2379 unload_data *data = (unload_data*)arg;
2380 MonoDomain *domain = data->domain;
2384 /* Have to attach to the runtime so shutdown can wait for this thread */
2385 /* Force it to be attached to avoid racing during shutdown. */
2386 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2388 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2389 if (!is_ok (&error)) {
2390 data->failure_reason = g_strdup (mono_error_get_message (&error));
2391 mono_error_cleanup (&error);
2396 * FIXME: Abort our parent thread last, so we can return a failure
2397 * indication if aborting times out.
2399 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2400 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2404 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2405 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2409 /* Finalize all finalizable objects in the doomed appdomain */
2410 if (!mono_domain_finalize (domain, -1)) {
2411 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2415 /* Clear references to our vtables in class->runtime_info.
2416 * We also hold the loader lock because we're going to change
2417 * class->runtime_info.
2420 mono_loader_lock (); //FIXME why do we need the loader lock here?
2421 mono_domain_lock (domain);
2424 * We need to make sure that we don't have any remsets
2425 * pointing into static data of the to-be-freed domain because
2426 * at the next collections they would be invalid. So what we
2427 * do is we first zero all static data and then do a minor
2428 * collection. Because all references in the static data will
2429 * now be null we won't do any unnecessary copies and after
2430 * the collection there won't be any more remsets.
2432 for (i = 0; i < domain->class_vtable_array->len; ++i)
2433 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2434 mono_gc_collect (0);
2436 for (i = 0; i < domain->class_vtable_array->len; ++i)
2437 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2438 deregister_reflection_info_roots (domain);
2440 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2442 mono_domain_unlock (domain);
2443 mono_loader_unlock ();
2445 mono_threads_clear_cached_culture (domain);
2447 domain->state = MONO_APPDOMAIN_UNLOADED;
2449 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2451 /* remove from the handle table the items related to this domain */
2452 mono_gchandle_free_domain (domain);
2454 mono_domain_free (domain, FALSE);
2456 mono_gc_collect (mono_gc_max_generation ());
2458 mono_atomic_store_release (&data->done, TRUE);
2459 unload_data_unref (data);
2460 mono_thread_detach (thread);
2464 mono_atomic_store_release (&data->done, TRUE);
2465 unload_data_unref (data);
2466 mono_thread_detach (thread);
2471 * mono_domain_unload:
2472 * @domain: The domain to unload
2474 * Unloads an appdomain. Follows the process outlined in the comment
2475 * for mono_domain_try_unload.
2478 mono_domain_unload (MonoDomain *domain)
2480 MonoObject *exc = NULL;
2481 mono_domain_try_unload (domain, &exc);
2484 static MonoThreadInfoWaitRet
2485 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2487 MonoThreadInfoWaitRet result;
2490 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2497 * mono_domain_unload:
2498 * @domain: The domain to unload
2499 * @exc: Exception information
2501 * Unloads an appdomain. Follows the process outlined in:
2502 * http://blogs.gotdotnet.com/cbrumme
2504 * If doing things the 'right' way is too hard or complex, we do it the
2505 * 'simple' way, which means do everything needed to avoid crashes and
2506 * memory leaks, but not much else.
2508 * It is required to pass a valid reference to the exc argument, upon return
2509 * from this function *exc will be set to the exception thrown, if any.
2511 * If this method is not called from an icall (embedded scenario for instance),
2512 * it must not be called with any managed frames on the stack, since the unload
2513 * process could end up trying to abort the current thread.
2516 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2519 MonoThreadHandle *thread_handle;
2520 MonoAppDomainState prev_state;
2522 unload_data *thread_data;
2523 MonoNativeThreadId tid;
2524 MonoDomain *caller_domain = mono_domain_get ();
2526 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2528 /* Atomically change our state to UNLOADING */
2529 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2530 MONO_APPDOMAIN_UNLOADING_START,
2531 MONO_APPDOMAIN_CREATED);
2532 if (prev_state != MONO_APPDOMAIN_CREATED) {
2533 switch (prev_state) {
2534 case MONO_APPDOMAIN_UNLOADING_START:
2535 case MONO_APPDOMAIN_UNLOADING:
2536 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2538 case MONO_APPDOMAIN_UNLOADED:
2539 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2542 g_warning ("Invalid appdomain state %d", prev_state);
2543 g_assert_not_reached ();
2547 mono_domain_set (domain, FALSE);
2548 /* Notify OnDomainUnload listeners */
2549 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2552 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2554 if (!mono_error_ok (&error)) {
2556 mono_error_cleanup (&error);
2558 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2562 /* Roll back the state change */
2563 domain->state = MONO_APPDOMAIN_CREATED;
2564 mono_domain_set (caller_domain, FALSE);
2567 mono_domain_set (caller_domain, FALSE);
2569 thread_data = g_new0 (unload_data, 1);
2570 thread_data->domain = domain;
2571 thread_data->failure_reason = NULL;
2572 thread_data->done = FALSE;
2573 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2575 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2576 domain->state = MONO_APPDOMAIN_UNLOADING;
2578 * First we create a separate thread for unloading, since
2579 * we might have to abort some threads, including the current one.
2581 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, NULL, &tid);
2582 if (thread_handle == NULL)
2585 /* Wait for the thread */
2586 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2587 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2588 /* The unload thread tries to abort us */
2589 /* The icall wrapper will execute the abort */
2590 mono_threads_close_thread_handle (thread_handle);
2591 unload_data_unref (thread_data);
2596 mono_threads_close_thread_handle (thread_handle);
2598 if (thread_data->failure_reason) {
2599 /* Roll back the state change */
2600 domain->state = MONO_APPDOMAIN_CREATED;
2602 g_warning ("%s", thread_data->failure_reason);
2604 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2606 g_free (thread_data->failure_reason);
2607 thread_data->failure_reason = NULL;
2610 unload_data_unref (thread_data);