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-internal.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/socket-io.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/gc-internal.h>
45 #include <mono/metadata/mono-gc.h>
46 #include <mono/metadata/marshal.h>
47 #include <mono/metadata/monitor.h>
48 #include <mono/metadata/threadpool.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/utils/mono-uri.h>
58 #include <mono/utils/mono-logger-internal.h>
59 #include <mono/utils/mono-path.h>
60 #include <mono/utils/mono-stdlib.h>
61 #include <mono/utils/mono-io-portability.h>
62 #include <mono/utils/mono-error-internals.h>
63 #include <mono/utils/atomic.h>
64 #include <mono/utils/mono-memory-model.h>
65 #include <mono/utils/mono-threads.h>
71 * This is the version number of the corlib-runtime interface. When
72 * making changes to this interface (by changing the layout
73 * of classes the runtime knows about, changing icall signature or
74 * semantics etc), increment this variable. Also increment the
75 * pair of this variable in mscorlib in:
76 * mcs/class/mscorlib/System/Environment.cs
78 * Changes which are already detected at runtime, like the addition
79 * of icalls, do not require an increment.
81 #define MONO_CORLIB_VERSION 118
86 int assemblybinding_count;
91 mono_mutex_t mono_delegate_section;
93 mono_mutex_t mono_strtod_mutex;
95 static gunichar2 process_guid [36];
96 static gboolean process_guid_set = FALSE;
98 static gboolean no_exec = FALSE;
100 static MonoAssembly *
101 mono_domain_assembly_preload (MonoAssemblyName *aname,
102 gchar **assemblies_path,
105 static MonoAssembly *
106 mono_domain_assembly_search (MonoAssemblyName *aname,
110 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
113 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
115 static MonoAppDomain *
116 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
119 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
121 static MonoLoadFunc load_function = NULL;
124 mono_install_runtime_load (MonoLoadFunc func)
126 load_function = func;
130 mono_runtime_load (const char *filename, const char *runtime_version)
132 g_assert (load_function);
133 return load_function (filename, runtime_version);
137 * mono_runtime_set_no_exec:
139 * Instructs the runtime to operate in static mode, i.e. avoid/do not
140 * allow managed code execution. This is useful for running the AOT
141 * compiler on platforms which allow full-aot execution only. This
142 * should be called before mono_runtime_init ().
145 mono_runtime_set_no_exec (gboolean val)
151 * mono_runtime_get_no_exec:
153 * If true, then the runtime will not allow managed code execution.
156 mono_runtime_get_no_exec (void)
162 create_domain_objects (MonoDomain *domain)
164 MonoDomain *old_domain = mono_domain_get ();
167 if (domain != old_domain) {
168 mono_thread_push_appdomain_ref (domain);
169 mono_domain_set_internal_with_options (domain, FALSE);
173 * Create an instance early since we can't do it when there is no memory.
175 arg = mono_string_new (domain, "Out of memory");
176 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
179 * These two are needed because the signal handlers might be executing on
180 * an alternate stack, and Boehm GC can't handle that.
182 arg = mono_string_new (domain, "A null value was found where an object instance was required");
183 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
184 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
185 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
187 /*The ephemeron tombstone i*/
188 domain->ephemeron_tombstone = mono_object_new (domain, mono_defaults.object_class);
190 if (domain != old_domain) {
191 mono_thread_pop_appdomain_ref ();
192 mono_domain_set_internal_with_options (old_domain, FALSE);
196 * This class is used during exception handling, so initialize it here, to prevent
197 * stack overflows while handling stack overflows.
199 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
204 * @domain: domain returned by mono_init ()
206 * Initialize the core AppDomain: this function will run also some
207 * IL initialization code, so it needs the execution engine to be fully
210 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
211 * we know the entry_assembly.
215 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
216 MonoThreadAttachCB attach_cb)
218 MonoAppDomainSetup *setup;
222 mono_portability_helpers_init ();
224 mono_gc_base_init ();
225 mono_monitor_init ();
226 mono_thread_pool_init ();
227 mono_marshal_init ();
229 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
230 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
231 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
232 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
233 mono_install_assembly_postload_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
234 mono_install_assembly_postload_refonly_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
235 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
236 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
238 mono_thread_init (start_cb, attach_cb);
240 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
241 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, class);
243 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
244 ad = (MonoAppDomain *) mono_object_new_pinned (domain, class);
247 domain->setup = setup;
249 mono_mutex_init_recursive (&mono_delegate_section);
251 mono_mutex_init_recursive (&mono_strtod_mutex);
253 mono_thread_attach (domain);
254 mono_context_init (domain);
255 mono_context_set (domain->default_context);
257 mono_type_initialization_init ();
259 if (!mono_runtime_get_no_exec ())
260 create_domain_objects (domain);
262 /* GC init has to happen after thread init */
265 #ifndef DISABLE_SOCKETS
266 mono_network_init ();
269 mono_console_init ();
272 mono_locks_tracer_init ();
274 /* mscorlib is loaded before we install the load hook */
275 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
281 mono_get_corlib_version (void)
284 MonoClassField *field;
287 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
288 mono_class_init (klass);
289 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
292 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
294 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
295 return *(gint32*)((gchar*)value + sizeof (MonoObject));
299 * mono_check_corlib_version
301 * Checks that the corlib that is loaded matches the version of this runtime.
303 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
304 * allocated string with the error otherwise.
307 mono_check_corlib_version (void)
309 int version = mono_get_corlib_version ();
310 if (version != MONO_CORLIB_VERSION)
311 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
318 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
320 * Initializes the @domain's default System.Runtime.Remoting's Context.
323 mono_context_init (MonoDomain *domain)
326 MonoAppContext *context;
328 class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
329 context = (MonoAppContext *) mono_object_new_pinned (domain, class);
330 context->domain_id = domain->domain_id;
331 context->context_id = 0;
332 domain->default_context = context;
336 * mono_runtime_cleanup:
341 * This must not be called while there are still running threads executing
345 mono_runtime_cleanup (MonoDomain *domain)
347 mono_attach_cleanup ();
349 /* This ends up calling any pending pending (for at most 2 seconds) */
352 mono_thread_cleanup ();
354 #ifndef DISABLE_SOCKETS
355 mono_network_cleanup ();
357 mono_marshal_cleanup ();
359 mono_type_initialization_cleanup ();
361 mono_monitor_cleanup ();
364 static MonoDomainFunc quit_function = NULL;
367 mono_install_runtime_cleanup (MonoDomainFunc func)
369 quit_function = func;
375 if (quit_function != NULL)
376 quit_function (mono_get_root_domain (), NULL);
380 * mono_domain_create_appdomain:
381 * @friendly_name: The friendly name of the appdomain to create
382 * @configuration_file: The configuration file to initialize the appdomain with
384 * Returns a MonoDomain initialized with the appdomain
387 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
390 MonoAppDomainSetup *setup;
393 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
394 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
395 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
397 ad = mono_domain_create_appdomain_internal (friendly_name, setup);
399 return mono_domain_from_appdomain (ad);
403 * mono_domain_set_config:
404 * @domain: MonoDomain initialized with the appdomain we want to change
405 * @base_dir: new base directory for the appdomain
406 * @config_file_name: path to the new configuration for the app domain
408 * Used to set the system configuration for an appdomain
410 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
411 * Error Initializing the configuration system. ---> System.ArgumentException:
412 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
415 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
417 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
418 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
421 static MonoAppDomainSetup*
422 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
424 MonoDomain *caller_domain = mono_domain_get ();
425 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
426 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
428 mono_domain_set_internal (domain);
430 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
431 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
432 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
433 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
434 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
435 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
436 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
437 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
438 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
439 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
440 copy->publisher_policy = setup->publisher_policy;
441 copy->path_changed = setup->path_changed;
442 copy->loader_optimization = setup->loader_optimization;
443 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
444 copy->disallow_code_downloads = setup->disallow_code_downloads;
445 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
446 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
447 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
448 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
449 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
451 mono_domain_set_internal (caller_domain);
456 static MonoAppDomain *
457 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
463 char *shadow_location;
465 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
467 /* FIXME: pin all those objects */
468 data = mono_domain_create();
470 ad = (MonoAppDomain *) mono_object_new (data, adclass);
473 data->friendly_name = g_strdup (friendly_name);
475 if (!setup->application_base) {
476 /* Inherit from the root domain since MS.NET does this */
477 MonoDomain *root = mono_get_root_domain ();
478 if (root->setup->application_base)
479 MONO_OBJECT_SETREF (setup, application_base, mono_string_new_utf16 (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base)));
482 mono_context_init (data);
484 data->setup = copy_app_domain_setup (data, setup);
485 mono_set_private_bin_path_from_config (data);
486 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
488 #ifndef DISABLE_SHADOW_COPY
489 /*FIXME, guard this for when the debugger is not running */
490 shadow_location = get_shadow_assembly_location_base (data, &error);
491 if (!mono_error_ok (&error))
492 mono_error_raise_exception (&error);
493 g_free (shadow_location);
496 create_domain_objects (data);
502 * mono_domain_has_type_resolve:
503 * @domain: application domains being looked up
505 * Returns true if the AppDomain.TypeResolve field has been
509 mono_domain_has_type_resolve (MonoDomain *domain)
511 static MonoClassField *field = NULL;
515 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
519 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
523 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
528 * mono_domain_try_type_resolve:
529 * @domain: application domainwhere the name where the type is going to be resolved
530 * @name: the name of the type to resolve or NULL.
531 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
533 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
534 * the assembly that matches name.
536 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
538 * Returns: A MonoReflectionAssembly or NULL if not found
540 MonoReflectionAssembly *
541 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
545 static MonoMethod *method = NULL;
547 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
549 if (method == NULL) {
550 klass = domain->domain->mbr.obj.vtable->klass;
553 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
554 if (method == NULL) {
555 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
561 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
564 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
568 * mono_domain_owns_vtable_slot:
570 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
573 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
577 mono_domain_lock (domain);
578 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
579 mono_domain_unlock (domain);
586 * @force: force setting.
588 * Set the current appdomain to @domain. If @force is set, set it even
589 * if it is being unloaded.
593 * FALSE if the domain is unloaded
596 mono_domain_set (MonoDomain *domain, gboolean force)
598 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
601 mono_domain_set_internal (domain);
607 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
613 MONO_CHECK_ARG_NULL (name, NULL);
615 g_assert (ad != NULL);
617 g_assert (add != NULL);
619 str = mono_string_to_utf8 (name);
621 mono_domain_lock (add);
623 if (!strcmp (str, "APPBASE"))
624 o = (MonoObject *)add->setup->application_base;
625 else if (!strcmp (str, "APP_CONFIG_FILE"))
626 o = (MonoObject *)add->setup->configuration_file;
627 else if (!strcmp (str, "DYNAMIC_BASE"))
628 o = (MonoObject *)add->setup->dynamic_base;
629 else if (!strcmp (str, "APP_NAME"))
630 o = (MonoObject *)add->setup->application_name;
631 else if (!strcmp (str, "CACHE_BASE"))
632 o = (MonoObject *)add->setup->cache_path;
633 else if (!strcmp (str, "PRIVATE_BINPATH"))
634 o = (MonoObject *)add->setup->private_bin_path;
635 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
636 o = (MonoObject *)add->setup->private_bin_path_probe;
637 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
638 o = (MonoObject *)add->setup->shadow_copy_directories;
639 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
640 o = (MonoObject *)add->setup->shadow_copy_files;
642 o = mono_g_hash_table_lookup (add->env, name);
644 mono_domain_unlock (add);
654 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
658 MONO_CHECK_ARG_NULL (name,);
660 g_assert (ad != NULL);
662 g_assert (add != NULL);
664 mono_domain_lock (add);
666 mono_g_hash_table_insert (add->env, name, data);
668 mono_domain_unlock (add);
672 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
674 g_assert (ad != NULL);
675 g_assert (ad->data != NULL);
677 return ad->data->setup;
681 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
683 g_assert (ad != NULL);
684 g_assert (ad->data != NULL);
686 return mono_string_new (ad->data, ad->data->friendly_name);
690 ves_icall_System_AppDomain_getCurDomain ()
692 MonoDomain *add = mono_domain_get ();
698 ves_icall_System_AppDomain_getRootDomain ()
700 MonoDomain *root = mono_get_root_domain ();
706 get_attribute_value (const gchar **attribute_names,
707 const gchar **attribute_values,
708 const char *att_name)
711 for (n = 0; attribute_names [n] != NULL; n++) {
712 if (strcmp (attribute_names [n], att_name) == 0)
713 return g_strdup (attribute_values [n]);
719 start_element (GMarkupParseContext *context,
720 const gchar *element_name,
721 const gchar **attribute_names,
722 const gchar **attribute_values,
726 RuntimeConfig *runtime_config = user_data;
728 if (strcmp (element_name, "runtime") == 0) {
729 runtime_config->runtime_count++;
733 if (strcmp (element_name, "assemblyBinding") == 0) {
734 runtime_config->assemblybinding_count++;
738 if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
741 if (strcmp (element_name, "probing") != 0)
744 g_free (runtime_config->domain->private_bin_path);
745 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
746 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
747 g_free (runtime_config->domain->private_bin_path);
748 runtime_config->domain->private_bin_path = NULL;
754 end_element (GMarkupParseContext *context,
755 const gchar *element_name,
759 RuntimeConfig *runtime_config = user_data;
760 if (strcmp (element_name, "runtime") == 0)
761 runtime_config->runtime_count--;
762 else if (strcmp (element_name, "assemblyBinding") == 0)
763 runtime_config->assemblybinding_count--;
767 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
769 RuntimeConfig *state = user_data;
771 const gchar *filename;
773 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
774 msg = error && error->message ? error->message : "";
775 g_warning ("Error parsing %s: %s", filename, msg);
778 static const GMarkupParser
788 mono_set_private_bin_path_from_config (MonoDomain *domain)
791 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
793 GMarkupParseContext *context;
794 RuntimeConfig runtime_config;
797 if (!domain || !domain->setup || !domain->setup->configuration_file)
800 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
801 if (!mono_error_ok (&error)) {
802 mono_error_cleanup (&error);
806 config_file_path = mono_portability_find_file (config_file_name, TRUE);
807 if (!config_file_path)
808 config_file_path = config_file_name;
810 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
813 runtime_config.runtime_count = 0;
814 runtime_config.assemblybinding_count = 0;
815 runtime_config.domain = domain;
816 runtime_config.filename = config_file_path;
819 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
820 offset = 3; /* Skip UTF-8 BOM */
822 context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
823 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
824 g_markup_parse_context_end_parse (context, NULL);
825 g_markup_parse_context_free (context);
829 if (config_file_name != config_file_path)
830 g_free (config_file_name);
831 g_free (config_file_path);
835 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
837 #ifdef DISABLE_APPDOMAINS
838 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
841 char *fname = mono_string_to_utf8 (friendly_name);
842 MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
851 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
853 MonoDomain *domain = ad->data;
855 static MonoClass *System_Reflection_Assembly;
859 GPtrArray *assemblies;
861 if (!System_Reflection_Assembly)
862 System_Reflection_Assembly = mono_class_from_name (
863 mono_defaults.corlib, "System.Reflection", "Assembly");
866 * Make a copy of the list of assemblies because we can't hold the assemblies
867 * lock while creating objects etc.
869 assemblies = g_ptr_array_new ();
870 /* Need to skip internal assembly builders created by remoting */
871 mono_domain_assemblies_lock (domain);
872 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
874 if (refonly != ass->ref_only)
876 if (ass->corlib_internal)
878 g_ptr_array_add (assemblies, ass);
880 mono_domain_assemblies_unlock (domain);
882 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
883 for (i = 0; i < assemblies->len; ++i) {
884 ass = g_ptr_array_index (assemblies, i);
885 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
888 g_ptr_array_free (assemblies, TRUE);
893 MonoReflectionAssembly *
894 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
898 MonoBoolean isrefonly;
901 if (mono_runtime_get_no_exec ())
904 g_assert (domain != NULL && fname != NULL);
906 klass = domain->domain->mbr.obj.vtable->klass;
909 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
910 if (method == NULL) {
911 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
915 isrefonly = refonly ? 1 : 0;
917 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
918 params [2] = &isrefonly;
919 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
923 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
926 MonoReflectionAssembly *assembly;
927 MonoDomain *domain = mono_domain_get ();
931 aname_str = mono_stringify_assembly_name (aname);
933 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
934 str = mono_string_new (domain, aname_str);
939 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
943 return assembly->assembly;
949 * LOCKING: assumes assemblies_lock in the domain is already locked.
952 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
956 gboolean destroy_ht = FALSE;
958 if (!ass->aname.name)
962 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
966 /* FIXME: handle lazy loaded assemblies */
967 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
968 g_hash_table_insert (ht, tmp->data, tmp->data);
970 if (!g_hash_table_lookup (ht, ass)) {
971 mono_assembly_addref (ass);
972 g_hash_table_insert (ht, ass, ass);
973 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
974 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);
977 if (ass->image->references) {
978 for (i = 0; ass->image->references [i] != NULL; i++) {
979 if (ass->image->references [i] != REFERENCE_MISSING)
980 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
981 add_assemblies_to_domain (domain, ass->image->references [i], ht);
986 g_hash_table_destroy (ht);
990 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
992 static MonoClassField *assembly_load_field;
993 static MonoMethod *assembly_load_method;
994 MonoDomain *domain = mono_domain_get ();
995 MonoReflectionAssembly *ref_assembly;
1000 if (!domain->domain)
1001 /* This can happen during startup */
1003 #ifdef ASSEMBLY_LOAD_DEBUG
1004 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1006 klass = domain->domain->mbr.obj.vtable->klass;
1008 mono_domain_assemblies_lock (domain);
1009 add_assemblies_to_domain (domain, assembly, NULL);
1010 mono_domain_assemblies_unlock (domain);
1012 if (assembly_load_field == NULL) {
1013 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1014 g_assert (assembly_load_field);
1017 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1018 if (load_value == NULL) {
1019 /* No events waiting to be triggered */
1023 ref_assembly = mono_assembly_get_object (domain, assembly);
1024 g_assert (ref_assembly);
1026 if (assembly_load_method == NULL) {
1027 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1028 g_assert (assembly_load_method);
1031 *params = ref_assembly;
1032 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1036 * LOCKING: Acquires the domain assemblies lock.
1039 set_domain_search_path (MonoDomain *domain)
1042 MonoAppDomainSetup *setup;
1044 gchar *search_path = NULL;
1047 gchar **pvt_split = NULL;
1048 GError *gerror = NULL;
1049 gint appbaselen = -1;
1052 * We use the low-level domain assemblies lock, since this is called from
1053 * assembly loads hooks, which means this thread might hold the loader lock.
1055 mono_domain_assemblies_lock (domain);
1057 if (!domain->setup) {
1058 mono_domain_assemblies_unlock (domain);
1062 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1063 mono_domain_assemblies_unlock (domain);
1066 setup = domain->setup;
1067 if (!setup->application_base) {
1068 mono_domain_assemblies_unlock (domain);
1069 return; /* Must set application base to get private path working */
1074 if (setup->private_bin_path) {
1075 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1076 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1077 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1078 mono_error_cleanup (&error);
1079 mono_domain_assemblies_unlock (domain);
1084 if (domain->private_bin_path) {
1085 if (search_path == NULL)
1086 search_path = domain->private_bin_path;
1088 gchar *tmp2 = search_path;
1089 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1096 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1097 * directories relative to ApplicationBase separated by semicolons (see
1098 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1099 * The loop below copes with the fact that some Unix applications may use ':' (or
1100 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1101 * ';' for the subsequent split.
1103 * The issue was reported in bug #81446
1106 #ifndef TARGET_WIN32
1109 slen = strlen (search_path);
1110 for (i = 0; i < slen; i++)
1111 if (search_path [i] == ':')
1112 search_path [i] = ';';
1115 pvt_split = g_strsplit (search_path, ";", 1000);
1116 g_free (search_path);
1117 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1122 g_strfreev (pvt_split);
1124 * Don't do this because the first time is called, the domain
1125 * setup is not finished.
1127 * domain->search_path = g_malloc (sizeof (char *));
1128 * domain->search_path [0] = NULL;
1130 mono_domain_assemblies_unlock (domain);
1134 if (domain->search_path)
1135 g_strfreev (domain->search_path);
1137 tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1138 tmp [npaths] = NULL;
1140 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1141 if (!mono_error_ok (&error)) {
1142 mono_error_cleanup (&error);
1143 g_strfreev (pvt_split);
1146 mono_domain_assemblies_unlock (domain);
1150 domain->search_path = tmp;
1152 /* FIXME: is this needed? */
1153 if (strncmp (*tmp, "file://", 7) == 0) {
1159 uri = g_strdup_printf ("file:///%s", uri + 7);
1162 uri = mono_escape_uri_string (tmpuri);
1163 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1169 if (gerror != NULL) {
1170 g_warning ("%s\n", gerror->message);
1171 g_error_free (gerror);
1178 for (i = 1; pvt_split && i < npaths; i++) {
1179 if (g_path_is_absolute (pvt_split [i - 1])) {
1180 tmp [i] = g_strdup (pvt_split [i - 1]);
1182 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1185 if (strchr (tmp [i], '.')) {
1189 reduced = mono_path_canonicalize (tmp [i]);
1190 if (appbaselen == -1)
1191 appbaselen = strlen (tmp [0]);
1193 if (strncmp (tmp [0], reduced, appbaselen)) {
1196 tmp [i] = g_strdup ("");
1206 if (setup->private_bin_path_probe != NULL) {
1208 tmp [0] = g_strdup ("");
1211 domain->setup->path_changed = FALSE;
1213 g_strfreev (pvt_split);
1215 mono_domain_assemblies_unlock (domain);
1218 #ifdef DISABLE_SHADOW_COPY
1220 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1226 mono_make_shadow_copy (const char *filename)
1228 return (char *) filename;
1232 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1234 guint16 *orig, *dest;
1235 gboolean copy_result;
1237 strcpy (src + srclen - tail_len, extension);
1239 if (IS_PORTABILITY_CASE) {
1240 gchar *file = mono_portability_find_file (src, TRUE);
1246 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1250 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1252 strcpy (target + targetlen - tail_len, extension);
1253 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1256 copy_result = CopyFile (orig, dest, FALSE);
1258 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1259 * overwritten when updated in their original locations. */
1261 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1270 get_cstring_hash (const char *str)
1276 if (!str || !str [0])
1281 for (i = 0; i < len; i++) {
1282 h = (h << 5) - h + *p;
1290 * Returned memory is malloc'd. Called must free it
1293 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1295 MonoAppDomainSetup *setup;
1296 char *cache_path, *appname;
1300 mono_error_init (error);
1302 setup = domain->setup;
1303 if (setup->cache_path != NULL && setup->application_name != NULL) {
1304 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1305 if (!mono_error_ok (error))
1307 #ifndef TARGET_WIN32
1310 for (i = strlen (cache_path) - 1; i >= 0; i--)
1311 if (cache_path [i] == '\\')
1312 cache_path [i] = '/';
1316 appname = mono_string_to_utf8_checked (setup->application_name, error);
1317 if (!mono_error_ok (error)) {
1318 g_free (cache_path);
1322 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1324 g_free (cache_path);
1326 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1327 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1334 get_shadow_assembly_location (const char *filename, MonoError *error)
1336 gint32 hash = 0, hash2 = 0;
1338 char path_hash [30];
1339 char *bname = g_path_get_basename (filename);
1340 char *dirname = g_path_get_dirname (filename);
1341 char *location, *tmploc;
1342 MonoDomain *domain = mono_domain_get ();
1344 mono_error_init (error);
1346 hash = get_cstring_hash (bname);
1347 hash2 = get_cstring_hash (dirname);
1348 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1349 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1350 tmploc = get_shadow_assembly_location_base (domain, error);
1351 if (!mono_error_ok (error)) {
1357 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1365 ensure_directory_exists (const char *filename)
1368 gchar *dir_utf8 = g_path_get_dirname (filename);
1370 gunichar2 *dir_utf16 = NULL;
1373 if (!dir_utf8 || !dir_utf8 [0])
1376 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1384 /* make life easy and only use one directory seperator */
1395 while (*p++ != '\\')
1401 p = wcschr (p, '\\');
1404 retval = _wmkdir (dir_utf16);
1405 if (retval != 0 && errno != EEXIST) {
1418 gchar *dir = g_path_get_dirname (filename);
1422 if (!dir || !dir [0]) {
1427 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1437 p = strchr (p, '/');
1440 retval = mkdir (dir, 0777);
1441 if (retval != 0 && errno != EEXIST) {
1456 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1458 struct stat sbuf_dest;
1460 gchar *real_src = mono_portability_find_file (src, TRUE);
1463 stat_src = (gchar*)src;
1465 stat_src = real_src;
1467 if (stat (stat_src, sbuf_src) == -1) {
1468 time_t tnow = time (NULL);
1473 memset (sbuf_src, 0, sizeof (*sbuf_src));
1474 sbuf_src->st_mtime = tnow;
1475 sbuf_src->st_atime = tnow;
1482 if (stat (dest, &sbuf_dest) == -1)
1485 if (sbuf_src->st_size == sbuf_dest.st_size &&
1486 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1493 shadow_copy_create_ini (const char *shadow, const char *filename)
1503 dir_name = g_path_get_dirname (shadow);
1504 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1506 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1511 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1516 handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1517 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1519 if (handle == INVALID_HANDLE_VALUE) {
1523 full_path = mono_path_resolve_symlinks (filename);
1524 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1526 CloseHandle (handle);
1531 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1534 MonoAppDomainSetup *setup;
1537 gchar **directories;
1538 gchar *shadow_status_string;
1540 gboolean shadow_enabled;
1541 gboolean found = FALSE;
1546 setup = domain->setup;
1547 if (setup == NULL || setup->shadow_copy_files == NULL)
1550 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1551 if (!mono_error_ok (&error)) {
1552 mono_error_cleanup (&error);
1555 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1556 g_free (shadow_status_string);
1558 if (!shadow_enabled)
1561 if (setup->shadow_copy_directories == NULL)
1564 /* Is dir_name a shadow_copy destination already? */
1565 base_dir = get_shadow_assembly_location_base (domain, &error);
1566 if (!mono_error_ok (&error)) {
1567 mono_error_cleanup (&error);
1571 if (strstr (dir_name, base_dir)) {
1577 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1578 if (!mono_error_ok (&error)) {
1579 mono_error_cleanup (&error);
1583 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1584 dir_ptr = directories;
1586 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1592 g_strfreev (directories);
1598 This function raises exceptions so it can cause as sorts of nasty stuff if called
1599 while holding a lock.
1600 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1601 or NULL if source file not found.
1602 FIXME bubble up the error instead of raising it here
1605 mono_make_shadow_copy (const char *filename)
1608 gchar *sibling_source, *sibling_target;
1609 gint sibling_source_len, sibling_target_len;
1610 guint16 *orig, *dest;
1613 gboolean copy_result;
1615 struct stat src_sbuf;
1616 struct utimbuf utbuf;
1617 char *dir_name = g_path_get_dirname (filename);
1618 MonoDomain *domain = mono_domain_get ();
1621 set_domain_search_path (domain);
1623 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1625 return (char *) filename;
1628 /* Is dir_name a shadow_copy destination already? */
1629 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1630 if (!mono_error_ok (&error)) {
1631 mono_error_cleanup (&error);
1633 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1634 mono_raise_exception (exc);
1637 if (strstr (dir_name, shadow_dir)) {
1638 g_free (shadow_dir);
1640 return (char *) filename;
1642 g_free (shadow_dir);
1645 shadow = get_shadow_assembly_location (filename, &error);
1646 if (!mono_error_ok (&error)) {
1647 mono_error_cleanup (&error);
1648 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1649 mono_raise_exception (exc);
1652 if (ensure_directory_exists (shadow) == FALSE) {
1654 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1655 mono_raise_exception (exc);
1658 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1659 return (char*) shadow;
1661 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1662 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1665 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1666 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1667 * and not have it runtime error" */
1668 attrs = GetFileAttributes (orig);
1669 if (attrs == INVALID_FILE_ATTRIBUTES) {
1671 return (char *)filename;
1674 copy_result = CopyFile (orig, dest, FALSE);
1676 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1677 * overwritten when updated in their original locations. */
1679 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1684 if (copy_result == FALSE) {
1687 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1688 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1689 return NULL; /* file not found, shadow copy failed */
1691 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1692 mono_raise_exception (exc);
1695 /* attempt to copy .mdb, .config if they exist */
1696 sibling_source = g_strconcat (filename, ".config", NULL);
1697 sibling_source_len = strlen (sibling_source);
1698 sibling_target = g_strconcat (shadow, ".config", NULL);
1699 sibling_target_len = strlen (sibling_target);
1701 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1702 if (copy_result == TRUE)
1703 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1705 g_free (sibling_source);
1706 g_free (sibling_target);
1708 if (copy_result == FALSE) {
1710 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1711 mono_raise_exception (exc);
1714 /* Create a .ini file containing the original assembly location */
1715 if (!shadow_copy_create_ini (shadow, filename)) {
1717 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1718 mono_raise_exception (exc);
1721 utbuf.actime = src_sbuf.st_atime;
1722 utbuf.modtime = src_sbuf.st_mtime;
1723 utime (shadow, &utbuf);
1727 #endif /* DISABLE_SHADOW_COPY */
1730 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1732 if (appdomain == NULL)
1735 return appdomain->data;
1739 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1740 const gchar *path3, const gchar *path4,
1741 gboolean refonly, gboolean is_private)
1744 gboolean found = FALSE;
1747 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1749 if (IS_PORTABILITY_SET) {
1750 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1753 fullpath = new_fullpath;
1757 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1760 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1763 return (*assembly != NULL);
1766 static MonoAssembly *
1767 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1769 MonoAssembly *result = NULL;
1772 const gchar *local_culture;
1774 gboolean is_private = FALSE;
1776 if (!culture || *culture == '\0') {
1779 local_culture = culture;
1782 filename = g_strconcat (name, ".dll", NULL);
1783 len = strlen (filename);
1785 for (path = search_path; *path; path++) {
1786 if (**path == '\0') {
1788 continue; /* Ignore empty ApplicationBase */
1791 /* See test cases in bug #58992 and bug #57710 */
1792 /* 1st try: [culture]/[name].dll (culture may be empty) */
1793 strcpy (filename + len - 4, ".dll");
1794 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1797 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1798 strcpy (filename + len - 4, ".exe");
1799 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1802 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1803 strcpy (filename + len - 4, ".dll");
1804 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1807 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1808 strcpy (filename + len - 4, ".exe");
1809 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1818 * Try loading the assembly from ApplicationBase and PrivateBinPath
1819 * and then from assemblies_path if any.
1820 * LOCKING: This is called from the assembly loading code, which means the caller
1821 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1823 static MonoAssembly *
1824 mono_domain_assembly_preload (MonoAssemblyName *aname,
1825 gchar **assemblies_path,
1828 MonoDomain *domain = mono_domain_get ();
1829 MonoAssembly *result = NULL;
1830 gboolean refonly = GPOINTER_TO_UINT (user_data);
1832 set_domain_search_path (domain);
1834 if (domain->search_path && domain->search_path [0] != NULL) {
1835 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1838 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1839 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1846 * Check whenever a given assembly was already loaded in the current appdomain.
1848 static MonoAssembly *
1849 mono_domain_assembly_search (MonoAssemblyName *aname,
1852 MonoDomain *domain = mono_domain_get ();
1855 gboolean refonly = GPOINTER_TO_UINT (user_data);
1857 mono_domain_assemblies_lock (domain);
1858 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1860 /* Dynamic assemblies can't match here in MS.NET */
1861 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1864 mono_domain_assemblies_unlock (domain);
1867 mono_domain_assemblies_unlock (domain);
1872 MonoReflectionAssembly *
1873 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1875 MonoDomain *domain = mono_domain_get ();
1876 char *name, *filename;
1877 MonoImageOpenStatus status = MONO_IMAGE_OK;
1880 if (fname == NULL) {
1881 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1882 mono_set_pending_exception (exc);
1886 name = filename = mono_string_to_utf8 (fname);
1888 ass = mono_assembly_open_full (filename, &status, refOnly);
1893 if (status == MONO_IMAGE_IMAGE_INVALID)
1894 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1896 exc = mono_get_exception_file_not_found2 (NULL, fname);
1898 mono_set_pending_exception (exc);
1904 return mono_assembly_get_object (domain, ass);
1907 MonoReflectionAssembly *
1908 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1909 MonoArray *raw_assembly,
1910 MonoArray *raw_symbol_store, MonoObject *evidence,
1911 MonoBoolean refonly)
1914 MonoReflectionAssembly *refass = NULL;
1915 MonoDomain *domain = ad->data;
1916 MonoImageOpenStatus status;
1917 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1918 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1921 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1925 if (raw_symbol_store != NULL)
1926 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1928 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1932 mono_image_close (image);
1933 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1937 refass = mono_assembly_get_object (domain, ass);
1938 MONO_OBJECT_SETREF (refass, evidence, evidence);
1942 MonoReflectionAssembly *
1943 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1945 MonoDomain *domain = ad->data;
1946 MonoImageOpenStatus status = MONO_IMAGE_OK;
1948 MonoAssemblyName aname;
1949 MonoReflectionAssembly *refass = NULL;
1953 g_assert (assRef != NULL);
1955 name = mono_string_to_utf8 (assRef);
1956 parsed = mono_assembly_name_parse (name, &aname);
1960 /* This is a parse error... */
1962 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1966 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1967 mono_assembly_name_free (&aname);
1970 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1972 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1981 refass = mono_assembly_get_object (domain, ass);
1983 MONO_OBJECT_SETREF (refass, evidence, evidence);
1988 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
1990 MonoDomain * domain = mono_domain_get_by_id (domain_id);
1992 if (NULL == domain) {
1993 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
1994 mono_set_pending_exception (exc);
1998 if (domain == mono_get_root_domain ()) {
1999 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2004 * Unloading seems to cause problems when running NUnit/NAnt, hence
2007 if (g_getenv ("MONO_NO_UNLOAD"))
2009 #ifdef __native_client__
2013 mono_domain_unload (domain);
2017 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2019 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2024 return mono_domain_is_unloading (domain);
2028 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2029 MonoReflectionAssembly *refass, MonoArray *args)
2036 image = refass->assembly->image;
2039 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2042 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2045 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2047 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2051 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2053 return ad->data->domain_id;
2057 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2059 MonoDomain *old_domain = mono_domain_get();
2061 if (!mono_domain_set (ad->data, FALSE)) {
2062 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2066 return old_domain->domain;
2070 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2072 MonoDomain *current_domain = mono_domain_get ();
2073 MonoDomain *domain = mono_domain_get_by_id (domainid);
2075 if (!domain || !mono_domain_set (domain, FALSE)) {
2076 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2080 return current_domain->domain;
2084 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2086 mono_thread_push_appdomain_ref (ad->data);
2090 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2092 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2096 * Raise an exception to prevent the managed code from executing a pop
2099 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2103 mono_thread_push_appdomain_ref (domain);
2107 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2109 mono_thread_pop_appdomain_ref ();
2113 ves_icall_System_AppDomain_InternalGetContext ()
2115 return mono_context_get ();
2119 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2121 return mono_domain_get ()->default_context;
2125 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2127 MonoAppContext *old_context = mono_context_get ();
2129 mono_context_set (mc);
2135 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2137 MonoDomain* mono_root_domain = mono_get_root_domain ();
2138 mono_domain_lock (mono_root_domain);
2139 if (process_guid_set) {
2140 mono_domain_unlock (mono_root_domain);
2141 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2143 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2144 process_guid_set = TRUE;
2145 mono_domain_unlock (mono_root_domain);
2150 mono_domain_is_unloading (MonoDomain *domain)
2152 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2159 clear_cached_vtable (MonoVTable *vtable)
2161 MonoClass *klass = vtable->klass;
2162 MonoDomain *domain = vtable->domain;
2163 MonoClassRuntimeInfo *runtime_info;
2166 runtime_info = klass->runtime_info;
2167 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2168 runtime_info->domain_vtables [domain->domain_id] = NULL;
2169 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2170 mono_gc_free_fixed (data);
2173 static G_GNUC_UNUSED void
2174 zero_static_data (MonoVTable *vtable)
2176 MonoClass *klass = vtable->klass;
2179 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2180 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2183 typedef struct unload_data {
2186 char *failure_reason;
2191 unload_data_unref (unload_data *data)
2195 mono_atomic_load_acquire (count, gint32, &data->refcount);
2196 g_assert (count >= 1 && count <= 2);
2201 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2205 deregister_reflection_info_roots_from_list (MonoImage *image)
2207 GSList *list = image->reflection_info_unregister_classes;
2210 MonoClass *class = list->data;
2212 mono_class_free_ref_info (class);
2217 image->reflection_info_unregister_classes = NULL;
2221 deregister_reflection_info_roots (MonoDomain *domain)
2225 mono_domain_assemblies_lock (domain);
2226 for (list = domain->domain_assemblies; list; list = list->next) {
2227 MonoAssembly *assembly = list->data;
2228 MonoImage *image = assembly->image;
2232 * No need to take the image lock here since dynamic images are appdomain bound and
2233 * at this point the mutator is gone. Taking the image lock here would mean
2234 * promoting it from a simple lock to a complex lock, which we better avoid if
2237 if (image_is_dynamic (image))
2238 deregister_reflection_info_roots_from_list (image);
2240 for (i = 0; i < image->module_count; ++i) {
2241 MonoImage *module = image->modules [i];
2242 if (module && image_is_dynamic (module))
2243 deregister_reflection_info_roots_from_list (module);
2246 mono_domain_assemblies_unlock (domain);
2249 static guint32 WINAPI
2250 unload_thread_main (void *arg)
2252 unload_data *data = (unload_data*)arg;
2253 MonoDomain *domain = data->domain;
2257 /* Have to attach to the runtime so shutdown can wait for this thread */
2258 /* Force it to be attached to avoid racing during shutdown. */
2259 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2262 * FIXME: Abort our parent thread last, so we can return a failure
2263 * indication if aborting times out.
2265 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2266 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2270 if (!mono_thread_pool_remove_domain_jobs (domain, -1)) {
2271 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2275 /* Finalize all finalizable objects in the doomed appdomain */
2276 if (!mono_domain_finalize (domain, -1)) {
2277 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2281 /* Clear references to our vtables in class->runtime_info.
2282 * We also hold the loader lock because we're going to change
2283 * class->runtime_info.
2286 mono_loader_lock (); //FIXME why do we need the loader lock here?
2287 mono_domain_lock (domain);
2290 * We need to make sure that we don't have any remsets
2291 * pointing into static data of the to-be-freed domain because
2292 * at the next collections they would be invalid. So what we
2293 * do is we first zero all static data and then do a minor
2294 * collection. Because all references in the static data will
2295 * now be null we won't do any unnecessary copies and after
2296 * the collection there won't be any more remsets.
2298 for (i = 0; i < domain->class_vtable_array->len; ++i)
2299 zero_static_data (g_ptr_array_index (domain->class_vtable_array, i));
2300 mono_gc_collect (0);
2302 for (i = 0; i < domain->class_vtable_array->len; ++i)
2303 clear_cached_vtable (g_ptr_array_index (domain->class_vtable_array, i));
2304 deregister_reflection_info_roots (domain);
2306 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2308 mono_domain_unlock (domain);
2309 mono_loader_unlock ();
2311 mono_threads_clear_cached_culture (domain);
2313 domain->state = MONO_APPDOMAIN_UNLOADED;
2315 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2317 /* remove from the handle table the items related to this domain */
2318 mono_gchandle_free_domain (domain);
2320 mono_domain_free (domain, FALSE);
2322 mono_gc_collect (mono_gc_max_generation ());
2324 mono_atomic_store_release (&data->done, TRUE);
2325 unload_data_unref (data);
2326 mono_thread_detach (thread);
2330 mono_atomic_store_release (&data->done, TRUE);
2331 unload_data_unref (data);
2332 mono_thread_detach (thread);
2337 * mono_domain_unload:
2338 * @domain: The domain to unload
2340 * Unloads an appdomain. Follows the process outlined in the comment
2341 * for mono_domain_try_unload.
2344 mono_domain_unload (MonoDomain *domain)
2346 MonoObject *exc = NULL;
2347 mono_domain_try_unload (domain, &exc);
2349 mono_raise_exception ((MonoException*)exc);
2353 * mono_domain_unload:
2354 * @domain: The domain to unload
2355 * @exc: Exception information
2357 * Unloads an appdomain. Follows the process outlined in:
2358 * http://blogs.gotdotnet.com/cbrumme
2360 * If doing things the 'right' way is too hard or complex, we do it the
2361 * 'simple' way, which means do everything needed to avoid crashes and
2362 * memory leaks, but not much else.
2364 * It is required to pass a valid reference to the exc argument, upon return
2365 * from this function *exc will be set to the exception thrown, if any.
2367 * If this method is not called from an icall (embedded scenario for instance),
2368 * it must not be called with any managed frames on the stack, since the unload
2369 * process could end up trying to abort the current thread.
2372 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2374 HANDLE thread_handle;
2375 MonoAppDomainState prev_state;
2377 unload_data *thread_data;
2378 MonoNativeThreadId tid;
2379 MonoDomain *caller_domain = mono_domain_get ();
2382 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2384 /* Atomically change our state to UNLOADING */
2385 prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2386 MONO_APPDOMAIN_UNLOADING_START,
2387 MONO_APPDOMAIN_CREATED);
2388 if (prev_state != MONO_APPDOMAIN_CREATED) {
2389 switch (prev_state) {
2390 case MONO_APPDOMAIN_UNLOADING_START:
2391 case MONO_APPDOMAIN_UNLOADING:
2392 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2394 case MONO_APPDOMAIN_UNLOADED:
2395 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2398 g_warning ("Invalid appdomain state %d", prev_state);
2399 g_assert_not_reached ();
2403 mono_domain_set (domain, FALSE);
2404 /* Notify OnDomainUnload listeners */
2405 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2408 mono_runtime_invoke (method, domain->domain, NULL, exc);
2410 /* Roll back the state change */
2411 domain->state = MONO_APPDOMAIN_CREATED;
2412 mono_domain_set (caller_domain, FALSE);
2415 mono_domain_set (caller_domain, FALSE);
2417 thread_data = g_new0 (unload_data, 1);
2418 thread_data->domain = domain;
2419 thread_data->failure_reason = NULL;
2420 thread_data->done = FALSE;
2421 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2423 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2424 domain->state = MONO_APPDOMAIN_UNLOADING;
2426 * First we create a separate thread for unloading, since
2427 * we might have to abort some threads, including the current one.
2429 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2430 if (thread_handle == NULL)
2432 name = g_strdup_printf ("Unload thread for domain %x", domain);
2433 mono_thread_info_set_name (tid, name);
2434 mono_thread_info_resume (tid);
2437 /* Wait for the thread */
2438 while (!thread_data->done && WaitForSingleObjectEx (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2439 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2440 /* The unload thread tries to abort us */
2441 /* The icall wrapper will execute the abort */
2442 CloseHandle (thread_handle);
2443 unload_data_unref (thread_data);
2447 CloseHandle (thread_handle);
2449 if (thread_data->failure_reason) {
2450 /* Roll back the state change */
2451 domain->state = MONO_APPDOMAIN_CREATED;
2453 g_warning ("%s", thread_data->failure_reason);
2455 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2457 g_free (thread_data->failure_reason);
2458 thread_data->failure_reason = NULL;
2461 unload_data_unref (thread_data);