2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #undef ASSEMBLY_LOAD_DEBUG
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/domain-internals.h>
39 #include "mono/metadata/metadata-internals.h"
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/exception.h>
42 #include <mono/metadata/threads.h>
43 #include <mono/metadata/threadpool-ms.h>
44 #include <mono/metadata/socket-io.h>
45 #include <mono/metadata/tabledefs.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/mono-gc.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/monitor.h>
50 #include <mono/metadata/mono-debug.h>
51 #include <mono/metadata/mono-debug-debugger.h>
52 #include <mono/metadata/attach.h>
53 #include <mono/metadata/file-io.h>
54 #include <mono/metadata/lock-tracer.h>
55 #include <mono/metadata/console-io.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/tokentype.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/utils/mono-uri.h>
61 #include <mono/utils/mono-logger-internals.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-stdlib.h>
64 #include <mono/utils/mono-io-portability.h>
65 #include <mono/utils/mono-error-internals.h>
66 #include <mono/utils/atomic.h>
67 #include <mono/utils/mono-memory-model.h>
68 #include <mono/utils/mono-threads.h>
74 * This is the version number of the corlib-runtime interface. When
75 * making changes to this interface (by changing the layout
76 * of classes the runtime knows about, changing icall signature or
77 * semantics etc), increment this variable. Also increment the
78 * pair of this variable in mscorlib in:
79 * mcs/class/corlib/System/Environment.cs
81 * Changes which are already detected at runtime, like the addition
82 * of icalls, do not require an increment.
84 #define MONO_CORLIB_VERSION 146
89 int assemblybinding_count;
94 static gunichar2 process_guid [36];
95 static gboolean process_guid_set = FALSE;
97 static gboolean no_exec = FALSE;
100 mono_domain_assembly_preload (MonoAssemblyName *aname,
101 gchar **assemblies_path,
104 static MonoAssembly *
105 mono_domain_assembly_search (MonoAssemblyName *aname,
109 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
112 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
114 static MonoAppDomain *
115 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
118 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
120 static MonoLoadFunc load_function = NULL;
122 /* Lazy class loading functions */
123 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
126 mono_install_runtime_load (MonoLoadFunc func)
128 load_function = func;
132 mono_runtime_load (const char *filename, const char *runtime_version)
134 g_assert (load_function);
135 return load_function (filename, runtime_version);
139 * mono_runtime_set_no_exec:
141 * Instructs the runtime to operate in static mode, i.e. avoid/do not
142 * allow managed code execution. This is useful for running the AOT
143 * compiler on platforms which allow full-aot execution only. This
144 * should be called before mono_runtime_init ().
147 mono_runtime_set_no_exec (gboolean val)
153 * mono_runtime_get_no_exec:
155 * If true, then the runtime will not allow managed code execution.
158 mono_runtime_get_no_exec (void)
164 create_domain_objects (MonoDomain *domain)
167 MonoDomain *old_domain = mono_domain_get ();
169 MonoVTable *string_vt;
170 MonoClassField *string_empty_fld;
172 if (domain != old_domain) {
173 mono_thread_push_appdomain_ref (domain);
174 mono_domain_set_internal_with_options (domain, FALSE);
178 * Initialize String.Empty. This enables the removal of
179 * the static cctor of the String class.
181 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
182 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
183 g_assert (string_empty_fld);
184 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
185 mono_error_assert_ok (&error);
186 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
189 * Create an instance early since we can't do it when there is no memory.
191 arg = mono_string_new (domain, "Out of memory");
192 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
195 * These two are needed because the signal handlers might be executing on
196 * an alternate stack, and Boehm GC can't handle that.
198 arg = mono_string_new (domain, "A null value was found where an object instance was required");
199 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
200 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
201 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
203 /*The ephemeron tombstone i*/
204 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
205 mono_error_assert_ok (&error);
207 if (domain != old_domain) {
208 mono_thread_pop_appdomain_ref ();
209 mono_domain_set_internal_with_options (old_domain, FALSE);
213 * This class is used during exception handling, so initialize it here, to prevent
214 * stack overflows while handling stack overflows.
216 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
221 * @domain: domain returned by mono_init ()
223 * Initialize the core AppDomain: this function will run also some
224 * IL initialization code, so it needs the execution engine to be fully
227 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
228 * we know the entry_assembly.
232 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
235 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
236 mono_error_cleanup (&error);
240 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
242 MonoAppDomainSetup *setup;
246 mono_error_init (error);
248 mono_portability_helpers_init ();
250 mono_gc_base_init ();
251 mono_monitor_init ();
252 mono_marshal_init ();
254 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
255 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
256 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
257 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
258 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
259 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
260 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
262 mono_thread_init (start_cb, attach_cb);
264 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
265 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
266 return_if_nok (error);
268 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
270 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
271 return_if_nok (error);
275 domain->setup = setup;
277 mono_thread_attach (domain);
279 mono_type_initialization_init ();
281 if (!mono_runtime_get_no_exec ())
282 create_domain_objects (domain);
284 /* GC init has to happen after thread init */
287 /* contexts use GC handles, so they must be initialized after the GC */
288 mono_context_init_checked (domain, error);
289 return_if_nok (error);
290 mono_context_set (domain->default_context);
292 #ifndef DISABLE_SOCKETS
293 mono_network_init ();
296 mono_console_init ();
299 mono_locks_tracer_init ();
301 /* mscorlib is loaded before we install the load hook */
302 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
308 mono_get_corlib_version (void)
312 MonoClassField *field;
315 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
316 mono_class_init (klass);
317 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
320 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
322 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
323 mono_error_assert_ok (&error);
324 return *(gint32*)((gchar*)value + sizeof (MonoObject));
328 * mono_check_corlib_version
330 * Checks that the corlib that is loaded matches the version of this runtime.
332 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
333 * allocated string with the error otherwise.
336 mono_check_corlib_version (void)
338 int version = mono_get_corlib_version ();
339 if (version != MONO_CORLIB_VERSION)
340 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
347 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
349 * Initializes the @domain's default System.Runtime.Remoting's Context.
352 mono_context_init (MonoDomain *domain)
355 mono_context_init_checked (domain, &error);
356 mono_error_cleanup (&error);
360 mono_context_init_checked (MonoDomain *domain, MonoError *error)
363 MonoAppContext *context;
365 mono_error_init (error);
367 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
368 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
369 return_if_nok (error);
371 context->domain_id = domain->domain_id;
372 context->context_id = 0;
373 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
374 domain->default_context = context;
378 * mono_runtime_cleanup:
383 * This must not be called while there are still running threads executing
387 mono_runtime_cleanup (MonoDomain *domain)
389 mono_attach_cleanup ();
391 /* This ends up calling any pending pending (for at most 2 seconds) */
394 mono_thread_cleanup ();
396 #ifndef DISABLE_SOCKETS
397 mono_network_cleanup ();
399 mono_marshal_cleanup ();
401 mono_type_initialization_cleanup ();
403 mono_monitor_cleanup ();
406 static MonoDomainFunc quit_function = NULL;
409 mono_install_runtime_cleanup (MonoDomainFunc func)
411 quit_function = func;
417 if (quit_function != NULL)
418 quit_function (mono_get_root_domain (), NULL);
422 * mono_domain_create_appdomain:
423 * @friendly_name: The friendly name of the appdomain to create
424 * @configuration_file: The configuration file to initialize the appdomain with
426 * Returns a MonoDomain initialized with the appdomain
429 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
433 MonoAppDomainSetup *setup;
436 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
437 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
440 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
442 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
446 return mono_domain_from_appdomain (ad);
448 mono_error_cleanup (&error);
453 * mono_domain_set_config:
454 * @domain: MonoDomain initialized with the appdomain we want to change
455 * @base_dir: new base directory for the appdomain
456 * @config_file_name: path to the new configuration for the app domain
458 * Used to set the system configuration for an appdomain
460 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
461 * Error Initializing the configuration system. ---> System.ArgumentException:
462 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
465 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
467 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
468 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
471 static MonoAppDomainSetup*
472 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
474 MonoDomain *caller_domain;
475 MonoClass *ads_class;
476 MonoAppDomainSetup *copy;
478 mono_error_init (error);
480 caller_domain = mono_domain_get ();
481 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
483 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
484 return_val_if_nok (error, NULL);
486 mono_domain_set_internal (domain);
488 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
489 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
490 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
491 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
492 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
493 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
494 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
495 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
496 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
497 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
498 copy->publisher_policy = setup->publisher_policy;
499 copy->path_changed = setup->path_changed;
500 copy->loader_optimization = setup->loader_optimization;
501 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
502 copy->disallow_code_downloads = setup->disallow_code_downloads;
503 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
504 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
505 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
506 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
507 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
509 mono_domain_set_internal (caller_domain);
514 static MonoAppDomain *
515 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
520 char *shadow_location;
522 mono_error_init (error);
524 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
526 /* FIXME: pin all those objects */
527 data = mono_domain_create();
529 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
530 return_val_if_nok (error, NULL);
533 data->friendly_name = g_strdup (friendly_name);
535 mono_profiler_appdomain_name (data, data->friendly_name);
537 if (!setup->application_base) {
538 /* Inherit from the root domain since MS.NET does this */
539 MonoDomain *root = mono_get_root_domain ();
540 if (root->setup->application_base) {
541 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
542 mono_error_assert_ok (error); /* FIXME don't swallow the error */
543 MONO_OBJECT_SETREF (setup, application_base, s);
547 mono_context_init_checked (data, error);
548 return_val_if_nok (error, NULL);
550 data->setup = copy_app_domain_setup (data, setup, error);
551 if (!mono_error_ok (error)) {
552 g_free (data->friendly_name);
556 mono_domain_set_options_from_config (data);
557 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
559 #ifndef DISABLE_SHADOW_COPY
560 /*FIXME, guard this for when the debugger is not running */
561 shadow_location = get_shadow_assembly_location_base (data, error);
562 if (!mono_error_ok (error)) {
563 g_free (data->friendly_name);
567 g_free (shadow_location);
570 create_domain_objects (data);
576 * mono_domain_has_type_resolve:
577 * @domain: application domains being looked up
579 * Returns: TRUE if the AppDomain.TypeResolve field has been
583 mono_domain_has_type_resolve (MonoDomain *domain)
585 static MonoClassField *field = NULL;
589 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
593 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
597 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
602 * mono_domain_try_type_resolve:
603 * @domain: application domainwhere the name where the type is going to be resolved
604 * @name: the name of the type to resolve or NULL.
605 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
607 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
608 * the assembly that matches name.
610 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
612 * Returns: A MonoReflectionAssembly or NULL if not found
614 MonoReflectionAssembly *
615 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
618 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
619 mono_error_cleanup (&error);
624 MonoReflectionAssembly *
625 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
627 static MonoMethod *method = NULL;
628 MonoReflectionAssembly *ret;
632 mono_error_init (error);
634 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
636 if (method == NULL) {
637 klass = domain->domain->mbr.obj.vtable->klass;
640 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
641 if (method == NULL) {
642 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
648 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
652 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
653 return_val_if_nok (error, NULL);
659 * mono_domain_owns_vtable_slot:
661 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
664 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
668 mono_domain_lock (domain);
669 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
670 mono_domain_unlock (domain);
677 * @force: force setting.
679 * Set the current appdomain to @domain. If @force is set, set it even
680 * if it is being unloaded.
684 * FALSE if the domain is unloaded
687 mono_domain_set (MonoDomain *domain, gboolean force)
689 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
692 mono_domain_set_internal (domain);
698 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
704 MONO_CHECK_ARG_NULL (name, NULL);
710 str = mono_string_to_utf8 (name);
712 mono_domain_lock (add);
714 if (!strcmp (str, "APPBASE"))
715 o = (MonoObject *)add->setup->application_base;
716 else if (!strcmp (str, "APP_CONFIG_FILE"))
717 o = (MonoObject *)add->setup->configuration_file;
718 else if (!strcmp (str, "DYNAMIC_BASE"))
719 o = (MonoObject *)add->setup->dynamic_base;
720 else if (!strcmp (str, "APP_NAME"))
721 o = (MonoObject *)add->setup->application_name;
722 else if (!strcmp (str, "CACHE_BASE"))
723 o = (MonoObject *)add->setup->cache_path;
724 else if (!strcmp (str, "PRIVATE_BINPATH"))
725 o = (MonoObject *)add->setup->private_bin_path;
726 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
727 o = (MonoObject *)add->setup->private_bin_path_probe;
728 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
729 o = (MonoObject *)add->setup->shadow_copy_directories;
730 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
731 o = (MonoObject *)add->setup->shadow_copy_files;
733 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
735 mono_domain_unlock (add);
745 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
749 MONO_CHECK_ARG_NULL (name,);
755 mono_domain_lock (add);
757 mono_g_hash_table_insert (add->env, name, data);
759 mono_domain_unlock (add);
763 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
768 return ad->data->setup;
772 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
777 return mono_string_new (ad->data, ad->data->friendly_name);
781 ves_icall_System_AppDomain_getCurDomain ()
783 MonoDomain *add = mono_domain_get ();
789 ves_icall_System_AppDomain_getRootDomain ()
791 MonoDomain *root = mono_get_root_domain ();
797 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
799 MonoDomain *domain = mono_domain_get ();
801 return domain->throw_unobserved_task_exceptions;
805 get_attribute_value (const gchar **attribute_names,
806 const gchar **attribute_values,
807 const char *att_name)
810 for (n = 0; attribute_names [n] != NULL; n++) {
811 if (strcmp (attribute_names [n], att_name) == 0)
812 return g_strdup (attribute_values [n]);
818 start_element (GMarkupParseContext *context,
819 const gchar *element_name,
820 const gchar **attribute_names,
821 const gchar **attribute_values,
825 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
827 if (strcmp (element_name, "runtime") == 0) {
828 runtime_config->runtime_count++;
832 if (strcmp (element_name, "assemblyBinding") == 0) {
833 runtime_config->assemblybinding_count++;
837 if (runtime_config->runtime_count != 1)
840 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
841 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
843 if (value && g_ascii_strcasecmp (value, "true") == 0)
844 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
847 if (runtime_config->assemblybinding_count != 1)
850 if (strcmp (element_name, "probing") != 0)
853 g_free (runtime_config->domain->private_bin_path);
854 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
855 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
856 g_free (runtime_config->domain->private_bin_path);
857 runtime_config->domain->private_bin_path = NULL;
863 end_element (GMarkupParseContext *context,
864 const gchar *element_name,
868 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
869 if (strcmp (element_name, "runtime") == 0)
870 runtime_config->runtime_count--;
871 else if (strcmp (element_name, "assemblyBinding") == 0)
872 runtime_config->assemblybinding_count--;
876 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
878 RuntimeConfig *state = (RuntimeConfig *)user_data;
880 const gchar *filename;
882 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
883 msg = error && error->message ? error->message : "";
884 g_warning ("Error parsing %s: %s", filename, msg);
887 static const GMarkupParser
897 mono_domain_set_options_from_config (MonoDomain *domain)
900 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
902 GMarkupParseContext *context;
903 RuntimeConfig runtime_config;
906 if (!domain || !domain->setup || !domain->setup->configuration_file)
909 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
910 if (!mono_error_ok (&error)) {
911 mono_error_cleanup (&error);
915 config_file_path = mono_portability_find_file (config_file_name, TRUE);
916 if (!config_file_path)
917 config_file_path = config_file_name;
919 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
922 runtime_config.runtime_count = 0;
923 runtime_config.assemblybinding_count = 0;
924 runtime_config.domain = domain;
925 runtime_config.filename = config_file_path;
928 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
929 offset = 3; /* Skip UTF-8 BOM */
931 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
932 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
933 g_markup_parse_context_end_parse (context, NULL);
934 g_markup_parse_context_free (context);
938 if (config_file_name != config_file_path)
939 g_free (config_file_name);
940 g_free (config_file_path);
944 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
947 MonoAppDomain *ad = NULL;
948 #ifdef DISABLE_APPDOMAINS
949 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
953 fname = mono_string_to_utf8 (friendly_name);
954 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
958 mono_error_set_pending_exception (&error);
963 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
966 MonoDomain *domain = ad->data;
971 GPtrArray *assemblies;
973 mono_error_init (&error);
976 * Make a copy of the list of assemblies because we can't hold the assemblies
977 * lock while creating objects etc.
979 assemblies = g_ptr_array_new ();
980 /* Need to skip internal assembly builders created by remoting */
981 mono_domain_assemblies_lock (domain);
982 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
983 ass = (MonoAssembly *)tmp->data;
984 if (refonly != ass->ref_only)
986 if (ass->corlib_internal)
988 g_ptr_array_add (assemblies, ass);
990 mono_domain_assemblies_unlock (domain);
992 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
995 for (i = 0; i < assemblies->len; ++i) {
996 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
997 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
998 if (!mono_error_ok (&error))
1000 mono_array_setref (res, i, ass_obj);
1004 g_ptr_array_free (assemblies, TRUE);
1005 if (!mono_error_ok (&error))
1006 mono_error_set_pending_exception (&error);
1010 MonoReflectionAssembly *
1011 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1013 MonoReflectionAssembly *ret;
1016 MonoBoolean isrefonly;
1017 gpointer params [3];
1019 mono_error_init (error);
1021 if (mono_runtime_get_no_exec ())
1024 g_assert (domain != NULL && fname != NULL);
1026 klass = domain->domain->mbr.obj.vtable->klass;
1029 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1030 if (method == NULL) {
1031 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1035 isrefonly = refonly ? 1 : 0;
1038 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1039 return_val_if_nok (error, NULL);
1042 params [2] = &isrefonly;
1044 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1045 return_val_if_nok (error, NULL);
1051 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1055 MonoReflectionAssembly *assembly;
1056 MonoDomain *domain = mono_domain_get ();
1060 aname_str = mono_stringify_assembly_name (aname);
1062 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1063 str = mono_string_new (domain, aname_str);
1069 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1070 mono_error_cleanup (&error);
1073 return assembly->assembly;
1079 * LOCKING: assumes assemblies_lock in the domain is already locked.
1082 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1086 gboolean destroy_ht = FALSE;
1088 if (!ass->aname.name)
1092 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1096 /* FIXME: handle lazy loaded assemblies */
1097 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1098 g_hash_table_insert (ht, tmp->data, tmp->data);
1100 if (!g_hash_table_lookup (ht, ass)) {
1101 mono_assembly_addref (ass);
1102 g_hash_table_insert (ht, ass, ass);
1103 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1104 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);
1107 if (ass->image->references) {
1108 for (i = 0; ass->image->references [i] != NULL; i++) {
1109 if (ass->image->references [i] != REFERENCE_MISSING)
1110 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1111 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1116 g_hash_table_destroy (ht);
1120 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1122 static MonoClassField *assembly_load_field;
1123 static MonoMethod *assembly_load_method;
1125 MonoDomain *domain = mono_domain_get ();
1126 MonoReflectionAssembly *ref_assembly;
1128 gpointer load_value;
1131 if (!domain->domain)
1132 /* This can happen during startup */
1134 #ifdef ASSEMBLY_LOAD_DEBUG
1135 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1137 klass = domain->domain->mbr.obj.vtable->klass;
1139 mono_domain_assemblies_lock (domain);
1140 add_assemblies_to_domain (domain, assembly, NULL);
1141 mono_domain_assemblies_unlock (domain);
1143 if (assembly_load_field == NULL) {
1144 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1145 g_assert (assembly_load_field);
1148 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1149 if (load_value == NULL) {
1150 /* No events waiting to be triggered */
1154 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1155 mono_error_assert_ok (&error);
1157 if (assembly_load_method == NULL) {
1158 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1159 g_assert (assembly_load_method);
1162 *params = ref_assembly;
1164 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1165 mono_error_cleanup (&error);
1169 * LOCKING: Acquires the domain assemblies lock.
1172 set_domain_search_path (MonoDomain *domain)
1175 MonoAppDomainSetup *setup;
1177 gchar *search_path = NULL;
1180 gchar **pvt_split = NULL;
1181 GError *gerror = NULL;
1182 gint appbaselen = -1;
1185 * We use the low-level domain assemblies lock, since this is called from
1186 * assembly loads hooks, which means this thread might hold the loader lock.
1188 mono_domain_assemblies_lock (domain);
1190 if (!domain->setup) {
1191 mono_domain_assemblies_unlock (domain);
1195 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1196 mono_domain_assemblies_unlock (domain);
1199 setup = domain->setup;
1200 if (!setup->application_base) {
1201 mono_domain_assemblies_unlock (domain);
1202 return; /* Must set application base to get private path working */
1207 if (setup->private_bin_path) {
1208 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1209 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1210 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1211 mono_error_cleanup (&error);
1212 mono_domain_assemblies_unlock (domain);
1217 if (domain->private_bin_path) {
1218 if (search_path == NULL)
1219 search_path = domain->private_bin_path;
1221 gchar *tmp2 = search_path;
1222 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1229 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1230 * directories relative to ApplicationBase separated by semicolons (see
1231 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1232 * The loop below copes with the fact that some Unix applications may use ':' (or
1233 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1234 * ';' for the subsequent split.
1236 * The issue was reported in bug #81446
1239 #ifndef TARGET_WIN32
1242 slen = strlen (search_path);
1243 for (i = 0; i < slen; i++)
1244 if (search_path [i] == ':')
1245 search_path [i] = ';';
1248 pvt_split = g_strsplit (search_path, ";", 1000);
1249 g_free (search_path);
1250 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1255 g_strfreev (pvt_split);
1257 * Don't do this because the first time is called, the domain
1258 * setup is not finished.
1260 * domain->search_path = g_malloc (sizeof (char *));
1261 * domain->search_path [0] = NULL;
1263 mono_domain_assemblies_unlock (domain);
1267 if (domain->search_path)
1268 g_strfreev (domain->search_path);
1270 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1271 tmp [npaths] = NULL;
1273 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1274 if (!mono_error_ok (&error)) {
1275 mono_error_cleanup (&error);
1276 g_strfreev (pvt_split);
1279 mono_domain_assemblies_unlock (domain);
1283 domain->search_path = tmp;
1285 /* FIXME: is this needed? */
1286 if (strncmp (*tmp, "file://", 7) == 0) {
1292 uri = g_strdup_printf ("file:///%s", uri + 7);
1295 uri = mono_escape_uri_string (tmpuri);
1296 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1302 if (gerror != NULL) {
1303 g_warning ("%s\n", gerror->message);
1304 g_error_free (gerror);
1311 for (i = 1; pvt_split && i < npaths; i++) {
1312 if (g_path_is_absolute (pvt_split [i - 1])) {
1313 tmp [i] = g_strdup (pvt_split [i - 1]);
1315 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1318 if (strchr (tmp [i], '.')) {
1322 reduced = mono_path_canonicalize (tmp [i]);
1323 if (appbaselen == -1)
1324 appbaselen = strlen (tmp [0]);
1326 if (strncmp (tmp [0], reduced, appbaselen)) {
1329 tmp [i] = g_strdup ("");
1339 if (setup->private_bin_path_probe != NULL) {
1341 tmp [0] = g_strdup ("");
1344 domain->setup->path_changed = FALSE;
1346 g_strfreev (pvt_split);
1348 mono_domain_assemblies_unlock (domain);
1351 #ifdef DISABLE_SHADOW_COPY
1353 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1359 mono_make_shadow_copy (const char *filename, MonoError *error)
1361 mono_error_init (error);
1362 return (char *) filename;
1366 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1368 guint16 *orig, *dest;
1369 gboolean copy_result;
1371 strcpy (src + srclen - tail_len, extension);
1373 if (IS_PORTABILITY_CASE) {
1374 gchar *file = mono_portability_find_file (src, TRUE);
1380 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1384 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1386 strcpy (target + targetlen - tail_len, extension);
1387 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1390 copy_result = CopyFile (orig, dest, FALSE);
1392 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1393 * overwritten when updated in their original locations. */
1395 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1404 get_cstring_hash (const char *str)
1410 if (!str || !str [0])
1415 for (i = 0; i < len; i++) {
1416 h = (h << 5) - h + *p;
1424 * Returned memory is malloc'd. Called must free it
1427 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1429 MonoAppDomainSetup *setup;
1430 char *cache_path, *appname;
1434 mono_error_init (error);
1436 setup = domain->setup;
1437 if (setup->cache_path != NULL && setup->application_name != NULL) {
1438 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1439 return_val_if_nok (error, NULL);
1441 #ifndef TARGET_WIN32
1444 for (i = strlen (cache_path) - 1; i >= 0; i--)
1445 if (cache_path [i] == '\\')
1446 cache_path [i] = '/';
1450 appname = mono_string_to_utf8_checked (setup->application_name, error);
1451 if (!mono_error_ok (error)) {
1452 g_free (cache_path);
1456 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1458 g_free (cache_path);
1460 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1461 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1468 get_shadow_assembly_location (const char *filename, MonoError *error)
1470 gint32 hash = 0, hash2 = 0;
1472 char path_hash [30];
1473 char *bname = g_path_get_basename (filename);
1474 char *dirname = g_path_get_dirname (filename);
1475 char *location, *tmploc;
1476 MonoDomain *domain = mono_domain_get ();
1478 mono_error_init (error);
1480 hash = get_cstring_hash (bname);
1481 hash2 = get_cstring_hash (dirname);
1482 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1483 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1484 tmploc = get_shadow_assembly_location_base (domain, error);
1485 if (!mono_error_ok (error)) {
1491 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1499 ensure_directory_exists (const char *filename)
1502 gchar *dir_utf8 = g_path_get_dirname (filename);
1504 gunichar2 *dir_utf16 = NULL;
1507 if (!dir_utf8 || !dir_utf8 [0])
1510 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1518 /* make life easy and only use one directory seperator */
1529 while (*p++ != '\\')
1535 p = wcschr (p, '\\');
1538 retval = _wmkdir (dir_utf16);
1539 if (retval != 0 && errno != EEXIST) {
1552 gchar *dir = g_path_get_dirname (filename);
1556 if (!dir || !dir [0]) {
1561 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1571 p = strchr (p, '/');
1574 retval = mkdir (dir, 0777);
1575 if (retval != 0 && errno != EEXIST) {
1590 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1592 struct stat sbuf_dest;
1594 gchar *real_src = mono_portability_find_file (src, TRUE);
1597 stat_src = (gchar*)src;
1599 stat_src = real_src;
1601 if (stat (stat_src, sbuf_src) == -1) {
1602 time_t tnow = time (NULL);
1607 memset (sbuf_src, 0, sizeof (*sbuf_src));
1608 sbuf_src->st_mtime = tnow;
1609 sbuf_src->st_atime = tnow;
1616 if (stat (dest, &sbuf_dest) == -1)
1619 if (sbuf_src->st_size == sbuf_dest.st_size &&
1620 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1627 shadow_copy_create_ini (const char *shadow, const char *filename)
1637 dir_name = g_path_get_dirname (shadow);
1638 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1640 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1645 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1650 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1651 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1653 if (handle == INVALID_HANDLE_VALUE) {
1657 full_path = mono_path_resolve_symlinks (filename);
1658 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1660 CloseHandle (handle);
1665 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1668 MonoAppDomainSetup *setup;
1671 gchar **directories;
1672 gchar *shadow_status_string;
1674 gboolean shadow_enabled;
1675 gboolean found = FALSE;
1680 setup = domain->setup;
1681 if (setup == NULL || setup->shadow_copy_files == NULL)
1684 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1685 if (!mono_error_ok (&error)) {
1686 mono_error_cleanup (&error);
1689 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1690 g_free (shadow_status_string);
1692 if (!shadow_enabled)
1695 if (setup->shadow_copy_directories == NULL)
1698 /* Is dir_name a shadow_copy destination already? */
1699 base_dir = get_shadow_assembly_location_base (domain, &error);
1700 if (!mono_error_ok (&error)) {
1701 mono_error_cleanup (&error);
1705 if (strstr (dir_name, base_dir)) {
1711 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1712 if (!mono_error_ok (&error)) {
1713 mono_error_cleanup (&error);
1717 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1718 dir_ptr = directories;
1720 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1726 g_strfreev (directories);
1732 This function raises exceptions so it can cause as sorts of nasty stuff if called
1733 while holding a lock.
1734 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1735 or NULL if source file not found.
1736 FIXME bubble up the error instead of raising it here
1739 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1742 gchar *sibling_source, *sibling_target;
1743 gint sibling_source_len, sibling_target_len;
1744 guint16 *orig, *dest;
1747 gboolean copy_result;
1748 struct stat src_sbuf;
1749 struct utimbuf utbuf;
1750 char *dir_name = g_path_get_dirname (filename);
1751 MonoDomain *domain = mono_domain_get ();
1754 mono_error_init (oerror);
1756 set_domain_search_path (domain);
1758 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1760 return (char *) filename;
1763 /* Is dir_name a shadow_copy destination already? */
1764 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1765 if (!mono_error_ok (&error)) {
1766 mono_error_cleanup (&error);
1768 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1772 if (strstr (dir_name, shadow_dir)) {
1773 g_free (shadow_dir);
1775 return (char *) filename;
1777 g_free (shadow_dir);
1780 shadow = get_shadow_assembly_location (filename, &error);
1781 if (!mono_error_ok (&error)) {
1782 mono_error_cleanup (&error);
1783 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1787 if (ensure_directory_exists (shadow) == FALSE) {
1789 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1793 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1794 return (char*) shadow;
1796 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1797 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1800 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1801 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1802 * and not have it runtime error" */
1803 attrs = GetFileAttributes (orig);
1804 if (attrs == INVALID_FILE_ATTRIBUTES) {
1806 return (char *)filename;
1809 copy_result = CopyFile (orig, dest, FALSE);
1811 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1812 * overwritten when updated in their original locations. */
1814 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1819 if (copy_result == FALSE) {
1822 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1823 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1824 return NULL; /* file not found, shadow copy failed */
1826 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1830 /* attempt to copy .mdb, .config if they exist */
1831 sibling_source = g_strconcat (filename, ".config", NULL);
1832 sibling_source_len = strlen (sibling_source);
1833 sibling_target = g_strconcat (shadow, ".config", NULL);
1834 sibling_target_len = strlen (sibling_target);
1836 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1837 if (copy_result == TRUE)
1838 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1840 g_free (sibling_source);
1841 g_free (sibling_target);
1843 if (copy_result == FALSE) {
1845 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1849 /* Create a .ini file containing the original assembly location */
1850 if (!shadow_copy_create_ini (shadow, filename)) {
1852 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1856 utbuf.actime = src_sbuf.st_atime;
1857 utbuf.modtime = src_sbuf.st_mtime;
1858 utime (shadow, &utbuf);
1862 #endif /* DISABLE_SHADOW_COPY */
1865 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1867 if (appdomain == NULL)
1870 return appdomain->data;
1874 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1875 const gchar *path3, const gchar *path4,
1876 gboolean refonly, gboolean is_private)
1879 gboolean found = FALSE;
1882 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1884 if (IS_PORTABILITY_SET) {
1885 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1888 fullpath = new_fullpath;
1892 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1895 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1898 return (*assembly != NULL);
1901 static MonoAssembly *
1902 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1904 MonoAssembly *result = NULL;
1907 const gchar *local_culture;
1909 gboolean is_private = FALSE;
1911 if (!culture || *culture == '\0') {
1914 local_culture = culture;
1917 filename = g_strconcat (name, ".dll", NULL);
1918 len = strlen (filename);
1920 for (path = search_path; *path; path++) {
1921 if (**path == '\0') {
1923 continue; /* Ignore empty ApplicationBase */
1926 /* See test cases in bug #58992 and bug #57710 */
1927 /* 1st try: [culture]/[name].dll (culture may be empty) */
1928 strcpy (filename + len - 4, ".dll");
1929 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1932 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1933 strcpy (filename + len - 4, ".exe");
1934 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1937 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1938 strcpy (filename + len - 4, ".dll");
1939 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1942 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1943 strcpy (filename + len - 4, ".exe");
1944 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1953 * Try loading the assembly from ApplicationBase and PrivateBinPath
1954 * and then from assemblies_path if any.
1955 * LOCKING: This is called from the assembly loading code, which means the caller
1956 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1958 static MonoAssembly *
1959 mono_domain_assembly_preload (MonoAssemblyName *aname,
1960 gchar **assemblies_path,
1963 MonoDomain *domain = mono_domain_get ();
1964 MonoAssembly *result = NULL;
1965 gboolean refonly = GPOINTER_TO_UINT (user_data);
1967 set_domain_search_path (domain);
1969 if (domain->search_path && domain->search_path [0] != NULL) {
1970 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1973 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1974 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1981 * Check whenever a given assembly was already loaded in the current appdomain.
1983 static MonoAssembly *
1984 mono_domain_assembly_search (MonoAssemblyName *aname,
1987 MonoDomain *domain = mono_domain_get ();
1990 gboolean refonly = GPOINTER_TO_UINT (user_data);
1992 mono_domain_assemblies_lock (domain);
1993 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1994 ass = (MonoAssembly *)tmp->data;
1995 /* Dynamic assemblies can't match here in MS.NET */
1996 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1999 mono_domain_assemblies_unlock (domain);
2002 mono_domain_assemblies_unlock (domain);
2007 MonoReflectionAssembly *
2008 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2011 MonoReflectionAssembly *result;
2012 MonoDomain *domain = mono_domain_get ();
2013 char *name, *filename;
2014 MonoImageOpenStatus status = MONO_IMAGE_OK;
2017 if (fname == NULL) {
2018 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2019 mono_set_pending_exception (exc);
2023 name = filename = mono_string_to_utf8 (fname);
2025 ass = mono_assembly_open_full (filename, &status, refOnly);
2030 if (status == MONO_IMAGE_IMAGE_INVALID)
2031 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2033 exc = mono_get_exception_file_not_found2 (NULL, fname);
2035 mono_set_pending_exception (exc);
2041 result = mono_assembly_get_object_checked (domain, ass, &error);
2043 mono_error_set_pending_exception (&error);
2047 MonoReflectionAssembly *
2048 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2049 MonoArray *raw_assembly,
2050 MonoArray *raw_symbol_store, MonoObject *evidence,
2051 MonoBoolean refonly)
2055 MonoReflectionAssembly *refass = NULL;
2056 MonoDomain *domain = ad->data;
2057 MonoImageOpenStatus status;
2058 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2059 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2062 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2066 if (raw_symbol_store != NULL)
2067 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2069 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2073 mono_image_close (image);
2074 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2078 refass = mono_assembly_get_object_checked (domain, ass, &error);
2080 mono_error_set_pending_exception (&error);
2082 MONO_OBJECT_SETREF (refass, evidence, evidence);
2086 MonoReflectionAssembly *
2087 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2090 MonoDomain *domain = ad->data;
2091 MonoImageOpenStatus status = MONO_IMAGE_OK;
2093 MonoAssemblyName aname;
2094 MonoReflectionAssembly *refass = NULL;
2100 name = mono_string_to_utf8 (assRef);
2101 parsed = mono_assembly_name_parse (name, &aname);
2105 /* This is a parse error... */
2107 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2108 if (!mono_error_ok (&error)) {
2109 mono_error_set_pending_exception (&error);
2116 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2117 mono_assembly_name_free (&aname);
2120 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2122 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2123 if (!mono_error_ok (&error)) {
2124 mono_error_set_pending_exception (&error);
2136 refass = mono_assembly_get_object_checked (domain, ass, &error);
2139 mono_error_set_pending_exception (&error);
2141 MONO_OBJECT_SETREF (refass, evidence, evidence);
2146 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2148 MonoException *exc = NULL;
2149 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2151 if (NULL == domain) {
2152 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2153 mono_set_pending_exception (exc);
2157 if (domain == mono_get_root_domain ()) {
2158 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2163 * Unloading seems to cause problems when running NUnit/NAnt, hence
2166 if (g_getenv ("MONO_NO_UNLOAD"))
2168 #ifdef __native_client__
2172 mono_domain_try_unload (domain, (MonoObject**)&exc);
2174 mono_set_pending_exception (exc);
2178 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2180 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2185 return mono_domain_is_unloading (domain);
2189 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2191 mono_unhandled_exception ((MonoObject*) exc);
2195 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2196 MonoReflectionAssembly *refass, MonoArray *args)
2203 image = refass->assembly->image;
2206 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2209 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2212 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2213 mono_error_assert_ok (&error);
2216 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2220 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2222 return ad->data->domain_id;
2226 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2228 MonoDomain *old_domain = mono_domain_get();
2230 if (!mono_domain_set (ad->data, FALSE)) {
2231 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2235 return old_domain->domain;
2239 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2241 MonoDomain *current_domain = mono_domain_get ();
2242 MonoDomain *domain = mono_domain_get_by_id (domainid);
2244 if (!domain || !mono_domain_set (domain, FALSE)) {
2245 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2249 return current_domain->domain;
2253 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2255 mono_thread_push_appdomain_ref (ad->data);
2259 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2261 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2265 * Raise an exception to prevent the managed code from executing a pop
2268 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2272 mono_thread_push_appdomain_ref (domain);
2276 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2278 mono_thread_pop_appdomain_ref ();
2282 ves_icall_System_AppDomain_InternalGetContext ()
2284 return mono_context_get ();
2288 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2290 return mono_domain_get ()->default_context;
2294 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2296 MonoAppContext *old_context = mono_context_get ();
2298 mono_context_set (mc);
2304 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2306 MonoDomain* mono_root_domain = mono_get_root_domain ();
2307 mono_domain_lock (mono_root_domain);
2308 if (process_guid_set) {
2309 mono_domain_unlock (mono_root_domain);
2311 MonoString *res = NULL;
2312 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2313 mono_error_set_pending_exception (&error);
2316 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2317 process_guid_set = TRUE;
2318 mono_domain_unlock (mono_root_domain);
2323 mono_domain_is_unloading (MonoDomain *domain)
2325 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2332 clear_cached_vtable (MonoVTable *vtable)
2334 MonoClass *klass = vtable->klass;
2335 MonoDomain *domain = vtable->domain;
2336 MonoClassRuntimeInfo *runtime_info;
2339 runtime_info = klass->runtime_info;
2340 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2341 runtime_info->domain_vtables [domain->domain_id] = NULL;
2342 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2343 mono_gc_free_fixed (data);
2346 static G_GNUC_UNUSED void
2347 zero_static_data (MonoVTable *vtable)
2349 MonoClass *klass = vtable->klass;
2352 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2353 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2356 typedef struct unload_data {
2359 char *failure_reason;
2364 unload_data_unref (unload_data *data)
2368 mono_atomic_load_acquire (count, gint32, &data->refcount);
2369 g_assert (count >= 1 && count <= 2);
2374 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2378 deregister_reflection_info_roots_from_list (MonoImage *image)
2380 GSList *list = image->reflection_info_unregister_classes;
2383 MonoClass *klass = (MonoClass *)list->data;
2385 mono_class_free_ref_info (klass);
2390 image->reflection_info_unregister_classes = NULL;
2394 deregister_reflection_info_roots (MonoDomain *domain)
2398 mono_domain_assemblies_lock (domain);
2399 for (list = domain->domain_assemblies; list; list = list->next) {
2400 MonoAssembly *assembly = (MonoAssembly *)list->data;
2401 MonoImage *image = assembly->image;
2405 * No need to take the image lock here since dynamic images are appdomain bound and
2406 * at this point the mutator is gone. Taking the image lock here would mean
2407 * promoting it from a simple lock to a complex lock, which we better avoid if
2410 if (image_is_dynamic (image))
2411 deregister_reflection_info_roots_from_list (image);
2413 for (i = 0; i < image->module_count; ++i) {
2414 MonoImage *module = image->modules [i];
2415 if (module && image_is_dynamic (module))
2416 deregister_reflection_info_roots_from_list (module);
2419 mono_domain_assemblies_unlock (domain);
2422 static guint32 WINAPI
2423 unload_thread_main (void *arg)
2426 unload_data *data = (unload_data*)arg;
2427 MonoDomain *domain = data->domain;
2431 /* Have to attach to the runtime so shutdown can wait for this thread */
2432 /* Force it to be attached to avoid racing during shutdown. */
2433 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2434 if (!is_ok (&error)) {
2435 data->failure_reason = g_strdup (mono_error_get_message (&error));
2436 mono_error_cleanup (&error);
2439 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2440 if (!is_ok (&error)) {
2441 data->failure_reason = g_strdup (mono_error_get_message (&error));
2442 mono_error_cleanup (&error);
2447 * FIXME: Abort our parent thread last, so we can return a failure
2448 * indication if aborting times out.
2450 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2451 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2455 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2456 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2460 /* Finalize all finalizable objects in the doomed appdomain */
2461 if (!mono_domain_finalize (domain, -1)) {
2462 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2466 /* Clear references to our vtables in class->runtime_info.
2467 * We also hold the loader lock because we're going to change
2468 * class->runtime_info.
2471 mono_loader_lock (); //FIXME why do we need the loader lock here?
2472 mono_domain_lock (domain);
2475 * We need to make sure that we don't have any remsets
2476 * pointing into static data of the to-be-freed domain because
2477 * at the next collections they would be invalid. So what we
2478 * do is we first zero all static data and then do a minor
2479 * collection. Because all references in the static data will
2480 * now be null we won't do any unnecessary copies and after
2481 * the collection there won't be any more remsets.
2483 for (i = 0; i < domain->class_vtable_array->len; ++i)
2484 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2485 mono_gc_collect (0);
2487 for (i = 0; i < domain->class_vtable_array->len; ++i)
2488 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2489 deregister_reflection_info_roots (domain);
2491 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2493 mono_domain_unlock (domain);
2494 mono_loader_unlock ();
2496 mono_threads_clear_cached_culture (domain);
2498 domain->state = MONO_APPDOMAIN_UNLOADED;
2500 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2502 /* remove from the handle table the items related to this domain */
2503 mono_gchandle_free_domain (domain);
2505 mono_domain_free (domain, FALSE);
2507 mono_gc_collect (mono_gc_max_generation ());
2509 mono_atomic_store_release (&data->done, TRUE);
2510 unload_data_unref (data);
2511 mono_thread_detach (thread);
2515 mono_atomic_store_release (&data->done, TRUE);
2516 unload_data_unref (data);
2517 mono_thread_detach (thread);
2522 * mono_domain_unload:
2523 * @domain: The domain to unload
2525 * Unloads an appdomain. Follows the process outlined in the comment
2526 * for mono_domain_try_unload.
2529 mono_domain_unload (MonoDomain *domain)
2531 MonoObject *exc = NULL;
2532 mono_domain_try_unload (domain, &exc);
2536 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2540 MONO_PREPARE_BLOCKING;
2541 result = WaitForSingleObjectEx (handle, timeout, alertable);
2542 MONO_FINISH_BLOCKING;
2548 * mono_domain_unload:
2549 * @domain: The domain to unload
2550 * @exc: Exception information
2552 * Unloads an appdomain. Follows the process outlined in:
2553 * http://blogs.gotdotnet.com/cbrumme
2555 * If doing things the 'right' way is too hard or complex, we do it the
2556 * 'simple' way, which means do everything needed to avoid crashes and
2557 * memory leaks, but not much else.
2559 * It is required to pass a valid reference to the exc argument, upon return
2560 * from this function *exc will be set to the exception thrown, if any.
2562 * If this method is not called from an icall (embedded scenario for instance),
2563 * it must not be called with any managed frames on the stack, since the unload
2564 * process could end up trying to abort the current thread.
2567 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2570 HANDLE thread_handle;
2571 MonoAppDomainState prev_state;
2573 unload_data *thread_data;
2574 MonoNativeThreadId tid;
2575 MonoDomain *caller_domain = mono_domain_get ();
2577 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2579 /* Atomically change our state to UNLOADING */
2580 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2581 MONO_APPDOMAIN_UNLOADING_START,
2582 MONO_APPDOMAIN_CREATED);
2583 if (prev_state != MONO_APPDOMAIN_CREATED) {
2584 switch (prev_state) {
2585 case MONO_APPDOMAIN_UNLOADING_START:
2586 case MONO_APPDOMAIN_UNLOADING:
2587 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2589 case MONO_APPDOMAIN_UNLOADED:
2590 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2593 g_warning ("Invalid appdomain state %d", prev_state);
2594 g_assert_not_reached ();
2598 mono_domain_set (domain, FALSE);
2599 /* Notify OnDomainUnload listeners */
2600 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2603 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2605 if (!mono_error_ok (&error)) {
2607 mono_error_cleanup (&error);
2609 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2613 /* Roll back the state change */
2614 domain->state = MONO_APPDOMAIN_CREATED;
2615 mono_domain_set (caller_domain, FALSE);
2618 mono_domain_set (caller_domain, FALSE);
2620 thread_data = g_new0 (unload_data, 1);
2621 thread_data->domain = domain;
2622 thread_data->failure_reason = NULL;
2623 thread_data->done = FALSE;
2624 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2626 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2627 domain->state = MONO_APPDOMAIN_UNLOADING;
2629 * First we create a separate thread for unloading, since
2630 * we might have to abort some threads, including the current one.
2632 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2633 if (thread_handle == NULL)
2635 mono_thread_info_resume (tid);
2637 /* Wait for the thread */
2638 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2639 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2640 /* The unload thread tries to abort us */
2641 /* The icall wrapper will execute the abort */
2642 CloseHandle (thread_handle);
2643 unload_data_unref (thread_data);
2647 CloseHandle (thread_handle);
2649 if (thread_data->failure_reason) {
2650 /* Roll back the state change */
2651 domain->state = MONO_APPDOMAIN_CREATED;
2653 g_warning ("%s", thread_data->failure_reason);
2655 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2657 g_free (thread_data->failure_reason);
2658 thread_data->failure_reason = NULL;
2661 unload_data_unref (thread_data);