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 163
92 int assemblybinding_count;
97 static gunichar2 process_guid [36];
98 static gboolean process_guid_set = FALSE;
100 static gboolean no_exec = FALSE;
102 static MonoAssembly *
103 mono_domain_assembly_preload (MonoAssemblyName *aname,
104 gchar **assemblies_path,
107 static MonoAssembly *
108 mono_domain_assembly_search (MonoAssemblyName *aname,
112 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
115 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
117 static MonoAppDomain *
118 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
121 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
123 static MonoLoadFunc load_function = NULL;
125 /* Lazy class loading functions */
126 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
129 mono_install_runtime_load (MonoLoadFunc func)
131 load_function = func;
135 mono_runtime_load (const char *filename, const char *runtime_version)
137 g_assert (load_function);
138 return load_function (filename, runtime_version);
142 * mono_runtime_set_no_exec:
144 * Instructs the runtime to operate in static mode, i.e. avoid/do not
145 * allow managed code execution. This is useful for running the AOT
146 * compiler on platforms which allow full-aot execution only. This
147 * should be called before mono_runtime_init ().
150 mono_runtime_set_no_exec (gboolean val)
156 * mono_runtime_get_no_exec:
158 * If true, then the runtime will not allow managed code execution.
161 mono_runtime_get_no_exec (void)
167 create_domain_objects (MonoDomain *domain)
170 MonoDomain *old_domain = mono_domain_get ();
172 MonoVTable *string_vt;
173 MonoClassField *string_empty_fld;
175 if (domain != old_domain) {
176 mono_thread_push_appdomain_ref (domain);
177 mono_domain_set_internal_with_options (domain, FALSE);
181 * Initialize String.Empty. This enables the removal of
182 * the static cctor of the String class.
184 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
185 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
186 g_assert (string_empty_fld);
187 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
188 mono_error_assert_ok (&error);
189 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
192 * Create an instance early since we can't do it when there is no memory.
194 arg = mono_string_new (domain, "Out of memory");
195 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
196 mono_error_assert_ok (&error);
199 * These two are needed because the signal handlers might be executing on
200 * an alternate stack, and Boehm GC can't handle that.
202 arg = mono_string_new (domain, "A null value was found where an object instance was required");
203 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
204 mono_error_assert_ok (&error);
205 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
206 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
207 mono_error_assert_ok (&error);
209 /*The ephemeron tombstone i*/
210 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
211 mono_error_assert_ok (&error);
213 if (domain != old_domain) {
214 mono_thread_pop_appdomain_ref ();
215 mono_domain_set_internal_with_options (old_domain, FALSE);
219 * This class is used during exception handling, so initialize it here, to prevent
220 * stack overflows while handling stack overflows.
222 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
227 * @domain: domain returned by mono_init ()
229 * Initialize the core AppDomain: this function will run also some
230 * IL initialization code, so it needs the execution engine to be fully
233 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
234 * we know the entry_assembly.
238 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
241 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
242 mono_error_cleanup (&error);
246 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
248 MonoAppDomainSetup *setup;
252 mono_error_init (error);
254 mono_portability_helpers_init ();
256 mono_gc_base_init ();
257 mono_monitor_init ();
258 mono_marshal_init ();
260 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
261 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
262 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
263 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
264 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
265 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
266 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
268 mono_thread_init (start_cb, attach_cb);
270 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
271 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
272 return_if_nok (error);
274 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
276 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
277 return_if_nok (error);
281 domain->setup = setup;
283 mono_thread_attach (domain);
285 mono_type_initialization_init ();
287 if (!mono_runtime_get_no_exec ())
288 create_domain_objects (domain);
290 /* GC init has to happen after thread init */
293 /* contexts use GC handles, so they must be initialized after the GC */
294 mono_context_init_checked (domain, error);
295 return_if_nok (error);
296 mono_context_set (domain->default_context);
298 #ifndef DISABLE_SOCKETS
299 mono_network_init ();
302 mono_console_init ();
305 mono_locks_tracer_init ();
307 /* mscorlib is loaded before we install the load hook */
308 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
314 mono_get_corlib_version (void)
318 MonoClassField *field;
321 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
322 mono_class_init (klass);
323 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
326 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
328 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
329 mono_error_assert_ok (&error);
330 return *(gint32*)((gchar*)value + sizeof (MonoObject));
334 * mono_check_corlib_version
336 * Checks that the corlib that is loaded matches the version of this runtime.
338 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
339 * allocated string with the error otherwise.
342 mono_check_corlib_version (void)
344 int version = mono_get_corlib_version ();
345 if (version != MONO_CORLIB_VERSION)
346 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
348 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
349 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
350 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
351 if (native_offset != managed_offset)
352 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
359 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
361 * Initializes the @domain's default System.Runtime.Remoting's Context.
364 mono_context_init (MonoDomain *domain)
367 mono_context_init_checked (domain, &error);
368 mono_error_cleanup (&error);
372 mono_context_init_checked (MonoDomain *domain, MonoError *error)
375 MonoAppContext *context;
377 mono_error_init (error);
379 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
380 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
381 return_if_nok (error);
383 context->domain_id = domain->domain_id;
384 context->context_id = 0;
385 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
386 domain->default_context = context;
390 * mono_runtime_cleanup:
395 * This must not be called while there are still running threads executing
399 mono_runtime_cleanup (MonoDomain *domain)
401 mono_attach_cleanup ();
403 /* This ends up calling any pending pending (for at most 2 seconds) */
406 mono_thread_cleanup ();
408 #ifndef DISABLE_SOCKETS
409 mono_network_cleanup ();
411 mono_marshal_cleanup ();
413 mono_type_initialization_cleanup ();
415 mono_monitor_cleanup ();
418 static MonoDomainFunc quit_function = NULL;
421 mono_install_runtime_cleanup (MonoDomainFunc func)
423 quit_function = func;
429 if (quit_function != NULL)
430 quit_function (mono_get_root_domain (), NULL);
434 * mono_domain_create_appdomain:
435 * @friendly_name: The friendly name of the appdomain to create
436 * @configuration_file: The configuration file to initialize the appdomain with
438 * Returns a MonoDomain initialized with the appdomain
441 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
445 MonoAppDomainSetup *setup;
448 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
449 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
452 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
454 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
458 return mono_domain_from_appdomain (ad);
460 mono_error_cleanup (&error);
465 * mono_domain_set_config:
466 * @domain: MonoDomain initialized with the appdomain we want to change
467 * @base_dir: new base directory for the appdomain
468 * @config_file_name: path to the new configuration for the app domain
470 * Used to set the system configuration for an appdomain
472 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
473 * Error Initializing the configuration system. ---> System.ArgumentException:
474 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
477 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
479 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
480 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
483 static MonoAppDomainSetup*
484 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
486 MonoDomain *caller_domain;
487 MonoClass *ads_class;
488 MonoAppDomainSetup *copy;
490 mono_error_init (error);
492 caller_domain = mono_domain_get ();
493 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
495 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
496 return_val_if_nok (error, NULL);
498 mono_domain_set_internal (domain);
500 #define XCOPY_FIELD(dst,field,src,error) \
502 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
503 return_val_if_nok (error, NULL); \
504 MONO_OBJECT_SETREF ((dst),field,copied_val); \
507 XCOPY_FIELD (copy, application_base, setup->application_base, error);
508 XCOPY_FIELD (copy, application_name, setup->application_name, error);
509 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
510 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
511 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
512 XCOPY_FIELD (copy, license_file, setup->license_file, error);
513 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
514 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
515 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
516 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
517 copy->publisher_policy = setup->publisher_policy;
518 copy->path_changed = setup->path_changed;
519 copy->loader_optimization = setup->loader_optimization;
520 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
521 copy->disallow_code_downloads = setup->disallow_code_downloads;
522 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
523 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
524 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
525 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
526 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
530 mono_domain_set_internal (caller_domain);
535 static MonoAppDomain *
536 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
541 char *shadow_location;
543 mono_error_init (error);
545 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
547 /* FIXME: pin all those objects */
548 data = mono_domain_create();
550 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
551 return_val_if_nok (error, NULL);
554 data->friendly_name = g_strdup (friendly_name);
556 mono_profiler_appdomain_name (data, data->friendly_name);
558 if (!setup->application_base) {
559 /* Inherit from the root domain since MS.NET does this */
560 MonoDomain *root = mono_get_root_domain ();
561 if (root->setup->application_base) {
562 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
563 mono_error_assert_ok (error); /* FIXME don't swallow the error */
564 MONO_OBJECT_SETREF (setup, application_base, s);
568 mono_context_init_checked (data, error);
569 return_val_if_nok (error, NULL);
571 data->setup = copy_app_domain_setup (data, setup, error);
572 if (!mono_error_ok (error)) {
573 g_free (data->friendly_name);
577 mono_domain_set_options_from_config (data);
578 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
580 #ifndef DISABLE_SHADOW_COPY
581 /*FIXME, guard this for when the debugger is not running */
582 shadow_location = get_shadow_assembly_location_base (data, error);
583 if (!mono_error_ok (error)) {
584 g_free (data->friendly_name);
588 g_free (shadow_location);
591 create_domain_objects (data);
597 * mono_domain_has_type_resolve:
598 * @domain: application domains being looked up
600 * Returns: TRUE if the AppDomain.TypeResolve field has been
604 mono_domain_has_type_resolve (MonoDomain *domain)
606 static MonoClassField *field = NULL;
610 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
614 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
618 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
623 * mono_domain_try_type_resolve:
624 * @domain: application domainwhere the name where the type is going to be resolved
625 * @name: the name of the type to resolve or NULL.
626 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
628 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
629 * the assembly that matches name.
631 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
633 * Returns: A MonoReflectionAssembly or NULL if not found
635 MonoReflectionAssembly *
636 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
639 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
640 mono_error_cleanup (&error);
645 MonoReflectionAssembly *
646 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
648 static MonoMethod *method = NULL;
649 MonoReflectionAssembly *ret;
653 mono_error_init (error);
655 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
657 if (method == NULL) {
658 klass = domain->domain->mbr.obj.vtable->klass;
661 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
662 if (method == NULL) {
663 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
669 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
673 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
674 return_val_if_nok (error, NULL);
680 * mono_domain_owns_vtable_slot:
682 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
685 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
689 mono_domain_lock (domain);
690 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
691 mono_domain_unlock (domain);
698 * @force: force setting.
700 * Set the current appdomain to @domain. If @force is set, set it even
701 * if it is being unloaded.
705 * FALSE if the domain is unloaded
708 mono_domain_set (MonoDomain *domain, gboolean force)
710 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
713 mono_domain_set_internal (domain);
719 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
726 MONO_CHECK_ARG_NULL (name, NULL);
732 str = mono_string_to_utf8_checked (name, &error);
733 if (mono_error_set_pending_exception (&error))
736 mono_domain_lock (add);
738 if (!strcmp (str, "APPBASE"))
739 o = (MonoObject *)add->setup->application_base;
740 else if (!strcmp (str, "APP_CONFIG_FILE"))
741 o = (MonoObject *)add->setup->configuration_file;
742 else if (!strcmp (str, "DYNAMIC_BASE"))
743 o = (MonoObject *)add->setup->dynamic_base;
744 else if (!strcmp (str, "APP_NAME"))
745 o = (MonoObject *)add->setup->application_name;
746 else if (!strcmp (str, "CACHE_BASE"))
747 o = (MonoObject *)add->setup->cache_path;
748 else if (!strcmp (str, "PRIVATE_BINPATH"))
749 o = (MonoObject *)add->setup->private_bin_path;
750 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
751 o = (MonoObject *)add->setup->private_bin_path_probe;
752 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
753 o = (MonoObject *)add->setup->shadow_copy_directories;
754 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
755 o = (MonoObject *)add->setup->shadow_copy_files;
757 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
759 mono_domain_unlock (add);
769 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
773 MONO_CHECK_ARG_NULL (name,);
779 mono_domain_lock (add);
781 mono_g_hash_table_insert (add->env, name, data);
783 mono_domain_unlock (add);
787 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
792 return ad->data->setup;
796 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
801 return mono_string_new (ad->data, ad->data->friendly_name);
805 ves_icall_System_AppDomain_getCurDomain ()
807 MonoDomain *add = mono_domain_get ();
813 ves_icall_System_AppDomain_getRootDomain ()
815 MonoDomain *root = mono_get_root_domain ();
821 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
823 MonoDomain *domain = mono_domain_get ();
825 return domain->throw_unobserved_task_exceptions;
829 get_attribute_value (const gchar **attribute_names,
830 const gchar **attribute_values,
831 const char *att_name)
834 for (n = 0; attribute_names [n] != NULL; n++) {
835 if (strcmp (attribute_names [n], att_name) == 0)
836 return g_strdup (attribute_values [n]);
842 start_element (GMarkupParseContext *context,
843 const gchar *element_name,
844 const gchar **attribute_names,
845 const gchar **attribute_values,
849 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
851 if (strcmp (element_name, "runtime") == 0) {
852 runtime_config->runtime_count++;
856 if (strcmp (element_name, "assemblyBinding") == 0) {
857 runtime_config->assemblybinding_count++;
861 if (runtime_config->runtime_count != 1)
864 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
865 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
867 if (value && g_ascii_strcasecmp (value, "true") == 0)
868 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
871 if (runtime_config->assemblybinding_count != 1)
874 if (strcmp (element_name, "probing") != 0)
877 g_free (runtime_config->domain->private_bin_path);
878 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
879 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
880 g_free (runtime_config->domain->private_bin_path);
881 runtime_config->domain->private_bin_path = NULL;
887 end_element (GMarkupParseContext *context,
888 const gchar *element_name,
892 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
893 if (strcmp (element_name, "runtime") == 0)
894 runtime_config->runtime_count--;
895 else if (strcmp (element_name, "assemblyBinding") == 0)
896 runtime_config->assemblybinding_count--;
900 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
902 RuntimeConfig *state = (RuntimeConfig *)user_data;
904 const gchar *filename;
906 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
907 msg = error && error->message ? error->message : "";
908 g_warning ("Error parsing %s: %s", filename, msg);
911 static const GMarkupParser
921 mono_domain_set_options_from_config (MonoDomain *domain)
924 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
926 GMarkupParseContext *context;
927 RuntimeConfig runtime_config;
930 if (!domain || !domain->setup || !domain->setup->configuration_file)
933 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
934 if (!mono_error_ok (&error)) {
935 mono_error_cleanup (&error);
939 config_file_path = mono_portability_find_file (config_file_name, TRUE);
940 if (!config_file_path)
941 config_file_path = config_file_name;
943 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
946 runtime_config.runtime_count = 0;
947 runtime_config.assemblybinding_count = 0;
948 runtime_config.domain = domain;
949 runtime_config.filename = config_file_path;
952 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
953 offset = 3; /* Skip UTF-8 BOM */
955 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
956 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
957 g_markup_parse_context_end_parse (context, NULL);
958 g_markup_parse_context_free (context);
962 if (config_file_name != config_file_path)
963 g_free (config_file_name);
964 g_free (config_file_path);
968 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
971 MonoAppDomain *ad = NULL;
973 #ifdef DISABLE_APPDOMAINS
974 mono_error_init (&error);
975 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
979 fname = mono_string_to_utf8_checked (friendly_name, &error);
980 if (mono_error_set_pending_exception (&error))
982 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
986 mono_error_set_pending_exception (&error);
991 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
994 MonoDomain *domain = ad->data;
999 GPtrArray *assemblies;
1001 mono_error_init (&error);
1004 * Make a copy of the list of assemblies because we can't hold the assemblies
1005 * lock while creating objects etc.
1007 assemblies = g_ptr_array_new ();
1008 /* Need to skip internal assembly builders created by remoting */
1009 mono_domain_assemblies_lock (domain);
1010 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1011 ass = (MonoAssembly *)tmp->data;
1012 if (refonly != ass->ref_only)
1014 if (ass->corlib_internal)
1016 g_ptr_array_add (assemblies, ass);
1018 mono_domain_assemblies_unlock (domain);
1020 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1021 if (!is_ok (&error))
1023 for (i = 0; i < assemblies->len; ++i) {
1024 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1025 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1026 if (!mono_error_ok (&error))
1028 mono_array_setref (res, i, ass_obj);
1032 g_ptr_array_free (assemblies, TRUE);
1033 if (!mono_error_ok (&error))
1034 mono_error_set_pending_exception (&error);
1038 MonoReflectionAssembly *
1039 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1041 MonoReflectionAssembly *ret;
1044 MonoBoolean isrefonly;
1045 gpointer params [3];
1047 mono_error_init (error);
1049 if (mono_runtime_get_no_exec ())
1052 g_assert (domain != NULL && fname != NULL);
1054 klass = domain->domain->mbr.obj.vtable->klass;
1057 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1058 if (method == NULL) {
1059 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1063 isrefonly = refonly ? 1 : 0;
1066 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1067 return_val_if_nok (error, NULL);
1070 params [2] = &isrefonly;
1072 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1073 return_val_if_nok (error, NULL);
1079 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1083 MonoReflectionAssembly *assembly;
1084 MonoDomain *domain = mono_domain_get ();
1088 aname_str = mono_stringify_assembly_name (aname);
1090 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1091 str = mono_string_new (domain, aname_str);
1097 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1098 mono_error_cleanup (&error);
1101 return assembly->assembly;
1107 * LOCKING: assumes assemblies_lock in the domain is already locked.
1110 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1114 gboolean destroy_ht = FALSE;
1116 if (!ass->aname.name)
1120 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1124 /* FIXME: handle lazy loaded assemblies */
1125 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1126 g_hash_table_insert (ht, tmp->data, tmp->data);
1128 if (!g_hash_table_lookup (ht, ass)) {
1129 mono_assembly_addref (ass);
1130 g_hash_table_insert (ht, ass, ass);
1131 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1132 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to domain %s, ref_count=%d", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
1135 if (ass->image->references) {
1136 for (i = 0; ass->image->references [i] != NULL; i++) {
1137 if (ass->image->references [i] != REFERENCE_MISSING)
1138 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1139 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1144 g_hash_table_destroy (ht);
1148 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1150 static MonoClassField *assembly_load_field;
1151 static MonoMethod *assembly_load_method;
1153 MonoDomain *domain = mono_domain_get ();
1154 MonoReflectionAssembly *ref_assembly;
1156 gpointer load_value;
1159 if (!domain->domain)
1160 /* This can happen during startup */
1162 #ifdef ASSEMBLY_LOAD_DEBUG
1163 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1165 klass = domain->domain->mbr.obj.vtable->klass;
1167 mono_domain_assemblies_lock (domain);
1168 add_assemblies_to_domain (domain, assembly, NULL);
1169 mono_domain_assemblies_unlock (domain);
1171 if (assembly_load_field == NULL) {
1172 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1173 g_assert (assembly_load_field);
1176 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1177 if (load_value == NULL) {
1178 /* No events waiting to be triggered */
1182 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1183 mono_error_assert_ok (&error);
1185 if (assembly_load_method == NULL) {
1186 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1187 g_assert (assembly_load_method);
1190 *params = ref_assembly;
1192 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1193 mono_error_cleanup (&error);
1197 * LOCKING: Acquires the domain assemblies lock.
1200 set_domain_search_path (MonoDomain *domain)
1203 MonoAppDomainSetup *setup;
1205 gchar *search_path = NULL;
1208 gchar **pvt_split = NULL;
1209 GError *gerror = NULL;
1210 gint appbaselen = -1;
1213 * We use the low-level domain assemblies lock, since this is called from
1214 * assembly loads hooks, which means this thread might hold the loader lock.
1216 mono_domain_assemblies_lock (domain);
1218 if (!domain->setup) {
1219 mono_domain_assemblies_unlock (domain);
1223 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1224 mono_domain_assemblies_unlock (domain);
1227 setup = domain->setup;
1228 if (!setup->application_base) {
1229 mono_domain_assemblies_unlock (domain);
1230 return; /* Must set application base to get private path working */
1235 if (setup->private_bin_path) {
1236 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1237 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1238 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1239 mono_error_cleanup (&error);
1240 mono_domain_assemblies_unlock (domain);
1245 if (domain->private_bin_path) {
1246 if (search_path == NULL)
1247 search_path = domain->private_bin_path;
1249 gchar *tmp2 = search_path;
1250 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1257 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1258 * directories relative to ApplicationBase separated by semicolons (see
1259 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1260 * The loop below copes with the fact that some Unix applications may use ':' (or
1261 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1262 * ';' for the subsequent split.
1264 * The issue was reported in bug #81446
1267 #ifndef TARGET_WIN32
1270 slen = strlen (search_path);
1271 for (i = 0; i < slen; i++)
1272 if (search_path [i] == ':')
1273 search_path [i] = ';';
1276 pvt_split = g_strsplit (search_path, ";", 1000);
1277 g_free (search_path);
1278 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1283 g_strfreev (pvt_split);
1285 * Don't do this because the first time is called, the domain
1286 * setup is not finished.
1288 * domain->search_path = g_malloc (sizeof (char *));
1289 * domain->search_path [0] = NULL;
1291 mono_domain_assemblies_unlock (domain);
1295 if (domain->search_path)
1296 g_strfreev (domain->search_path);
1298 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1299 tmp [npaths] = NULL;
1301 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1302 if (!mono_error_ok (&error)) {
1303 mono_error_cleanup (&error);
1304 g_strfreev (pvt_split);
1307 mono_domain_assemblies_unlock (domain);
1311 domain->search_path = tmp;
1313 /* FIXME: is this needed? */
1314 if (strncmp (*tmp, "file://", 7) == 0) {
1320 uri = g_strdup_printf ("file:///%s", uri + 7);
1323 uri = mono_escape_uri_string (tmpuri);
1324 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1330 if (gerror != NULL) {
1331 g_warning ("%s\n", gerror->message);
1332 g_error_free (gerror);
1339 for (i = 1; pvt_split && i < npaths; i++) {
1340 if (g_path_is_absolute (pvt_split [i - 1])) {
1341 tmp [i] = g_strdup (pvt_split [i - 1]);
1343 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1346 if (strchr (tmp [i], '.')) {
1350 reduced = mono_path_canonicalize (tmp [i]);
1351 if (appbaselen == -1)
1352 appbaselen = strlen (tmp [0]);
1354 if (strncmp (tmp [0], reduced, appbaselen)) {
1357 tmp [i] = g_strdup ("");
1367 if (setup->private_bin_path_probe != NULL) {
1369 tmp [0] = g_strdup ("");
1372 domain->setup->path_changed = FALSE;
1374 g_strfreev (pvt_split);
1376 mono_domain_assemblies_unlock (domain);
1379 #ifdef DISABLE_SHADOW_COPY
1381 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1387 mono_make_shadow_copy (const char *filename, MonoError *error)
1389 mono_error_init (error);
1390 return (char *) filename;
1394 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1396 guint16 *orig, *dest;
1397 gboolean copy_result;
1399 strcpy (src + srclen - tail_len, extension);
1401 if (IS_PORTABILITY_CASE) {
1402 gchar *file = mono_portability_find_file (src, TRUE);
1408 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1412 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1414 strcpy (target + targetlen - tail_len, extension);
1415 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1419 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1420 copy_result = CopyFile (orig, dest, FALSE);
1422 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1425 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1426 * overwritten when updated in their original locations. */
1428 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1437 get_cstring_hash (const char *str)
1443 if (!str || !str [0])
1448 for (i = 0; i < len; i++) {
1449 h = (h << 5) - h + *p;
1457 * Returned memory is malloc'd. Called must free it
1460 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1462 MonoAppDomainSetup *setup;
1463 char *cache_path, *appname;
1467 mono_error_init (error);
1469 setup = domain->setup;
1470 if (setup->cache_path != NULL && setup->application_name != NULL) {
1471 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1472 return_val_if_nok (error, NULL);
1474 #ifndef TARGET_WIN32
1477 for (i = strlen (cache_path) - 1; i >= 0; i--)
1478 if (cache_path [i] == '\\')
1479 cache_path [i] = '/';
1483 appname = mono_string_to_utf8_checked (setup->application_name, error);
1484 if (!mono_error_ok (error)) {
1485 g_free (cache_path);
1489 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1491 g_free (cache_path);
1493 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1494 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1501 get_shadow_assembly_location (const char *filename, MonoError *error)
1503 gint32 hash = 0, hash2 = 0;
1505 char path_hash [30];
1506 char *bname = g_path_get_basename (filename);
1507 char *dirname = g_path_get_dirname (filename);
1508 char *location, *tmploc;
1509 MonoDomain *domain = mono_domain_get ();
1511 mono_error_init (error);
1513 hash = get_cstring_hash (bname);
1514 hash2 = get_cstring_hash (dirname);
1515 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1516 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1517 tmploc = get_shadow_assembly_location_base (domain, error);
1518 if (!mono_error_ok (error)) {
1524 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1532 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1534 struct stat sbuf_dest;
1536 gchar *real_src = mono_portability_find_file (src, TRUE);
1539 stat_src = (gchar*)src;
1541 stat_src = real_src;
1543 if (stat (stat_src, sbuf_src) == -1) {
1544 time_t tnow = time (NULL);
1549 memset (sbuf_src, 0, sizeof (*sbuf_src));
1550 sbuf_src->st_mtime = tnow;
1551 sbuf_src->st_atime = tnow;
1558 if (stat (dest, &sbuf_dest) == -1)
1561 if (sbuf_src->st_size == sbuf_dest.st_size &&
1562 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1569 shadow_copy_create_ini (const char *shadow, const char *filename)
1579 dir_name = g_path_get_dirname (shadow);
1580 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1582 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1587 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1592 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1593 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1595 if (handle == INVALID_HANDLE_VALUE) {
1599 full_path = mono_path_resolve_symlinks (filename);
1600 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1602 CloseHandle (handle);
1607 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1610 MonoAppDomainSetup *setup;
1613 gchar **directories;
1614 gchar *shadow_status_string;
1616 gboolean shadow_enabled;
1617 gboolean found = FALSE;
1622 setup = domain->setup;
1623 if (setup == NULL || setup->shadow_copy_files == NULL)
1626 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1627 if (!mono_error_ok (&error)) {
1628 mono_error_cleanup (&error);
1631 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1632 g_free (shadow_status_string);
1634 if (!shadow_enabled)
1637 if (setup->shadow_copy_directories == NULL)
1640 /* Is dir_name a shadow_copy destination already? */
1641 base_dir = get_shadow_assembly_location_base (domain, &error);
1642 if (!mono_error_ok (&error)) {
1643 mono_error_cleanup (&error);
1647 if (strstr (dir_name, base_dir)) {
1653 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1654 if (!mono_error_ok (&error)) {
1655 mono_error_cleanup (&error);
1659 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1660 dir_ptr = directories;
1662 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1668 g_strfreev (directories);
1674 This function raises exceptions so it can cause as sorts of nasty stuff if called
1675 while holding a lock.
1676 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1677 or NULL if source file not found.
1678 FIXME bubble up the error instead of raising it here
1681 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1684 gchar *sibling_source, *sibling_target;
1685 gint sibling_source_len, sibling_target_len;
1686 guint16 *orig, *dest;
1689 gboolean copy_result;
1690 struct stat src_sbuf;
1691 struct utimbuf utbuf;
1692 char *dir_name = g_path_get_dirname (filename);
1693 MonoDomain *domain = mono_domain_get ();
1696 mono_error_init (oerror);
1698 set_domain_search_path (domain);
1700 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1702 return (char *) filename;
1705 /* Is dir_name a shadow_copy destination already? */
1706 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1707 if (!mono_error_ok (&error)) {
1708 mono_error_cleanup (&error);
1710 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1714 if (strstr (dir_name, shadow_dir)) {
1715 g_free (shadow_dir);
1717 return (char *) filename;
1719 g_free (shadow_dir);
1722 shadow = get_shadow_assembly_location (filename, &error);
1723 if (!mono_error_ok (&error)) {
1724 mono_error_cleanup (&error);
1725 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1729 if (g_ensure_directory_exists (shadow) == FALSE) {
1731 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1735 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1736 return (char*) shadow;
1738 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1739 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1742 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1743 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1744 * and not have it runtime error" */
1745 attrs = GetFileAttributes (orig);
1746 if (attrs == INVALID_FILE_ATTRIBUTES) {
1748 return (char *)filename;
1751 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1752 copy_result = CopyFile (orig, dest, FALSE);
1754 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1757 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1758 * overwritten when updated in their original locations. */
1760 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1765 if (copy_result == FALSE) {
1768 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1769 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1770 return NULL; /* file not found, shadow copy failed */
1772 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1776 /* attempt to copy .mdb, .config if they exist */
1777 sibling_source = g_strconcat (filename, ".config", NULL);
1778 sibling_source_len = strlen (sibling_source);
1779 sibling_target = g_strconcat (shadow, ".config", NULL);
1780 sibling_target_len = strlen (sibling_target);
1782 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1784 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1786 g_free (sibling_source);
1787 g_free (sibling_target);
1791 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1795 /* Create a .ini file containing the original assembly location */
1796 if (!shadow_copy_create_ini (shadow, filename)) {
1798 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1802 utbuf.actime = src_sbuf.st_atime;
1803 utbuf.modtime = src_sbuf.st_mtime;
1804 utime (shadow, &utbuf);
1808 #endif /* DISABLE_SHADOW_COPY */
1811 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1813 if (appdomain == NULL)
1816 return appdomain->data;
1820 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1821 const gchar *path3, const gchar *path4,
1822 gboolean refonly, gboolean is_private)
1825 gboolean found = FALSE;
1828 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1830 if (IS_PORTABILITY_SET) {
1831 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1834 fullpath = new_fullpath;
1838 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1841 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1844 return (*assembly != NULL);
1847 static MonoAssembly *
1848 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1850 MonoAssembly *result = NULL;
1853 const gchar *local_culture;
1855 gboolean is_private = FALSE;
1857 if (!culture || *culture == '\0') {
1860 local_culture = culture;
1863 filename = g_strconcat (name, ".dll", NULL);
1864 len = strlen (filename);
1866 for (path = search_path; *path; path++) {
1867 if (**path == '\0') {
1869 continue; /* Ignore empty ApplicationBase */
1872 /* See test cases in bug #58992 and bug #57710 */
1873 /* 1st try: [culture]/[name].dll (culture may be empty) */
1874 strcpy (filename + len - 4, ".dll");
1875 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1878 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1879 strcpy (filename + len - 4, ".exe");
1880 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1883 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1884 strcpy (filename + len - 4, ".dll");
1885 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1888 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1889 strcpy (filename + len - 4, ".exe");
1890 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1899 * Try loading the assembly from ApplicationBase and PrivateBinPath
1900 * and then from assemblies_path if any.
1901 * LOCKING: This is called from the assembly loading code, which means the caller
1902 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1904 static MonoAssembly *
1905 mono_domain_assembly_preload (MonoAssemblyName *aname,
1906 gchar **assemblies_path,
1909 MonoDomain *domain = mono_domain_get ();
1910 MonoAssembly *result = NULL;
1911 gboolean refonly = GPOINTER_TO_UINT (user_data);
1913 set_domain_search_path (domain);
1915 if (domain->search_path && domain->search_path [0] != NULL) {
1916 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1919 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1920 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1927 * Check whenever a given assembly was already loaded in the current appdomain.
1929 static MonoAssembly *
1930 mono_domain_assembly_search (MonoAssemblyName *aname,
1933 MonoDomain *domain = mono_domain_get ();
1936 gboolean refonly = GPOINTER_TO_UINT (user_data);
1938 mono_domain_assemblies_lock (domain);
1939 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1940 ass = (MonoAssembly *)tmp->data;
1941 /* Dynamic assemblies can't match here in MS.NET */
1942 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1945 mono_domain_assemblies_unlock (domain);
1948 mono_domain_assemblies_unlock (domain);
1953 MonoReflectionAssembly *
1954 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1957 MonoReflectionAssembly *result;
1958 MonoDomain *domain = mono_domain_get ();
1959 char *name, *filename;
1960 MonoImageOpenStatus status = MONO_IMAGE_OK;
1961 MonoAssembly *ass = NULL;
1966 mono_error_init (&error);
1968 if (fname == NULL) {
1969 mono_error_set_argument_null (&error, "assemblyFile", "");
1973 name = filename = mono_string_to_utf8_checked (fname, &error);
1974 if (!is_ok (&error))
1977 ass = mono_assembly_open_full (filename, &status, refOnly);
1980 if (status == MONO_IMAGE_IMAGE_INVALID)
1981 mono_error_set_bad_image_name (&error, name, "");
1983 mono_error_set_exception_instance (&error, mono_get_exception_file_not_found2 (NULL, fname));
1987 result = mono_assembly_get_object_checked (domain, ass, &error);
1990 mono_error_set_pending_exception (&error);
1995 MonoReflectionAssembly *
1996 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1997 MonoArray *raw_assembly,
1998 MonoArray *raw_symbol_store, MonoObject *evidence,
1999 MonoBoolean refonly)
2003 MonoReflectionAssembly *refass = NULL;
2004 MonoDomain *domain = ad->data;
2005 MonoImageOpenStatus status;
2006 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2007 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2010 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2014 if (raw_symbol_store != NULL)
2015 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2017 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2021 mono_image_close (image);
2022 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2026 refass = mono_assembly_get_object_checked (domain, ass, &error);
2028 mono_error_set_pending_exception (&error);
2030 MONO_OBJECT_SETREF (refass, evidence, evidence);
2034 MonoReflectionAssembly *
2035 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2038 MonoDomain *domain = ad->data;
2039 MonoImageOpenStatus status = MONO_IMAGE_OK;
2041 MonoAssemblyName aname;
2042 MonoReflectionAssembly *refass = NULL;
2048 name = mono_string_to_utf8_checked (assRef, &error);
2049 if (mono_error_set_pending_exception (&error))
2051 parsed = mono_assembly_name_parse (name, &aname);
2054 /* This is a parse error... */
2056 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2057 if (!is_ok (&error))
2063 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2064 mono_assembly_name_free (&aname);
2067 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2069 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2070 if (!is_ok (&error))
2077 ass = refass->assembly;
2081 if (refass == NULL) {
2082 refass = mono_assembly_get_object_checked (domain, ass, &error);
2083 if (!is_ok (&error))
2087 MONO_OBJECT_SETREF (refass, evidence, evidence);
2091 mono_error_set_pending_exception (&error);
2096 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2098 MonoException *exc = NULL;
2099 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2101 if (NULL == domain) {
2102 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2103 mono_set_pending_exception (exc);
2107 if (domain == mono_get_root_domain ()) {
2108 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2113 * Unloading seems to cause problems when running NUnit/NAnt, hence
2116 if (g_getenv ("MONO_NO_UNLOAD"))
2118 #ifdef __native_client__
2122 mono_domain_try_unload (domain, (MonoObject**)&exc);
2124 mono_set_pending_exception (exc);
2128 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2130 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2135 return mono_domain_is_unloading (domain);
2139 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2141 mono_unhandled_exception ((MonoObject*) exc);
2145 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2146 MonoReflectionAssembly *refass, MonoArray *args)
2153 image = refass->assembly->image;
2156 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2159 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2162 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2163 mono_error_assert_ok (&error);
2166 int res = mono_runtime_exec_main_checked (method, (MonoArray *)args, &error);
2167 mono_error_set_pending_exception (&error);
2172 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2174 return ad->data->domain_id;
2178 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2180 MonoDomain *old_domain = mono_domain_get();
2182 if (!mono_domain_set (ad->data, FALSE)) {
2183 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2187 return old_domain->domain;
2191 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2193 MonoDomain *current_domain = mono_domain_get ();
2194 MonoDomain *domain = mono_domain_get_by_id (domainid);
2196 if (!domain || !mono_domain_set (domain, FALSE)) {
2197 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2201 return current_domain->domain;
2205 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2207 mono_thread_push_appdomain_ref (ad->data);
2211 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2213 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2217 * Raise an exception to prevent the managed code from executing a pop
2220 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2224 mono_thread_push_appdomain_ref (domain);
2228 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2230 mono_thread_pop_appdomain_ref ();
2234 ves_icall_System_AppDomain_InternalGetContext ()
2236 return mono_context_get ();
2240 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2242 return mono_domain_get ()->default_context;
2246 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2248 MonoAppContext *old_context = mono_context_get ();
2250 mono_context_set (mc);
2256 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2258 MonoDomain* mono_root_domain = mono_get_root_domain ();
2259 mono_domain_lock (mono_root_domain);
2260 if (process_guid_set) {
2261 mono_domain_unlock (mono_root_domain);
2263 MonoString *res = NULL;
2264 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2265 mono_error_set_pending_exception (&error);
2268 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2269 process_guid_set = TRUE;
2270 mono_domain_unlock (mono_root_domain);
2275 mono_domain_is_unloading (MonoDomain *domain)
2277 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2284 clear_cached_vtable (MonoVTable *vtable)
2286 MonoClass *klass = vtable->klass;
2287 MonoDomain *domain = vtable->domain;
2288 MonoClassRuntimeInfo *runtime_info;
2291 runtime_info = klass->runtime_info;
2292 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2293 runtime_info->domain_vtables [domain->domain_id] = NULL;
2294 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2295 mono_gc_free_fixed (data);
2298 static G_GNUC_UNUSED void
2299 zero_static_data (MonoVTable *vtable)
2301 MonoClass *klass = vtable->klass;
2304 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2305 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2308 typedef struct unload_data {
2311 char *failure_reason;
2316 unload_data_unref (unload_data *data)
2320 mono_atomic_load_acquire (count, gint32, &data->refcount);
2321 g_assert (count >= 1 && count <= 2);
2326 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2330 deregister_reflection_info_roots_from_list (MonoImage *image)
2332 GSList *list = image->reflection_info_unregister_classes;
2335 MonoClass *klass = (MonoClass *)list->data;
2337 mono_class_free_ref_info (klass);
2342 image->reflection_info_unregister_classes = NULL;
2346 deregister_reflection_info_roots (MonoDomain *domain)
2350 mono_domain_assemblies_lock (domain);
2351 for (list = domain->domain_assemblies; list; list = list->next) {
2352 MonoAssembly *assembly = (MonoAssembly *)list->data;
2353 MonoImage *image = assembly->image;
2357 * No need to take the image lock here since dynamic images are appdomain bound and
2358 * at this point the mutator is gone. Taking the image lock here would mean
2359 * promoting it from a simple lock to a complex lock, which we better avoid if
2362 if (image_is_dynamic (image))
2363 deregister_reflection_info_roots_from_list (image);
2365 for (i = 0; i < image->module_count; ++i) {
2366 MonoImage *module = image->modules [i];
2367 if (module && image_is_dynamic (module))
2368 deregister_reflection_info_roots_from_list (module);
2371 mono_domain_assemblies_unlock (domain);
2375 unload_thread_main (void *arg)
2378 unload_data *data = (unload_data*)arg;
2379 MonoDomain *domain = data->domain;
2383 /* Have to attach to the runtime so shutdown can wait for this thread */
2384 /* Force it to be attached to avoid racing during shutdown. */
2385 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2387 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2388 if (!is_ok (&error)) {
2389 data->failure_reason = g_strdup (mono_error_get_message (&error));
2390 mono_error_cleanup (&error);
2395 * FIXME: Abort our parent thread last, so we can return a failure
2396 * indication if aborting times out.
2398 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2399 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2403 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2404 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2408 /* Finalize all finalizable objects in the doomed appdomain */
2409 if (!mono_domain_finalize (domain, -1)) {
2410 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2414 /* Clear references to our vtables in class->runtime_info.
2415 * We also hold the loader lock because we're going to change
2416 * class->runtime_info.
2419 mono_loader_lock (); //FIXME why do we need the loader lock here?
2420 mono_domain_lock (domain);
2423 * We need to make sure that we don't have any remsets
2424 * pointing into static data of the to-be-freed domain because
2425 * at the next collections they would be invalid. So what we
2426 * do is we first zero all static data and then do a minor
2427 * collection. Because all references in the static data will
2428 * now be null we won't do any unnecessary copies and after
2429 * the collection there won't be any more remsets.
2431 for (i = 0; i < domain->class_vtable_array->len; ++i)
2432 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2433 mono_gc_collect (0);
2435 for (i = 0; i < domain->class_vtable_array->len; ++i)
2436 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2437 deregister_reflection_info_roots (domain);
2439 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2441 mono_domain_unlock (domain);
2442 mono_loader_unlock ();
2444 mono_threads_clear_cached_culture (domain);
2446 domain->state = MONO_APPDOMAIN_UNLOADED;
2448 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2450 /* remove from the handle table the items related to this domain */
2451 mono_gchandle_free_domain (domain);
2453 mono_domain_free (domain, FALSE);
2455 mono_gc_collect (mono_gc_max_generation ());
2457 mono_atomic_store_release (&data->done, TRUE);
2458 unload_data_unref (data);
2459 mono_thread_detach (thread);
2463 mono_atomic_store_release (&data->done, TRUE);
2464 unload_data_unref (data);
2465 mono_thread_detach (thread);
2470 * mono_domain_unload:
2471 * @domain: The domain to unload
2473 * Unloads an appdomain. Follows the process outlined in the comment
2474 * for mono_domain_try_unload.
2477 mono_domain_unload (MonoDomain *domain)
2479 MonoObject *exc = NULL;
2480 mono_domain_try_unload (domain, &exc);
2483 static MonoThreadInfoWaitRet
2484 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2486 MonoThreadInfoWaitRet result;
2489 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2496 * mono_domain_unload:
2497 * @domain: The domain to unload
2498 * @exc: Exception information
2500 * Unloads an appdomain. Follows the process outlined in:
2501 * http://blogs.gotdotnet.com/cbrumme
2503 * If doing things the 'right' way is too hard or complex, we do it the
2504 * 'simple' way, which means do everything needed to avoid crashes and
2505 * memory leaks, but not much else.
2507 * It is required to pass a valid reference to the exc argument, upon return
2508 * from this function *exc will be set to the exception thrown, if any.
2510 * If this method is not called from an icall (embedded scenario for instance),
2511 * it must not be called with any managed frames on the stack, since the unload
2512 * process could end up trying to abort the current thread.
2515 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2518 MonoThreadHandle *thread_handle;
2519 MonoAppDomainState prev_state;
2521 unload_data *thread_data;
2522 MonoNativeThreadId tid;
2523 MonoDomain *caller_domain = mono_domain_get ();
2525 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2527 /* Atomically change our state to UNLOADING */
2528 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2529 MONO_APPDOMAIN_UNLOADING_START,
2530 MONO_APPDOMAIN_CREATED);
2531 if (prev_state != MONO_APPDOMAIN_CREATED) {
2532 switch (prev_state) {
2533 case MONO_APPDOMAIN_UNLOADING_START:
2534 case MONO_APPDOMAIN_UNLOADING:
2535 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2537 case MONO_APPDOMAIN_UNLOADED:
2538 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2541 g_warning ("Invalid appdomain state %d", prev_state);
2542 g_assert_not_reached ();
2546 mono_domain_set (domain, FALSE);
2547 /* Notify OnDomainUnload listeners */
2548 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2551 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2553 if (!mono_error_ok (&error)) {
2555 mono_error_cleanup (&error);
2557 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2561 /* Roll back the state change */
2562 domain->state = MONO_APPDOMAIN_CREATED;
2563 mono_domain_set (caller_domain, FALSE);
2566 mono_domain_set (caller_domain, FALSE);
2568 thread_data = g_new0 (unload_data, 1);
2569 thread_data->domain = domain;
2570 thread_data->failure_reason = NULL;
2571 thread_data->done = FALSE;
2572 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2574 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2575 domain->state = MONO_APPDOMAIN_UNLOADING;
2577 * First we create a separate thread for unloading, since
2578 * we might have to abort some threads, including the current one.
2580 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, NULL, &tid);
2581 if (thread_handle == NULL)
2584 /* Wait for the thread */
2585 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2586 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2587 /* The unload thread tries to abort us */
2588 /* The icall wrapper will execute the abort */
2589 mono_threads_close_thread_handle (thread_handle);
2590 unload_data_unref (thread_data);
2595 mono_threads_close_thread_handle (thread_handle);
2597 if (thread_data->failure_reason) {
2598 /* Roll back the state change */
2599 domain->state = MONO_APPDOMAIN_CREATED;
2601 g_warning ("%s", thread_data->failure_reason);
2603 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2605 g_free (thread_data->failure_reason);
2606 thread_data->failure_reason = NULL;
2609 unload_data_unref (thread_data);