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/threadpool-ms.h>
43 #include <mono/metadata/socket-io.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/gc-internal.h>
46 #include <mono/metadata/mono-gc.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/monitor.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/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/corlib/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 135
86 int assemblybinding_count;
91 mono_mutex_t mono_delegate_section;
93 static gunichar2 process_guid [36];
94 static gboolean process_guid_set = FALSE;
96 static gboolean no_exec = FALSE;
99 mono_domain_assembly_preload (MonoAssemblyName *aname,
100 gchar **assemblies_path,
103 static MonoAssembly *
104 mono_domain_assembly_search (MonoAssemblyName *aname,
108 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
111 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
113 static MonoAppDomain *
114 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
117 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
119 static MonoLoadFunc load_function = NULL;
122 mono_install_runtime_load (MonoLoadFunc func)
124 load_function = func;
128 mono_runtime_load (const char *filename, const char *runtime_version)
130 g_assert (load_function);
131 return load_function (filename, runtime_version);
135 * mono_runtime_set_no_exec:
137 * Instructs the runtime to operate in static mode, i.e. avoid/do not
138 * allow managed code execution. This is useful for running the AOT
139 * compiler on platforms which allow full-aot execution only. This
140 * should be called before mono_runtime_init ().
143 mono_runtime_set_no_exec (gboolean val)
149 * mono_runtime_get_no_exec:
151 * If true, then the runtime will not allow managed code execution.
154 mono_runtime_get_no_exec (void)
160 create_domain_objects (MonoDomain *domain)
162 MonoDomain *old_domain = mono_domain_get ();
164 MonoVTable *string_vt;
165 MonoClassField *string_empty_fld;
167 if (domain != old_domain) {
168 mono_thread_push_appdomain_ref (domain);
169 mono_domain_set_internal_with_options (domain, FALSE);
173 * Initialize String.Empty. This enables the removal of
174 * the static cctor of the String class.
176 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
177 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
178 g_assert (string_empty_fld);
179 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
182 * Create an instance early since we can't do it when there is no memory.
184 arg = mono_string_new (domain, "Out of memory");
185 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
188 * These two are needed because the signal handlers might be executing on
189 * an alternate stack, and Boehm GC can't handle that.
191 arg = mono_string_new (domain, "A null value was found where an object instance was required");
192 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
193 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
194 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
196 /*The ephemeron tombstone i*/
197 domain->ephemeron_tombstone = mono_object_new (domain, mono_defaults.object_class);
199 if (domain != old_domain) {
200 mono_thread_pop_appdomain_ref ();
201 mono_domain_set_internal_with_options (old_domain, FALSE);
205 * This class is used during exception handling, so initialize it here, to prevent
206 * stack overflows while handling stack overflows.
208 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
213 * @domain: domain returned by mono_init ()
215 * Initialize the core AppDomain: this function will run also some
216 * IL initialization code, so it needs the execution engine to be fully
219 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
220 * we know the entry_assembly.
224 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
225 MonoThreadAttachCB attach_cb)
227 MonoAppDomainSetup *setup;
231 mono_portability_helpers_init ();
233 mono_gc_base_init ();
234 mono_monitor_init ();
235 mono_marshal_init ();
237 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
238 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
239 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
240 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
241 mono_install_assembly_postload_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
242 mono_install_assembly_postload_refonly_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
243 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
244 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
246 mono_thread_init (start_cb, attach_cb);
248 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
249 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, class);
251 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
252 ad = (MonoAppDomain *) mono_object_new_pinned (domain, class);
255 domain->setup = setup;
257 mono_mutex_init_recursive (&mono_delegate_section);
259 mono_thread_attach (domain);
261 mono_type_initialization_init ();
263 if (!mono_runtime_get_no_exec ())
264 create_domain_objects (domain);
266 /* GC init has to happen after thread init */
269 /* contexts use GC handles, so they must be initialized after the GC */
270 mono_context_init (domain);
271 mono_context_set (domain->default_context);
273 #ifndef DISABLE_SOCKETS
274 mono_network_init ();
277 mono_console_init ();
280 mono_locks_tracer_init ();
282 /* mscorlib is loaded before we install the load hook */
283 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
289 mono_get_corlib_version (void)
292 MonoClassField *field;
295 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
296 mono_class_init (klass);
297 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
300 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
302 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
303 return *(gint32*)((gchar*)value + sizeof (MonoObject));
307 * mono_check_corlib_version
309 * Checks that the corlib that is loaded matches the version of this runtime.
311 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
312 * allocated string with the error otherwise.
315 mono_check_corlib_version (void)
317 int version = mono_get_corlib_version ();
318 if (version != MONO_CORLIB_VERSION)
319 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
326 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
328 * Initializes the @domain's default System.Runtime.Remoting's Context.
331 mono_context_init (MonoDomain *domain)
334 MonoAppContext *context;
336 class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
337 context = (MonoAppContext *) mono_object_new_pinned (domain, class);
338 context->domain_id = domain->domain_id;
339 context->context_id = 0;
340 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
341 domain->default_context = context;
345 * mono_runtime_cleanup:
350 * This must not be called while there are still running threads executing
354 mono_runtime_cleanup (MonoDomain *domain)
356 mono_attach_cleanup ();
358 /* This ends up calling any pending pending (for at most 2 seconds) */
361 mono_thread_cleanup ();
363 #ifndef DISABLE_SOCKETS
364 mono_network_cleanup ();
366 mono_marshal_cleanup ();
368 mono_type_initialization_cleanup ();
370 mono_monitor_cleanup ();
373 static MonoDomainFunc quit_function = NULL;
376 mono_install_runtime_cleanup (MonoDomainFunc func)
378 quit_function = func;
384 if (quit_function != NULL)
385 quit_function (mono_get_root_domain (), NULL);
389 * mono_domain_create_appdomain:
390 * @friendly_name: The friendly name of the appdomain to create
391 * @configuration_file: The configuration file to initialize the appdomain with
393 * Returns a MonoDomain initialized with the appdomain
396 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
399 MonoAppDomainSetup *setup;
402 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
403 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
404 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
406 ad = mono_domain_create_appdomain_internal (friendly_name, setup);
408 return mono_domain_from_appdomain (ad);
412 * mono_domain_set_config:
413 * @domain: MonoDomain initialized with the appdomain we want to change
414 * @base_dir: new base directory for the appdomain
415 * @config_file_name: path to the new configuration for the app domain
417 * Used to set the system configuration for an appdomain
419 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
420 * Error Initializing the configuration system. ---> System.ArgumentException:
421 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
424 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
426 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
427 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
430 static MonoAppDomainSetup*
431 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
433 MonoDomain *caller_domain = mono_domain_get ();
434 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
435 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
437 mono_domain_set_internal (domain);
439 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
440 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
441 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
442 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
443 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
444 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
445 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
446 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
447 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
448 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
449 copy->publisher_policy = setup->publisher_policy;
450 copy->path_changed = setup->path_changed;
451 copy->loader_optimization = setup->loader_optimization;
452 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
453 copy->disallow_code_downloads = setup->disallow_code_downloads;
454 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
455 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
456 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
457 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
458 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
460 mono_domain_set_internal (caller_domain);
465 static MonoAppDomain *
466 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
472 char *shadow_location;
474 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
476 /* FIXME: pin all those objects */
477 data = mono_domain_create();
479 ad = (MonoAppDomain *) mono_object_new (data, adclass);
482 data->friendly_name = g_strdup (friendly_name);
484 if (!setup->application_base) {
485 /* Inherit from the root domain since MS.NET does this */
486 MonoDomain *root = mono_get_root_domain ();
487 if (root->setup->application_base)
488 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)));
491 mono_context_init (data);
493 data->setup = copy_app_domain_setup (data, setup);
494 mono_set_private_bin_path_from_config (data);
495 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
497 #ifndef DISABLE_SHADOW_COPY
498 /*FIXME, guard this for when the debugger is not running */
499 shadow_location = get_shadow_assembly_location_base (data, &error);
500 if (!mono_error_ok (&error))
501 mono_error_raise_exception (&error);
502 g_free (shadow_location);
505 create_domain_objects (data);
511 * mono_domain_has_type_resolve:
512 * @domain: application domains being looked up
514 * Returns true if the AppDomain.TypeResolve field has been
518 mono_domain_has_type_resolve (MonoDomain *domain)
520 static MonoClassField *field = NULL;
524 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
528 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
532 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
537 * mono_domain_try_type_resolve:
538 * @domain: application domainwhere the name where the type is going to be resolved
539 * @name: the name of the type to resolve or NULL.
540 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
542 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
543 * the assembly that matches name.
545 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
547 * Returns: A MonoReflectionAssembly or NULL if not found
549 MonoReflectionAssembly *
550 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
554 static MonoMethod *method = NULL;
556 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
558 if (method == NULL) {
559 klass = domain->domain->mbr.obj.vtable->klass;
562 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
563 if (method == NULL) {
564 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
570 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
573 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
577 * mono_domain_owns_vtable_slot:
579 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
582 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
586 mono_domain_lock (domain);
587 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
588 mono_domain_unlock (domain);
595 * @force: force setting.
597 * Set the current appdomain to @domain. If @force is set, set it even
598 * if it is being unloaded.
602 * FALSE if the domain is unloaded
605 mono_domain_set (MonoDomain *domain, gboolean force)
607 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
610 mono_domain_set_internal (domain);
616 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
622 MONO_CHECK_ARG_NULL (name, NULL);
624 g_assert (ad != NULL);
626 g_assert (add != NULL);
628 str = mono_string_to_utf8 (name);
630 mono_domain_lock (add);
632 if (!strcmp (str, "APPBASE"))
633 o = (MonoObject *)add->setup->application_base;
634 else if (!strcmp (str, "APP_CONFIG_FILE"))
635 o = (MonoObject *)add->setup->configuration_file;
636 else if (!strcmp (str, "DYNAMIC_BASE"))
637 o = (MonoObject *)add->setup->dynamic_base;
638 else if (!strcmp (str, "APP_NAME"))
639 o = (MonoObject *)add->setup->application_name;
640 else if (!strcmp (str, "CACHE_BASE"))
641 o = (MonoObject *)add->setup->cache_path;
642 else if (!strcmp (str, "PRIVATE_BINPATH"))
643 o = (MonoObject *)add->setup->private_bin_path;
644 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
645 o = (MonoObject *)add->setup->private_bin_path_probe;
646 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
647 o = (MonoObject *)add->setup->shadow_copy_directories;
648 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
649 o = (MonoObject *)add->setup->shadow_copy_files;
651 o = mono_g_hash_table_lookup (add->env, name);
653 mono_domain_unlock (add);
663 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
667 MONO_CHECK_ARG_NULL (name,);
669 g_assert (ad != NULL);
671 g_assert (add != NULL);
673 mono_domain_lock (add);
675 mono_g_hash_table_insert (add->env, name, data);
677 mono_domain_unlock (add);
681 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
683 g_assert (ad != NULL);
684 g_assert (ad->data != NULL);
686 return ad->data->setup;
690 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
692 g_assert (ad != NULL);
693 g_assert (ad->data != NULL);
695 return mono_string_new (ad->data, ad->data->friendly_name);
699 ves_icall_System_AppDomain_getCurDomain ()
701 MonoDomain *add = mono_domain_get ();
707 ves_icall_System_AppDomain_getRootDomain ()
709 MonoDomain *root = mono_get_root_domain ();
715 get_attribute_value (const gchar **attribute_names,
716 const gchar **attribute_values,
717 const char *att_name)
720 for (n = 0; attribute_names [n] != NULL; n++) {
721 if (strcmp (attribute_names [n], att_name) == 0)
722 return g_strdup (attribute_values [n]);
728 start_element (GMarkupParseContext *context,
729 const gchar *element_name,
730 const gchar **attribute_names,
731 const gchar **attribute_values,
735 RuntimeConfig *runtime_config = user_data;
737 if (strcmp (element_name, "runtime") == 0) {
738 runtime_config->runtime_count++;
742 if (strcmp (element_name, "assemblyBinding") == 0) {
743 runtime_config->assemblybinding_count++;
747 if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
750 if (strcmp (element_name, "probing") != 0)
753 g_free (runtime_config->domain->private_bin_path);
754 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
755 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
756 g_free (runtime_config->domain->private_bin_path);
757 runtime_config->domain->private_bin_path = NULL;
763 end_element (GMarkupParseContext *context,
764 const gchar *element_name,
768 RuntimeConfig *runtime_config = user_data;
769 if (strcmp (element_name, "runtime") == 0)
770 runtime_config->runtime_count--;
771 else if (strcmp (element_name, "assemblyBinding") == 0)
772 runtime_config->assemblybinding_count--;
776 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
778 RuntimeConfig *state = user_data;
780 const gchar *filename;
782 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
783 msg = error && error->message ? error->message : "";
784 g_warning ("Error parsing %s: %s", filename, msg);
787 static const GMarkupParser
797 mono_set_private_bin_path_from_config (MonoDomain *domain)
800 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
802 GMarkupParseContext *context;
803 RuntimeConfig runtime_config;
806 if (!domain || !domain->setup || !domain->setup->configuration_file)
809 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
810 if (!mono_error_ok (&error)) {
811 mono_error_cleanup (&error);
815 config_file_path = mono_portability_find_file (config_file_name, TRUE);
816 if (!config_file_path)
817 config_file_path = config_file_name;
819 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
822 runtime_config.runtime_count = 0;
823 runtime_config.assemblybinding_count = 0;
824 runtime_config.domain = domain;
825 runtime_config.filename = config_file_path;
828 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
829 offset = 3; /* Skip UTF-8 BOM */
831 context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
832 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
833 g_markup_parse_context_end_parse (context, NULL);
834 g_markup_parse_context_free (context);
838 if (config_file_name != config_file_path)
839 g_free (config_file_name);
840 g_free (config_file_path);
844 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
846 #ifdef DISABLE_APPDOMAINS
847 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
850 char *fname = mono_string_to_utf8 (friendly_name);
851 MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
860 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
862 MonoDomain *domain = ad->data;
864 static MonoClass *System_Reflection_Assembly;
868 GPtrArray *assemblies;
870 if (!System_Reflection_Assembly)
871 System_Reflection_Assembly = mono_class_from_name (
872 mono_defaults.corlib, "System.Reflection", "Assembly");
875 * Make a copy of the list of assemblies because we can't hold the assemblies
876 * lock while creating objects etc.
878 assemblies = g_ptr_array_new ();
879 /* Need to skip internal assembly builders created by remoting */
880 mono_domain_assemblies_lock (domain);
881 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
883 if (refonly != ass->ref_only)
885 if (ass->corlib_internal)
887 g_ptr_array_add (assemblies, ass);
889 mono_domain_assemblies_unlock (domain);
891 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
892 for (i = 0; i < assemblies->len; ++i) {
893 ass = g_ptr_array_index (assemblies, i);
894 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
897 g_ptr_array_free (assemblies, TRUE);
902 MonoReflectionAssembly *
903 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
907 MonoBoolean isrefonly;
910 if (mono_runtime_get_no_exec ())
913 g_assert (domain != NULL && fname != NULL);
915 klass = domain->domain->mbr.obj.vtable->klass;
918 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
919 if (method == NULL) {
920 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
924 isrefonly = refonly ? 1 : 0;
926 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
927 params [2] = &isrefonly;
928 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
932 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
935 MonoReflectionAssembly *assembly;
936 MonoDomain *domain = mono_domain_get ();
940 aname_str = mono_stringify_assembly_name (aname);
942 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
943 str = mono_string_new (domain, aname_str);
948 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
952 return assembly->assembly;
958 * LOCKING: assumes assemblies_lock in the domain is already locked.
961 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
965 gboolean destroy_ht = FALSE;
967 if (!ass->aname.name)
971 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
975 /* FIXME: handle lazy loaded assemblies */
976 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
977 g_hash_table_insert (ht, tmp->data, tmp->data);
979 if (!g_hash_table_lookup (ht, ass)) {
980 mono_assembly_addref (ass);
981 g_hash_table_insert (ht, ass, ass);
982 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
983 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);
986 if (ass->image->references) {
987 for (i = 0; ass->image->references [i] != NULL; i++) {
988 if (ass->image->references [i] != REFERENCE_MISSING)
989 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
990 add_assemblies_to_domain (domain, ass->image->references [i], ht);
995 g_hash_table_destroy (ht);
999 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1001 static MonoClassField *assembly_load_field;
1002 static MonoMethod *assembly_load_method;
1003 MonoDomain *domain = mono_domain_get ();
1004 MonoReflectionAssembly *ref_assembly;
1006 gpointer load_value;
1009 if (!domain->domain)
1010 /* This can happen during startup */
1012 #ifdef ASSEMBLY_LOAD_DEBUG
1013 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1015 klass = domain->domain->mbr.obj.vtable->klass;
1017 mono_domain_assemblies_lock (domain);
1018 add_assemblies_to_domain (domain, assembly, NULL);
1019 mono_domain_assemblies_unlock (domain);
1021 if (assembly_load_field == NULL) {
1022 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1023 g_assert (assembly_load_field);
1026 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1027 if (load_value == NULL) {
1028 /* No events waiting to be triggered */
1032 ref_assembly = mono_assembly_get_object (domain, assembly);
1033 g_assert (ref_assembly);
1035 if (assembly_load_method == NULL) {
1036 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1037 g_assert (assembly_load_method);
1040 *params = ref_assembly;
1041 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1045 * LOCKING: Acquires the domain assemblies lock.
1048 set_domain_search_path (MonoDomain *domain)
1051 MonoAppDomainSetup *setup;
1053 gchar *search_path = NULL;
1056 gchar **pvt_split = NULL;
1057 GError *gerror = NULL;
1058 gint appbaselen = -1;
1061 * We use the low-level domain assemblies lock, since this is called from
1062 * assembly loads hooks, which means this thread might hold the loader lock.
1064 mono_domain_assemblies_lock (domain);
1066 if (!domain->setup) {
1067 mono_domain_assemblies_unlock (domain);
1071 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1072 mono_domain_assemblies_unlock (domain);
1075 setup = domain->setup;
1076 if (!setup->application_base) {
1077 mono_domain_assemblies_unlock (domain);
1078 return; /* Must set application base to get private path working */
1083 if (setup->private_bin_path) {
1084 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1085 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1086 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1087 mono_error_cleanup (&error);
1088 mono_domain_assemblies_unlock (domain);
1093 if (domain->private_bin_path) {
1094 if (search_path == NULL)
1095 search_path = domain->private_bin_path;
1097 gchar *tmp2 = search_path;
1098 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1105 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1106 * directories relative to ApplicationBase separated by semicolons (see
1107 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1108 * The loop below copes with the fact that some Unix applications may use ':' (or
1109 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1110 * ';' for the subsequent split.
1112 * The issue was reported in bug #81446
1115 #ifndef TARGET_WIN32
1118 slen = strlen (search_path);
1119 for (i = 0; i < slen; i++)
1120 if (search_path [i] == ':')
1121 search_path [i] = ';';
1124 pvt_split = g_strsplit (search_path, ";", 1000);
1125 g_free (search_path);
1126 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1131 g_strfreev (pvt_split);
1133 * Don't do this because the first time is called, the domain
1134 * setup is not finished.
1136 * domain->search_path = g_malloc (sizeof (char *));
1137 * domain->search_path [0] = NULL;
1139 mono_domain_assemblies_unlock (domain);
1143 if (domain->search_path)
1144 g_strfreev (domain->search_path);
1146 tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1147 tmp [npaths] = NULL;
1149 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1150 if (!mono_error_ok (&error)) {
1151 mono_error_cleanup (&error);
1152 g_strfreev (pvt_split);
1155 mono_domain_assemblies_unlock (domain);
1159 domain->search_path = tmp;
1161 /* FIXME: is this needed? */
1162 if (strncmp (*tmp, "file://", 7) == 0) {
1168 uri = g_strdup_printf ("file:///%s", uri + 7);
1171 uri = mono_escape_uri_string (tmpuri);
1172 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1178 if (gerror != NULL) {
1179 g_warning ("%s\n", gerror->message);
1180 g_error_free (gerror);
1187 for (i = 1; pvt_split && i < npaths; i++) {
1188 if (g_path_is_absolute (pvt_split [i - 1])) {
1189 tmp [i] = g_strdup (pvt_split [i - 1]);
1191 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1194 if (strchr (tmp [i], '.')) {
1198 reduced = mono_path_canonicalize (tmp [i]);
1199 if (appbaselen == -1)
1200 appbaselen = strlen (tmp [0]);
1202 if (strncmp (tmp [0], reduced, appbaselen)) {
1205 tmp [i] = g_strdup ("");
1215 if (setup->private_bin_path_probe != NULL) {
1217 tmp [0] = g_strdup ("");
1220 domain->setup->path_changed = FALSE;
1222 g_strfreev (pvt_split);
1224 mono_domain_assemblies_unlock (domain);
1227 #ifdef DISABLE_SHADOW_COPY
1229 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1235 mono_make_shadow_copy (const char *filename)
1237 return (char *) filename;
1241 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1243 guint16 *orig, *dest;
1244 gboolean copy_result;
1246 strcpy (src + srclen - tail_len, extension);
1248 if (IS_PORTABILITY_CASE) {
1249 gchar *file = mono_portability_find_file (src, TRUE);
1255 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1259 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1261 strcpy (target + targetlen - tail_len, extension);
1262 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1265 copy_result = CopyFile (orig, dest, FALSE);
1267 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1268 * overwritten when updated in their original locations. */
1270 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1279 get_cstring_hash (const char *str)
1285 if (!str || !str [0])
1290 for (i = 0; i < len; i++) {
1291 h = (h << 5) - h + *p;
1299 * Returned memory is malloc'd. Called must free it
1302 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1304 MonoAppDomainSetup *setup;
1305 char *cache_path, *appname;
1309 mono_error_init (error);
1311 setup = domain->setup;
1312 if (setup->cache_path != NULL && setup->application_name != NULL) {
1313 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1314 if (!mono_error_ok (error))
1316 #ifndef TARGET_WIN32
1319 for (i = strlen (cache_path) - 1; i >= 0; i--)
1320 if (cache_path [i] == '\\')
1321 cache_path [i] = '/';
1325 appname = mono_string_to_utf8_checked (setup->application_name, error);
1326 if (!mono_error_ok (error)) {
1327 g_free (cache_path);
1331 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1333 g_free (cache_path);
1335 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1336 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1343 get_shadow_assembly_location (const char *filename, MonoError *error)
1345 gint32 hash = 0, hash2 = 0;
1347 char path_hash [30];
1348 char *bname = g_path_get_basename (filename);
1349 char *dirname = g_path_get_dirname (filename);
1350 char *location, *tmploc;
1351 MonoDomain *domain = mono_domain_get ();
1353 mono_error_init (error);
1355 hash = get_cstring_hash (bname);
1356 hash2 = get_cstring_hash (dirname);
1357 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1358 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1359 tmploc = get_shadow_assembly_location_base (domain, error);
1360 if (!mono_error_ok (error)) {
1366 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1374 ensure_directory_exists (const char *filename)
1377 gchar *dir_utf8 = g_path_get_dirname (filename);
1379 gunichar2 *dir_utf16 = NULL;
1382 if (!dir_utf8 || !dir_utf8 [0])
1385 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1393 /* make life easy and only use one directory seperator */
1404 while (*p++ != '\\')
1410 p = wcschr (p, '\\');
1413 retval = _wmkdir (dir_utf16);
1414 if (retval != 0 && errno != EEXIST) {
1427 gchar *dir = g_path_get_dirname (filename);
1431 if (!dir || !dir [0]) {
1436 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1446 p = strchr (p, '/');
1449 retval = mkdir (dir, 0777);
1450 if (retval != 0 && errno != EEXIST) {
1465 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1467 struct stat sbuf_dest;
1469 gchar *real_src = mono_portability_find_file (src, TRUE);
1472 stat_src = (gchar*)src;
1474 stat_src = real_src;
1476 if (stat (stat_src, sbuf_src) == -1) {
1477 time_t tnow = time (NULL);
1482 memset (sbuf_src, 0, sizeof (*sbuf_src));
1483 sbuf_src->st_mtime = tnow;
1484 sbuf_src->st_atime = tnow;
1491 if (stat (dest, &sbuf_dest) == -1)
1494 if (sbuf_src->st_size == sbuf_dest.st_size &&
1495 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1502 shadow_copy_create_ini (const char *shadow, const char *filename)
1512 dir_name = g_path_get_dirname (shadow);
1513 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1515 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1520 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1525 handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1526 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1528 if (handle == INVALID_HANDLE_VALUE) {
1532 full_path = mono_path_resolve_symlinks (filename);
1533 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1535 CloseHandle (handle);
1540 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1543 MonoAppDomainSetup *setup;
1546 gchar **directories;
1547 gchar *shadow_status_string;
1549 gboolean shadow_enabled;
1550 gboolean found = FALSE;
1555 setup = domain->setup;
1556 if (setup == NULL || setup->shadow_copy_files == NULL)
1559 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1560 if (!mono_error_ok (&error)) {
1561 mono_error_cleanup (&error);
1564 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1565 g_free (shadow_status_string);
1567 if (!shadow_enabled)
1570 if (setup->shadow_copy_directories == NULL)
1573 /* Is dir_name a shadow_copy destination already? */
1574 base_dir = get_shadow_assembly_location_base (domain, &error);
1575 if (!mono_error_ok (&error)) {
1576 mono_error_cleanup (&error);
1580 if (strstr (dir_name, base_dir)) {
1586 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1587 if (!mono_error_ok (&error)) {
1588 mono_error_cleanup (&error);
1592 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1593 dir_ptr = directories;
1595 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1601 g_strfreev (directories);
1607 This function raises exceptions so it can cause as sorts of nasty stuff if called
1608 while holding a lock.
1609 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1610 or NULL if source file not found.
1611 FIXME bubble up the error instead of raising it here
1614 mono_make_shadow_copy (const char *filename)
1617 gchar *sibling_source, *sibling_target;
1618 gint sibling_source_len, sibling_target_len;
1619 guint16 *orig, *dest;
1622 gboolean copy_result;
1624 struct stat src_sbuf;
1625 struct utimbuf utbuf;
1626 char *dir_name = g_path_get_dirname (filename);
1627 MonoDomain *domain = mono_domain_get ();
1630 set_domain_search_path (domain);
1632 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1634 return (char *) filename;
1637 /* Is dir_name a shadow_copy destination already? */
1638 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1639 if (!mono_error_ok (&error)) {
1640 mono_error_cleanup (&error);
1642 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1643 mono_raise_exception (exc);
1646 if (strstr (dir_name, shadow_dir)) {
1647 g_free (shadow_dir);
1649 return (char *) filename;
1651 g_free (shadow_dir);
1654 shadow = get_shadow_assembly_location (filename, &error);
1655 if (!mono_error_ok (&error)) {
1656 mono_error_cleanup (&error);
1657 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1658 mono_raise_exception (exc);
1661 if (ensure_directory_exists (shadow) == FALSE) {
1663 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1664 mono_raise_exception (exc);
1667 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1668 return (char*) shadow;
1670 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1671 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1674 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1675 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1676 * and not have it runtime error" */
1677 attrs = GetFileAttributes (orig);
1678 if (attrs == INVALID_FILE_ATTRIBUTES) {
1680 return (char *)filename;
1683 copy_result = CopyFile (orig, dest, FALSE);
1685 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1686 * overwritten when updated in their original locations. */
1688 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1693 if (copy_result == FALSE) {
1696 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1697 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1698 return NULL; /* file not found, shadow copy failed */
1700 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1701 mono_raise_exception (exc);
1704 /* attempt to copy .mdb, .config if they exist */
1705 sibling_source = g_strconcat (filename, ".config", NULL);
1706 sibling_source_len = strlen (sibling_source);
1707 sibling_target = g_strconcat (shadow, ".config", NULL);
1708 sibling_target_len = strlen (sibling_target);
1710 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1711 if (copy_result == TRUE)
1712 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1714 g_free (sibling_source);
1715 g_free (sibling_target);
1717 if (copy_result == FALSE) {
1719 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1720 mono_raise_exception (exc);
1723 /* Create a .ini file containing the original assembly location */
1724 if (!shadow_copy_create_ini (shadow, filename)) {
1726 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1727 mono_raise_exception (exc);
1730 utbuf.actime = src_sbuf.st_atime;
1731 utbuf.modtime = src_sbuf.st_mtime;
1732 utime (shadow, &utbuf);
1736 #endif /* DISABLE_SHADOW_COPY */
1739 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1741 if (appdomain == NULL)
1744 return appdomain->data;
1748 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1749 const gchar *path3, const gchar *path4,
1750 gboolean refonly, gboolean is_private)
1753 gboolean found = FALSE;
1756 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1758 if (IS_PORTABILITY_SET) {
1759 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1762 fullpath = new_fullpath;
1766 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1769 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1772 return (*assembly != NULL);
1775 static MonoAssembly *
1776 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1778 MonoAssembly *result = NULL;
1781 const gchar *local_culture;
1783 gboolean is_private = FALSE;
1785 if (!culture || *culture == '\0') {
1788 local_culture = culture;
1791 filename = g_strconcat (name, ".dll", NULL);
1792 len = strlen (filename);
1794 for (path = search_path; *path; path++) {
1795 if (**path == '\0') {
1797 continue; /* Ignore empty ApplicationBase */
1800 /* See test cases in bug #58992 and bug #57710 */
1801 /* 1st try: [culture]/[name].dll (culture may be empty) */
1802 strcpy (filename + len - 4, ".dll");
1803 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1806 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1807 strcpy (filename + len - 4, ".exe");
1808 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1811 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1812 strcpy (filename + len - 4, ".dll");
1813 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1816 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1817 strcpy (filename + len - 4, ".exe");
1818 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1827 * Try loading the assembly from ApplicationBase and PrivateBinPath
1828 * and then from assemblies_path if any.
1829 * LOCKING: This is called from the assembly loading code, which means the caller
1830 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1832 static MonoAssembly *
1833 mono_domain_assembly_preload (MonoAssemblyName *aname,
1834 gchar **assemblies_path,
1837 MonoDomain *domain = mono_domain_get ();
1838 MonoAssembly *result = NULL;
1839 gboolean refonly = GPOINTER_TO_UINT (user_data);
1841 set_domain_search_path (domain);
1843 if (domain->search_path && domain->search_path [0] != NULL) {
1844 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1847 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1848 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1855 * Check whenever a given assembly was already loaded in the current appdomain.
1857 static MonoAssembly *
1858 mono_domain_assembly_search (MonoAssemblyName *aname,
1861 MonoDomain *domain = mono_domain_get ();
1864 gboolean refonly = GPOINTER_TO_UINT (user_data);
1866 mono_domain_assemblies_lock (domain);
1867 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1869 /* Dynamic assemblies can't match here in MS.NET */
1870 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1873 mono_domain_assemblies_unlock (domain);
1876 mono_domain_assemblies_unlock (domain);
1881 MonoReflectionAssembly *
1882 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1884 MonoDomain *domain = mono_domain_get ();
1885 char *name, *filename;
1886 MonoImageOpenStatus status = MONO_IMAGE_OK;
1889 if (fname == NULL) {
1890 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1891 mono_set_pending_exception (exc);
1895 name = filename = mono_string_to_utf8 (fname);
1897 ass = mono_assembly_open_full (filename, &status, refOnly);
1902 if (status == MONO_IMAGE_IMAGE_INVALID)
1903 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1905 exc = mono_get_exception_file_not_found2 (NULL, fname);
1907 mono_set_pending_exception (exc);
1913 return mono_assembly_get_object (domain, ass);
1916 MonoReflectionAssembly *
1917 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1918 MonoArray *raw_assembly,
1919 MonoArray *raw_symbol_store, MonoObject *evidence,
1920 MonoBoolean refonly)
1923 MonoReflectionAssembly *refass = NULL;
1924 MonoDomain *domain = ad->data;
1925 MonoImageOpenStatus status;
1926 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1927 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1930 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1934 if (raw_symbol_store != NULL)
1935 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1937 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1941 mono_image_close (image);
1942 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1946 refass = mono_assembly_get_object (domain, ass);
1947 MONO_OBJECT_SETREF (refass, evidence, evidence);
1951 MonoReflectionAssembly *
1952 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1954 MonoDomain *domain = ad->data;
1955 MonoImageOpenStatus status = MONO_IMAGE_OK;
1957 MonoAssemblyName aname;
1958 MonoReflectionAssembly *refass = NULL;
1962 g_assert (assRef != NULL);
1964 name = mono_string_to_utf8 (assRef);
1965 parsed = mono_assembly_name_parse (name, &aname);
1969 /* This is a parse error... */
1971 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1975 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1976 mono_assembly_name_free (&aname);
1979 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1981 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1990 refass = mono_assembly_get_object (domain, ass);
1992 MONO_OBJECT_SETREF (refass, evidence, evidence);
1997 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
1999 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2001 if (NULL == domain) {
2002 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2003 mono_set_pending_exception (exc);
2007 if (domain == mono_get_root_domain ()) {
2008 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2013 * Unloading seems to cause problems when running NUnit/NAnt, hence
2016 if (g_getenv ("MONO_NO_UNLOAD"))
2018 #ifdef __native_client__
2022 mono_domain_unload (domain);
2026 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2028 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2033 return mono_domain_is_unloading (domain);
2037 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2038 MonoReflectionAssembly *refass, MonoArray *args)
2045 image = refass->assembly->image;
2048 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2051 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2054 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2056 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2060 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2062 return ad->data->domain_id;
2066 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2068 MonoDomain *old_domain = mono_domain_get();
2070 if (!mono_domain_set (ad->data, FALSE)) {
2071 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2075 return old_domain->domain;
2079 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2081 MonoDomain *current_domain = mono_domain_get ();
2082 MonoDomain *domain = mono_domain_get_by_id (domainid);
2084 if (!domain || !mono_domain_set (domain, FALSE)) {
2085 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2089 return current_domain->domain;
2093 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2095 mono_thread_push_appdomain_ref (ad->data);
2099 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2101 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2105 * Raise an exception to prevent the managed code from executing a pop
2108 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2112 mono_thread_push_appdomain_ref (domain);
2116 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2118 mono_thread_pop_appdomain_ref ();
2122 ves_icall_System_AppDomain_InternalGetContext ()
2124 return mono_context_get ();
2128 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2130 return mono_domain_get ()->default_context;
2134 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2136 MonoAppContext *old_context = mono_context_get ();
2138 mono_context_set (mc);
2144 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2146 MonoDomain* mono_root_domain = mono_get_root_domain ();
2147 mono_domain_lock (mono_root_domain);
2148 if (process_guid_set) {
2149 mono_domain_unlock (mono_root_domain);
2150 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2152 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2153 process_guid_set = TRUE;
2154 mono_domain_unlock (mono_root_domain);
2159 mono_domain_is_unloading (MonoDomain *domain)
2161 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2168 clear_cached_vtable (MonoVTable *vtable)
2170 MonoClass *klass = vtable->klass;
2171 MonoDomain *domain = vtable->domain;
2172 MonoClassRuntimeInfo *runtime_info;
2175 runtime_info = klass->runtime_info;
2176 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2177 runtime_info->domain_vtables [domain->domain_id] = NULL;
2178 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2179 mono_gc_free_fixed (data);
2182 static G_GNUC_UNUSED void
2183 zero_static_data (MonoVTable *vtable)
2185 MonoClass *klass = vtable->klass;
2188 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2189 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2192 typedef struct unload_data {
2195 char *failure_reason;
2200 unload_data_unref (unload_data *data)
2204 mono_atomic_load_acquire (count, gint32, &data->refcount);
2205 g_assert (count >= 1 && count <= 2);
2210 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2214 deregister_reflection_info_roots_from_list (MonoImage *image)
2216 GSList *list = image->reflection_info_unregister_classes;
2219 MonoClass *class = list->data;
2221 mono_class_free_ref_info (class);
2226 image->reflection_info_unregister_classes = NULL;
2230 deregister_reflection_info_roots (MonoDomain *domain)
2234 mono_domain_assemblies_lock (domain);
2235 for (list = domain->domain_assemblies; list; list = list->next) {
2236 MonoAssembly *assembly = list->data;
2237 MonoImage *image = assembly->image;
2241 * No need to take the image lock here since dynamic images are appdomain bound and
2242 * at this point the mutator is gone. Taking the image lock here would mean
2243 * promoting it from a simple lock to a complex lock, which we better avoid if
2246 if (image_is_dynamic (image))
2247 deregister_reflection_info_roots_from_list (image);
2249 for (i = 0; i < image->module_count; ++i) {
2250 MonoImage *module = image->modules [i];
2251 if (module && image_is_dynamic (module))
2252 deregister_reflection_info_roots_from_list (module);
2255 mono_domain_assemblies_unlock (domain);
2258 static guint32 WINAPI
2259 unload_thread_main (void *arg)
2261 unload_data *data = (unload_data*)arg;
2262 MonoDomain *domain = data->domain;
2266 /* Have to attach to the runtime so shutdown can wait for this thread */
2267 /* Force it to be attached to avoid racing during shutdown. */
2268 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2271 * FIXME: Abort our parent thread last, so we can return a failure
2272 * indication if aborting times out.
2274 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2275 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2279 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2280 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2284 /* Finalize all finalizable objects in the doomed appdomain */
2285 if (!mono_domain_finalize (domain, -1)) {
2286 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2290 /* Clear references to our vtables in class->runtime_info.
2291 * We also hold the loader lock because we're going to change
2292 * class->runtime_info.
2295 mono_loader_lock (); //FIXME why do we need the loader lock here?
2296 mono_domain_lock (domain);
2299 * We need to make sure that we don't have any remsets
2300 * pointing into static data of the to-be-freed domain because
2301 * at the next collections they would be invalid. So what we
2302 * do is we first zero all static data and then do a minor
2303 * collection. Because all references in the static data will
2304 * now be null we won't do any unnecessary copies and after
2305 * the collection there won't be any more remsets.
2307 for (i = 0; i < domain->class_vtable_array->len; ++i)
2308 zero_static_data (g_ptr_array_index (domain->class_vtable_array, i));
2309 mono_gc_collect (0);
2311 for (i = 0; i < domain->class_vtable_array->len; ++i)
2312 clear_cached_vtable (g_ptr_array_index (domain->class_vtable_array, i));
2313 deregister_reflection_info_roots (domain);
2315 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2317 mono_domain_unlock (domain);
2318 mono_loader_unlock ();
2320 mono_threads_clear_cached_culture (domain);
2322 domain->state = MONO_APPDOMAIN_UNLOADED;
2324 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2326 /* remove from the handle table the items related to this domain */
2327 mono_gchandle_free_domain (domain);
2329 mono_domain_free (domain, FALSE);
2331 mono_gc_collect (mono_gc_max_generation ());
2333 mono_atomic_store_release (&data->done, TRUE);
2334 unload_data_unref (data);
2335 mono_thread_detach (thread);
2339 mono_atomic_store_release (&data->done, TRUE);
2340 unload_data_unref (data);
2341 mono_thread_detach (thread);
2346 * mono_domain_unload:
2347 * @domain: The domain to unload
2349 * Unloads an appdomain. Follows the process outlined in the comment
2350 * for mono_domain_try_unload.
2353 mono_domain_unload (MonoDomain *domain)
2355 MonoObject *exc = NULL;
2356 mono_domain_try_unload (domain, &exc);
2358 mono_raise_exception ((MonoException*)exc);
2362 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2366 MONO_PREPARE_BLOCKING
2367 result = WaitForSingleObjectEx (handle, timeout, alertable);
2368 MONO_FINISH_BLOCKING
2374 * mono_domain_unload:
2375 * @domain: The domain to unload
2376 * @exc: Exception information
2378 * Unloads an appdomain. Follows the process outlined in:
2379 * http://blogs.gotdotnet.com/cbrumme
2381 * If doing things the 'right' way is too hard or complex, we do it the
2382 * 'simple' way, which means do everything needed to avoid crashes and
2383 * memory leaks, but not much else.
2385 * It is required to pass a valid reference to the exc argument, upon return
2386 * from this function *exc will be set to the exception thrown, if any.
2388 * If this method is not called from an icall (embedded scenario for instance),
2389 * it must not be called with any managed frames on the stack, since the unload
2390 * process could end up trying to abort the current thread.
2393 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2395 HANDLE thread_handle;
2396 MonoAppDomainState prev_state;
2398 unload_data *thread_data;
2399 MonoNativeThreadId tid;
2400 MonoDomain *caller_domain = mono_domain_get ();
2403 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2405 /* Atomically change our state to UNLOADING */
2406 prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2407 MONO_APPDOMAIN_UNLOADING_START,
2408 MONO_APPDOMAIN_CREATED);
2409 if (prev_state != MONO_APPDOMAIN_CREATED) {
2410 switch (prev_state) {
2411 case MONO_APPDOMAIN_UNLOADING_START:
2412 case MONO_APPDOMAIN_UNLOADING:
2413 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2415 case MONO_APPDOMAIN_UNLOADED:
2416 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2419 g_warning ("Invalid appdomain state %d", prev_state);
2420 g_assert_not_reached ();
2424 mono_domain_set (domain, FALSE);
2425 /* Notify OnDomainUnload listeners */
2426 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2429 mono_runtime_invoke (method, domain->domain, NULL, exc);
2431 /* Roll back the state change */
2432 domain->state = MONO_APPDOMAIN_CREATED;
2433 mono_domain_set (caller_domain, FALSE);
2436 mono_domain_set (caller_domain, FALSE);
2438 thread_data = g_new0 (unload_data, 1);
2439 thread_data->domain = domain;
2440 thread_data->failure_reason = NULL;
2441 thread_data->done = FALSE;
2442 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2444 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2445 domain->state = MONO_APPDOMAIN_UNLOADING;
2447 * First we create a separate thread for unloading, since
2448 * we might have to abort some threads, including the current one.
2450 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2451 if (thread_handle == NULL)
2453 name = g_strdup_printf ("Unload thread for domain %x", domain);
2454 mono_thread_info_set_name (tid, name);
2455 mono_thread_info_resume (tid);
2458 /* Wait for the thread */
2459 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2460 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2461 /* The unload thread tries to abort us */
2462 /* The icall wrapper will execute the abort */
2463 CloseHandle (thread_handle);
2464 unload_data_unref (thread_data);
2468 CloseHandle (thread_handle);
2470 if (thread_data->failure_reason) {
2471 /* Roll back the state change */
2472 domain->state = MONO_APPDOMAIN_CREATED;
2474 g_warning ("%s", thread_data->failure_reason);
2476 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2478 g_free (thread_data->failure_reason);
2479 thread_data->failure_reason = NULL;
2482 unload_data_unref (thread_data);