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 117
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 g_assert (ad != NULL);
615 g_assert (add != NULL);
618 mono_raise_exception (mono_get_exception_argument_null ("name"));
620 str = mono_string_to_utf8 (name);
622 mono_domain_lock (add);
624 if (!strcmp (str, "APPBASE"))
625 o = (MonoObject *)add->setup->application_base;
626 else if (!strcmp (str, "APP_CONFIG_FILE"))
627 o = (MonoObject *)add->setup->configuration_file;
628 else if (!strcmp (str, "DYNAMIC_BASE"))
629 o = (MonoObject *)add->setup->dynamic_base;
630 else if (!strcmp (str, "APP_NAME"))
631 o = (MonoObject *)add->setup->application_name;
632 else if (!strcmp (str, "CACHE_BASE"))
633 o = (MonoObject *)add->setup->cache_path;
634 else if (!strcmp (str, "PRIVATE_BINPATH"))
635 o = (MonoObject *)add->setup->private_bin_path;
636 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
637 o = (MonoObject *)add->setup->private_bin_path_probe;
638 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
639 o = (MonoObject *)add->setup->shadow_copy_directories;
640 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
641 o = (MonoObject *)add->setup->shadow_copy_files;
643 o = mono_g_hash_table_lookup (add->env, name);
645 mono_domain_unlock (add);
655 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
659 g_assert (ad != NULL);
661 g_assert (add != NULL);
664 mono_raise_exception (mono_get_exception_argument_null ("name"));
666 mono_domain_lock (add);
668 mono_g_hash_table_insert (add->env, name, data);
670 mono_domain_unlock (add);
674 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
676 g_assert (ad != NULL);
677 g_assert (ad->data != NULL);
679 return ad->data->setup;
683 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
685 g_assert (ad != NULL);
686 g_assert (ad->data != NULL);
688 return mono_string_new (ad->data, ad->data->friendly_name);
692 ves_icall_System_AppDomain_getCurDomain ()
694 MonoDomain *add = mono_domain_get ();
700 ves_icall_System_AppDomain_getRootDomain ()
702 MonoDomain *root = mono_get_root_domain ();
708 get_attribute_value (const gchar **attribute_names,
709 const gchar **attribute_values,
710 const char *att_name)
713 for (n = 0; attribute_names [n] != NULL; n++) {
714 if (strcmp (attribute_names [n], att_name) == 0)
715 return g_strdup (attribute_values [n]);
721 start_element (GMarkupParseContext *context,
722 const gchar *element_name,
723 const gchar **attribute_names,
724 const gchar **attribute_values,
728 RuntimeConfig *runtime_config = user_data;
730 if (strcmp (element_name, "runtime") == 0) {
731 runtime_config->runtime_count++;
735 if (strcmp (element_name, "assemblyBinding") == 0) {
736 runtime_config->assemblybinding_count++;
740 if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
743 if (strcmp (element_name, "probing") != 0)
746 g_free (runtime_config->domain->private_bin_path);
747 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
748 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
749 g_free (runtime_config->domain->private_bin_path);
750 runtime_config->domain->private_bin_path = NULL;
756 end_element (GMarkupParseContext *context,
757 const gchar *element_name,
761 RuntimeConfig *runtime_config = user_data;
762 if (strcmp (element_name, "runtime") == 0)
763 runtime_config->runtime_count--;
764 else if (strcmp (element_name, "assemblyBinding") == 0)
765 runtime_config->assemblybinding_count--;
769 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
771 RuntimeConfig *state = user_data;
773 const gchar *filename;
775 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
776 msg = error && error->message ? error->message : "";
777 g_warning ("Error parsing %s: %s", filename, msg);
780 static const GMarkupParser
790 mono_set_private_bin_path_from_config (MonoDomain *domain)
793 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
795 GMarkupParseContext *context;
796 RuntimeConfig runtime_config;
799 if (!domain || !domain->setup || !domain->setup->configuration_file)
802 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
803 if (!mono_error_ok (&error)) {
804 mono_error_cleanup (&error);
808 config_file_path = mono_portability_find_file (config_file_name, TRUE);
809 if (!config_file_path)
810 config_file_path = config_file_name;
812 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
815 runtime_config.runtime_count = 0;
816 runtime_config.assemblybinding_count = 0;
817 runtime_config.domain = domain;
818 runtime_config.filename = config_file_path;
821 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
822 offset = 3; /* Skip UTF-8 BOM */
824 context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
825 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
826 g_markup_parse_context_end_parse (context, NULL);
827 g_markup_parse_context_free (context);
831 if (config_file_name != config_file_path)
832 g_free (config_file_name);
833 g_free (config_file_path);
837 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
839 #ifdef DISABLE_APPDOMAINS
840 mono_raise_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
843 char *fname = mono_string_to_utf8 (friendly_name);
844 MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
853 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
855 MonoDomain *domain = ad->data;
857 static MonoClass *System_Reflection_Assembly;
861 GPtrArray *assemblies;
863 if (!System_Reflection_Assembly)
864 System_Reflection_Assembly = mono_class_from_name (
865 mono_defaults.corlib, "System.Reflection", "Assembly");
868 * Make a copy of the list of assemblies because we can't hold the assemblies
869 * lock while creating objects etc.
871 assemblies = g_ptr_array_new ();
872 /* Need to skip internal assembly builders created by remoting */
873 mono_domain_assemblies_lock (domain);
874 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
876 if (refonly != ass->ref_only)
878 if (ass->corlib_internal)
880 g_ptr_array_add (assemblies, ass);
882 mono_domain_assemblies_unlock (domain);
884 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
885 for (i = 0; i < assemblies->len; ++i) {
886 ass = g_ptr_array_index (assemblies, i);
887 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
890 g_ptr_array_free (assemblies, TRUE);
895 MonoReflectionAssembly *
896 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
900 MonoBoolean isrefonly;
903 if (mono_runtime_get_no_exec ())
906 g_assert (domain != NULL && fname != NULL);
908 klass = domain->domain->mbr.obj.vtable->klass;
911 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
912 if (method == NULL) {
913 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
917 isrefonly = refonly ? 1 : 0;
919 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
920 params [2] = &isrefonly;
921 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
925 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
928 MonoReflectionAssembly *assembly;
929 MonoDomain *domain = mono_domain_get ();
933 aname_str = mono_stringify_assembly_name (aname);
935 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
936 str = mono_string_new (domain, aname_str);
941 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
945 return assembly->assembly;
951 * LOCKING: assumes assemblies_lock in the domain is already locked.
954 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
958 gboolean destroy_ht = FALSE;
960 if (!ass->aname.name)
964 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
968 /* FIXME: handle lazy loaded assemblies */
969 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
970 g_hash_table_insert (ht, tmp->data, tmp->data);
972 if (!g_hash_table_lookup (ht, ass)) {
973 mono_assembly_addref (ass);
974 g_hash_table_insert (ht, ass, ass);
975 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
976 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);
979 if (ass->image->references) {
980 for (i = 0; ass->image->references [i] != NULL; i++) {
981 if (ass->image->references [i] != REFERENCE_MISSING)
982 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
983 add_assemblies_to_domain (domain, ass->image->references [i], ht);
988 g_hash_table_destroy (ht);
992 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
994 static MonoClassField *assembly_load_field;
995 static MonoMethod *assembly_load_method;
996 MonoDomain *domain = mono_domain_get ();
997 MonoReflectionAssembly *ref_assembly;
1002 if (!domain->domain)
1003 /* This can happen during startup */
1005 #ifdef ASSEMBLY_LOAD_DEBUG
1006 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1008 klass = domain->domain->mbr.obj.vtable->klass;
1010 mono_domain_assemblies_lock (domain);
1011 add_assemblies_to_domain (domain, assembly, NULL);
1012 mono_domain_assemblies_unlock (domain);
1014 if (assembly_load_field == NULL) {
1015 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1016 g_assert (assembly_load_field);
1019 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1020 if (load_value == NULL) {
1021 /* No events waiting to be triggered */
1025 ref_assembly = mono_assembly_get_object (domain, assembly);
1026 g_assert (ref_assembly);
1028 if (assembly_load_method == NULL) {
1029 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1030 g_assert (assembly_load_method);
1033 *params = ref_assembly;
1034 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1038 * LOCKING: Acquires the domain assemblies lock.
1041 set_domain_search_path (MonoDomain *domain)
1044 MonoAppDomainSetup *setup;
1046 gchar *search_path = NULL;
1049 gchar **pvt_split = NULL;
1050 GError *gerror = NULL;
1051 gint appbaselen = -1;
1054 * We use the low-level domain assemblies lock, since this is called from
1055 * assembly loads hooks, which means this thread might hold the loader lock.
1057 mono_domain_assemblies_lock (domain);
1059 if (!domain->setup) {
1060 mono_domain_assemblies_unlock (domain);
1064 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1065 mono_domain_assemblies_unlock (domain);
1068 setup = domain->setup;
1069 if (!setup->application_base) {
1070 mono_domain_assemblies_unlock (domain);
1071 return; /* Must set application base to get private path working */
1076 if (setup->private_bin_path) {
1077 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1078 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1079 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1080 mono_error_cleanup (&error);
1081 mono_domain_assemblies_unlock (domain);
1086 if (domain->private_bin_path) {
1087 if (search_path == NULL)
1088 search_path = domain->private_bin_path;
1090 gchar *tmp2 = search_path;
1091 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1098 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1099 * directories relative to ApplicationBase separated by semicolons (see
1100 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1101 * The loop below copes with the fact that some Unix applications may use ':' (or
1102 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1103 * ';' for the subsequent split.
1105 * The issue was reported in bug #81446
1108 #ifndef TARGET_WIN32
1111 slen = strlen (search_path);
1112 for (i = 0; i < slen; i++)
1113 if (search_path [i] == ':')
1114 search_path [i] = ';';
1117 pvt_split = g_strsplit (search_path, ";", 1000);
1118 g_free (search_path);
1119 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1124 g_strfreev (pvt_split);
1126 * Don't do this because the first time is called, the domain
1127 * setup is not finished.
1129 * domain->search_path = g_malloc (sizeof (char *));
1130 * domain->search_path [0] = NULL;
1132 mono_domain_assemblies_unlock (domain);
1136 if (domain->search_path)
1137 g_strfreev (domain->search_path);
1139 tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1140 tmp [npaths] = NULL;
1142 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1143 if (!mono_error_ok (&error)) {
1144 mono_error_cleanup (&error);
1145 g_strfreev (pvt_split);
1148 mono_domain_assemblies_unlock (domain);
1152 domain->search_path = tmp;
1154 /* FIXME: is this needed? */
1155 if (strncmp (*tmp, "file://", 7) == 0) {
1161 uri = g_strdup_printf ("file:///%s", uri + 7);
1164 uri = mono_escape_uri_string (tmpuri);
1165 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1171 if (gerror != NULL) {
1172 g_warning ("%s\n", gerror->message);
1173 g_error_free (gerror);
1180 for (i = 1; pvt_split && i < npaths; i++) {
1181 if (g_path_is_absolute (pvt_split [i - 1])) {
1182 tmp [i] = g_strdup (pvt_split [i - 1]);
1184 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1187 if (strchr (tmp [i], '.')) {
1191 reduced = mono_path_canonicalize (tmp [i]);
1192 if (appbaselen == -1)
1193 appbaselen = strlen (tmp [0]);
1195 if (strncmp (tmp [0], reduced, appbaselen)) {
1198 tmp [i] = g_strdup ("");
1208 if (setup->private_bin_path_probe != NULL) {
1210 tmp [0] = g_strdup ("");
1213 domain->setup->path_changed = FALSE;
1215 g_strfreev (pvt_split);
1217 mono_domain_assemblies_unlock (domain);
1220 #ifdef DISABLE_SHADOW_COPY
1222 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1228 mono_make_shadow_copy (const char *filename)
1230 return (char *) filename;
1234 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1236 guint16 *orig, *dest;
1237 gboolean copy_result;
1239 strcpy (src + srclen - tail_len, extension);
1241 if (IS_PORTABILITY_CASE) {
1242 gchar *file = mono_portability_find_file (src, TRUE);
1248 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1252 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1254 strcpy (target + targetlen - tail_len, extension);
1255 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1258 copy_result = CopyFile (orig, dest, FALSE);
1260 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1261 * overwritten when updated in their original locations. */
1263 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1272 get_cstring_hash (const char *str)
1278 if (!str || !str [0])
1283 for (i = 0; i < len; i++) {
1284 h = (h << 5) - h + *p;
1292 * Returned memory is malloc'd. Called must free it
1295 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1297 MonoAppDomainSetup *setup;
1298 char *cache_path, *appname;
1302 mono_error_init (error);
1304 setup = domain->setup;
1305 if (setup->cache_path != NULL && setup->application_name != NULL) {
1306 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1307 if (!mono_error_ok (error))
1309 #ifndef TARGET_WIN32
1312 for (i = strlen (cache_path) - 1; i >= 0; i--)
1313 if (cache_path [i] == '\\')
1314 cache_path [i] = '/';
1318 appname = mono_string_to_utf8_checked (setup->application_name, error);
1319 if (!mono_error_ok (error)) {
1320 g_free (cache_path);
1324 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1326 g_free (cache_path);
1328 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1329 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1336 get_shadow_assembly_location (const char *filename, MonoError *error)
1338 gint32 hash = 0, hash2 = 0;
1340 char path_hash [30];
1341 char *bname = g_path_get_basename (filename);
1342 char *dirname = g_path_get_dirname (filename);
1343 char *location, *tmploc;
1344 MonoDomain *domain = mono_domain_get ();
1346 mono_error_init (error);
1348 hash = get_cstring_hash (bname);
1349 hash2 = get_cstring_hash (dirname);
1350 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1351 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1352 tmploc = get_shadow_assembly_location_base (domain, error);
1353 if (!mono_error_ok (error)) {
1359 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1367 ensure_directory_exists (const char *filename)
1370 gchar *dir_utf8 = g_path_get_dirname (filename);
1372 gunichar2 *dir_utf16 = NULL;
1375 if (!dir_utf8 || !dir_utf8 [0])
1378 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1386 /* make life easy and only use one directory seperator */
1397 while (*p++ != '\\')
1403 p = wcschr (p, '\\');
1406 retval = _wmkdir (dir_utf16);
1407 if (retval != 0 && errno != EEXIST) {
1420 gchar *dir = g_path_get_dirname (filename);
1424 if (!dir || !dir [0]) {
1429 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1439 p = strchr (p, '/');
1442 retval = mkdir (dir, 0777);
1443 if (retval != 0 && errno != EEXIST) {
1458 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1460 struct stat sbuf_dest;
1462 gchar *real_src = mono_portability_find_file (src, TRUE);
1465 stat_src = (gchar*)src;
1467 stat_src = real_src;
1469 if (stat (stat_src, sbuf_src) == -1) {
1470 time_t tnow = time (NULL);
1475 memset (sbuf_src, 0, sizeof (*sbuf_src));
1476 sbuf_src->st_mtime = tnow;
1477 sbuf_src->st_atime = tnow;
1484 if (stat (dest, &sbuf_dest) == -1)
1487 if (sbuf_src->st_size == sbuf_dest.st_size &&
1488 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1495 shadow_copy_create_ini (const char *shadow, const char *filename)
1505 dir_name = g_path_get_dirname (shadow);
1506 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1508 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1513 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1518 handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1519 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1521 if (handle == INVALID_HANDLE_VALUE) {
1525 full_path = mono_path_resolve_symlinks (filename);
1526 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1528 CloseHandle (handle);
1533 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1536 MonoAppDomainSetup *setup;
1539 gchar **directories;
1540 gchar *shadow_status_string;
1542 gboolean shadow_enabled;
1543 gboolean found = FALSE;
1548 setup = domain->setup;
1549 if (setup == NULL || setup->shadow_copy_files == NULL)
1552 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1553 if (!mono_error_ok (&error)) {
1554 mono_error_cleanup (&error);
1557 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1558 g_free (shadow_status_string);
1560 if (!shadow_enabled)
1563 if (setup->shadow_copy_directories == NULL)
1566 /* Is dir_name a shadow_copy destination already? */
1567 base_dir = get_shadow_assembly_location_base (domain, &error);
1568 if (!mono_error_ok (&error)) {
1569 mono_error_cleanup (&error);
1573 if (strstr (dir_name, base_dir)) {
1579 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1580 if (!mono_error_ok (&error)) {
1581 mono_error_cleanup (&error);
1585 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1586 dir_ptr = directories;
1588 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1594 g_strfreev (directories);
1600 This function raises exceptions so it can cause as sorts of nasty stuff if called
1601 while holding a lock.
1602 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1603 or NULL if source file not found.
1604 FIXME bubble up the error instead of raising it here
1607 mono_make_shadow_copy (const char *filename)
1610 gchar *sibling_source, *sibling_target;
1611 gint sibling_source_len, sibling_target_len;
1612 guint16 *orig, *dest;
1615 gboolean copy_result;
1617 struct stat src_sbuf;
1618 struct utimbuf utbuf;
1619 char *dir_name = g_path_get_dirname (filename);
1620 MonoDomain *domain = mono_domain_get ();
1623 set_domain_search_path (domain);
1625 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1627 return (char *) filename;
1630 /* Is dir_name a shadow_copy destination already? */
1631 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1632 if (!mono_error_ok (&error)) {
1633 mono_error_cleanup (&error);
1635 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1636 mono_raise_exception (exc);
1639 if (strstr (dir_name, shadow_dir)) {
1640 g_free (shadow_dir);
1642 return (char *) filename;
1644 g_free (shadow_dir);
1647 shadow = get_shadow_assembly_location (filename, &error);
1648 if (!mono_error_ok (&error)) {
1649 mono_error_cleanup (&error);
1650 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1651 mono_raise_exception (exc);
1654 if (ensure_directory_exists (shadow) == FALSE) {
1656 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1657 mono_raise_exception (exc);
1660 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1661 return (char*) shadow;
1663 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1664 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1667 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1668 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1669 * and not have it runtime error" */
1670 attrs = GetFileAttributes (orig);
1671 if (attrs == INVALID_FILE_ATTRIBUTES) {
1673 return (char *)filename;
1676 copy_result = CopyFile (orig, dest, FALSE);
1678 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1679 * overwritten when updated in their original locations. */
1681 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1686 if (copy_result == FALSE) {
1689 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1690 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1691 return NULL; /* file not found, shadow copy failed */
1693 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1694 mono_raise_exception (exc);
1697 /* attempt to copy .mdb, .config if they exist */
1698 sibling_source = g_strconcat (filename, ".config", NULL);
1699 sibling_source_len = strlen (sibling_source);
1700 sibling_target = g_strconcat (shadow, ".config", NULL);
1701 sibling_target_len = strlen (sibling_target);
1703 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1704 if (copy_result == TRUE)
1705 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1707 g_free (sibling_source);
1708 g_free (sibling_target);
1710 if (copy_result == FALSE) {
1712 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1713 mono_raise_exception (exc);
1716 /* Create a .ini file containing the original assembly location */
1717 if (!shadow_copy_create_ini (shadow, filename)) {
1719 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1720 mono_raise_exception (exc);
1723 utbuf.actime = src_sbuf.st_atime;
1724 utbuf.modtime = src_sbuf.st_mtime;
1725 utime (shadow, &utbuf);
1729 #endif /* DISABLE_SHADOW_COPY */
1732 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1734 if (appdomain == NULL)
1737 return appdomain->data;
1741 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1742 const gchar *path3, const gchar *path4,
1743 gboolean refonly, gboolean is_private)
1746 gboolean found = FALSE;
1749 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1751 if (IS_PORTABILITY_SET) {
1752 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1755 fullpath = new_fullpath;
1759 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1762 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1765 return (*assembly != NULL);
1768 static MonoAssembly *
1769 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1771 MonoAssembly *result = NULL;
1774 const gchar *local_culture;
1776 gboolean is_private = FALSE;
1778 if (!culture || *culture == '\0') {
1781 local_culture = culture;
1784 filename = g_strconcat (name, ".dll", NULL);
1785 len = strlen (filename);
1787 for (path = search_path; *path; path++) {
1788 if (**path == '\0') {
1790 continue; /* Ignore empty ApplicationBase */
1793 /* See test cases in bug #58992 and bug #57710 */
1794 /* 1st try: [culture]/[name].dll (culture may be empty) */
1795 strcpy (filename + len - 4, ".dll");
1796 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1799 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1800 strcpy (filename + len - 4, ".exe");
1801 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1804 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1805 strcpy (filename + len - 4, ".dll");
1806 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1809 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1810 strcpy (filename + len - 4, ".exe");
1811 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1820 * Try loading the assembly from ApplicationBase and PrivateBinPath
1821 * and then from assemblies_path if any.
1822 * LOCKING: This is called from the assembly loading code, which means the caller
1823 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1825 static MonoAssembly *
1826 mono_domain_assembly_preload (MonoAssemblyName *aname,
1827 gchar **assemblies_path,
1830 MonoDomain *domain = mono_domain_get ();
1831 MonoAssembly *result = NULL;
1832 gboolean refonly = GPOINTER_TO_UINT (user_data);
1834 set_domain_search_path (domain);
1836 if (domain->search_path && domain->search_path [0] != NULL) {
1837 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1840 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1841 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1848 * Check whenever a given assembly was already loaded in the current appdomain.
1850 static MonoAssembly *
1851 mono_domain_assembly_search (MonoAssemblyName *aname,
1854 MonoDomain *domain = mono_domain_get ();
1857 gboolean refonly = GPOINTER_TO_UINT (user_data);
1859 mono_domain_assemblies_lock (domain);
1860 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1862 /* Dynamic assemblies can't match here in MS.NET */
1863 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1866 mono_domain_assemblies_unlock (domain);
1869 mono_domain_assemblies_unlock (domain);
1874 MonoReflectionAssembly *
1875 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1877 MonoDomain *domain = mono_domain_get ();
1878 char *name, *filename;
1879 MonoImageOpenStatus status = MONO_IMAGE_OK;
1882 if (fname == NULL) {
1883 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1884 mono_raise_exception (exc);
1887 name = filename = mono_string_to_utf8 (fname);
1889 ass = mono_assembly_open_full (filename, &status, refOnly);
1894 if (status == MONO_IMAGE_IMAGE_INVALID)
1895 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1897 exc = mono_get_exception_file_not_found2 (NULL, fname);
1899 mono_raise_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_raise_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_raise_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_raise_exception (exc);
1997 if (domain == mono_get_root_domain ()) {
1998 mono_raise_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2003 * Unloading seems to cause problems when running NUnit/NAnt, hence
2006 if (g_getenv ("MONO_NO_UNLOAD"))
2008 #ifdef __native_client__
2012 mono_domain_unload (domain);
2016 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2018 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2023 return mono_domain_is_unloading (domain);
2027 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2028 MonoReflectionAssembly *refass, MonoArray *args)
2035 image = refass->assembly->image;
2038 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2041 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2044 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2046 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2050 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2052 return ad->data->domain_id;
2056 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2058 MonoDomain *old_domain = mono_domain_get();
2060 if (!mono_domain_set (ad->data, FALSE))
2061 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2063 return old_domain->domain;
2067 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2069 MonoDomain *current_domain = mono_domain_get ();
2070 MonoDomain *domain = mono_domain_get_by_id (domainid);
2072 if (!domain || !mono_domain_set (domain, FALSE))
2073 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2075 return current_domain->domain;
2079 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2081 mono_thread_push_appdomain_ref (ad->data);
2085 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2087 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2091 * Raise an exception to prevent the managed code from executing a pop
2094 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2096 mono_thread_push_appdomain_ref (domain);
2100 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2102 mono_thread_pop_appdomain_ref ();
2106 ves_icall_System_AppDomain_InternalGetContext ()
2108 return mono_context_get ();
2112 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2114 return mono_domain_get ()->default_context;
2118 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2120 MonoAppContext *old_context = mono_context_get ();
2122 mono_context_set (mc);
2128 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2130 MonoDomain* mono_root_domain = mono_get_root_domain ();
2131 mono_domain_lock (mono_root_domain);
2132 if (process_guid_set) {
2133 mono_domain_unlock (mono_root_domain);
2134 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2136 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2137 process_guid_set = TRUE;
2138 mono_domain_unlock (mono_root_domain);
2143 mono_domain_is_unloading (MonoDomain *domain)
2145 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2152 clear_cached_vtable (MonoVTable *vtable)
2154 MonoClass *klass = vtable->klass;
2155 MonoDomain *domain = vtable->domain;
2156 MonoClassRuntimeInfo *runtime_info;
2159 runtime_info = klass->runtime_info;
2160 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2161 runtime_info->domain_vtables [domain->domain_id] = NULL;
2162 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2163 mono_gc_free_fixed (data);
2166 static G_GNUC_UNUSED void
2167 zero_static_data (MonoVTable *vtable)
2169 MonoClass *klass = vtable->klass;
2172 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2173 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2176 typedef struct unload_data {
2179 char *failure_reason;
2184 unload_data_unref (unload_data *data)
2188 mono_atomic_load_acquire (count, gint32, &data->refcount);
2189 g_assert (count >= 1 && count <= 2);
2194 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2198 deregister_reflection_info_roots_from_list (MonoImage *image)
2200 GSList *list = image->reflection_info_unregister_classes;
2203 MonoClass *class = list->data;
2205 mono_class_free_ref_info (class);
2210 image->reflection_info_unregister_classes = NULL;
2214 deregister_reflection_info_roots (MonoDomain *domain)
2218 mono_domain_assemblies_lock (domain);
2219 for (list = domain->domain_assemblies; list; list = list->next) {
2220 MonoAssembly *assembly = list->data;
2221 MonoImage *image = assembly->image;
2225 * No need to take the image lock here since dynamic images are appdomain bound and
2226 * at this point the mutator is gone. Taking the image lock here would mean
2227 * promoting it from a simple lock to a complex lock, which we better avoid if
2230 if (image_is_dynamic (image))
2231 deregister_reflection_info_roots_from_list (image);
2233 for (i = 0; i < image->module_count; ++i) {
2234 MonoImage *module = image->modules [i];
2235 if (module && image_is_dynamic (module))
2236 deregister_reflection_info_roots_from_list (module);
2239 mono_domain_assemblies_unlock (domain);
2242 static guint32 WINAPI
2243 unload_thread_main (void *arg)
2245 unload_data *data = (unload_data*)arg;
2246 MonoDomain *domain = data->domain;
2250 /* Have to attach to the runtime so shutdown can wait for this thread */
2251 /* Force it to be attached to avoid racing during shutdown. */
2252 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2255 * FIXME: Abort our parent thread last, so we can return a failure
2256 * indication if aborting times out.
2258 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2259 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2263 if (!mono_thread_pool_remove_domain_jobs (domain, -1)) {
2264 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2268 /* Finalize all finalizable objects in the doomed appdomain */
2269 if (!mono_domain_finalize (domain, -1)) {
2270 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2274 /* Clear references to our vtables in class->runtime_info.
2275 * We also hold the loader lock because we're going to change
2276 * class->runtime_info.
2279 mono_loader_lock (); //FIXME why do we need the loader lock here?
2280 mono_domain_lock (domain);
2283 * We need to make sure that we don't have any remsets
2284 * pointing into static data of the to-be-freed domain because
2285 * at the next collections they would be invalid. So what we
2286 * do is we first zero all static data and then do a minor
2287 * collection. Because all references in the static data will
2288 * now be null we won't do any unnecessary copies and after
2289 * the collection there won't be any more remsets.
2291 for (i = 0; i < domain->class_vtable_array->len; ++i)
2292 zero_static_data (g_ptr_array_index (domain->class_vtable_array, i));
2293 mono_gc_collect (0);
2295 for (i = 0; i < domain->class_vtable_array->len; ++i)
2296 clear_cached_vtable (g_ptr_array_index (domain->class_vtable_array, i));
2297 deregister_reflection_info_roots (domain);
2299 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2301 mono_domain_unlock (domain);
2302 mono_loader_unlock ();
2304 mono_threads_clear_cached_culture (domain);
2306 domain->state = MONO_APPDOMAIN_UNLOADED;
2308 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2310 /* remove from the handle table the items related to this domain */
2311 mono_gchandle_free_domain (domain);
2313 mono_domain_free (domain, FALSE);
2315 mono_gc_collect (mono_gc_max_generation ());
2317 mono_atomic_store_release (&data->done, TRUE);
2318 unload_data_unref (data);
2319 mono_thread_detach (thread);
2323 mono_atomic_store_release (&data->done, TRUE);
2324 unload_data_unref (data);
2325 mono_thread_detach (thread);
2330 * mono_domain_unload:
2331 * @domain: The domain to unload
2333 * Unloads an appdomain. Follows the process outlined in the comment
2334 * for mono_domain_try_unload.
2337 mono_domain_unload (MonoDomain *domain)
2339 MonoObject *exc = NULL;
2340 mono_domain_try_unload (domain, &exc);
2342 mono_raise_exception ((MonoException*)exc);
2346 * mono_domain_unload:
2347 * @domain: The domain to unload
2348 * @exc: Exception information
2350 * Unloads an appdomain. Follows the process outlined in:
2351 * http://blogs.gotdotnet.com/cbrumme
2353 * If doing things the 'right' way is too hard or complex, we do it the
2354 * 'simple' way, which means do everything needed to avoid crashes and
2355 * memory leaks, but not much else.
2357 * It is required to pass a valid reference to the exc argument, upon return
2358 * from this function *exc will be set to the exception thrown, if any.
2360 * If this method is not called from an icall (embedded scenario for instance),
2361 * it must not be called with any managed frames on the stack, since the unload
2362 * process could end up trying to abort the current thread.
2365 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2367 HANDLE thread_handle;
2368 MonoAppDomainState prev_state;
2370 unload_data *thread_data;
2371 MonoNativeThreadId tid;
2372 MonoDomain *caller_domain = mono_domain_get ();
2375 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2377 /* Atomically change our state to UNLOADING */
2378 prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2379 MONO_APPDOMAIN_UNLOADING_START,
2380 MONO_APPDOMAIN_CREATED);
2381 if (prev_state != MONO_APPDOMAIN_CREATED) {
2382 switch (prev_state) {
2383 case MONO_APPDOMAIN_UNLOADING_START:
2384 case MONO_APPDOMAIN_UNLOADING:
2385 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2387 case MONO_APPDOMAIN_UNLOADED:
2388 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2391 g_warning ("Invalid appdomain state %d", prev_state);
2392 g_assert_not_reached ();
2396 mono_domain_set (domain, FALSE);
2397 /* Notify OnDomainUnload listeners */
2398 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2401 mono_runtime_invoke (method, domain->domain, NULL, exc);
2403 /* Roll back the state change */
2404 domain->state = MONO_APPDOMAIN_CREATED;
2405 mono_domain_set (caller_domain, FALSE);
2408 mono_domain_set (caller_domain, FALSE);
2410 thread_data = g_new0 (unload_data, 1);
2411 thread_data->domain = domain;
2412 thread_data->failure_reason = NULL;
2413 thread_data->done = FALSE;
2414 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2416 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2417 domain->state = MONO_APPDOMAIN_UNLOADING;
2419 * First we create a separate thread for unloading, since
2420 * we might have to abort some threads, including the current one.
2422 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2423 if (thread_handle == NULL)
2425 name = g_strdup_printf ("Unload thread for domain %x", domain);
2426 mono_thread_info_set_name (tid, name);
2427 mono_thread_info_resume (tid);
2430 /* Wait for the thread */
2431 while (!thread_data->done && WaitForSingleObjectEx (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2432 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2433 /* The unload thread tries to abort us */
2434 /* The icall wrapper will execute the abort */
2435 CloseHandle (thread_handle);
2436 unload_data_unref (thread_data);
2440 CloseHandle (thread_handle);
2442 if (thread_data->failure_reason) {
2443 /* Roll back the state change */
2444 domain->state = MONO_APPDOMAIN_CREATED;
2446 g_warning ("%s", thread_data->failure_reason);
2448 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2450 g_free (thread_data->failure_reason);
2451 thread_data->failure_reason = NULL;
2454 unload_data_unref (thread_data);