2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
13 #undef ASSEMBLY_LOAD_DEBUG
19 #include <sys/types.h>
21 #ifdef HAVE_SYS_TIME_H
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
35 #include <mono/metadata/gc-internals.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/threadpool-ms.h>
43 #include <mono/metadata/socket-io.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/gc-internals.h>
46 #include <mono/metadata/mono-gc.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/monitor.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/reflection-internals.h>
59 #include <mono/utils/mono-uri.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-path.h>
62 #include <mono/utils/mono-stdlib.h>
63 #include <mono/utils/mono-io-portability.h>
64 #include <mono/utils/mono-error-internals.h>
65 #include <mono/utils/atomic.h>
66 #include <mono/utils/mono-memory-model.h>
67 #include <mono/utils/mono-threads.h>
73 * This is the version number of the corlib-runtime interface. When
74 * making changes to this interface (by changing the layout
75 * of classes the runtime knows about, changing icall signature or
76 * semantics etc), increment this variable. Also increment the
77 * pair of this variable in mscorlib in:
78 * mcs/class/corlib/System/Environment.cs
80 * Changes which are already detected at runtime, like the addition
81 * of icalls, do not require an increment.
83 #define MONO_CORLIB_VERSION 143
88 int assemblybinding_count;
93 static gunichar2 process_guid [36];
94 static gboolean process_guid_set = FALSE;
96 static gboolean no_exec = FALSE;
99 mono_domain_assembly_preload (MonoAssemblyName *aname,
100 gchar **assemblies_path,
103 static MonoAssembly *
104 mono_domain_assembly_search (MonoAssemblyName *aname,
108 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
111 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
113 static MonoAppDomain *
114 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
117 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
119 static MonoLoadFunc load_function = NULL;
121 /* Lazy class loading functions */
122 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
125 mono_install_runtime_load (MonoLoadFunc func)
127 load_function = func;
131 mono_runtime_load (const char *filename, const char *runtime_version)
133 g_assert (load_function);
134 return load_function (filename, runtime_version);
138 * mono_runtime_set_no_exec:
140 * Instructs the runtime to operate in static mode, i.e. avoid/do not
141 * allow managed code execution. This is useful for running the AOT
142 * compiler on platforms which allow full-aot execution only. This
143 * should be called before mono_runtime_init ().
146 mono_runtime_set_no_exec (gboolean val)
152 * mono_runtime_get_no_exec:
154 * If true, then the runtime will not allow managed code execution.
157 mono_runtime_get_no_exec (void)
163 create_domain_objects (MonoDomain *domain)
166 MonoDomain *old_domain = mono_domain_get ();
168 MonoVTable *string_vt;
169 MonoClassField *string_empty_fld;
171 if (domain != old_domain) {
172 mono_thread_push_appdomain_ref (domain);
173 mono_domain_set_internal_with_options (domain, FALSE);
177 * Initialize String.Empty. This enables the removal of
178 * the static cctor of the String class.
180 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
181 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
182 g_assert (string_empty_fld);
183 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
184 mono_error_assert_ok (&error);
185 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
188 * Create an instance early since we can't do it when there is no memory.
190 arg = mono_string_new (domain, "Out of memory");
191 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
194 * These two are needed because the signal handlers might be executing on
195 * an alternate stack, and Boehm GC can't handle that.
197 arg = mono_string_new (domain, "A null value was found where an object instance was required");
198 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
199 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
200 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
202 /*The ephemeron tombstone i*/
203 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
204 mono_error_assert_ok (&error);
206 if (domain != old_domain) {
207 mono_thread_pop_appdomain_ref ();
208 mono_domain_set_internal_with_options (old_domain, FALSE);
212 * This class is used during exception handling, so initialize it here, to prevent
213 * stack overflows while handling stack overflows.
215 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
220 * @domain: domain returned by mono_init ()
222 * Initialize the core AppDomain: this function will run also some
223 * IL initialization code, so it needs the execution engine to be fully
226 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
227 * we know the entry_assembly.
231 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
234 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
235 mono_error_cleanup (&error);
239 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
241 MonoAppDomainSetup *setup;
245 mono_error_init (error);
247 mono_portability_helpers_init ();
249 mono_gc_base_init ();
250 mono_monitor_init ();
251 mono_marshal_init ();
253 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
254 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
255 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
256 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
257 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
258 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
259 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
260 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
262 mono_thread_init (start_cb, attach_cb);
264 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
265 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
266 return_if_nok (error);
268 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
270 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
271 return_if_nok (error);
275 domain->setup = setup;
277 mono_thread_attach (domain);
279 mono_type_initialization_init ();
281 if (!mono_runtime_get_no_exec ())
282 create_domain_objects (domain);
284 /* GC init has to happen after thread init */
287 /* contexts use GC handles, so they must be initialized after the GC */
288 mono_context_init_checked (domain, error);
289 return_if_nok (error);
290 mono_context_set (domain->default_context);
292 #ifndef DISABLE_SOCKETS
293 mono_network_init ();
296 mono_console_init ();
299 mono_locks_tracer_init ();
301 /* mscorlib is loaded before we install the load hook */
302 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
308 mono_get_corlib_version (void)
311 MonoClassField *field;
314 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
315 mono_class_init (klass);
316 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
319 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
321 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
322 return *(gint32*)((gchar*)value + sizeof (MonoObject));
326 * mono_check_corlib_version
328 * Checks that the corlib that is loaded matches the version of this runtime.
330 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
331 * allocated string with the error otherwise.
334 mono_check_corlib_version (void)
336 int version = mono_get_corlib_version ();
337 if (version != MONO_CORLIB_VERSION)
338 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
345 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
347 * Initializes the @domain's default System.Runtime.Remoting's Context.
350 mono_context_init (MonoDomain *domain)
353 mono_context_init_checked (domain, &error);
354 mono_error_cleanup (&error);
358 mono_context_init_checked (MonoDomain *domain, MonoError *error)
361 MonoAppContext *context;
363 mono_error_init (error);
365 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
366 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
367 return_if_nok (error);
369 context->domain_id = domain->domain_id;
370 context->context_id = 0;
371 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
372 domain->default_context = context;
376 * mono_runtime_cleanup:
381 * This must not be called while there are still running threads executing
385 mono_runtime_cleanup (MonoDomain *domain)
387 mono_attach_cleanup ();
389 /* This ends up calling any pending pending (for at most 2 seconds) */
392 mono_thread_cleanup ();
394 #ifndef DISABLE_SOCKETS
395 mono_network_cleanup ();
397 mono_marshal_cleanup ();
399 mono_type_initialization_cleanup ();
401 mono_monitor_cleanup ();
404 static MonoDomainFunc quit_function = NULL;
407 mono_install_runtime_cleanup (MonoDomainFunc func)
409 quit_function = func;
415 if (quit_function != NULL)
416 quit_function (mono_get_root_domain (), NULL);
420 * mono_domain_create_appdomain:
421 * @friendly_name: The friendly name of the appdomain to create
422 * @configuration_file: The configuration file to initialize the appdomain with
424 * Returns a MonoDomain initialized with the appdomain
427 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
431 MonoAppDomainSetup *setup;
434 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
435 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
436 mono_error_raise_exception (&error); /* FIXME don't raise here */
437 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
439 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
440 mono_error_raise_exception (&error); /* FIXME don't raise here */
442 return mono_domain_from_appdomain (ad);
446 * mono_domain_set_config:
447 * @domain: MonoDomain initialized with the appdomain we want to change
448 * @base_dir: new base directory for the appdomain
449 * @config_file_name: path to the new configuration for the app domain
451 * Used to set the system configuration for an appdomain
453 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
454 * Error Initializing the configuration system. ---> System.ArgumentException:
455 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
458 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
460 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
461 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
464 static MonoAppDomainSetup*
465 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
467 MonoDomain *caller_domain;
468 MonoClass *ads_class;
469 MonoAppDomainSetup *copy;
471 mono_error_init (error);
473 caller_domain = mono_domain_get ();
474 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
476 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
477 return_val_if_nok (error, NULL);
479 mono_domain_set_internal (domain);
481 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
482 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
483 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
484 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
485 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
486 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
487 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
488 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
489 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
490 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
491 copy->publisher_policy = setup->publisher_policy;
492 copy->path_changed = setup->path_changed;
493 copy->loader_optimization = setup->loader_optimization;
494 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
495 copy->disallow_code_downloads = setup->disallow_code_downloads;
496 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
497 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
498 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
499 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
500 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
502 mono_domain_set_internal (caller_domain);
507 static MonoAppDomain *
508 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
513 char *shadow_location;
515 mono_error_init (error);
517 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
519 /* FIXME: pin all those objects */
520 data = mono_domain_create();
522 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
523 return_val_if_nok (error, NULL);
526 data->friendly_name = g_strdup (friendly_name);
528 mono_profiler_appdomain_name (data, data->friendly_name);
530 if (!setup->application_base) {
531 /* Inherit from the root domain since MS.NET does this */
532 MonoDomain *root = mono_get_root_domain ();
533 if (root->setup->application_base) {
534 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
535 mono_error_assert_ok (error); /* FIXME don't swallow the error */
536 MONO_OBJECT_SETREF (setup, application_base, s);
540 mono_context_init_checked (data, error);
541 return_val_if_nok (error, NULL);
543 data->setup = copy_app_domain_setup (data, setup, error);
544 if (!mono_error_ok (error)) {
545 g_free (data->friendly_name);
549 mono_domain_set_options_from_config (data);
550 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
552 #ifndef DISABLE_SHADOW_COPY
553 /*FIXME, guard this for when the debugger is not running */
554 shadow_location = get_shadow_assembly_location_base (data, error);
555 if (!mono_error_ok (error)) {
556 g_free (data->friendly_name);
560 g_free (shadow_location);
563 create_domain_objects (data);
569 * mono_domain_has_type_resolve:
570 * @domain: application domains being looked up
572 * Returns: TRUE if the AppDomain.TypeResolve field has been
576 mono_domain_has_type_resolve (MonoDomain *domain)
578 static MonoClassField *field = NULL;
582 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
586 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
590 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
595 * mono_domain_try_type_resolve:
596 * @domain: application domainwhere the name where the type is going to be resolved
597 * @name: the name of the type to resolve or NULL.
598 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
600 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
601 * the assembly that matches name.
603 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
605 * Returns: A MonoReflectionAssembly or NULL if not found
607 MonoReflectionAssembly *
608 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
611 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
612 mono_error_cleanup (&error);
617 MonoReflectionAssembly *
618 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
620 static MonoMethod *method = NULL;
621 MonoReflectionAssembly *ret;
625 mono_error_init (error);
627 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
629 if (method == NULL) {
630 klass = domain->domain->mbr.obj.vtable->klass;
633 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
634 if (method == NULL) {
635 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
641 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
645 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
646 return_val_if_nok (error, NULL);
652 * mono_domain_owns_vtable_slot:
654 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
657 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
661 mono_domain_lock (domain);
662 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
663 mono_domain_unlock (domain);
670 * @force: force setting.
672 * Set the current appdomain to @domain. If @force is set, set it even
673 * if it is being unloaded.
677 * FALSE if the domain is unloaded
680 mono_domain_set (MonoDomain *domain, gboolean force)
682 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
685 mono_domain_set_internal (domain);
691 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
697 MONO_CHECK_ARG_NULL (name, NULL);
703 str = mono_string_to_utf8 (name);
705 mono_domain_lock (add);
707 if (!strcmp (str, "APPBASE"))
708 o = (MonoObject *)add->setup->application_base;
709 else if (!strcmp (str, "APP_CONFIG_FILE"))
710 o = (MonoObject *)add->setup->configuration_file;
711 else if (!strcmp (str, "DYNAMIC_BASE"))
712 o = (MonoObject *)add->setup->dynamic_base;
713 else if (!strcmp (str, "APP_NAME"))
714 o = (MonoObject *)add->setup->application_name;
715 else if (!strcmp (str, "CACHE_BASE"))
716 o = (MonoObject *)add->setup->cache_path;
717 else if (!strcmp (str, "PRIVATE_BINPATH"))
718 o = (MonoObject *)add->setup->private_bin_path;
719 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
720 o = (MonoObject *)add->setup->private_bin_path_probe;
721 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
722 o = (MonoObject *)add->setup->shadow_copy_directories;
723 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
724 o = (MonoObject *)add->setup->shadow_copy_files;
726 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
728 mono_domain_unlock (add);
738 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
742 MONO_CHECK_ARG_NULL (name,);
748 mono_domain_lock (add);
750 mono_g_hash_table_insert (add->env, name, data);
752 mono_domain_unlock (add);
756 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
761 return ad->data->setup;
765 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
770 return mono_string_new (ad->data, ad->data->friendly_name);
774 ves_icall_System_AppDomain_getCurDomain ()
776 MonoDomain *add = mono_domain_get ();
782 ves_icall_System_AppDomain_getRootDomain ()
784 MonoDomain *root = mono_get_root_domain ();
790 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
792 MonoDomain *domain = mono_domain_get ();
794 return domain->throw_unobserved_task_exceptions;
798 get_attribute_value (const gchar **attribute_names,
799 const gchar **attribute_values,
800 const char *att_name)
803 for (n = 0; attribute_names [n] != NULL; n++) {
804 if (strcmp (attribute_names [n], att_name) == 0)
805 return g_strdup (attribute_values [n]);
811 start_element (GMarkupParseContext *context,
812 const gchar *element_name,
813 const gchar **attribute_names,
814 const gchar **attribute_values,
818 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
820 if (strcmp (element_name, "runtime") == 0) {
821 runtime_config->runtime_count++;
825 if (strcmp (element_name, "assemblyBinding") == 0) {
826 runtime_config->assemblybinding_count++;
830 if (runtime_config->runtime_count != 1)
833 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
834 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
836 if (value && g_ascii_strcasecmp (value, "true") == 0)
837 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
840 if (runtime_config->assemblybinding_count != 1)
843 if (strcmp (element_name, "probing") != 0)
846 g_free (runtime_config->domain->private_bin_path);
847 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
848 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
849 g_free (runtime_config->domain->private_bin_path);
850 runtime_config->domain->private_bin_path = NULL;
856 end_element (GMarkupParseContext *context,
857 const gchar *element_name,
861 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
862 if (strcmp (element_name, "runtime") == 0)
863 runtime_config->runtime_count--;
864 else if (strcmp (element_name, "assemblyBinding") == 0)
865 runtime_config->assemblybinding_count--;
869 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
871 RuntimeConfig *state = (RuntimeConfig *)user_data;
873 const gchar *filename;
875 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
876 msg = error && error->message ? error->message : "";
877 g_warning ("Error parsing %s: %s", filename, msg);
880 static const GMarkupParser
890 mono_domain_set_options_from_config (MonoDomain *domain)
893 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
895 GMarkupParseContext *context;
896 RuntimeConfig runtime_config;
899 if (!domain || !domain->setup || !domain->setup->configuration_file)
902 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
903 if (!mono_error_ok (&error)) {
904 mono_error_cleanup (&error);
908 config_file_path = mono_portability_find_file (config_file_name, TRUE);
909 if (!config_file_path)
910 config_file_path = config_file_name;
912 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
915 runtime_config.runtime_count = 0;
916 runtime_config.assemblybinding_count = 0;
917 runtime_config.domain = domain;
918 runtime_config.filename = config_file_path;
921 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
922 offset = 3; /* Skip UTF-8 BOM */
924 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
925 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
926 g_markup_parse_context_end_parse (context, NULL);
927 g_markup_parse_context_free (context);
931 if (config_file_name != config_file_path)
932 g_free (config_file_name);
933 g_free (config_file_path);
937 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
939 #ifdef DISABLE_APPDOMAINS
940 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
947 fname = mono_string_to_utf8 (friendly_name);
948 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
952 mono_error_raise_exception (&error);
959 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
962 MonoDomain *domain = ad->data;
967 GPtrArray *assemblies;
969 mono_error_init (&error);
972 * Make a copy of the list of assemblies because we can't hold the assemblies
973 * lock while creating objects etc.
975 assemblies = g_ptr_array_new ();
976 /* Need to skip internal assembly builders created by remoting */
977 mono_domain_assemblies_lock (domain);
978 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
979 ass = (MonoAssembly *)tmp->data;
980 if (refonly != ass->ref_only)
982 if (ass->corlib_internal)
984 g_ptr_array_add (assemblies, ass);
986 mono_domain_assemblies_unlock (domain);
988 res = mono_array_new (domain, mono_class_get_assembly_class (), assemblies->len);
989 for (i = 0; i < assemblies->len; ++i) {
990 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
991 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
992 if (!mono_error_ok (&error))
994 mono_array_setref (res, i, ass_obj);
998 g_ptr_array_free (assemblies, TRUE);
999 if (!mono_error_ok (&error))
1000 mono_error_set_pending_exception (&error);
1004 MonoReflectionAssembly *
1005 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1007 MonoReflectionAssembly *ret;
1010 MonoBoolean isrefonly;
1011 gpointer params [3];
1013 mono_error_init (error);
1015 if (mono_runtime_get_no_exec ())
1018 g_assert (domain != NULL && fname != NULL);
1020 klass = domain->domain->mbr.obj.vtable->klass;
1023 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1024 if (method == NULL) {
1025 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1029 isrefonly = refonly ? 1 : 0;
1032 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1033 return_val_if_nok (error, NULL);
1036 params [2] = &isrefonly;
1038 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1039 return_val_if_nok (error, NULL);
1045 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1049 MonoReflectionAssembly *assembly;
1050 MonoDomain *domain = mono_domain_get ();
1054 aname_str = mono_stringify_assembly_name (aname);
1056 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1057 str = mono_string_new (domain, aname_str);
1063 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1064 if (!mono_error_ok (&error)) {
1066 mono_error_raise_exception (&error); /* FIXME don't raise here */
1072 return assembly->assembly;
1078 * LOCKING: assumes assemblies_lock in the domain is already locked.
1081 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1085 gboolean destroy_ht = FALSE;
1087 if (!ass->aname.name)
1091 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1095 /* FIXME: handle lazy loaded assemblies */
1096 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1097 g_hash_table_insert (ht, tmp->data, tmp->data);
1099 if (!g_hash_table_lookup (ht, ass)) {
1100 mono_assembly_addref (ass);
1101 g_hash_table_insert (ht, ass, ass);
1102 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1103 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);
1106 if (ass->image->references) {
1107 for (i = 0; ass->image->references [i] != NULL; i++) {
1108 if (ass->image->references [i] != REFERENCE_MISSING)
1109 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1110 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1115 g_hash_table_destroy (ht);
1119 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1121 static MonoClassField *assembly_load_field;
1122 static MonoMethod *assembly_load_method;
1124 MonoDomain *domain = mono_domain_get ();
1125 MonoReflectionAssembly *ref_assembly;
1127 gpointer load_value;
1130 if (!domain->domain)
1131 /* This can happen during startup */
1133 #ifdef ASSEMBLY_LOAD_DEBUG
1134 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1136 klass = domain->domain->mbr.obj.vtable->klass;
1138 mono_domain_assemblies_lock (domain);
1139 add_assemblies_to_domain (domain, assembly, NULL);
1140 mono_domain_assemblies_unlock (domain);
1142 if (assembly_load_field == NULL) {
1143 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1144 g_assert (assembly_load_field);
1147 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1148 if (load_value == NULL) {
1149 /* No events waiting to be triggered */
1153 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1154 mono_error_assert_ok (&error);
1156 if (assembly_load_method == NULL) {
1157 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1158 g_assert (assembly_load_method);
1161 *params = ref_assembly;
1163 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1164 mono_error_raise_exception (&error); /* FIXME don't raise here */
1168 * LOCKING: Acquires the domain assemblies lock.
1171 set_domain_search_path (MonoDomain *domain)
1174 MonoAppDomainSetup *setup;
1176 gchar *search_path = NULL;
1179 gchar **pvt_split = NULL;
1180 GError *gerror = NULL;
1181 gint appbaselen = -1;
1184 * We use the low-level domain assemblies lock, since this is called from
1185 * assembly loads hooks, which means this thread might hold the loader lock.
1187 mono_domain_assemblies_lock (domain);
1189 if (!domain->setup) {
1190 mono_domain_assemblies_unlock (domain);
1194 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1195 mono_domain_assemblies_unlock (domain);
1198 setup = domain->setup;
1199 if (!setup->application_base) {
1200 mono_domain_assemblies_unlock (domain);
1201 return; /* Must set application base to get private path working */
1206 if (setup->private_bin_path) {
1207 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1208 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1209 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1210 mono_error_cleanup (&error);
1211 mono_domain_assemblies_unlock (domain);
1216 if (domain->private_bin_path) {
1217 if (search_path == NULL)
1218 search_path = domain->private_bin_path;
1220 gchar *tmp2 = search_path;
1221 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1228 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1229 * directories relative to ApplicationBase separated by semicolons (see
1230 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1231 * The loop below copes with the fact that some Unix applications may use ':' (or
1232 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1233 * ';' for the subsequent split.
1235 * The issue was reported in bug #81446
1238 #ifndef TARGET_WIN32
1241 slen = strlen (search_path);
1242 for (i = 0; i < slen; i++)
1243 if (search_path [i] == ':')
1244 search_path [i] = ';';
1247 pvt_split = g_strsplit (search_path, ";", 1000);
1248 g_free (search_path);
1249 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1254 g_strfreev (pvt_split);
1256 * Don't do this because the first time is called, the domain
1257 * setup is not finished.
1259 * domain->search_path = g_malloc (sizeof (char *));
1260 * domain->search_path [0] = NULL;
1262 mono_domain_assemblies_unlock (domain);
1266 if (domain->search_path)
1267 g_strfreev (domain->search_path);
1269 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1270 tmp [npaths] = NULL;
1272 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1273 if (!mono_error_ok (&error)) {
1274 mono_error_cleanup (&error);
1275 g_strfreev (pvt_split);
1278 mono_domain_assemblies_unlock (domain);
1282 domain->search_path = tmp;
1284 /* FIXME: is this needed? */
1285 if (strncmp (*tmp, "file://", 7) == 0) {
1291 uri = g_strdup_printf ("file:///%s", uri + 7);
1294 uri = mono_escape_uri_string (tmpuri);
1295 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1301 if (gerror != NULL) {
1302 g_warning ("%s\n", gerror->message);
1303 g_error_free (gerror);
1310 for (i = 1; pvt_split && i < npaths; i++) {
1311 if (g_path_is_absolute (pvt_split [i - 1])) {
1312 tmp [i] = g_strdup (pvt_split [i - 1]);
1314 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1317 if (strchr (tmp [i], '.')) {
1321 reduced = mono_path_canonicalize (tmp [i]);
1322 if (appbaselen == -1)
1323 appbaselen = strlen (tmp [0]);
1325 if (strncmp (tmp [0], reduced, appbaselen)) {
1328 tmp [i] = g_strdup ("");
1338 if (setup->private_bin_path_probe != NULL) {
1340 tmp [0] = g_strdup ("");
1343 domain->setup->path_changed = FALSE;
1345 g_strfreev (pvt_split);
1347 mono_domain_assemblies_unlock (domain);
1350 #ifdef DISABLE_SHADOW_COPY
1352 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1358 mono_make_shadow_copy (const char *filename, MonoError *error)
1360 mono_error_init (error);
1361 return (char *) filename;
1365 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1367 guint16 *orig, *dest;
1368 gboolean copy_result;
1370 strcpy (src + srclen - tail_len, extension);
1372 if (IS_PORTABILITY_CASE) {
1373 gchar *file = mono_portability_find_file (src, TRUE);
1379 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1383 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1385 strcpy (target + targetlen - tail_len, extension);
1386 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1389 copy_result = CopyFile (orig, dest, FALSE);
1391 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1392 * overwritten when updated in their original locations. */
1394 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1403 get_cstring_hash (const char *str)
1409 if (!str || !str [0])
1414 for (i = 0; i < len; i++) {
1415 h = (h << 5) - h + *p;
1423 * Returned memory is malloc'd. Called must free it
1426 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1428 MonoAppDomainSetup *setup;
1429 char *cache_path, *appname;
1433 mono_error_init (error);
1435 setup = domain->setup;
1436 if (setup->cache_path != NULL && setup->application_name != NULL) {
1437 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1438 return_val_if_nok (error, NULL);
1440 #ifndef TARGET_WIN32
1443 for (i = strlen (cache_path) - 1; i >= 0; i--)
1444 if (cache_path [i] == '\\')
1445 cache_path [i] = '/';
1449 appname = mono_string_to_utf8_checked (setup->application_name, error);
1450 if (!mono_error_ok (error)) {
1451 g_free (cache_path);
1455 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1457 g_free (cache_path);
1459 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1460 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1467 get_shadow_assembly_location (const char *filename, MonoError *error)
1469 gint32 hash = 0, hash2 = 0;
1471 char path_hash [30];
1472 char *bname = g_path_get_basename (filename);
1473 char *dirname = g_path_get_dirname (filename);
1474 char *location, *tmploc;
1475 MonoDomain *domain = mono_domain_get ();
1477 mono_error_init (error);
1479 hash = get_cstring_hash (bname);
1480 hash2 = get_cstring_hash (dirname);
1481 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1482 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1483 tmploc = get_shadow_assembly_location_base (domain, error);
1484 if (!mono_error_ok (error)) {
1490 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1498 ensure_directory_exists (const char *filename)
1501 gchar *dir_utf8 = g_path_get_dirname (filename);
1503 gunichar2 *dir_utf16 = NULL;
1506 if (!dir_utf8 || !dir_utf8 [0])
1509 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1517 /* make life easy and only use one directory seperator */
1528 while (*p++ != '\\')
1534 p = wcschr (p, '\\');
1537 retval = _wmkdir (dir_utf16);
1538 if (retval != 0 && errno != EEXIST) {
1551 gchar *dir = g_path_get_dirname (filename);
1555 if (!dir || !dir [0]) {
1560 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1570 p = strchr (p, '/');
1573 retval = mkdir (dir, 0777);
1574 if (retval != 0 && errno != EEXIST) {
1589 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1591 struct stat sbuf_dest;
1593 gchar *real_src = mono_portability_find_file (src, TRUE);
1596 stat_src = (gchar*)src;
1598 stat_src = real_src;
1600 if (stat (stat_src, sbuf_src) == -1) {
1601 time_t tnow = time (NULL);
1606 memset (sbuf_src, 0, sizeof (*sbuf_src));
1607 sbuf_src->st_mtime = tnow;
1608 sbuf_src->st_atime = tnow;
1615 if (stat (dest, &sbuf_dest) == -1)
1618 if (sbuf_src->st_size == sbuf_dest.st_size &&
1619 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1626 shadow_copy_create_ini (const char *shadow, const char *filename)
1636 dir_name = g_path_get_dirname (shadow);
1637 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1639 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1644 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1649 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1650 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1652 if (handle == INVALID_HANDLE_VALUE) {
1656 full_path = mono_path_resolve_symlinks (filename);
1657 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1659 CloseHandle (handle);
1664 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1667 MonoAppDomainSetup *setup;
1670 gchar **directories;
1671 gchar *shadow_status_string;
1673 gboolean shadow_enabled;
1674 gboolean found = FALSE;
1679 setup = domain->setup;
1680 if (setup == NULL || setup->shadow_copy_files == NULL)
1683 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1684 if (!mono_error_ok (&error)) {
1685 mono_error_cleanup (&error);
1688 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1689 g_free (shadow_status_string);
1691 if (!shadow_enabled)
1694 if (setup->shadow_copy_directories == NULL)
1697 /* Is dir_name a shadow_copy destination already? */
1698 base_dir = get_shadow_assembly_location_base (domain, &error);
1699 if (!mono_error_ok (&error)) {
1700 mono_error_cleanup (&error);
1704 if (strstr (dir_name, base_dir)) {
1710 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1711 if (!mono_error_ok (&error)) {
1712 mono_error_cleanup (&error);
1716 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1717 dir_ptr = directories;
1719 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1725 g_strfreev (directories);
1731 This function raises exceptions so it can cause as sorts of nasty stuff if called
1732 while holding a lock.
1733 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1734 or NULL if source file not found.
1735 FIXME bubble up the error instead of raising it here
1738 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1741 gchar *sibling_source, *sibling_target;
1742 gint sibling_source_len, sibling_target_len;
1743 guint16 *orig, *dest;
1746 gboolean copy_result;
1747 struct stat src_sbuf;
1748 struct utimbuf utbuf;
1749 char *dir_name = g_path_get_dirname (filename);
1750 MonoDomain *domain = mono_domain_get ();
1753 mono_error_init (oerror);
1755 set_domain_search_path (domain);
1757 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1759 return (char *) filename;
1762 /* Is dir_name a shadow_copy destination already? */
1763 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1764 if (!mono_error_ok (&error)) {
1765 mono_error_cleanup (&error);
1767 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1771 if (strstr (dir_name, shadow_dir)) {
1772 g_free (shadow_dir);
1774 return (char *) filename;
1776 g_free (shadow_dir);
1779 shadow = get_shadow_assembly_location (filename, &error);
1780 if (!mono_error_ok (&error)) {
1781 mono_error_cleanup (&error);
1782 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1786 if (ensure_directory_exists (shadow) == FALSE) {
1788 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1792 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1793 return (char*) shadow;
1795 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1796 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1799 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1800 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1801 * and not have it runtime error" */
1802 attrs = GetFileAttributes (orig);
1803 if (attrs == INVALID_FILE_ATTRIBUTES) {
1805 return (char *)filename;
1808 copy_result = CopyFile (orig, dest, FALSE);
1810 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1811 * overwritten when updated in their original locations. */
1813 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1818 if (copy_result == FALSE) {
1821 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1822 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1823 return NULL; /* file not found, shadow copy failed */
1825 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1829 /* attempt to copy .mdb, .config if they exist */
1830 sibling_source = g_strconcat (filename, ".config", NULL);
1831 sibling_source_len = strlen (sibling_source);
1832 sibling_target = g_strconcat (shadow, ".config", NULL);
1833 sibling_target_len = strlen (sibling_target);
1835 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1836 if (copy_result == TRUE)
1837 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1839 g_free (sibling_source);
1840 g_free (sibling_target);
1842 if (copy_result == FALSE) {
1844 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1848 /* Create a .ini file containing the original assembly location */
1849 if (!shadow_copy_create_ini (shadow, filename)) {
1851 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1855 utbuf.actime = src_sbuf.st_atime;
1856 utbuf.modtime = src_sbuf.st_mtime;
1857 utime (shadow, &utbuf);
1861 #endif /* DISABLE_SHADOW_COPY */
1864 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1866 if (appdomain == NULL)
1869 return appdomain->data;
1873 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1874 const gchar *path3, const gchar *path4,
1875 gboolean refonly, gboolean is_private)
1878 gboolean found = FALSE;
1881 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1883 if (IS_PORTABILITY_SET) {
1884 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1887 fullpath = new_fullpath;
1891 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1894 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1897 return (*assembly != NULL);
1900 static MonoAssembly *
1901 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1903 MonoAssembly *result = NULL;
1906 const gchar *local_culture;
1908 gboolean is_private = FALSE;
1910 if (!culture || *culture == '\0') {
1913 local_culture = culture;
1916 filename = g_strconcat (name, ".dll", NULL);
1917 len = strlen (filename);
1919 for (path = search_path; *path; path++) {
1920 if (**path == '\0') {
1922 continue; /* Ignore empty ApplicationBase */
1925 /* See test cases in bug #58992 and bug #57710 */
1926 /* 1st try: [culture]/[name].dll (culture may be empty) */
1927 strcpy (filename + len - 4, ".dll");
1928 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1931 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1932 strcpy (filename + len - 4, ".exe");
1933 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1936 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1937 strcpy (filename + len - 4, ".dll");
1938 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1941 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1942 strcpy (filename + len - 4, ".exe");
1943 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1952 * Try loading the assembly from ApplicationBase and PrivateBinPath
1953 * and then from assemblies_path if any.
1954 * LOCKING: This is called from the assembly loading code, which means the caller
1955 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1957 static MonoAssembly *
1958 mono_domain_assembly_preload (MonoAssemblyName *aname,
1959 gchar **assemblies_path,
1962 MonoDomain *domain = mono_domain_get ();
1963 MonoAssembly *result = NULL;
1964 gboolean refonly = GPOINTER_TO_UINT (user_data);
1966 set_domain_search_path (domain);
1968 if (domain->search_path && domain->search_path [0] != NULL) {
1969 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1972 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1973 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1980 * Check whenever a given assembly was already loaded in the current appdomain.
1982 static MonoAssembly *
1983 mono_domain_assembly_search (MonoAssemblyName *aname,
1986 MonoDomain *domain = mono_domain_get ();
1989 gboolean refonly = GPOINTER_TO_UINT (user_data);
1991 mono_domain_assemblies_lock (domain);
1992 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1993 ass = (MonoAssembly *)tmp->data;
1994 /* Dynamic assemblies can't match here in MS.NET */
1995 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1998 mono_domain_assemblies_unlock (domain);
2001 mono_domain_assemblies_unlock (domain);
2006 MonoReflectionAssembly *
2007 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2010 MonoReflectionAssembly *result;
2011 MonoDomain *domain = mono_domain_get ();
2012 char *name, *filename;
2013 MonoImageOpenStatus status = MONO_IMAGE_OK;
2016 if (fname == NULL) {
2017 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2018 mono_set_pending_exception (exc);
2022 name = filename = mono_string_to_utf8 (fname);
2024 ass = mono_assembly_open_full (filename, &status, refOnly);
2029 if (status == MONO_IMAGE_IMAGE_INVALID)
2030 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2032 exc = mono_get_exception_file_not_found2 (NULL, fname);
2034 mono_set_pending_exception (exc);
2040 result = mono_assembly_get_object_checked (domain, ass, &error);
2042 mono_error_set_pending_exception (&error);
2046 MonoReflectionAssembly *
2047 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2048 MonoArray *raw_assembly,
2049 MonoArray *raw_symbol_store, MonoObject *evidence,
2050 MonoBoolean refonly)
2054 MonoReflectionAssembly *refass = NULL;
2055 MonoDomain *domain = ad->data;
2056 MonoImageOpenStatus status;
2057 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2058 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2061 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2065 if (raw_symbol_store != NULL)
2066 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2068 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2072 mono_image_close (image);
2073 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2077 refass = mono_assembly_get_object_checked (domain, ass, &error);
2079 mono_error_set_pending_exception (&error);
2081 MONO_OBJECT_SETREF (refass, evidence, evidence);
2085 MonoReflectionAssembly *
2086 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2089 MonoDomain *domain = ad->data;
2090 MonoImageOpenStatus status = MONO_IMAGE_OK;
2092 MonoAssemblyName aname;
2093 MonoReflectionAssembly *refass = NULL;
2099 name = mono_string_to_utf8 (assRef);
2100 parsed = mono_assembly_name_parse (name, &aname);
2104 /* This is a parse error... */
2106 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2107 if (!mono_error_ok (&error)) {
2108 mono_error_set_pending_exception (&error);
2115 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2116 mono_assembly_name_free (&aname);
2119 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2121 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2122 if (!mono_error_ok (&error)) {
2123 mono_error_set_pending_exception (&error);
2135 refass = mono_assembly_get_object_checked (domain, ass, &error);
2138 mono_error_set_pending_exception (&error);
2140 MONO_OBJECT_SETREF (refass, evidence, evidence);
2145 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2147 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2149 if (NULL == domain) {
2150 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2151 mono_set_pending_exception (exc);
2155 if (domain == mono_get_root_domain ()) {
2156 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2161 * Unloading seems to cause problems when running NUnit/NAnt, hence
2164 if (g_getenv ("MONO_NO_UNLOAD"))
2166 #ifdef __native_client__
2170 mono_domain_unload (domain);
2174 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2176 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2181 return mono_domain_is_unloading (domain);
2185 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2187 mono_unhandled_exception ((MonoObject*) exc);
2191 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2192 MonoReflectionAssembly *refass, MonoArray *args)
2199 image = refass->assembly->image;
2202 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2205 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2208 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2210 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2214 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2216 return ad->data->domain_id;
2220 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2222 MonoDomain *old_domain = mono_domain_get();
2224 if (!mono_domain_set (ad->data, FALSE)) {
2225 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2229 return old_domain->domain;
2233 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2235 MonoDomain *current_domain = mono_domain_get ();
2236 MonoDomain *domain = mono_domain_get_by_id (domainid);
2238 if (!domain || !mono_domain_set (domain, FALSE)) {
2239 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2243 return current_domain->domain;
2247 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2249 mono_thread_push_appdomain_ref (ad->data);
2253 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2255 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2259 * Raise an exception to prevent the managed code from executing a pop
2262 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2266 mono_thread_push_appdomain_ref (domain);
2270 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2272 mono_thread_pop_appdomain_ref ();
2276 ves_icall_System_AppDomain_InternalGetContext ()
2278 return mono_context_get ();
2282 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2284 return mono_domain_get ()->default_context;
2288 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2290 MonoAppContext *old_context = mono_context_get ();
2292 mono_context_set (mc);
2298 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2300 MonoDomain* mono_root_domain = mono_get_root_domain ();
2301 mono_domain_lock (mono_root_domain);
2302 if (process_guid_set) {
2303 mono_domain_unlock (mono_root_domain);
2305 MonoString *res = NULL;
2306 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2307 mono_error_raise_exception (&error);
2310 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2311 process_guid_set = TRUE;
2312 mono_domain_unlock (mono_root_domain);
2317 mono_domain_is_unloading (MonoDomain *domain)
2319 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2326 clear_cached_vtable (MonoVTable *vtable)
2328 MonoClass *klass = vtable->klass;
2329 MonoDomain *domain = vtable->domain;
2330 MonoClassRuntimeInfo *runtime_info;
2333 runtime_info = klass->runtime_info;
2334 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2335 runtime_info->domain_vtables [domain->domain_id] = NULL;
2336 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2337 mono_gc_free_fixed (data);
2340 static G_GNUC_UNUSED void
2341 zero_static_data (MonoVTable *vtable)
2343 MonoClass *klass = vtable->klass;
2346 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2347 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2350 typedef struct unload_data {
2353 char *failure_reason;
2358 unload_data_unref (unload_data *data)
2362 mono_atomic_load_acquire (count, gint32, &data->refcount);
2363 g_assert (count >= 1 && count <= 2);
2368 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2372 deregister_reflection_info_roots_from_list (MonoImage *image)
2374 GSList *list = image->reflection_info_unregister_classes;
2377 MonoClass *klass = (MonoClass *)list->data;
2379 mono_class_free_ref_info (klass);
2384 image->reflection_info_unregister_classes = NULL;
2388 deregister_reflection_info_roots (MonoDomain *domain)
2392 mono_domain_assemblies_lock (domain);
2393 for (list = domain->domain_assemblies; list; list = list->next) {
2394 MonoAssembly *assembly = (MonoAssembly *)list->data;
2395 MonoImage *image = assembly->image;
2399 * No need to take the image lock here since dynamic images are appdomain bound and
2400 * at this point the mutator is gone. Taking the image lock here would mean
2401 * promoting it from a simple lock to a complex lock, which we better avoid if
2404 if (image_is_dynamic (image))
2405 deregister_reflection_info_roots_from_list (image);
2407 for (i = 0; i < image->module_count; ++i) {
2408 MonoImage *module = image->modules [i];
2409 if (module && image_is_dynamic (module))
2410 deregister_reflection_info_roots_from_list (module);
2413 mono_domain_assemblies_unlock (domain);
2416 static guint32 WINAPI
2417 unload_thread_main (void *arg)
2420 unload_data *data = (unload_data*)arg;
2421 MonoDomain *domain = data->domain;
2425 /* Have to attach to the runtime so shutdown can wait for this thread */
2426 /* Force it to be attached to avoid racing during shutdown. */
2427 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2428 mono_error_raise_exception (&error); /* FIXME don't raise here */
2431 * FIXME: Abort our parent thread last, so we can return a failure
2432 * indication if aborting times out.
2434 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2435 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2439 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2440 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2444 /* Finalize all finalizable objects in the doomed appdomain */
2445 if (!mono_domain_finalize (domain, -1)) {
2446 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2450 /* Clear references to our vtables in class->runtime_info.
2451 * We also hold the loader lock because we're going to change
2452 * class->runtime_info.
2455 mono_loader_lock (); //FIXME why do we need the loader lock here?
2456 mono_domain_lock (domain);
2459 * We need to make sure that we don't have any remsets
2460 * pointing into static data of the to-be-freed domain because
2461 * at the next collections they would be invalid. So what we
2462 * do is we first zero all static data and then do a minor
2463 * collection. Because all references in the static data will
2464 * now be null we won't do any unnecessary copies and after
2465 * the collection there won't be any more remsets.
2467 for (i = 0; i < domain->class_vtable_array->len; ++i)
2468 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2469 mono_gc_collect (0);
2471 for (i = 0; i < domain->class_vtable_array->len; ++i)
2472 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2473 deregister_reflection_info_roots (domain);
2475 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2477 mono_domain_unlock (domain);
2478 mono_loader_unlock ();
2480 mono_threads_clear_cached_culture (domain);
2482 domain->state = MONO_APPDOMAIN_UNLOADED;
2484 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2486 /* remove from the handle table the items related to this domain */
2487 mono_gchandle_free_domain (domain);
2489 mono_domain_free (domain, FALSE);
2491 mono_gc_collect (mono_gc_max_generation ());
2493 mono_atomic_store_release (&data->done, TRUE);
2494 unload_data_unref (data);
2495 mono_thread_detach (thread);
2499 mono_atomic_store_release (&data->done, TRUE);
2500 unload_data_unref (data);
2501 mono_thread_detach (thread);
2506 * mono_domain_unload:
2507 * @domain: The domain to unload
2509 * Unloads an appdomain. Follows the process outlined in the comment
2510 * for mono_domain_try_unload.
2513 mono_domain_unload (MonoDomain *domain)
2515 MonoObject *exc = NULL;
2516 mono_domain_try_unload (domain, &exc);
2518 mono_raise_exception ((MonoException*)exc);
2522 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2526 MONO_PREPARE_BLOCKING;
2527 result = WaitForSingleObjectEx (handle, timeout, alertable);
2528 MONO_FINISH_BLOCKING;
2534 * mono_domain_unload:
2535 * @domain: The domain to unload
2536 * @exc: Exception information
2538 * Unloads an appdomain. Follows the process outlined in:
2539 * http://blogs.gotdotnet.com/cbrumme
2541 * If doing things the 'right' way is too hard or complex, we do it the
2542 * 'simple' way, which means do everything needed to avoid crashes and
2543 * memory leaks, but not much else.
2545 * It is required to pass a valid reference to the exc argument, upon return
2546 * from this function *exc will be set to the exception thrown, if any.
2548 * If this method is not called from an icall (embedded scenario for instance),
2549 * it must not be called with any managed frames on the stack, since the unload
2550 * process could end up trying to abort the current thread.
2553 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2556 HANDLE thread_handle;
2557 MonoAppDomainState prev_state;
2559 unload_data *thread_data;
2560 MonoNativeThreadId tid;
2561 MonoDomain *caller_domain = mono_domain_get ();
2564 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2566 /* Atomically change our state to UNLOADING */
2567 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2568 MONO_APPDOMAIN_UNLOADING_START,
2569 MONO_APPDOMAIN_CREATED);
2570 if (prev_state != MONO_APPDOMAIN_CREATED) {
2571 switch (prev_state) {
2572 case MONO_APPDOMAIN_UNLOADING_START:
2573 case MONO_APPDOMAIN_UNLOADING:
2574 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2576 case MONO_APPDOMAIN_UNLOADED:
2577 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2580 g_warning ("Invalid appdomain state %d", prev_state);
2581 g_assert_not_reached ();
2585 mono_domain_set (domain, FALSE);
2586 /* Notify OnDomainUnload listeners */
2587 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2590 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2592 if (!mono_error_ok (&error)) {
2594 mono_error_cleanup (&error);
2596 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2600 /* Roll back the state change */
2601 domain->state = MONO_APPDOMAIN_CREATED;
2602 mono_domain_set (caller_domain, FALSE);
2605 mono_domain_set (caller_domain, FALSE);
2607 thread_data = g_new0 (unload_data, 1);
2608 thread_data->domain = domain;
2609 thread_data->failure_reason = NULL;
2610 thread_data->done = FALSE;
2611 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2613 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2614 domain->state = MONO_APPDOMAIN_UNLOADING;
2616 * First we create a separate thread for unloading, since
2617 * we might have to abort some threads, including the current one.
2619 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2620 if (thread_handle == NULL)
2622 name = g_strdup_printf ("Unload thread for domain %x", domain);
2623 mono_thread_info_set_name (tid, name);
2624 mono_thread_info_resume (tid);
2627 /* Wait for the thread */
2628 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2629 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2630 /* The unload thread tries to abort us */
2631 /* The icall wrapper will execute the abort */
2632 CloseHandle (thread_handle);
2633 unload_data_unref (thread_data);
2637 CloseHandle (thread_handle);
2639 if (thread_data->failure_reason) {
2640 /* Roll back the state change */
2641 domain->state = MONO_APPDOMAIN_CREATED;
2643 g_warning ("%s", thread_data->failure_reason);
2645 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2647 g_free (thread_data->failure_reason);
2648 thread_data->failure_reason = NULL;
2651 unload_data_unref (thread_data);