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 142
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, MonoError *error)
441 MonoDomain *caller_domain;
442 MonoClass *ads_class;
443 MonoAppDomainSetup *copy;
445 mono_error_init (error);
447 caller_domain = mono_domain_get ();
448 ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
450 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
451 return_val_if_nok (error, NULL);
453 mono_domain_set_internal (domain);
455 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
456 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
457 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
458 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
459 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
460 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
461 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
462 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
463 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
464 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
465 copy->publisher_policy = setup->publisher_policy;
466 copy->path_changed = setup->path_changed;
467 copy->loader_optimization = setup->loader_optimization;
468 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
469 copy->disallow_code_downloads = setup->disallow_code_downloads;
470 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
471 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
472 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
473 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
474 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
476 mono_domain_set_internal (caller_domain);
481 static MonoAppDomain *
482 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
487 char *shadow_location;
489 mono_error_init (error);
491 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
493 /* FIXME: pin all those objects */
494 data = mono_domain_create();
496 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
497 return_val_if_nok (error, NULL);
500 data->friendly_name = g_strdup (friendly_name);
502 mono_profiler_appdomain_name (data, data->friendly_name);
504 if (!setup->application_base) {
505 /* Inherit from the root domain since MS.NET does this */
506 MonoDomain *root = mono_get_root_domain ();
507 if (root->setup->application_base) {
508 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
509 mono_error_assert_ok (error); /* FIXME don't swallow the error */
510 MONO_OBJECT_SETREF (setup, application_base, s);
514 mono_context_init (data);
516 data->setup = copy_app_domain_setup (data, setup, error);
517 if (!mono_error_ok (error)) {
518 g_free (data->friendly_name);
522 mono_domain_set_options_from_config (data);
523 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
525 #ifndef DISABLE_SHADOW_COPY
526 /*FIXME, guard this for when the debugger is not running */
527 shadow_location = get_shadow_assembly_location_base (data, error);
528 if (!mono_error_ok (error)) {
529 g_free (data->friendly_name);
533 g_free (shadow_location);
536 create_domain_objects (data);
542 * mono_domain_has_type_resolve:
543 * @domain: application domains being looked up
545 * Returns: TRUE if the AppDomain.TypeResolve field has been
549 mono_domain_has_type_resolve (MonoDomain *domain)
551 static MonoClassField *field = NULL;
555 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
559 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
563 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
568 * mono_domain_try_type_resolve:
569 * @domain: application domainwhere the name where the type is going to be resolved
570 * @name: the name of the type to resolve or NULL.
571 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
573 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
574 * the assembly that matches name.
576 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
578 * Returns: A MonoReflectionAssembly or NULL if not found
580 MonoReflectionAssembly *
581 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
584 MonoReflectionAssembly *ret;
587 static MonoMethod *method = NULL;
589 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
591 if (method == NULL) {
592 klass = domain->domain->mbr.obj.vtable->klass;
595 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
596 if (method == NULL) {
597 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
603 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
607 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, &error);
608 mono_error_raise_exception (&error); /* FIXME don't raise here */
614 * mono_domain_owns_vtable_slot:
616 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
619 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
623 mono_domain_lock (domain);
624 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
625 mono_domain_unlock (domain);
632 * @force: force setting.
634 * Set the current appdomain to @domain. If @force is set, set it even
635 * if it is being unloaded.
639 * FALSE if the domain is unloaded
642 mono_domain_set (MonoDomain *domain, gboolean force)
644 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
647 mono_domain_set_internal (domain);
653 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
659 MONO_CHECK_ARG_NULL (name, NULL);
665 str = mono_string_to_utf8 (name);
667 mono_domain_lock (add);
669 if (!strcmp (str, "APPBASE"))
670 o = (MonoObject *)add->setup->application_base;
671 else if (!strcmp (str, "APP_CONFIG_FILE"))
672 o = (MonoObject *)add->setup->configuration_file;
673 else if (!strcmp (str, "DYNAMIC_BASE"))
674 o = (MonoObject *)add->setup->dynamic_base;
675 else if (!strcmp (str, "APP_NAME"))
676 o = (MonoObject *)add->setup->application_name;
677 else if (!strcmp (str, "CACHE_BASE"))
678 o = (MonoObject *)add->setup->cache_path;
679 else if (!strcmp (str, "PRIVATE_BINPATH"))
680 o = (MonoObject *)add->setup->private_bin_path;
681 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
682 o = (MonoObject *)add->setup->private_bin_path_probe;
683 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
684 o = (MonoObject *)add->setup->shadow_copy_directories;
685 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
686 o = (MonoObject *)add->setup->shadow_copy_files;
688 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
690 mono_domain_unlock (add);
700 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
704 MONO_CHECK_ARG_NULL (name,);
710 mono_domain_lock (add);
712 mono_g_hash_table_insert (add->env, name, data);
714 mono_domain_unlock (add);
718 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
723 return ad->data->setup;
727 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
732 return mono_string_new (ad->data, ad->data->friendly_name);
736 ves_icall_System_AppDomain_getCurDomain ()
738 MonoDomain *add = mono_domain_get ();
744 ves_icall_System_AppDomain_getRootDomain ()
746 MonoDomain *root = mono_get_root_domain ();
752 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
754 MonoDomain *domain = mono_domain_get ();
756 return domain->throw_unobserved_task_exceptions;
760 get_attribute_value (const gchar **attribute_names,
761 const gchar **attribute_values,
762 const char *att_name)
765 for (n = 0; attribute_names [n] != NULL; n++) {
766 if (strcmp (attribute_names [n], att_name) == 0)
767 return g_strdup (attribute_values [n]);
773 start_element (GMarkupParseContext *context,
774 const gchar *element_name,
775 const gchar **attribute_names,
776 const gchar **attribute_values,
780 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
782 if (strcmp (element_name, "runtime") == 0) {
783 runtime_config->runtime_count++;
787 if (strcmp (element_name, "assemblyBinding") == 0) {
788 runtime_config->assemblybinding_count++;
792 if (runtime_config->runtime_count != 1)
795 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
796 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
798 if (value && g_ascii_strcasecmp (value, "true") == 0)
799 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
802 if (runtime_config->assemblybinding_count != 1)
805 if (strcmp (element_name, "probing") != 0)
808 g_free (runtime_config->domain->private_bin_path);
809 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
810 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
811 g_free (runtime_config->domain->private_bin_path);
812 runtime_config->domain->private_bin_path = NULL;
818 end_element (GMarkupParseContext *context,
819 const gchar *element_name,
823 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
824 if (strcmp (element_name, "runtime") == 0)
825 runtime_config->runtime_count--;
826 else if (strcmp (element_name, "assemblyBinding") == 0)
827 runtime_config->assemblybinding_count--;
831 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
833 RuntimeConfig *state = (RuntimeConfig *)user_data;
835 const gchar *filename;
837 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
838 msg = error && error->message ? error->message : "";
839 g_warning ("Error parsing %s: %s", filename, msg);
842 static const GMarkupParser
852 mono_domain_set_options_from_config (MonoDomain *domain)
855 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
857 GMarkupParseContext *context;
858 RuntimeConfig runtime_config;
861 if (!domain || !domain->setup || !domain->setup->configuration_file)
864 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
865 if (!mono_error_ok (&error)) {
866 mono_error_cleanup (&error);
870 config_file_path = mono_portability_find_file (config_file_name, TRUE);
871 if (!config_file_path)
872 config_file_path = config_file_name;
874 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
877 runtime_config.runtime_count = 0;
878 runtime_config.assemblybinding_count = 0;
879 runtime_config.domain = domain;
880 runtime_config.filename = config_file_path;
883 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
884 offset = 3; /* Skip UTF-8 BOM */
886 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
887 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
888 g_markup_parse_context_end_parse (context, NULL);
889 g_markup_parse_context_free (context);
893 if (config_file_name != config_file_path)
894 g_free (config_file_name);
895 g_free (config_file_path);
899 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
901 #ifdef DISABLE_APPDOMAINS
902 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
909 fname = mono_string_to_utf8 (friendly_name);
910 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
914 mono_error_raise_exception (&error);
921 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
924 MonoDomain *domain = ad->data;
926 static MonoClass *System_Reflection_Assembly;
930 GPtrArray *assemblies;
932 mono_error_init (&error);
934 if (!System_Reflection_Assembly)
935 System_Reflection_Assembly = mono_class_from_name (
936 mono_defaults.corlib, "System.Reflection", "Assembly");
939 * Make a copy of the list of assemblies because we can't hold the assemblies
940 * lock while creating objects etc.
942 assemblies = g_ptr_array_new ();
943 /* Need to skip internal assembly builders created by remoting */
944 mono_domain_assemblies_lock (domain);
945 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
946 ass = (MonoAssembly *)tmp->data;
947 if (refonly != ass->ref_only)
949 if (ass->corlib_internal)
951 g_ptr_array_add (assemblies, ass);
953 mono_domain_assemblies_unlock (domain);
955 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
956 for (i = 0; i < assemblies->len; ++i) {
957 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
958 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
959 if (!mono_error_ok (&error))
961 mono_array_setref (res, i, ass_obj);
965 g_ptr_array_free (assemblies, TRUE);
966 if (!mono_error_ok (&error))
967 mono_error_set_pending_exception (&error);
971 MonoReflectionAssembly *
972 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
975 MonoReflectionAssembly *ret;
978 MonoBoolean isrefonly;
981 if (mono_runtime_get_no_exec ())
984 g_assert (domain != NULL && fname != NULL);
986 klass = domain->domain->mbr.obj.vtable->klass;
989 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
990 if (method == NULL) {
991 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
995 isrefonly = refonly ? 1 : 0;
998 params[1] = mono_assembly_get_object_checked (domain, requesting, &error);
999 if (!mono_error_ok (&error))
1000 mono_error_raise_exception (&error); /* FIXME don't raise here */
1003 params [2] = &isrefonly;
1005 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, &error);
1006 mono_error_raise_exception (&error); /* FIXME don't raise here */
1012 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1015 MonoReflectionAssembly *assembly;
1016 MonoDomain *domain = mono_domain_get ();
1020 aname_str = mono_stringify_assembly_name (aname);
1022 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1023 str = mono_string_new (domain, aname_str);
1028 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
1032 return assembly->assembly;
1038 * LOCKING: assumes assemblies_lock in the domain is already locked.
1041 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1045 gboolean destroy_ht = FALSE;
1047 if (!ass->aname.name)
1051 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1055 /* FIXME: handle lazy loaded assemblies */
1056 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1057 g_hash_table_insert (ht, tmp->data, tmp->data);
1059 if (!g_hash_table_lookup (ht, ass)) {
1060 mono_assembly_addref (ass);
1061 g_hash_table_insert (ht, ass, ass);
1062 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1063 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);
1066 if (ass->image->references) {
1067 for (i = 0; ass->image->references [i] != NULL; i++) {
1068 if (ass->image->references [i] != REFERENCE_MISSING)
1069 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1070 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1075 g_hash_table_destroy (ht);
1079 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1081 static MonoClassField *assembly_load_field;
1082 static MonoMethod *assembly_load_method;
1084 MonoDomain *domain = mono_domain_get ();
1085 MonoReflectionAssembly *ref_assembly;
1087 gpointer load_value;
1090 if (!domain->domain)
1091 /* This can happen during startup */
1093 #ifdef ASSEMBLY_LOAD_DEBUG
1094 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1096 klass = domain->domain->mbr.obj.vtable->klass;
1098 mono_domain_assemblies_lock (domain);
1099 add_assemblies_to_domain (domain, assembly, NULL);
1100 mono_domain_assemblies_unlock (domain);
1102 if (assembly_load_field == NULL) {
1103 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1104 g_assert (assembly_load_field);
1107 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1108 if (load_value == NULL) {
1109 /* No events waiting to be triggered */
1113 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1114 mono_error_assert_ok (&error);
1116 if (assembly_load_method == NULL) {
1117 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1118 g_assert (assembly_load_method);
1121 *params = ref_assembly;
1123 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1124 mono_error_raise_exception (&error); /* FIXME don't raise here */
1128 * LOCKING: Acquires the domain assemblies lock.
1131 set_domain_search_path (MonoDomain *domain)
1134 MonoAppDomainSetup *setup;
1136 gchar *search_path = NULL;
1139 gchar **pvt_split = NULL;
1140 GError *gerror = NULL;
1141 gint appbaselen = -1;
1144 * We use the low-level domain assemblies lock, since this is called from
1145 * assembly loads hooks, which means this thread might hold the loader lock.
1147 mono_domain_assemblies_lock (domain);
1149 if (!domain->setup) {
1150 mono_domain_assemblies_unlock (domain);
1154 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1155 mono_domain_assemblies_unlock (domain);
1158 setup = domain->setup;
1159 if (!setup->application_base) {
1160 mono_domain_assemblies_unlock (domain);
1161 return; /* Must set application base to get private path working */
1166 if (setup->private_bin_path) {
1167 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1168 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1169 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1170 mono_error_cleanup (&error);
1171 mono_domain_assemblies_unlock (domain);
1176 if (domain->private_bin_path) {
1177 if (search_path == NULL)
1178 search_path = domain->private_bin_path;
1180 gchar *tmp2 = search_path;
1181 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1188 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1189 * directories relative to ApplicationBase separated by semicolons (see
1190 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1191 * The loop below copes with the fact that some Unix applications may use ':' (or
1192 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1193 * ';' for the subsequent split.
1195 * The issue was reported in bug #81446
1198 #ifndef TARGET_WIN32
1201 slen = strlen (search_path);
1202 for (i = 0; i < slen; i++)
1203 if (search_path [i] == ':')
1204 search_path [i] = ';';
1207 pvt_split = g_strsplit (search_path, ";", 1000);
1208 g_free (search_path);
1209 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1214 g_strfreev (pvt_split);
1216 * Don't do this because the first time is called, the domain
1217 * setup is not finished.
1219 * domain->search_path = g_malloc (sizeof (char *));
1220 * domain->search_path [0] = NULL;
1222 mono_domain_assemblies_unlock (domain);
1226 if (domain->search_path)
1227 g_strfreev (domain->search_path);
1229 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1230 tmp [npaths] = NULL;
1232 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1233 if (!mono_error_ok (&error)) {
1234 mono_error_cleanup (&error);
1235 g_strfreev (pvt_split);
1238 mono_domain_assemblies_unlock (domain);
1242 domain->search_path = tmp;
1244 /* FIXME: is this needed? */
1245 if (strncmp (*tmp, "file://", 7) == 0) {
1251 uri = g_strdup_printf ("file:///%s", uri + 7);
1254 uri = mono_escape_uri_string (tmpuri);
1255 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1261 if (gerror != NULL) {
1262 g_warning ("%s\n", gerror->message);
1263 g_error_free (gerror);
1270 for (i = 1; pvt_split && i < npaths; i++) {
1271 if (g_path_is_absolute (pvt_split [i - 1])) {
1272 tmp [i] = g_strdup (pvt_split [i - 1]);
1274 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1277 if (strchr (tmp [i], '.')) {
1281 reduced = mono_path_canonicalize (tmp [i]);
1282 if (appbaselen == -1)
1283 appbaselen = strlen (tmp [0]);
1285 if (strncmp (tmp [0], reduced, appbaselen)) {
1288 tmp [i] = g_strdup ("");
1298 if (setup->private_bin_path_probe != NULL) {
1300 tmp [0] = g_strdup ("");
1303 domain->setup->path_changed = FALSE;
1305 g_strfreev (pvt_split);
1307 mono_domain_assemblies_unlock (domain);
1310 #ifdef DISABLE_SHADOW_COPY
1312 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1318 mono_make_shadow_copy (const char *filename, MonoError *error)
1320 mono_error_init (error);
1321 return (char *) filename;
1325 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1327 guint16 *orig, *dest;
1328 gboolean copy_result;
1330 strcpy (src + srclen - tail_len, extension);
1332 if (IS_PORTABILITY_CASE) {
1333 gchar *file = mono_portability_find_file (src, TRUE);
1339 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1343 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1345 strcpy (target + targetlen - tail_len, extension);
1346 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1349 copy_result = CopyFile (orig, dest, FALSE);
1351 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1352 * overwritten when updated in their original locations. */
1354 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1363 get_cstring_hash (const char *str)
1369 if (!str || !str [0])
1374 for (i = 0; i < len; i++) {
1375 h = (h << 5) - h + *p;
1383 * Returned memory is malloc'd. Called must free it
1386 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1388 MonoAppDomainSetup *setup;
1389 char *cache_path, *appname;
1393 mono_error_init (error);
1395 setup = domain->setup;
1396 if (setup->cache_path != NULL && setup->application_name != NULL) {
1397 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1398 return_val_if_nok (error, NULL);
1400 #ifndef TARGET_WIN32
1403 for (i = strlen (cache_path) - 1; i >= 0; i--)
1404 if (cache_path [i] == '\\')
1405 cache_path [i] = '/';
1409 appname = mono_string_to_utf8_checked (setup->application_name, error);
1410 if (!mono_error_ok (error)) {
1411 g_free (cache_path);
1415 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1417 g_free (cache_path);
1419 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1420 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1427 get_shadow_assembly_location (const char *filename, MonoError *error)
1429 gint32 hash = 0, hash2 = 0;
1431 char path_hash [30];
1432 char *bname = g_path_get_basename (filename);
1433 char *dirname = g_path_get_dirname (filename);
1434 char *location, *tmploc;
1435 MonoDomain *domain = mono_domain_get ();
1437 mono_error_init (error);
1439 hash = get_cstring_hash (bname);
1440 hash2 = get_cstring_hash (dirname);
1441 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1442 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1443 tmploc = get_shadow_assembly_location_base (domain, error);
1444 if (!mono_error_ok (error)) {
1450 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1458 ensure_directory_exists (const char *filename)
1461 gchar *dir_utf8 = g_path_get_dirname (filename);
1463 gunichar2 *dir_utf16 = NULL;
1466 if (!dir_utf8 || !dir_utf8 [0])
1469 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1477 /* make life easy and only use one directory seperator */
1488 while (*p++ != '\\')
1494 p = wcschr (p, '\\');
1497 retval = _wmkdir (dir_utf16);
1498 if (retval != 0 && errno != EEXIST) {
1511 gchar *dir = g_path_get_dirname (filename);
1515 if (!dir || !dir [0]) {
1520 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1530 p = strchr (p, '/');
1533 retval = mkdir (dir, 0777);
1534 if (retval != 0 && errno != EEXIST) {
1549 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1551 struct stat sbuf_dest;
1553 gchar *real_src = mono_portability_find_file (src, TRUE);
1556 stat_src = (gchar*)src;
1558 stat_src = real_src;
1560 if (stat (stat_src, sbuf_src) == -1) {
1561 time_t tnow = time (NULL);
1566 memset (sbuf_src, 0, sizeof (*sbuf_src));
1567 sbuf_src->st_mtime = tnow;
1568 sbuf_src->st_atime = tnow;
1575 if (stat (dest, &sbuf_dest) == -1)
1578 if (sbuf_src->st_size == sbuf_dest.st_size &&
1579 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1586 shadow_copy_create_ini (const char *shadow, const char *filename)
1596 dir_name = g_path_get_dirname (shadow);
1597 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1599 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1604 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1609 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1610 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1612 if (handle == INVALID_HANDLE_VALUE) {
1616 full_path = mono_path_resolve_symlinks (filename);
1617 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1619 CloseHandle (handle);
1624 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1627 MonoAppDomainSetup *setup;
1630 gchar **directories;
1631 gchar *shadow_status_string;
1633 gboolean shadow_enabled;
1634 gboolean found = FALSE;
1639 setup = domain->setup;
1640 if (setup == NULL || setup->shadow_copy_files == NULL)
1643 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1644 if (!mono_error_ok (&error)) {
1645 mono_error_cleanup (&error);
1648 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1649 g_free (shadow_status_string);
1651 if (!shadow_enabled)
1654 if (setup->shadow_copy_directories == NULL)
1657 /* Is dir_name a shadow_copy destination already? */
1658 base_dir = get_shadow_assembly_location_base (domain, &error);
1659 if (!mono_error_ok (&error)) {
1660 mono_error_cleanup (&error);
1664 if (strstr (dir_name, base_dir)) {
1670 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1671 if (!mono_error_ok (&error)) {
1672 mono_error_cleanup (&error);
1676 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1677 dir_ptr = directories;
1679 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1685 g_strfreev (directories);
1691 This function raises exceptions so it can cause as sorts of nasty stuff if called
1692 while holding a lock.
1693 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1694 or NULL if source file not found.
1695 FIXME bubble up the error instead of raising it here
1698 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1701 gchar *sibling_source, *sibling_target;
1702 gint sibling_source_len, sibling_target_len;
1703 guint16 *orig, *dest;
1706 gboolean copy_result;
1707 struct stat src_sbuf;
1708 struct utimbuf utbuf;
1709 char *dir_name = g_path_get_dirname (filename);
1710 MonoDomain *domain = mono_domain_get ();
1713 mono_error_init (oerror);
1715 set_domain_search_path (domain);
1717 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1719 return (char *) filename;
1722 /* Is dir_name a shadow_copy destination already? */
1723 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1724 if (!mono_error_ok (&error)) {
1725 mono_error_cleanup (&error);
1727 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1731 if (strstr (dir_name, shadow_dir)) {
1732 g_free (shadow_dir);
1734 return (char *) filename;
1736 g_free (shadow_dir);
1739 shadow = get_shadow_assembly_location (filename, &error);
1740 if (!mono_error_ok (&error)) {
1741 mono_error_cleanup (&error);
1742 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1746 if (ensure_directory_exists (shadow) == FALSE) {
1748 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1752 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1753 return (char*) shadow;
1755 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1756 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1759 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1760 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1761 * and not have it runtime error" */
1762 attrs = GetFileAttributes (orig);
1763 if (attrs == INVALID_FILE_ATTRIBUTES) {
1765 return (char *)filename;
1768 copy_result = CopyFile (orig, dest, FALSE);
1770 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1771 * overwritten when updated in their original locations. */
1773 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1778 if (copy_result == FALSE) {
1781 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1782 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1783 return NULL; /* file not found, shadow copy failed */
1785 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1789 /* attempt to copy .mdb, .config if they exist */
1790 sibling_source = g_strconcat (filename, ".config", NULL);
1791 sibling_source_len = strlen (sibling_source);
1792 sibling_target = g_strconcat (shadow, ".config", NULL);
1793 sibling_target_len = strlen (sibling_target);
1795 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1796 if (copy_result == TRUE)
1797 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1799 g_free (sibling_source);
1800 g_free (sibling_target);
1802 if (copy_result == FALSE) {
1804 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1808 /* Create a .ini file containing the original assembly location */
1809 if (!shadow_copy_create_ini (shadow, filename)) {
1811 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1815 utbuf.actime = src_sbuf.st_atime;
1816 utbuf.modtime = src_sbuf.st_mtime;
1817 utime (shadow, &utbuf);
1821 #endif /* DISABLE_SHADOW_COPY */
1824 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1826 if (appdomain == NULL)
1829 return appdomain->data;
1833 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1834 const gchar *path3, const gchar *path4,
1835 gboolean refonly, gboolean is_private)
1838 gboolean found = FALSE;
1841 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1843 if (IS_PORTABILITY_SET) {
1844 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1847 fullpath = new_fullpath;
1851 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1854 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1857 return (*assembly != NULL);
1860 static MonoAssembly *
1861 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1863 MonoAssembly *result = NULL;
1866 const gchar *local_culture;
1868 gboolean is_private = FALSE;
1870 if (!culture || *culture == '\0') {
1873 local_culture = culture;
1876 filename = g_strconcat (name, ".dll", NULL);
1877 len = strlen (filename);
1879 for (path = search_path; *path; path++) {
1880 if (**path == '\0') {
1882 continue; /* Ignore empty ApplicationBase */
1885 /* See test cases in bug #58992 and bug #57710 */
1886 /* 1st try: [culture]/[name].dll (culture may be empty) */
1887 strcpy (filename + len - 4, ".dll");
1888 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1891 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1892 strcpy (filename + len - 4, ".exe");
1893 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1896 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1897 strcpy (filename + len - 4, ".dll");
1898 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1901 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1902 strcpy (filename + len - 4, ".exe");
1903 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1912 * Try loading the assembly from ApplicationBase and PrivateBinPath
1913 * and then from assemblies_path if any.
1914 * LOCKING: This is called from the assembly loading code, which means the caller
1915 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1917 static MonoAssembly *
1918 mono_domain_assembly_preload (MonoAssemblyName *aname,
1919 gchar **assemblies_path,
1922 MonoDomain *domain = mono_domain_get ();
1923 MonoAssembly *result = NULL;
1924 gboolean refonly = GPOINTER_TO_UINT (user_data);
1926 set_domain_search_path (domain);
1928 if (domain->search_path && domain->search_path [0] != NULL) {
1929 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1932 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1933 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1940 * Check whenever a given assembly was already loaded in the current appdomain.
1942 static MonoAssembly *
1943 mono_domain_assembly_search (MonoAssemblyName *aname,
1946 MonoDomain *domain = mono_domain_get ();
1949 gboolean refonly = GPOINTER_TO_UINT (user_data);
1951 mono_domain_assemblies_lock (domain);
1952 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1953 ass = (MonoAssembly *)tmp->data;
1954 /* Dynamic assemblies can't match here in MS.NET */
1955 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1958 mono_domain_assemblies_unlock (domain);
1961 mono_domain_assemblies_unlock (domain);
1966 MonoReflectionAssembly *
1967 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1970 MonoReflectionAssembly *result;
1971 MonoDomain *domain = mono_domain_get ();
1972 char *name, *filename;
1973 MonoImageOpenStatus status = MONO_IMAGE_OK;
1976 if (fname == NULL) {
1977 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1978 mono_set_pending_exception (exc);
1982 name = filename = mono_string_to_utf8 (fname);
1984 ass = mono_assembly_open_full (filename, &status, refOnly);
1989 if (status == MONO_IMAGE_IMAGE_INVALID)
1990 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1992 exc = mono_get_exception_file_not_found2 (NULL, fname);
1994 mono_set_pending_exception (exc);
2000 result = mono_assembly_get_object_checked (domain, ass, &error);
2002 mono_error_set_pending_exception (&error);
2006 MonoReflectionAssembly *
2007 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2008 MonoArray *raw_assembly,
2009 MonoArray *raw_symbol_store, MonoObject *evidence,
2010 MonoBoolean refonly)
2014 MonoReflectionAssembly *refass = NULL;
2015 MonoDomain *domain = ad->data;
2016 MonoImageOpenStatus status;
2017 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2018 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2021 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2025 if (raw_symbol_store != NULL)
2026 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2028 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2032 mono_image_close (image);
2033 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2037 refass = mono_assembly_get_object_checked (domain, ass, &error);
2039 mono_error_set_pending_exception (&error);
2041 MONO_OBJECT_SETREF (refass, evidence, evidence);
2045 MonoReflectionAssembly *
2046 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2049 MonoDomain *domain = ad->data;
2050 MonoImageOpenStatus status = MONO_IMAGE_OK;
2052 MonoAssemblyName aname;
2053 MonoReflectionAssembly *refass = NULL;
2059 name = mono_string_to_utf8 (assRef);
2060 parsed = mono_assembly_name_parse (name, &aname);
2064 /* This is a parse error... */
2066 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2070 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2071 mono_assembly_name_free (&aname);
2074 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2076 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2085 refass = mono_assembly_get_object_checked (domain, ass, &error);
2088 mono_error_set_pending_exception (&error);
2090 MONO_OBJECT_SETREF (refass, evidence, evidence);
2095 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2097 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2099 if (NULL == domain) {
2100 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2101 mono_set_pending_exception (exc);
2105 if (domain == mono_get_root_domain ()) {
2106 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2111 * Unloading seems to cause problems when running NUnit/NAnt, hence
2114 if (g_getenv ("MONO_NO_UNLOAD"))
2116 #ifdef __native_client__
2120 mono_domain_unload (domain);
2124 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2126 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2131 return mono_domain_is_unloading (domain);
2135 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2137 mono_unhandled_exception ((MonoObject*) exc);
2141 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2142 MonoReflectionAssembly *refass, MonoArray *args)
2149 image = refass->assembly->image;
2152 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2155 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2158 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2160 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2164 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2166 return ad->data->domain_id;
2170 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2172 MonoDomain *old_domain = mono_domain_get();
2174 if (!mono_domain_set (ad->data, FALSE)) {
2175 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2179 return old_domain->domain;
2183 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2185 MonoDomain *current_domain = mono_domain_get ();
2186 MonoDomain *domain = mono_domain_get_by_id (domainid);
2188 if (!domain || !mono_domain_set (domain, FALSE)) {
2189 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2193 return current_domain->domain;
2197 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2199 mono_thread_push_appdomain_ref (ad->data);
2203 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2205 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2209 * Raise an exception to prevent the managed code from executing a pop
2212 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2216 mono_thread_push_appdomain_ref (domain);
2220 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2222 mono_thread_pop_appdomain_ref ();
2226 ves_icall_System_AppDomain_InternalGetContext ()
2228 return mono_context_get ();
2232 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2234 return mono_domain_get ()->default_context;
2238 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2240 MonoAppContext *old_context = mono_context_get ();
2242 mono_context_set (mc);
2248 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2250 MonoDomain* mono_root_domain = mono_get_root_domain ();
2251 mono_domain_lock (mono_root_domain);
2252 if (process_guid_set) {
2253 mono_domain_unlock (mono_root_domain);
2255 MonoString *res = NULL;
2256 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2257 mono_error_raise_exception (&error);
2260 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2261 process_guid_set = TRUE;
2262 mono_domain_unlock (mono_root_domain);
2267 mono_domain_is_unloading (MonoDomain *domain)
2269 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2276 clear_cached_vtable (MonoVTable *vtable)
2278 MonoClass *klass = vtable->klass;
2279 MonoDomain *domain = vtable->domain;
2280 MonoClassRuntimeInfo *runtime_info;
2283 runtime_info = klass->runtime_info;
2284 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2285 runtime_info->domain_vtables [domain->domain_id] = NULL;
2286 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2287 mono_gc_free_fixed (data);
2290 static G_GNUC_UNUSED void
2291 zero_static_data (MonoVTable *vtable)
2293 MonoClass *klass = vtable->klass;
2296 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2297 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2300 typedef struct unload_data {
2303 char *failure_reason;
2308 unload_data_unref (unload_data *data)
2312 mono_atomic_load_acquire (count, gint32, &data->refcount);
2313 g_assert (count >= 1 && count <= 2);
2318 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2322 deregister_reflection_info_roots_from_list (MonoImage *image)
2324 GSList *list = image->reflection_info_unregister_classes;
2327 MonoClass *klass = (MonoClass *)list->data;
2329 mono_class_free_ref_info (klass);
2334 image->reflection_info_unregister_classes = NULL;
2338 deregister_reflection_info_roots (MonoDomain *domain)
2342 mono_domain_assemblies_lock (domain);
2343 for (list = domain->domain_assemblies; list; list = list->next) {
2344 MonoAssembly *assembly = (MonoAssembly *)list->data;
2345 MonoImage *image = assembly->image;
2349 * No need to take the image lock here since dynamic images are appdomain bound and
2350 * at this point the mutator is gone. Taking the image lock here would mean
2351 * promoting it from a simple lock to a complex lock, which we better avoid if
2354 if (image_is_dynamic (image))
2355 deregister_reflection_info_roots_from_list (image);
2357 for (i = 0; i < image->module_count; ++i) {
2358 MonoImage *module = image->modules [i];
2359 if (module && image_is_dynamic (module))
2360 deregister_reflection_info_roots_from_list (module);
2363 mono_domain_assemblies_unlock (domain);
2366 static guint32 WINAPI
2367 unload_thread_main (void *arg)
2370 unload_data *data = (unload_data*)arg;
2371 MonoDomain *domain = data->domain;
2375 /* Have to attach to the runtime so shutdown can wait for this thread */
2376 /* Force it to be attached to avoid racing during shutdown. */
2377 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2378 mono_error_raise_exception (&error); /* FIXME don't raise here */
2381 * FIXME: Abort our parent thread last, so we can return a failure
2382 * indication if aborting times out.
2384 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2385 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2389 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2390 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2394 /* Finalize all finalizable objects in the doomed appdomain */
2395 if (!mono_domain_finalize (domain, -1)) {
2396 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2400 /* Clear references to our vtables in class->runtime_info.
2401 * We also hold the loader lock because we're going to change
2402 * class->runtime_info.
2405 mono_loader_lock (); //FIXME why do we need the loader lock here?
2406 mono_domain_lock (domain);
2409 * We need to make sure that we don't have any remsets
2410 * pointing into static data of the to-be-freed domain because
2411 * at the next collections they would be invalid. So what we
2412 * do is we first zero all static data and then do a minor
2413 * collection. Because all references in the static data will
2414 * now be null we won't do any unnecessary copies and after
2415 * the collection there won't be any more remsets.
2417 for (i = 0; i < domain->class_vtable_array->len; ++i)
2418 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2419 mono_gc_collect (0);
2421 for (i = 0; i < domain->class_vtable_array->len; ++i)
2422 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2423 deregister_reflection_info_roots (domain);
2425 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2427 mono_domain_unlock (domain);
2428 mono_loader_unlock ();
2430 mono_threads_clear_cached_culture (domain);
2432 domain->state = MONO_APPDOMAIN_UNLOADED;
2434 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2436 /* remove from the handle table the items related to this domain */
2437 mono_gchandle_free_domain (domain);
2439 mono_domain_free (domain, FALSE);
2441 mono_gc_collect (mono_gc_max_generation ());
2443 mono_atomic_store_release (&data->done, TRUE);
2444 unload_data_unref (data);
2445 mono_thread_detach (thread);
2449 mono_atomic_store_release (&data->done, TRUE);
2450 unload_data_unref (data);
2451 mono_thread_detach (thread);
2456 * mono_domain_unload:
2457 * @domain: The domain to unload
2459 * Unloads an appdomain. Follows the process outlined in the comment
2460 * for mono_domain_try_unload.
2463 mono_domain_unload (MonoDomain *domain)
2465 MonoObject *exc = NULL;
2466 mono_domain_try_unload (domain, &exc);
2468 mono_raise_exception ((MonoException*)exc);
2472 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2476 MONO_PREPARE_BLOCKING;
2477 result = WaitForSingleObjectEx (handle, timeout, alertable);
2478 MONO_FINISH_BLOCKING;
2484 * mono_domain_unload:
2485 * @domain: The domain to unload
2486 * @exc: Exception information
2488 * Unloads an appdomain. Follows the process outlined in:
2489 * http://blogs.gotdotnet.com/cbrumme
2491 * If doing things the 'right' way is too hard or complex, we do it the
2492 * 'simple' way, which means do everything needed to avoid crashes and
2493 * memory leaks, but not much else.
2495 * It is required to pass a valid reference to the exc argument, upon return
2496 * from this function *exc will be set to the exception thrown, if any.
2498 * If this method is not called from an icall (embedded scenario for instance),
2499 * it must not be called with any managed frames on the stack, since the unload
2500 * process could end up trying to abort the current thread.
2503 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2506 HANDLE thread_handle;
2507 MonoAppDomainState prev_state;
2509 unload_data *thread_data;
2510 MonoNativeThreadId tid;
2511 MonoDomain *caller_domain = mono_domain_get ();
2514 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2516 /* Atomically change our state to UNLOADING */
2517 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2518 MONO_APPDOMAIN_UNLOADING_START,
2519 MONO_APPDOMAIN_CREATED);
2520 if (prev_state != MONO_APPDOMAIN_CREATED) {
2521 switch (prev_state) {
2522 case MONO_APPDOMAIN_UNLOADING_START:
2523 case MONO_APPDOMAIN_UNLOADING:
2524 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2526 case MONO_APPDOMAIN_UNLOADED:
2527 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2530 g_warning ("Invalid appdomain state %d", prev_state);
2531 g_assert_not_reached ();
2535 mono_domain_set (domain, FALSE);
2536 /* Notify OnDomainUnload listeners */
2537 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2540 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2542 if (!mono_error_ok (&error)) {
2544 mono_error_cleanup (&error);
2546 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2550 /* Roll back the state change */
2551 domain->state = MONO_APPDOMAIN_CREATED;
2552 mono_domain_set (caller_domain, FALSE);
2555 mono_domain_set (caller_domain, FALSE);
2557 thread_data = g_new0 (unload_data, 1);
2558 thread_data->domain = domain;
2559 thread_data->failure_reason = NULL;
2560 thread_data->done = FALSE;
2561 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2563 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2564 domain->state = MONO_APPDOMAIN_UNLOADING;
2566 * First we create a separate thread for unloading, since
2567 * we might have to abort some threads, including the current one.
2569 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2570 if (thread_handle == NULL)
2572 name = g_strdup_printf ("Unload thread for domain %x", domain);
2573 mono_thread_info_set_name (tid, name);
2574 mono_thread_info_resume (tid);
2577 /* Wait for the thread */
2578 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2579 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2580 /* The unload thread tries to abort us */
2581 /* The icall wrapper will execute the abort */
2582 CloseHandle (thread_handle);
2583 unload_data_unref (thread_data);
2587 CloseHandle (thread_handle);
2589 if (thread_data->failure_reason) {
2590 /* Roll back the state change */
2591 domain->state = MONO_APPDOMAIN_CREATED;
2593 g_warning ("%s", thread_data->failure_reason);
2595 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2597 g_free (thread_data->failure_reason);
2598 thread_data->failure_reason = NULL;
2601 unload_data_unref (thread_data);