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 140
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;
122 mono_install_runtime_load (MonoLoadFunc func)
124 load_function = func;
128 mono_runtime_load (const char *filename, const char *runtime_version)
130 g_assert (load_function);
131 return load_function (filename, runtime_version);
135 * mono_runtime_set_no_exec:
137 * Instructs the runtime to operate in static mode, i.e. avoid/do not
138 * allow managed code execution. This is useful for running the AOT
139 * compiler on platforms which allow full-aot execution only. This
140 * should be called before mono_runtime_init ().
143 mono_runtime_set_no_exec (gboolean val)
149 * mono_runtime_get_no_exec:
151 * If true, then the runtime will not allow managed code execution.
154 mono_runtime_get_no_exec (void)
160 create_domain_objects (MonoDomain *domain)
163 MonoDomain *old_domain = mono_domain_get ();
165 MonoVTable *string_vt;
166 MonoClassField *string_empty_fld;
168 if (domain != old_domain) {
169 mono_thread_push_appdomain_ref (domain);
170 mono_domain_set_internal_with_options (domain, FALSE);
174 * Initialize String.Empty. This enables the removal of
175 * the static cctor of the String class.
177 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
178 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
179 g_assert (string_empty_fld);
180 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
183 * Create an instance early since we can't do it when there is no memory.
185 arg = mono_string_new (domain, "Out of memory");
186 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
189 * These two are needed because the signal handlers might be executing on
190 * an alternate stack, and Boehm GC can't handle that.
192 arg = mono_string_new (domain, "A null value was found where an object instance was required");
193 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
194 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
195 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
197 /*The ephemeron tombstone i*/
198 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
199 mono_error_assert_ok (&error);
201 if (domain != old_domain) {
202 mono_thread_pop_appdomain_ref ();
203 mono_domain_set_internal_with_options (old_domain, FALSE);
207 * This class is used during exception handling, so initialize it here, to prevent
208 * stack overflows while handling stack overflows.
210 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
215 * @domain: domain returned by mono_init ()
217 * Initialize the core AppDomain: this function will run also some
218 * IL initialization code, so it needs the execution engine to be fully
221 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
222 * we know the entry_assembly.
226 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
227 MonoThreadAttachCB attach_cb)
230 MonoAppDomainSetup *setup;
234 mono_portability_helpers_init ();
236 mono_gc_base_init ();
237 mono_monitor_init ();
238 mono_marshal_init ();
240 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
241 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
242 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
243 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
244 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
245 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
246 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
247 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
249 mono_thread_init (start_cb, attach_cb);
251 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
252 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, &error);
253 mono_error_raise_exception (&error); /* FIXME don't raise here */
255 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
256 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, &error);
257 mono_error_raise_exception (&error); /* FIXME don't raise here */
260 domain->setup = setup;
262 mono_thread_attach (domain);
264 mono_type_initialization_init ();
266 if (!mono_runtime_get_no_exec ())
267 create_domain_objects (domain);
269 /* GC init has to happen after thread init */
272 /* contexts use GC handles, so they must be initialized after the GC */
273 mono_context_init (domain);
274 mono_context_set (domain->default_context);
276 #ifndef DISABLE_SOCKETS
277 mono_network_init ();
280 mono_console_init ();
283 mono_locks_tracer_init ();
285 /* mscorlib is loaded before we install the load hook */
286 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
292 mono_get_corlib_version (void)
295 MonoClassField *field;
298 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
299 mono_class_init (klass);
300 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
303 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
305 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
306 return *(gint32*)((gchar*)value + sizeof (MonoObject));
310 * mono_check_corlib_version
312 * Checks that the corlib that is loaded matches the version of this runtime.
314 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
315 * allocated string with the error otherwise.
318 mono_check_corlib_version (void)
320 int version = mono_get_corlib_version ();
321 if (version != MONO_CORLIB_VERSION)
322 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
329 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
331 * Initializes the @domain's default System.Runtime.Remoting's Context.
334 mono_context_init (MonoDomain *domain)
338 MonoAppContext *context;
340 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
341 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, &error);
342 mono_error_raise_exception (&error); /* FIXME don't raise here */
343 context->domain_id = domain->domain_id;
344 context->context_id = 0;
345 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
346 domain->default_context = context;
350 * mono_runtime_cleanup:
355 * This must not be called while there are still running threads executing
359 mono_runtime_cleanup (MonoDomain *domain)
361 mono_attach_cleanup ();
363 /* This ends up calling any pending pending (for at most 2 seconds) */
366 mono_thread_cleanup ();
368 #ifndef DISABLE_SOCKETS
369 mono_network_cleanup ();
371 mono_marshal_cleanup ();
373 mono_type_initialization_cleanup ();
375 mono_monitor_cleanup ();
378 static MonoDomainFunc quit_function = NULL;
381 mono_install_runtime_cleanup (MonoDomainFunc func)
383 quit_function = func;
389 if (quit_function != NULL)
390 quit_function (mono_get_root_domain (), NULL);
394 * mono_domain_create_appdomain:
395 * @friendly_name: The friendly name of the appdomain to create
396 * @configuration_file: The configuration file to initialize the appdomain with
398 * Returns a MonoDomain initialized with the appdomain
401 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
405 MonoAppDomainSetup *setup;
408 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
409 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
410 mono_error_raise_exception (&error); /* FIXME don't raise here */
411 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
413 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
414 mono_error_raise_exception (&error); /* FIXME don't raise here */
416 return mono_domain_from_appdomain (ad);
420 * mono_domain_set_config:
421 * @domain: MonoDomain initialized with the appdomain we want to change
422 * @base_dir: new base directory for the appdomain
423 * @config_file_name: path to the new configuration for the app domain
425 * Used to set the system configuration for an appdomain
427 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
428 * Error Initializing the configuration system. ---> System.ArgumentException:
429 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
432 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
434 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
435 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
438 static MonoAppDomainSetup*
439 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
442 MonoDomain *caller_domain = mono_domain_get ();
443 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
444 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, &error);
445 mono_error_raise_exception (&error); /* FIXME don't raise here */
447 mono_domain_set_internal (domain);
449 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
450 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
451 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
452 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
453 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
454 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
455 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
456 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
457 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
458 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
459 copy->publisher_policy = setup->publisher_policy;
460 copy->path_changed = setup->path_changed;
461 copy->loader_optimization = setup->loader_optimization;
462 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
463 copy->disallow_code_downloads = setup->disallow_code_downloads;
464 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
465 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
466 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
467 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
468 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
470 mono_domain_set_internal (caller_domain);
475 static MonoAppDomain *
476 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
481 char *shadow_location;
483 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
485 /* FIXME: pin all those objects */
486 data = mono_domain_create();
488 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
489 if (!mono_error_ok (error)) return NULL;
492 data->friendly_name = g_strdup (friendly_name);
494 mono_profiler_appdomain_name (data, data->friendly_name);
496 if (!setup->application_base) {
497 /* Inherit from the root domain since MS.NET does this */
498 MonoDomain *root = mono_get_root_domain ();
499 if (root->setup->application_base) {
500 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
501 mono_error_assert_ok (error); /* FIXME don't swallow the error */
502 MONO_OBJECT_SETREF (setup, application_base, s);
506 mono_context_init (data);
508 data->setup = copy_app_domain_setup (data, setup);
509 mono_domain_set_options_from_config (data);
510 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
512 #ifndef DISABLE_SHADOW_COPY
513 /*FIXME, guard this for when the debugger is not running */
514 shadow_location = get_shadow_assembly_location_base (data, error);
515 if (!mono_error_ok (error))
518 g_free (shadow_location);
521 create_domain_objects (data);
527 * mono_domain_has_type_resolve:
528 * @domain: application domains being looked up
530 * Returns true if the AppDomain.TypeResolve field has been
534 mono_domain_has_type_resolve (MonoDomain *domain)
536 static MonoClassField *field = NULL;
540 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
544 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
548 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
553 * mono_domain_try_type_resolve:
554 * @domain: application domainwhere the name where the type is going to be resolved
555 * @name: the name of the type to resolve or NULL.
556 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
558 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
559 * the assembly that matches name.
561 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
563 * Returns: A MonoReflectionAssembly or NULL if not found
565 MonoReflectionAssembly *
566 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
570 static MonoMethod *method = NULL;
572 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
574 if (method == NULL) {
575 klass = domain->domain->mbr.obj.vtable->klass;
578 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
579 if (method == NULL) {
580 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
586 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
589 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
593 * mono_domain_owns_vtable_slot:
595 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
598 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
602 mono_domain_lock (domain);
603 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
604 mono_domain_unlock (domain);
611 * @force: force setting.
613 * Set the current appdomain to @domain. If @force is set, set it even
614 * if it is being unloaded.
618 * FALSE if the domain is unloaded
621 mono_domain_set (MonoDomain *domain, gboolean force)
623 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
626 mono_domain_set_internal (domain);
632 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
638 MONO_CHECK_ARG_NULL (name, NULL);
644 str = mono_string_to_utf8 (name);
646 mono_domain_lock (add);
648 if (!strcmp (str, "APPBASE"))
649 o = (MonoObject *)add->setup->application_base;
650 else if (!strcmp (str, "APP_CONFIG_FILE"))
651 o = (MonoObject *)add->setup->configuration_file;
652 else if (!strcmp (str, "DYNAMIC_BASE"))
653 o = (MonoObject *)add->setup->dynamic_base;
654 else if (!strcmp (str, "APP_NAME"))
655 o = (MonoObject *)add->setup->application_name;
656 else if (!strcmp (str, "CACHE_BASE"))
657 o = (MonoObject *)add->setup->cache_path;
658 else if (!strcmp (str, "PRIVATE_BINPATH"))
659 o = (MonoObject *)add->setup->private_bin_path;
660 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
661 o = (MonoObject *)add->setup->private_bin_path_probe;
662 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
663 o = (MonoObject *)add->setup->shadow_copy_directories;
664 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
665 o = (MonoObject *)add->setup->shadow_copy_files;
667 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
669 mono_domain_unlock (add);
679 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
683 MONO_CHECK_ARG_NULL (name,);
689 mono_domain_lock (add);
691 mono_g_hash_table_insert (add->env, name, data);
693 mono_domain_unlock (add);
697 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
702 return ad->data->setup;
706 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
711 return mono_string_new (ad->data, ad->data->friendly_name);
715 ves_icall_System_AppDomain_getCurDomain ()
717 MonoDomain *add = mono_domain_get ();
723 ves_icall_System_AppDomain_getRootDomain ()
725 MonoDomain *root = mono_get_root_domain ();
731 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
733 MonoDomain *domain = mono_domain_get ();
735 return domain->throw_unobserved_task_exceptions;
739 get_attribute_value (const gchar **attribute_names,
740 const gchar **attribute_values,
741 const char *att_name)
744 for (n = 0; attribute_names [n] != NULL; n++) {
745 if (strcmp (attribute_names [n], att_name) == 0)
746 return g_strdup (attribute_values [n]);
752 start_element (GMarkupParseContext *context,
753 const gchar *element_name,
754 const gchar **attribute_names,
755 const gchar **attribute_values,
759 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
761 if (strcmp (element_name, "runtime") == 0) {
762 runtime_config->runtime_count++;
766 if (strcmp (element_name, "assemblyBinding") == 0) {
767 runtime_config->assemblybinding_count++;
771 if (runtime_config->runtime_count != 1)
774 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
775 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
777 if (value && g_ascii_strcasecmp (value, "true") == 0)
778 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
781 if (runtime_config->assemblybinding_count != 1)
784 if (strcmp (element_name, "probing") != 0)
787 g_free (runtime_config->domain->private_bin_path);
788 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
789 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
790 g_free (runtime_config->domain->private_bin_path);
791 runtime_config->domain->private_bin_path = NULL;
797 end_element (GMarkupParseContext *context,
798 const gchar *element_name,
802 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
803 if (strcmp (element_name, "runtime") == 0)
804 runtime_config->runtime_count--;
805 else if (strcmp (element_name, "assemblyBinding") == 0)
806 runtime_config->assemblybinding_count--;
810 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
812 RuntimeConfig *state = (RuntimeConfig *)user_data;
814 const gchar *filename;
816 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
817 msg = error && error->message ? error->message : "";
818 g_warning ("Error parsing %s: %s", filename, msg);
821 static const GMarkupParser
831 mono_domain_set_options_from_config (MonoDomain *domain)
834 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
836 GMarkupParseContext *context;
837 RuntimeConfig runtime_config;
840 if (!domain || !domain->setup || !domain->setup->configuration_file)
843 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
844 if (!mono_error_ok (&error)) {
845 mono_error_cleanup (&error);
849 config_file_path = mono_portability_find_file (config_file_name, TRUE);
850 if (!config_file_path)
851 config_file_path = config_file_name;
853 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
856 runtime_config.runtime_count = 0;
857 runtime_config.assemblybinding_count = 0;
858 runtime_config.domain = domain;
859 runtime_config.filename = config_file_path;
862 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
863 offset = 3; /* Skip UTF-8 BOM */
865 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
866 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
867 g_markup_parse_context_end_parse (context, NULL);
868 g_markup_parse_context_free (context);
872 if (config_file_name != config_file_path)
873 g_free (config_file_name);
874 g_free (config_file_path);
878 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
880 #ifdef DISABLE_APPDOMAINS
881 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
888 fname = mono_string_to_utf8 (friendly_name);
889 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
893 mono_error_raise_exception (&error);
900 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
903 MonoDomain *domain = ad->data;
905 static MonoClass *System_Reflection_Assembly;
909 GPtrArray *assemblies;
911 mono_error_init (&error);
913 if (!System_Reflection_Assembly)
914 System_Reflection_Assembly = mono_class_from_name (
915 mono_defaults.corlib, "System.Reflection", "Assembly");
918 * Make a copy of the list of assemblies because we can't hold the assemblies
919 * lock while creating objects etc.
921 assemblies = g_ptr_array_new ();
922 /* Need to skip internal assembly builders created by remoting */
923 mono_domain_assemblies_lock (domain);
924 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
925 ass = (MonoAssembly *)tmp->data;
926 if (refonly != ass->ref_only)
928 if (ass->corlib_internal)
930 g_ptr_array_add (assemblies, ass);
932 mono_domain_assemblies_unlock (domain);
934 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
935 for (i = 0; i < assemblies->len; ++i) {
936 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
937 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
938 if (!mono_error_ok (&error))
940 mono_array_setref (res, i, ass_obj);
944 g_ptr_array_free (assemblies, TRUE);
945 if (!mono_error_ok (&error))
946 mono_error_set_pending_exception (&error);
950 MonoReflectionAssembly *
951 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
956 MonoBoolean isrefonly;
959 if (mono_runtime_get_no_exec ())
962 g_assert (domain != NULL && fname != NULL);
964 klass = domain->domain->mbr.obj.vtable->klass;
967 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
968 if (method == NULL) {
969 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
973 isrefonly = refonly ? 1 : 0;
976 params[1] = mono_assembly_get_object_checked (domain, requesting, &error);
977 if (!mono_error_ok (&error))
978 mono_error_raise_exception (&error); /* FIXME don't raise here */
981 params [2] = &isrefonly;
982 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
986 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
989 MonoReflectionAssembly *assembly;
990 MonoDomain *domain = mono_domain_get ();
994 aname_str = mono_stringify_assembly_name (aname);
996 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
997 str = mono_string_new (domain, aname_str);
1002 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
1006 return assembly->assembly;
1012 * LOCKING: assumes assemblies_lock in the domain is already locked.
1015 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1019 gboolean destroy_ht = FALSE;
1021 if (!ass->aname.name)
1025 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1029 /* FIXME: handle lazy loaded assemblies */
1030 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1031 g_hash_table_insert (ht, tmp->data, tmp->data);
1033 if (!g_hash_table_lookup (ht, ass)) {
1034 mono_assembly_addref (ass);
1035 g_hash_table_insert (ht, ass, ass);
1036 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1037 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);
1040 if (ass->image->references) {
1041 for (i = 0; ass->image->references [i] != NULL; i++) {
1042 if (ass->image->references [i] != REFERENCE_MISSING)
1043 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1044 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1049 g_hash_table_destroy (ht);
1053 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1055 static MonoClassField *assembly_load_field;
1056 static MonoMethod *assembly_load_method;
1058 MonoDomain *domain = mono_domain_get ();
1059 MonoReflectionAssembly *ref_assembly;
1061 gpointer load_value;
1064 if (!domain->domain)
1065 /* This can happen during startup */
1067 #ifdef ASSEMBLY_LOAD_DEBUG
1068 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1070 klass = domain->domain->mbr.obj.vtable->klass;
1072 mono_domain_assemblies_lock (domain);
1073 add_assemblies_to_domain (domain, assembly, NULL);
1074 mono_domain_assemblies_unlock (domain);
1076 if (assembly_load_field == NULL) {
1077 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1078 g_assert (assembly_load_field);
1081 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1082 if (load_value == NULL) {
1083 /* No events waiting to be triggered */
1087 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1088 mono_error_assert_ok (&error);
1090 if (assembly_load_method == NULL) {
1091 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1092 g_assert (assembly_load_method);
1095 *params = ref_assembly;
1096 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1100 * LOCKING: Acquires the domain assemblies lock.
1103 set_domain_search_path (MonoDomain *domain)
1106 MonoAppDomainSetup *setup;
1108 gchar *search_path = NULL;
1111 gchar **pvt_split = NULL;
1112 GError *gerror = NULL;
1113 gint appbaselen = -1;
1116 * We use the low-level domain assemblies lock, since this is called from
1117 * assembly loads hooks, which means this thread might hold the loader lock.
1119 mono_domain_assemblies_lock (domain);
1121 if (!domain->setup) {
1122 mono_domain_assemblies_unlock (domain);
1126 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1127 mono_domain_assemblies_unlock (domain);
1130 setup = domain->setup;
1131 if (!setup->application_base) {
1132 mono_domain_assemblies_unlock (domain);
1133 return; /* Must set application base to get private path working */
1138 if (setup->private_bin_path) {
1139 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1140 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1141 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1142 mono_error_cleanup (&error);
1143 mono_domain_assemblies_unlock (domain);
1148 if (domain->private_bin_path) {
1149 if (search_path == NULL)
1150 search_path = domain->private_bin_path;
1152 gchar *tmp2 = search_path;
1153 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1160 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1161 * directories relative to ApplicationBase separated by semicolons (see
1162 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1163 * The loop below copes with the fact that some Unix applications may use ':' (or
1164 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1165 * ';' for the subsequent split.
1167 * The issue was reported in bug #81446
1170 #ifndef TARGET_WIN32
1173 slen = strlen (search_path);
1174 for (i = 0; i < slen; i++)
1175 if (search_path [i] == ':')
1176 search_path [i] = ';';
1179 pvt_split = g_strsplit (search_path, ";", 1000);
1180 g_free (search_path);
1181 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1186 g_strfreev (pvt_split);
1188 * Don't do this because the first time is called, the domain
1189 * setup is not finished.
1191 * domain->search_path = g_malloc (sizeof (char *));
1192 * domain->search_path [0] = NULL;
1194 mono_domain_assemblies_unlock (domain);
1198 if (domain->search_path)
1199 g_strfreev (domain->search_path);
1201 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1202 tmp [npaths] = NULL;
1204 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1205 if (!mono_error_ok (&error)) {
1206 mono_error_cleanup (&error);
1207 g_strfreev (pvt_split);
1210 mono_domain_assemblies_unlock (domain);
1214 domain->search_path = tmp;
1216 /* FIXME: is this needed? */
1217 if (strncmp (*tmp, "file://", 7) == 0) {
1223 uri = g_strdup_printf ("file:///%s", uri + 7);
1226 uri = mono_escape_uri_string (tmpuri);
1227 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1233 if (gerror != NULL) {
1234 g_warning ("%s\n", gerror->message);
1235 g_error_free (gerror);
1242 for (i = 1; pvt_split && i < npaths; i++) {
1243 if (g_path_is_absolute (pvt_split [i - 1])) {
1244 tmp [i] = g_strdup (pvt_split [i - 1]);
1246 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1249 if (strchr (tmp [i], '.')) {
1253 reduced = mono_path_canonicalize (tmp [i]);
1254 if (appbaselen == -1)
1255 appbaselen = strlen (tmp [0]);
1257 if (strncmp (tmp [0], reduced, appbaselen)) {
1260 tmp [i] = g_strdup ("");
1270 if (setup->private_bin_path_probe != NULL) {
1272 tmp [0] = g_strdup ("");
1275 domain->setup->path_changed = FALSE;
1277 g_strfreev (pvt_split);
1279 mono_domain_assemblies_unlock (domain);
1282 #ifdef DISABLE_SHADOW_COPY
1284 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1290 mono_make_shadow_copy (const char *filename, MonoError *error)
1292 mono_error_init (error);
1293 return (char *) filename;
1297 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1299 guint16 *orig, *dest;
1300 gboolean copy_result;
1302 strcpy (src + srclen - tail_len, extension);
1304 if (IS_PORTABILITY_CASE) {
1305 gchar *file = mono_portability_find_file (src, TRUE);
1311 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1315 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1317 strcpy (target + targetlen - tail_len, extension);
1318 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1321 copy_result = CopyFile (orig, dest, FALSE);
1323 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1324 * overwritten when updated in their original locations. */
1326 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1335 get_cstring_hash (const char *str)
1341 if (!str || !str [0])
1346 for (i = 0; i < len; i++) {
1347 h = (h << 5) - h + *p;
1355 * Returned memory is malloc'd. Called must free it
1358 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1360 MonoAppDomainSetup *setup;
1361 char *cache_path, *appname;
1365 mono_error_init (error);
1367 setup = domain->setup;
1368 if (setup->cache_path != NULL && setup->application_name != NULL) {
1369 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1370 return_val_if_nok (error, NULL);
1372 #ifndef TARGET_WIN32
1375 for (i = strlen (cache_path) - 1; i >= 0; i--)
1376 if (cache_path [i] == '\\')
1377 cache_path [i] = '/';
1381 appname = mono_string_to_utf8_checked (setup->application_name, error);
1382 if (!mono_error_ok (error)) {
1383 g_free (cache_path);
1387 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1389 g_free (cache_path);
1391 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1392 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1399 get_shadow_assembly_location (const char *filename, MonoError *error)
1401 gint32 hash = 0, hash2 = 0;
1403 char path_hash [30];
1404 char *bname = g_path_get_basename (filename);
1405 char *dirname = g_path_get_dirname (filename);
1406 char *location, *tmploc;
1407 MonoDomain *domain = mono_domain_get ();
1409 mono_error_init (error);
1411 hash = get_cstring_hash (bname);
1412 hash2 = get_cstring_hash (dirname);
1413 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1414 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1415 tmploc = get_shadow_assembly_location_base (domain, error);
1416 if (!mono_error_ok (error)) {
1422 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1430 ensure_directory_exists (const char *filename)
1433 gchar *dir_utf8 = g_path_get_dirname (filename);
1435 gunichar2 *dir_utf16 = NULL;
1438 if (!dir_utf8 || !dir_utf8 [0])
1441 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1449 /* make life easy and only use one directory seperator */
1460 while (*p++ != '\\')
1466 p = wcschr (p, '\\');
1469 retval = _wmkdir (dir_utf16);
1470 if (retval != 0 && errno != EEXIST) {
1483 gchar *dir = g_path_get_dirname (filename);
1487 if (!dir || !dir [0]) {
1492 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1502 p = strchr (p, '/');
1505 retval = mkdir (dir, 0777);
1506 if (retval != 0 && errno != EEXIST) {
1521 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1523 struct stat sbuf_dest;
1525 gchar *real_src = mono_portability_find_file (src, TRUE);
1528 stat_src = (gchar*)src;
1530 stat_src = real_src;
1532 if (stat (stat_src, sbuf_src) == -1) {
1533 time_t tnow = time (NULL);
1538 memset (sbuf_src, 0, sizeof (*sbuf_src));
1539 sbuf_src->st_mtime = tnow;
1540 sbuf_src->st_atime = tnow;
1547 if (stat (dest, &sbuf_dest) == -1)
1550 if (sbuf_src->st_size == sbuf_dest.st_size &&
1551 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1558 shadow_copy_create_ini (const char *shadow, const char *filename)
1568 dir_name = g_path_get_dirname (shadow);
1569 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1571 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1576 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1581 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1582 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1584 if (handle == INVALID_HANDLE_VALUE) {
1588 full_path = mono_path_resolve_symlinks (filename);
1589 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1591 CloseHandle (handle);
1596 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1599 MonoAppDomainSetup *setup;
1602 gchar **directories;
1603 gchar *shadow_status_string;
1605 gboolean shadow_enabled;
1606 gboolean found = FALSE;
1611 setup = domain->setup;
1612 if (setup == NULL || setup->shadow_copy_files == NULL)
1615 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1616 if (!mono_error_ok (&error)) {
1617 mono_error_cleanup (&error);
1620 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1621 g_free (shadow_status_string);
1623 if (!shadow_enabled)
1626 if (setup->shadow_copy_directories == NULL)
1629 /* Is dir_name a shadow_copy destination already? */
1630 base_dir = get_shadow_assembly_location_base (domain, &error);
1631 if (!mono_error_ok (&error)) {
1632 mono_error_cleanup (&error);
1636 if (strstr (dir_name, base_dir)) {
1642 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1643 if (!mono_error_ok (&error)) {
1644 mono_error_cleanup (&error);
1648 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1649 dir_ptr = directories;
1651 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1657 g_strfreev (directories);
1663 This function raises exceptions so it can cause as sorts of nasty stuff if called
1664 while holding a lock.
1665 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1666 or NULL if source file not found.
1667 FIXME bubble up the error instead of raising it here
1670 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1673 gchar *sibling_source, *sibling_target;
1674 gint sibling_source_len, sibling_target_len;
1675 guint16 *orig, *dest;
1678 gboolean copy_result;
1679 struct stat src_sbuf;
1680 struct utimbuf utbuf;
1681 char *dir_name = g_path_get_dirname (filename);
1682 MonoDomain *domain = mono_domain_get ();
1685 mono_error_init (oerror);
1687 set_domain_search_path (domain);
1689 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1691 return (char *) filename;
1694 /* Is dir_name a shadow_copy destination already? */
1695 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1696 if (!mono_error_ok (&error)) {
1697 mono_error_cleanup (&error);
1699 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1703 if (strstr (dir_name, shadow_dir)) {
1704 g_free (shadow_dir);
1706 return (char *) filename;
1708 g_free (shadow_dir);
1711 shadow = get_shadow_assembly_location (filename, &error);
1712 if (!mono_error_ok (&error)) {
1713 mono_error_cleanup (&error);
1714 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1718 if (ensure_directory_exists (shadow) == FALSE) {
1720 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1724 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1725 return (char*) shadow;
1727 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1728 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1731 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1732 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1733 * and not have it runtime error" */
1734 attrs = GetFileAttributes (orig);
1735 if (attrs == INVALID_FILE_ATTRIBUTES) {
1737 return (char *)filename;
1740 copy_result = CopyFile (orig, dest, FALSE);
1742 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1743 * overwritten when updated in their original locations. */
1745 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1750 if (copy_result == FALSE) {
1753 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1754 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1755 return NULL; /* file not found, shadow copy failed */
1757 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1761 /* attempt to copy .mdb, .config if they exist */
1762 sibling_source = g_strconcat (filename, ".config", NULL);
1763 sibling_source_len = strlen (sibling_source);
1764 sibling_target = g_strconcat (shadow, ".config", NULL);
1765 sibling_target_len = strlen (sibling_target);
1767 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1768 if (copy_result == TRUE)
1769 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1771 g_free (sibling_source);
1772 g_free (sibling_target);
1774 if (copy_result == FALSE) {
1776 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1780 /* Create a .ini file containing the original assembly location */
1781 if (!shadow_copy_create_ini (shadow, filename)) {
1783 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1787 utbuf.actime = src_sbuf.st_atime;
1788 utbuf.modtime = src_sbuf.st_mtime;
1789 utime (shadow, &utbuf);
1793 #endif /* DISABLE_SHADOW_COPY */
1796 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1798 if (appdomain == NULL)
1801 return appdomain->data;
1805 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1806 const gchar *path3, const gchar *path4,
1807 gboolean refonly, gboolean is_private)
1810 gboolean found = FALSE;
1813 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1815 if (IS_PORTABILITY_SET) {
1816 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1819 fullpath = new_fullpath;
1823 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1826 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1829 return (*assembly != NULL);
1832 static MonoAssembly *
1833 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1835 MonoAssembly *result = NULL;
1838 const gchar *local_culture;
1840 gboolean is_private = FALSE;
1842 if (!culture || *culture == '\0') {
1845 local_culture = culture;
1848 filename = g_strconcat (name, ".dll", NULL);
1849 len = strlen (filename);
1851 for (path = search_path; *path; path++) {
1852 if (**path == '\0') {
1854 continue; /* Ignore empty ApplicationBase */
1857 /* See test cases in bug #58992 and bug #57710 */
1858 /* 1st try: [culture]/[name].dll (culture may be empty) */
1859 strcpy (filename + len - 4, ".dll");
1860 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1863 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1864 strcpy (filename + len - 4, ".exe");
1865 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1868 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1869 strcpy (filename + len - 4, ".dll");
1870 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1873 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1874 strcpy (filename + len - 4, ".exe");
1875 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1884 * Try loading the assembly from ApplicationBase and PrivateBinPath
1885 * and then from assemblies_path if any.
1886 * LOCKING: This is called from the assembly loading code, which means the caller
1887 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1889 static MonoAssembly *
1890 mono_domain_assembly_preload (MonoAssemblyName *aname,
1891 gchar **assemblies_path,
1894 MonoDomain *domain = mono_domain_get ();
1895 MonoAssembly *result = NULL;
1896 gboolean refonly = GPOINTER_TO_UINT (user_data);
1898 set_domain_search_path (domain);
1900 if (domain->search_path && domain->search_path [0] != NULL) {
1901 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1904 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1905 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1912 * Check whenever a given assembly was already loaded in the current appdomain.
1914 static MonoAssembly *
1915 mono_domain_assembly_search (MonoAssemblyName *aname,
1918 MonoDomain *domain = mono_domain_get ();
1921 gboolean refonly = GPOINTER_TO_UINT (user_data);
1923 mono_domain_assemblies_lock (domain);
1924 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1925 ass = (MonoAssembly *)tmp->data;
1926 /* Dynamic assemblies can't match here in MS.NET */
1927 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1930 mono_domain_assemblies_unlock (domain);
1933 mono_domain_assemblies_unlock (domain);
1938 MonoReflectionAssembly *
1939 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1942 MonoReflectionAssembly *result;
1943 MonoDomain *domain = mono_domain_get ();
1944 char *name, *filename;
1945 MonoImageOpenStatus status = MONO_IMAGE_OK;
1948 if (fname == NULL) {
1949 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1950 mono_set_pending_exception (exc);
1954 name = filename = mono_string_to_utf8 (fname);
1956 ass = mono_assembly_open_full (filename, &status, refOnly);
1961 if (status == MONO_IMAGE_IMAGE_INVALID)
1962 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1964 exc = mono_get_exception_file_not_found2 (NULL, fname);
1966 mono_set_pending_exception (exc);
1972 result = mono_assembly_get_object_checked (domain, ass, &error);
1974 mono_error_set_pending_exception (&error);
1978 MonoReflectionAssembly *
1979 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1980 MonoArray *raw_assembly,
1981 MonoArray *raw_symbol_store, MonoObject *evidence,
1982 MonoBoolean refonly)
1986 MonoReflectionAssembly *refass = NULL;
1987 MonoDomain *domain = ad->data;
1988 MonoImageOpenStatus status;
1989 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1990 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1993 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1997 if (raw_symbol_store != NULL)
1998 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2000 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2004 mono_image_close (image);
2005 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2009 refass = mono_assembly_get_object_checked (domain, ass, &error);
2011 mono_error_set_pending_exception (&error);
2013 MONO_OBJECT_SETREF (refass, evidence, evidence);
2017 MonoReflectionAssembly *
2018 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2021 MonoDomain *domain = ad->data;
2022 MonoImageOpenStatus status = MONO_IMAGE_OK;
2024 MonoAssemblyName aname;
2025 MonoReflectionAssembly *refass = NULL;
2031 name = mono_string_to_utf8 (assRef);
2032 parsed = mono_assembly_name_parse (name, &aname);
2036 /* This is a parse error... */
2038 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2042 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2043 mono_assembly_name_free (&aname);
2046 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2048 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2057 refass = mono_assembly_get_object_checked (domain, ass, &error);
2060 mono_error_set_pending_exception (&error);
2062 MONO_OBJECT_SETREF (refass, evidence, evidence);
2067 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2069 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2071 if (NULL == domain) {
2072 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2073 mono_set_pending_exception (exc);
2077 if (domain == mono_get_root_domain ()) {
2078 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2083 * Unloading seems to cause problems when running NUnit/NAnt, hence
2086 if (g_getenv ("MONO_NO_UNLOAD"))
2088 #ifdef __native_client__
2092 mono_domain_unload (domain);
2096 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2098 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2103 return mono_domain_is_unloading (domain);
2107 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2109 mono_unhandled_exception ((MonoObject*) exc);
2113 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2114 MonoReflectionAssembly *refass, MonoArray *args)
2121 image = refass->assembly->image;
2124 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2127 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2130 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2132 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2136 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2138 return ad->data->domain_id;
2142 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2144 MonoDomain *old_domain = mono_domain_get();
2146 if (!mono_domain_set (ad->data, FALSE)) {
2147 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2151 return old_domain->domain;
2155 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2157 MonoDomain *current_domain = mono_domain_get ();
2158 MonoDomain *domain = mono_domain_get_by_id (domainid);
2160 if (!domain || !mono_domain_set (domain, FALSE)) {
2161 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2165 return current_domain->domain;
2169 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2171 mono_thread_push_appdomain_ref (ad->data);
2175 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2177 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2181 * Raise an exception to prevent the managed code from executing a pop
2184 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2188 mono_thread_push_appdomain_ref (domain);
2192 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2194 mono_thread_pop_appdomain_ref ();
2198 ves_icall_System_AppDomain_InternalGetContext ()
2200 return mono_context_get ();
2204 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2206 return mono_domain_get ()->default_context;
2210 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2212 MonoAppContext *old_context = mono_context_get ();
2214 mono_context_set (mc);
2220 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2222 MonoDomain* mono_root_domain = mono_get_root_domain ();
2223 mono_domain_lock (mono_root_domain);
2224 if (process_guid_set) {
2225 mono_domain_unlock (mono_root_domain);
2227 MonoString *res = NULL;
2228 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2229 mono_error_raise_exception (&error);
2232 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2233 process_guid_set = TRUE;
2234 mono_domain_unlock (mono_root_domain);
2239 mono_domain_is_unloading (MonoDomain *domain)
2241 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2248 clear_cached_vtable (MonoVTable *vtable)
2250 MonoClass *klass = vtable->klass;
2251 MonoDomain *domain = vtable->domain;
2252 MonoClassRuntimeInfo *runtime_info;
2255 runtime_info = klass->runtime_info;
2256 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2257 runtime_info->domain_vtables [domain->domain_id] = NULL;
2258 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2259 mono_gc_free_fixed (data);
2262 static G_GNUC_UNUSED void
2263 zero_static_data (MonoVTable *vtable)
2265 MonoClass *klass = vtable->klass;
2268 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2269 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2272 typedef struct unload_data {
2275 char *failure_reason;
2280 unload_data_unref (unload_data *data)
2284 mono_atomic_load_acquire (count, gint32, &data->refcount);
2285 g_assert (count >= 1 && count <= 2);
2290 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2294 deregister_reflection_info_roots_from_list (MonoImage *image)
2296 GSList *list = image->reflection_info_unregister_classes;
2299 MonoClass *klass = (MonoClass *)list->data;
2301 mono_class_free_ref_info (klass);
2306 image->reflection_info_unregister_classes = NULL;
2310 deregister_reflection_info_roots (MonoDomain *domain)
2314 mono_domain_assemblies_lock (domain);
2315 for (list = domain->domain_assemblies; list; list = list->next) {
2316 MonoAssembly *assembly = (MonoAssembly *)list->data;
2317 MonoImage *image = assembly->image;
2321 * No need to take the image lock here since dynamic images are appdomain bound and
2322 * at this point the mutator is gone. Taking the image lock here would mean
2323 * promoting it from a simple lock to a complex lock, which we better avoid if
2326 if (image_is_dynamic (image))
2327 deregister_reflection_info_roots_from_list (image);
2329 for (i = 0; i < image->module_count; ++i) {
2330 MonoImage *module = image->modules [i];
2331 if (module && image_is_dynamic (module))
2332 deregister_reflection_info_roots_from_list (module);
2335 mono_domain_assemblies_unlock (domain);
2338 static guint32 WINAPI
2339 unload_thread_main (void *arg)
2342 unload_data *data = (unload_data*)arg;
2343 MonoDomain *domain = data->domain;
2347 /* Have to attach to the runtime so shutdown can wait for this thread */
2348 /* Force it to be attached to avoid racing during shutdown. */
2349 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2350 mono_error_raise_exception (&error); /* FIXME don't raise here */
2353 * FIXME: Abort our parent thread last, so we can return a failure
2354 * indication if aborting times out.
2356 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2357 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2361 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2362 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2366 /* Finalize all finalizable objects in the doomed appdomain */
2367 if (!mono_domain_finalize (domain, -1)) {
2368 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2372 /* Clear references to our vtables in class->runtime_info.
2373 * We also hold the loader lock because we're going to change
2374 * class->runtime_info.
2377 mono_loader_lock (); //FIXME why do we need the loader lock here?
2378 mono_domain_lock (domain);
2381 * We need to make sure that we don't have any remsets
2382 * pointing into static data of the to-be-freed domain because
2383 * at the next collections they would be invalid. So what we
2384 * do is we first zero all static data and then do a minor
2385 * collection. Because all references in the static data will
2386 * now be null we won't do any unnecessary copies and after
2387 * the collection there won't be any more remsets.
2389 for (i = 0; i < domain->class_vtable_array->len; ++i)
2390 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2391 mono_gc_collect (0);
2393 for (i = 0; i < domain->class_vtable_array->len; ++i)
2394 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2395 deregister_reflection_info_roots (domain);
2397 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2399 mono_domain_unlock (domain);
2400 mono_loader_unlock ();
2402 mono_threads_clear_cached_culture (domain);
2404 domain->state = MONO_APPDOMAIN_UNLOADED;
2406 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2408 /* remove from the handle table the items related to this domain */
2409 mono_gchandle_free_domain (domain);
2411 mono_domain_free (domain, FALSE);
2413 mono_gc_collect (mono_gc_max_generation ());
2415 mono_atomic_store_release (&data->done, TRUE);
2416 unload_data_unref (data);
2417 mono_thread_detach (thread);
2421 mono_atomic_store_release (&data->done, TRUE);
2422 unload_data_unref (data);
2423 mono_thread_detach (thread);
2428 * mono_domain_unload:
2429 * @domain: The domain to unload
2431 * Unloads an appdomain. Follows the process outlined in the comment
2432 * for mono_domain_try_unload.
2435 mono_domain_unload (MonoDomain *domain)
2437 MonoObject *exc = NULL;
2438 mono_domain_try_unload (domain, &exc);
2440 mono_raise_exception ((MonoException*)exc);
2444 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2448 MONO_PREPARE_BLOCKING;
2449 result = WaitForSingleObjectEx (handle, timeout, alertable);
2450 MONO_FINISH_BLOCKING;
2456 * mono_domain_unload:
2457 * @domain: The domain to unload
2458 * @exc: Exception information
2460 * Unloads an appdomain. Follows the process outlined in:
2461 * http://blogs.gotdotnet.com/cbrumme
2463 * If doing things the 'right' way is too hard or complex, we do it the
2464 * 'simple' way, which means do everything needed to avoid crashes and
2465 * memory leaks, but not much else.
2467 * It is required to pass a valid reference to the exc argument, upon return
2468 * from this function *exc will be set to the exception thrown, if any.
2470 * If this method is not called from an icall (embedded scenario for instance),
2471 * it must not be called with any managed frames on the stack, since the unload
2472 * process could end up trying to abort the current thread.
2475 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2477 HANDLE thread_handle;
2478 MonoAppDomainState prev_state;
2480 unload_data *thread_data;
2481 MonoNativeThreadId tid;
2482 MonoDomain *caller_domain = mono_domain_get ();
2485 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2487 /* Atomically change our state to UNLOADING */
2488 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2489 MONO_APPDOMAIN_UNLOADING_START,
2490 MONO_APPDOMAIN_CREATED);
2491 if (prev_state != MONO_APPDOMAIN_CREATED) {
2492 switch (prev_state) {
2493 case MONO_APPDOMAIN_UNLOADING_START:
2494 case MONO_APPDOMAIN_UNLOADING:
2495 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2497 case MONO_APPDOMAIN_UNLOADED:
2498 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2501 g_warning ("Invalid appdomain state %d", prev_state);
2502 g_assert_not_reached ();
2506 mono_domain_set (domain, FALSE);
2507 /* Notify OnDomainUnload listeners */
2508 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2511 mono_runtime_invoke (method, domain->domain, NULL, exc);
2513 /* Roll back the state change */
2514 domain->state = MONO_APPDOMAIN_CREATED;
2515 mono_domain_set (caller_domain, FALSE);
2518 mono_domain_set (caller_domain, FALSE);
2520 thread_data = g_new0 (unload_data, 1);
2521 thread_data->domain = domain;
2522 thread_data->failure_reason = NULL;
2523 thread_data->done = FALSE;
2524 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2526 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2527 domain->state = MONO_APPDOMAIN_UNLOADING;
2529 * First we create a separate thread for unloading, since
2530 * we might have to abort some threads, including the current one.
2532 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2533 if (thread_handle == NULL)
2535 name = g_strdup_printf ("Unload thread for domain %x", domain);
2536 mono_thread_info_set_name (tid, name);
2537 mono_thread_info_resume (tid);
2540 /* Wait for the thread */
2541 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2542 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2543 /* The unload thread tries to abort us */
2544 /* The icall wrapper will execute the abort */
2545 CloseHandle (thread_handle);
2546 unload_data_unref (thread_data);
2550 CloseHandle (thread_handle);
2552 if (thread_data->failure_reason) {
2553 /* Roll back the state change */
2554 domain->state = MONO_APPDOMAIN_CREATED;
2556 g_warning ("%s", thread_data->failure_reason);
2558 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2560 g_free (thread_data->failure_reason);
2561 thread_data->failure_reason = NULL;
2564 unload_data_unref (thread_data);