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 111
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,
109 static MonoAssembly *
110 mono_domain_assembly_postload_search (MonoAssemblyName *aname,
114 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
117 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
119 static MonoAppDomain *
120 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
123 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
125 static MonoLoadFunc load_function = NULL;
128 mono_install_runtime_load (MonoLoadFunc func)
130 load_function = func;
134 mono_runtime_load (const char *filename, const char *runtime_version)
136 g_assert (load_function);
137 return load_function (filename, runtime_version);
141 * mono_runtime_set_no_exec:
143 * Instructs the runtime to operate in static mode, i.e. avoid/do not
144 * allow managed code execution. This is useful for running the AOT
145 * compiler on platforms which allow full-aot execution only. This
146 * should be called before mono_runtime_init ().
149 mono_runtime_set_no_exec (gboolean val)
155 * mono_runtime_get_no_exec:
157 * If true, then the runtime will not allow managed code execution.
160 mono_runtime_get_no_exec (void)
166 create_domain_objects (MonoDomain *domain)
168 MonoDomain *old_domain = mono_domain_get ();
171 if (domain != old_domain) {
172 mono_thread_push_appdomain_ref (domain);
173 mono_domain_set_internal_with_options (domain, FALSE);
177 * Create an instance early since we can't do it when there is no memory.
179 arg = mono_string_new (domain, "Out of memory");
180 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
183 * These two are needed because the signal handlers might be executing on
184 * an alternate stack, and Boehm GC can't handle that.
186 arg = mono_string_new (domain, "A null value was found where an object instance was required");
187 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
188 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
189 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
191 /*The ephemeron tombstone i*/
192 domain->ephemeron_tombstone = mono_object_new (domain, mono_defaults.object_class);
194 if (domain != old_domain) {
195 mono_thread_pop_appdomain_ref ();
196 mono_domain_set_internal_with_options (old_domain, FALSE);
200 * This class is used during exception handling, so initialize it here, to prevent
201 * stack overflows while handling stack overflows.
203 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
208 * @domain: domain returned by mono_init ()
210 * Initialize the core AppDomain: this function will run also some
211 * IL initialization code, so it needs the execution engine to be fully
214 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
215 * we know the entry_assembly.
219 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
220 MonoThreadAttachCB attach_cb)
222 MonoAppDomainSetup *setup;
226 mono_portability_helpers_init ();
228 mono_gc_base_init ();
229 mono_monitor_init ();
230 mono_thread_pool_init ();
231 mono_marshal_init ();
233 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
234 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
235 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
236 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
237 mono_install_assembly_postload_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
238 mono_install_assembly_postload_refonly_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
239 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
240 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
242 mono_thread_init (start_cb, attach_cb);
244 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
245 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, class);
247 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
248 ad = (MonoAppDomain *) mono_object_new_pinned (domain, class);
251 domain->setup = setup;
253 mono_mutex_init_recursive (&mono_delegate_section);
255 mono_mutex_init_recursive (&mono_strtod_mutex);
257 mono_thread_attach (domain);
258 mono_context_init (domain);
259 mono_context_set (domain->default_context);
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 #ifndef DISABLE_SOCKETS
270 mono_network_init ();
273 mono_console_init ();
276 mono_locks_tracer_init ();
278 /* mscorlib is loaded before we install the load hook */
279 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
285 mono_get_corlib_version (void)
288 MonoClassField *field;
291 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
292 mono_class_init (klass);
293 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
296 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
298 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
299 return *(gint32*)((gchar*)value + sizeof (MonoObject));
303 * mono_check_corlib_version
305 * Checks that the corlib that is loaded matches the version of this runtime.
307 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
308 * allocated string with the error otherwise.
311 mono_check_corlib_version (void)
313 int version = mono_get_corlib_version ();
314 if (version != MONO_CORLIB_VERSION)
315 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
322 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
324 * Initializes the @domain's default System.Runtime.Remoting's Context.
327 mono_context_init (MonoDomain *domain)
330 MonoAppContext *context;
332 class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
333 context = (MonoAppContext *) mono_object_new_pinned (domain, class);
334 context->domain_id = domain->domain_id;
335 context->context_id = 0;
336 domain->default_context = context;
340 * mono_runtime_cleanup:
345 * This must not be called while there are still running threads executing
349 mono_runtime_cleanup (MonoDomain *domain)
351 mono_attach_cleanup ();
353 /* This ends up calling any pending pending (for at most 2 seconds) */
356 mono_thread_cleanup ();
358 #ifndef DISABLE_SOCKETS
359 mono_network_cleanup ();
361 mono_marshal_cleanup ();
363 mono_type_initialization_cleanup ();
365 mono_monitor_cleanup ();
368 static MonoDomainFunc quit_function = NULL;
371 mono_install_runtime_cleanup (MonoDomainFunc func)
373 quit_function = func;
379 if (quit_function != NULL)
380 quit_function (mono_get_root_domain (), NULL);
384 * mono_domain_create_appdomain:
385 * @friendly_name: The friendly name of the appdomain to create
386 * @configuration_file: The configuration file to initialize the appdomain with
388 * Returns a MonoDomain initialized with the appdomain
391 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
394 MonoAppDomainSetup *setup;
397 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
398 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
399 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
401 ad = mono_domain_create_appdomain_internal (friendly_name, setup);
403 return mono_domain_from_appdomain (ad);
407 * mono_domain_set_config:
408 * @domain: MonoDomain initialized with the appdomain we want to change
409 * @base_dir: new base directory for the appdomain
410 * @config_file_name: path to the new configuration for the app domain
412 * Used to set the system configuration for an appdomain
414 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
415 * Error Initializing the configuration system. ---> System.ArgumentException:
416 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
419 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
421 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
422 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
425 static MonoAppDomainSetup*
426 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
428 MonoDomain *caller_domain = mono_domain_get ();
429 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
430 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
432 mono_domain_set_internal (domain);
434 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
435 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
436 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
437 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
438 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
439 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
440 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
441 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
442 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
443 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
444 copy->publisher_policy = setup->publisher_policy;
445 copy->path_changed = setup->path_changed;
446 copy->loader_optimization = setup->loader_optimization;
447 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
448 copy->disallow_code_downloads = setup->disallow_code_downloads;
449 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
450 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
451 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
452 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
453 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
455 mono_domain_set_internal (caller_domain);
460 static MonoAppDomain *
461 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
467 char *shadow_location;
471 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
473 /* FIXME: pin all those objects */
474 data = mono_domain_create();
476 ad = (MonoAppDomain *) mono_object_new (data, adclass);
479 data->friendly_name = g_strdup (friendly_name);
481 if (!setup->application_base) {
482 /* Inherit from the root domain since MS.NET does this */
483 MonoDomain *root = mono_get_root_domain ();
484 if (root->setup->application_base)
485 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)));
488 mono_context_init (data);
490 data->setup = copy_app_domain_setup (data, setup);
491 mono_set_private_bin_path_from_config (data);
492 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
494 #ifndef DISABLE_SHADOW_COPY
495 /*FIXME, guard this for when the debugger is not running */
496 shadow_location = get_shadow_assembly_location_base (data, &error);
497 if (!mono_error_ok (&error))
498 mono_error_raise_exception (&error);
499 g_free (shadow_location);
502 create_domain_objects (data);
508 * mono_domain_has_type_resolve:
509 * @domain: application domains being looked up
511 * Returns true if the AppDomain.TypeResolve field has been
515 mono_domain_has_type_resolve (MonoDomain *domain)
517 static MonoClassField *field = NULL;
521 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
525 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
529 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
534 * mono_domain_try_type_resolve:
535 * @domain: application domainwhere the name where the type is going to be resolved
536 * @name: the name of the type to resolve or NULL.
537 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
539 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
540 * the assembly that matches name.
542 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
544 * Returns: A MonoReflectionAssembly or NULL if not found
546 MonoReflectionAssembly *
547 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
551 static MonoMethod *method = NULL;
553 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
555 if (method == NULL) {
556 klass = domain->domain->mbr.obj.vtable->klass;
559 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
560 if (method == NULL) {
561 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
567 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
570 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
574 * mono_domain_owns_vtable_slot:
576 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
579 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
583 mono_domain_lock (domain);
584 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
585 mono_domain_unlock (domain);
592 * @force: force setting.
594 * Set the current appdomain to @domain. If @force is set, set it even
595 * if it is being unloaded.
599 * FALSE if the domain is unloaded
602 mono_domain_set (MonoDomain *domain, gboolean force)
604 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
607 mono_domain_set_internal (domain);
613 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
621 g_assert (ad != NULL);
623 g_assert (add != NULL);
626 mono_raise_exception (mono_get_exception_argument_null ("name"));
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)
669 g_assert (ad != NULL);
671 g_assert (add != NULL);
674 mono_raise_exception (mono_get_exception_argument_null ("name"));
676 mono_domain_lock (add);
678 mono_g_hash_table_insert (add->env, name, data);
680 mono_domain_unlock (add);
684 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
688 g_assert (ad != NULL);
689 g_assert (ad->data != NULL);
691 return ad->data->setup;
695 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
699 g_assert (ad != NULL);
700 g_assert (ad->data != NULL);
702 return mono_string_new (ad->data, ad->data->friendly_name);
706 ves_icall_System_AppDomain_getCurDomain ()
708 MonoDomain *add = mono_domain_get ();
716 ves_icall_System_AppDomain_getRootDomain ()
718 MonoDomain *root = mono_get_root_domain ();
726 get_attribute_value (const gchar **attribute_names,
727 const gchar **attribute_values,
728 const char *att_name)
731 for (n = 0; attribute_names [n] != NULL; n++) {
732 if (strcmp (attribute_names [n], att_name) == 0)
733 return g_strdup (attribute_values [n]);
739 start_element (GMarkupParseContext *context,
740 const gchar *element_name,
741 const gchar **attribute_names,
742 const gchar **attribute_values,
746 RuntimeConfig *runtime_config = user_data;
748 if (strcmp (element_name, "runtime") == 0) {
749 runtime_config->runtime_count++;
753 if (strcmp (element_name, "assemblyBinding") == 0) {
754 runtime_config->assemblybinding_count++;
758 if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
761 if (strcmp (element_name, "probing") != 0)
764 g_free (runtime_config->domain->private_bin_path);
765 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
766 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
767 g_free (runtime_config->domain->private_bin_path);
768 runtime_config->domain->private_bin_path = NULL;
774 end_element (GMarkupParseContext *context,
775 const gchar *element_name,
779 RuntimeConfig *runtime_config = user_data;
780 if (strcmp (element_name, "runtime") == 0)
781 runtime_config->runtime_count--;
782 else if (strcmp (element_name, "assemblyBinding") == 0)
783 runtime_config->assemblybinding_count--;
787 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
789 RuntimeConfig *state = user_data;
791 const gchar *filename;
793 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
794 msg = error && error->message ? error->message : "";
795 g_warning ("Error parsing %s: %s", filename, msg);
798 static const GMarkupParser
808 mono_set_private_bin_path_from_config (MonoDomain *domain)
811 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
813 GMarkupParseContext *context;
814 RuntimeConfig runtime_config;
817 if (!domain || !domain->setup || !domain->setup->configuration_file)
820 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
821 if (!mono_error_ok (&error)) {
822 mono_error_cleanup (&error);
826 config_file_path = mono_portability_find_file (config_file_name, TRUE);
827 if (!config_file_path)
828 config_file_path = config_file_name;
830 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
833 runtime_config.runtime_count = 0;
834 runtime_config.assemblybinding_count = 0;
835 runtime_config.domain = domain;
836 runtime_config.filename = config_file_path;
839 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
840 offset = 3; /* Skip UTF-8 BOM */
842 context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
843 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
844 g_markup_parse_context_end_parse (context, NULL);
845 g_markup_parse_context_free (context);
849 if (config_file_name != config_file_path)
850 g_free (config_file_name);
851 g_free (config_file_path);
855 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
857 #ifdef DISABLE_APPDOMAINS
858 mono_raise_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
861 char *fname = mono_string_to_utf8 (friendly_name);
862 MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
871 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
873 MonoDomain *domain = ad->data;
875 static MonoClass *System_Reflection_Assembly;
879 GPtrArray *assemblies;
883 if (!System_Reflection_Assembly)
884 System_Reflection_Assembly = mono_class_from_name (
885 mono_defaults.corlib, "System.Reflection", "Assembly");
888 * Make a copy of the list of assemblies because we can't hold the assemblies
889 * lock while creating objects etc.
891 assemblies = g_ptr_array_new ();
892 /* Need to skip internal assembly builders created by remoting */
893 mono_domain_assemblies_lock (domain);
894 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
896 if (refonly != ass->ref_only)
898 if (ass->corlib_internal)
900 g_ptr_array_add (assemblies, ass);
902 mono_domain_assemblies_unlock (domain);
904 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
905 for (i = 0; i < assemblies->len; ++i) {
906 ass = g_ptr_array_index (assemblies, i);
907 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
910 g_ptr_array_free (assemblies, TRUE);
915 MonoReflectionAssembly *
916 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, gboolean refonly)
920 MonoBoolean isrefonly;
923 if (mono_runtime_get_no_exec ())
926 g_assert (domain != NULL && fname != NULL);
928 klass = domain->domain->mbr.obj.vtable->klass;
931 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
932 if (method == NULL) {
933 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
937 isrefonly = refonly ? 1 : 0;
939 params [1] = &isrefonly;
940 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
943 static MonoAssembly *
944 mono_domain_assembly_postload_search (MonoAssemblyName *aname,
947 gboolean refonly = GPOINTER_TO_UINT (user_data);
948 MonoReflectionAssembly *assembly;
949 MonoDomain *domain = mono_domain_get ();
953 aname_str = mono_stringify_assembly_name (aname);
955 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
956 str = mono_string_new (domain, aname_str);
961 assembly = mono_try_assembly_resolve (domain, str, refonly);
965 return assembly->assembly;
971 * LOCKING: assumes assemblies_lock in the domain is already locked.
974 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
978 gboolean destroy_ht = FALSE;
980 if (!ass->aname.name)
984 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
988 /* FIXME: handle lazy loaded assemblies */
989 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
990 g_hash_table_insert (ht, tmp->data, tmp->data);
992 if (!g_hash_table_lookup (ht, ass)) {
993 mono_assembly_addref (ass);
994 g_hash_table_insert (ht, ass, ass);
995 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
996 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);
999 if (ass->image->references) {
1000 for (i = 0; ass->image->references [i] != NULL; i++) {
1001 if (ass->image->references [i] != REFERENCE_MISSING)
1002 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1003 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1008 g_hash_table_destroy (ht);
1012 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1014 static MonoClassField *assembly_load_field;
1015 static MonoMethod *assembly_load_method;
1016 MonoDomain *domain = mono_domain_get ();
1017 MonoReflectionAssembly *ref_assembly;
1019 gpointer load_value;
1022 if (!domain->domain)
1023 /* This can happen during startup */
1025 #ifdef ASSEMBLY_LOAD_DEBUG
1026 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1028 klass = domain->domain->mbr.obj.vtable->klass;
1030 mono_domain_assemblies_lock (domain);
1031 add_assemblies_to_domain (domain, assembly, NULL);
1032 mono_domain_assemblies_unlock (domain);
1034 if (assembly_load_field == NULL) {
1035 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1036 g_assert (assembly_load_field);
1039 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1040 if (load_value == NULL) {
1041 /* No events waiting to be triggered */
1045 ref_assembly = mono_assembly_get_object (domain, assembly);
1046 g_assert (ref_assembly);
1048 if (assembly_load_method == NULL) {
1049 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1050 g_assert (assembly_load_method);
1053 *params = ref_assembly;
1054 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1058 * LOCKING: Acquires the domain assemblies lock.
1061 set_domain_search_path (MonoDomain *domain)
1064 MonoAppDomainSetup *setup;
1066 gchar *search_path = NULL;
1069 gchar **pvt_split = NULL;
1070 GError *gerror = NULL;
1071 gint appbaselen = -1;
1074 * We use the low-level domain assemblies lock, since this is called from
1075 * assembly loads hooks, which means this thread might hold the loader lock.
1077 mono_domain_assemblies_lock (domain);
1079 if (!domain->setup) {
1080 mono_domain_assemblies_unlock (domain);
1084 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1085 mono_domain_assemblies_unlock (domain);
1088 setup = domain->setup;
1089 if (!setup->application_base) {
1090 mono_domain_assemblies_unlock (domain);
1091 return; /* Must set application base to get private path working */
1096 if (setup->private_bin_path) {
1097 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1098 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1099 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1100 mono_error_cleanup (&error);
1101 mono_domain_assemblies_unlock (domain);
1106 if (domain->private_bin_path) {
1107 if (search_path == NULL)
1108 search_path = domain->private_bin_path;
1110 gchar *tmp2 = search_path;
1111 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1118 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1119 * directories relative to ApplicationBase separated by semicolons (see
1120 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1121 * The loop below copes with the fact that some Unix applications may use ':' (or
1122 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1123 * ';' for the subsequent split.
1125 * The issue was reported in bug #81446
1128 #ifndef TARGET_WIN32
1131 slen = strlen (search_path);
1132 for (i = 0; i < slen; i++)
1133 if (search_path [i] == ':')
1134 search_path [i] = ';';
1137 pvt_split = g_strsplit (search_path, ";", 1000);
1138 g_free (search_path);
1139 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1144 g_strfreev (pvt_split);
1146 * Don't do this because the first time is called, the domain
1147 * setup is not finished.
1149 * domain->search_path = g_malloc (sizeof (char *));
1150 * domain->search_path [0] = NULL;
1152 mono_domain_assemblies_unlock (domain);
1156 if (domain->search_path)
1157 g_strfreev (domain->search_path);
1159 tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1160 tmp [npaths] = NULL;
1162 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1163 if (!mono_error_ok (&error)) {
1164 mono_error_cleanup (&error);
1165 g_strfreev (pvt_split);
1168 mono_domain_assemblies_unlock (domain);
1172 domain->search_path = tmp;
1174 /* FIXME: is this needed? */
1175 if (strncmp (*tmp, "file://", 7) == 0) {
1181 uri = g_strdup_printf ("file:///%s", uri + 7);
1184 uri = mono_escape_uri_string (tmpuri);
1185 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1191 if (gerror != NULL) {
1192 g_warning ("%s\n", gerror->message);
1193 g_error_free (gerror);
1200 for (i = 1; pvt_split && i < npaths; i++) {
1201 if (g_path_is_absolute (pvt_split [i - 1])) {
1202 tmp [i] = g_strdup (pvt_split [i - 1]);
1204 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1207 if (strchr (tmp [i], '.')) {
1211 reduced = mono_path_canonicalize (tmp [i]);
1212 if (appbaselen == -1)
1213 appbaselen = strlen (tmp [0]);
1215 if (strncmp (tmp [0], reduced, appbaselen)) {
1218 tmp [i] = g_strdup ("");
1228 if (setup->private_bin_path_probe != NULL) {
1230 tmp [0] = g_strdup ("");
1233 domain->setup->path_changed = FALSE;
1235 g_strfreev (pvt_split);
1237 mono_domain_assemblies_unlock (domain);
1240 #ifdef DISABLE_SHADOW_COPY
1242 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1248 mono_make_shadow_copy (const char *filename)
1250 return (char *) filename;
1254 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1256 guint16 *orig, *dest;
1257 gboolean copy_result;
1259 strcpy (src + srclen - tail_len, extension);
1261 if (IS_PORTABILITY_CASE) {
1262 gchar *file = mono_portability_find_file (src, TRUE);
1268 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1272 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1274 strcpy (target + targetlen - tail_len, extension);
1275 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1278 copy_result = CopyFile (orig, dest, FALSE);
1280 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1281 * overwritten when updated in their original locations. */
1283 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1292 get_cstring_hash (const char *str)
1298 if (!str || !str [0])
1303 for (i = 0; i < len; i++) {
1304 h = (h << 5) - h + *p;
1312 * Returned memory is malloc'd. Called must free it
1315 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1317 MonoAppDomainSetup *setup;
1318 char *cache_path, *appname;
1322 mono_error_init (error);
1324 setup = domain->setup;
1325 if (setup->cache_path != NULL && setup->application_name != NULL) {
1326 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1327 if (!mono_error_ok (error))
1329 #ifndef TARGET_WIN32
1332 for (i = strlen (cache_path) - 1; i >= 0; i--)
1333 if (cache_path [i] == '\\')
1334 cache_path [i] = '/';
1338 appname = mono_string_to_utf8_checked (setup->application_name, error);
1339 if (!mono_error_ok (error)) {
1340 g_free (cache_path);
1344 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1346 g_free (cache_path);
1348 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1349 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1356 get_shadow_assembly_location (const char *filename, MonoError *error)
1358 gint32 hash = 0, hash2 = 0;
1360 char path_hash [30];
1361 char *bname = g_path_get_basename (filename);
1362 char *dirname = g_path_get_dirname (filename);
1363 char *location, *tmploc;
1364 MonoDomain *domain = mono_domain_get ();
1366 mono_error_init (error);
1368 hash = get_cstring_hash (bname);
1369 hash2 = get_cstring_hash (dirname);
1370 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1371 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1372 tmploc = get_shadow_assembly_location_base (domain, error);
1373 if (!mono_error_ok (error)) {
1379 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1387 ensure_directory_exists (const char *filename)
1390 gchar *dir_utf8 = g_path_get_dirname (filename);
1392 gunichar2 *dir_utf16 = NULL;
1395 if (!dir_utf8 || !dir_utf8 [0])
1398 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1406 /* make life easy and only use one directory seperator */
1417 while (*p++ != '\\')
1423 p = wcschr (p, '\\');
1426 retval = _wmkdir (dir_utf16);
1427 if (retval != 0 && errno != EEXIST) {
1440 gchar *dir = g_path_get_dirname (filename);
1444 if (!dir || !dir [0]) {
1449 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1459 p = strchr (p, '/');
1462 retval = mkdir (dir, 0777);
1463 if (retval != 0 && errno != EEXIST) {
1478 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1480 struct stat sbuf_dest;
1482 gchar *real_src = mono_portability_find_file (src, TRUE);
1485 stat_src = (gchar*)src;
1487 stat_src = real_src;
1489 if (stat (stat_src, sbuf_src) == -1) {
1490 time_t tnow = time (NULL);
1495 memset (sbuf_src, 0, sizeof (*sbuf_src));
1496 sbuf_src->st_mtime = tnow;
1497 sbuf_src->st_atime = tnow;
1504 if (stat (dest, &sbuf_dest) == -1)
1507 if (sbuf_src->st_size == sbuf_dest.st_size &&
1508 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1515 shadow_copy_create_ini (const char *shadow, const char *filename)
1525 dir_name = g_path_get_dirname (shadow);
1526 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1528 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1533 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1538 handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1539 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1541 if (handle == INVALID_HANDLE_VALUE) {
1545 full_path = mono_path_resolve_symlinks (filename);
1546 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1548 CloseHandle (handle);
1553 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1556 MonoAppDomainSetup *setup;
1559 gchar **directories;
1560 gchar *shadow_status_string;
1562 gboolean shadow_enabled;
1563 gboolean found = FALSE;
1568 setup = domain->setup;
1569 if (setup == NULL || setup->shadow_copy_files == NULL)
1572 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1573 if (!mono_error_ok (&error)) {
1574 mono_error_cleanup (&error);
1577 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1578 g_free (shadow_status_string);
1580 if (!shadow_enabled)
1583 if (setup->shadow_copy_directories == NULL)
1586 /* Is dir_name a shadow_copy destination already? */
1587 base_dir = get_shadow_assembly_location_base (domain, &error);
1588 if (!mono_error_ok (&error)) {
1589 mono_error_cleanup (&error);
1593 if (strstr (dir_name, base_dir)) {
1599 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1600 if (!mono_error_ok (&error)) {
1601 mono_error_cleanup (&error);
1605 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1606 dir_ptr = directories;
1608 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1614 g_strfreev (directories);
1620 This function raises exceptions so it can cause as sorts of nasty stuff if called
1621 while holding a lock.
1622 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1623 or NULL if source file not found.
1624 FIXME bubble up the error instead of raising it here
1627 mono_make_shadow_copy (const char *filename)
1630 gchar *sibling_source, *sibling_target;
1631 gint sibling_source_len, sibling_target_len;
1632 guint16 *orig, *dest;
1635 gboolean copy_result;
1637 struct stat src_sbuf;
1638 struct utimbuf utbuf;
1639 char *dir_name = g_path_get_dirname (filename);
1640 MonoDomain *domain = mono_domain_get ();
1643 set_domain_search_path (domain);
1645 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1647 return (char *) filename;
1650 /* Is dir_name a shadow_copy destination already? */
1651 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1652 if (!mono_error_ok (&error)) {
1653 mono_error_cleanup (&error);
1655 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1656 mono_raise_exception (exc);
1659 if (strstr (dir_name, shadow_dir)) {
1660 g_free (shadow_dir);
1662 return (char *) filename;
1664 g_free (shadow_dir);
1667 shadow = get_shadow_assembly_location (filename, &error);
1668 if (!mono_error_ok (&error)) {
1669 mono_error_cleanup (&error);
1670 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1671 mono_raise_exception (exc);
1674 if (ensure_directory_exists (shadow) == FALSE) {
1676 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1677 mono_raise_exception (exc);
1680 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1681 return (char*) shadow;
1683 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1684 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1687 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1688 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1689 * and not have it runtime error" */
1690 attrs = GetFileAttributes (orig);
1691 if (attrs == INVALID_FILE_ATTRIBUTES) {
1693 return (char *)filename;
1696 copy_result = CopyFile (orig, dest, FALSE);
1698 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1699 * overwritten when updated in their original locations. */
1701 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1706 if (copy_result == FALSE) {
1709 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1710 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1711 return NULL; /* file not found, shadow copy failed */
1713 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1714 mono_raise_exception (exc);
1717 /* attempt to copy .mdb, .config if they exist */
1718 sibling_source = g_strconcat (filename, ".config", NULL);
1719 sibling_source_len = strlen (sibling_source);
1720 sibling_target = g_strconcat (shadow, ".config", NULL);
1721 sibling_target_len = strlen (sibling_target);
1723 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1724 if (copy_result == TRUE)
1725 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1727 g_free (sibling_source);
1728 g_free (sibling_target);
1730 if (copy_result == FALSE) {
1732 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1733 mono_raise_exception (exc);
1736 /* Create a .ini file containing the original assembly location */
1737 if (!shadow_copy_create_ini (shadow, filename)) {
1739 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1740 mono_raise_exception (exc);
1743 utbuf.actime = src_sbuf.st_atime;
1744 utbuf.modtime = src_sbuf.st_mtime;
1745 utime (shadow, &utbuf);
1749 #endif /* DISABLE_SHADOW_COPY */
1752 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1754 if (appdomain == NULL)
1757 return appdomain->data;
1761 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1762 const gchar *path3, const gchar *path4,
1763 gboolean refonly, gboolean is_private)
1766 gboolean found = FALSE;
1769 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1771 if (IS_PORTABILITY_SET) {
1772 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1775 fullpath = new_fullpath;
1779 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1782 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1785 return (*assembly != NULL);
1788 static MonoAssembly *
1789 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1791 MonoAssembly *result = NULL;
1794 const gchar *local_culture;
1796 gboolean is_private = FALSE;
1798 if (!culture || *culture == '\0') {
1801 local_culture = culture;
1804 filename = g_strconcat (name, ".dll", NULL);
1805 len = strlen (filename);
1807 for (path = search_path; *path; path++) {
1808 if (**path == '\0') {
1810 continue; /* Ignore empty ApplicationBase */
1813 /* See test cases in bug #58992 and bug #57710 */
1814 /* 1st try: [culture]/[name].dll (culture may be empty) */
1815 strcpy (filename + len - 4, ".dll");
1816 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1819 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1820 strcpy (filename + len - 4, ".exe");
1821 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1824 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1825 strcpy (filename + len - 4, ".dll");
1826 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1829 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1830 strcpy (filename + len - 4, ".exe");
1831 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1840 * Try loading the assembly from ApplicationBase and PrivateBinPath
1841 * and then from assemblies_path if any.
1842 * LOCKING: This is called from the assembly loading code, which means the caller
1843 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1845 static MonoAssembly *
1846 mono_domain_assembly_preload (MonoAssemblyName *aname,
1847 gchar **assemblies_path,
1850 MonoDomain *domain = mono_domain_get ();
1851 MonoAssembly *result = NULL;
1852 gboolean refonly = GPOINTER_TO_UINT (user_data);
1854 set_domain_search_path (domain);
1856 if (domain->search_path && domain->search_path [0] != NULL) {
1857 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1860 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1861 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1868 * Check whenever a given assembly was already loaded in the current appdomain.
1870 static MonoAssembly *
1871 mono_domain_assembly_search (MonoAssemblyName *aname,
1874 MonoDomain *domain = mono_domain_get ();
1877 gboolean refonly = GPOINTER_TO_UINT (user_data);
1879 mono_domain_assemblies_lock (domain);
1880 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1882 /* Dynamic assemblies can't match here in MS.NET */
1883 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1886 mono_domain_assemblies_unlock (domain);
1889 mono_domain_assemblies_unlock (domain);
1894 MonoReflectionAssembly *
1895 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1897 MonoDomain *domain = mono_domain_get ();
1898 char *name, *filename;
1899 MonoImageOpenStatus status = MONO_IMAGE_OK;
1902 MONO_ARCH_SAVE_REGS;
1904 if (fname == NULL) {
1905 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1906 mono_raise_exception (exc);
1909 name = filename = mono_string_to_utf8 (fname);
1911 ass = mono_assembly_open_full (filename, &status, refOnly);
1916 if (status == MONO_IMAGE_IMAGE_INVALID)
1917 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1919 exc = mono_get_exception_file_not_found2 (NULL, fname);
1921 mono_raise_exception (exc);
1926 return mono_assembly_get_object (domain, ass);
1929 MonoReflectionAssembly *
1930 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1931 MonoArray *raw_assembly,
1932 MonoArray *raw_symbol_store, MonoObject *evidence,
1933 MonoBoolean refonly)
1936 MonoReflectionAssembly *refass = NULL;
1937 MonoDomain *domain = ad->data;
1938 MonoImageOpenStatus status;
1939 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1940 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1943 mono_raise_exception (mono_get_exception_bad_image_format (""));
1947 if (raw_symbol_store != NULL)
1948 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1950 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1954 mono_image_close (image);
1955 mono_raise_exception (mono_get_exception_bad_image_format (""));
1959 refass = mono_assembly_get_object (domain, ass);
1960 MONO_OBJECT_SETREF (refass, evidence, evidence);
1964 MonoReflectionAssembly *
1965 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1967 MonoDomain *domain = ad->data;
1968 MonoImageOpenStatus status = MONO_IMAGE_OK;
1970 MonoAssemblyName aname;
1971 MonoReflectionAssembly *refass = NULL;
1975 MONO_ARCH_SAVE_REGS;
1977 g_assert (assRef != NULL);
1979 name = mono_string_to_utf8 (assRef);
1980 parsed = mono_assembly_name_parse (name, &aname);
1984 /* This is a parse error... */
1986 refass = mono_try_assembly_resolve (domain, assRef, refOnly);
1990 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1991 mono_assembly_name_free (&aname);
1994 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1996 refass = mono_try_assembly_resolve (domain, assRef, refOnly);
2005 refass = mono_assembly_get_object (domain, ass);
2007 MONO_OBJECT_SETREF (refass, evidence, evidence);
2012 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2014 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2016 MONO_ARCH_SAVE_REGS;
2018 if (NULL == domain) {
2019 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2020 mono_raise_exception (exc);
2023 if (domain == mono_get_root_domain ()) {
2024 mono_raise_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2029 * Unloading seems to cause problems when running NUnit/NAnt, hence
2032 if (g_getenv ("MONO_NO_UNLOAD"))
2034 #ifdef __native_client__
2038 mono_domain_unload (domain);
2042 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2044 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2049 return mono_domain_is_unloading (domain);
2053 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2054 MonoReflectionAssembly *refass, MonoArray *args)
2059 MONO_ARCH_SAVE_REGS;
2062 image = refass->assembly->image;
2065 method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
2068 g_error ("No entry point method found in %s", image->name);
2071 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2073 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2077 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2079 MONO_ARCH_SAVE_REGS;
2081 return ad->data->domain_id;
2085 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2087 MonoDomain *old_domain = mono_domain_get();
2089 MONO_ARCH_SAVE_REGS;
2091 if (!mono_domain_set (ad->data, FALSE))
2092 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2094 return old_domain->domain;
2098 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2100 MonoDomain *current_domain = mono_domain_get ();
2101 MonoDomain *domain = mono_domain_get_by_id (domainid);
2103 MONO_ARCH_SAVE_REGS;
2105 if (!domain || !mono_domain_set (domain, FALSE))
2106 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2108 return current_domain->domain;
2112 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2114 MONO_ARCH_SAVE_REGS;
2116 mono_thread_push_appdomain_ref (ad->data);
2120 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2122 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2124 MONO_ARCH_SAVE_REGS;
2128 * Raise an exception to prevent the managed code from executing a pop
2131 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2133 mono_thread_push_appdomain_ref (domain);
2137 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2139 MONO_ARCH_SAVE_REGS;
2141 mono_thread_pop_appdomain_ref ();
2145 ves_icall_System_AppDomain_InternalGetContext ()
2147 MONO_ARCH_SAVE_REGS;
2149 return mono_context_get ();
2153 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2155 MONO_ARCH_SAVE_REGS;
2157 return mono_domain_get ()->default_context;
2161 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2163 MonoAppContext *old_context = mono_context_get ();
2165 MONO_ARCH_SAVE_REGS;
2167 mono_context_set (mc);
2173 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2175 MonoDomain* mono_root_domain = mono_get_root_domain ();
2176 mono_domain_lock (mono_root_domain);
2177 if (process_guid_set) {
2178 mono_domain_unlock (mono_root_domain);
2179 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2181 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2182 process_guid_set = TRUE;
2183 mono_domain_unlock (mono_root_domain);
2188 mono_domain_is_unloading (MonoDomain *domain)
2190 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2197 clear_cached_vtable (MonoVTable *vtable)
2199 MonoClass *klass = vtable->klass;
2200 MonoDomain *domain = vtable->domain;
2201 MonoClassRuntimeInfo *runtime_info;
2204 runtime_info = klass->runtime_info;
2205 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2206 runtime_info->domain_vtables [domain->domain_id] = NULL;
2207 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2208 mono_gc_free_fixed (data);
2211 static G_GNUC_UNUSED void
2212 zero_static_data (MonoVTable *vtable)
2214 MonoClass *klass = vtable->klass;
2217 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2218 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2221 typedef struct unload_data {
2224 char *failure_reason;
2229 unload_data_unref (unload_data *data)
2233 mono_atomic_load_acquire (count, gint32, &data->refcount);
2234 g_assert (count >= 1 && count <= 2);
2239 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2243 deregister_reflection_info_roots_from_list (MonoImage *image)
2245 GSList *list = image->reflection_info_unregister_classes;
2248 MonoClass *class = list->data;
2250 mono_class_free_ref_info (class);
2255 image->reflection_info_unregister_classes = NULL;
2259 deregister_reflection_info_roots (MonoDomain *domain)
2263 mono_domain_assemblies_lock (domain);
2264 for (list = domain->domain_assemblies; list; list = list->next) {
2265 MonoAssembly *assembly = list->data;
2266 MonoImage *image = assembly->image;
2270 * No need to take the image lock here since dynamic images are appdomain bound and
2271 * at this point the mutator is gone. Taking the image lock here would mean
2272 * promoting it from a simple lock to a complex lock, which we better avoid if
2275 if (image_is_dynamic (image))
2276 deregister_reflection_info_roots_from_list (image);
2278 for (i = 0; i < image->module_count; ++i) {
2279 MonoImage *module = image->modules [i];
2280 if (module && image_is_dynamic (module))
2281 deregister_reflection_info_roots_from_list (module);
2284 mono_domain_assemblies_unlock (domain);
2287 static guint32 WINAPI
2288 unload_thread_main (void *arg)
2290 unload_data *data = (unload_data*)arg;
2291 MonoDomain *domain = data->domain;
2295 /* Have to attach to the runtime so shutdown can wait for this thread */
2296 /* Force it to be attached to avoid racing during shutdown. */
2297 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2300 * FIXME: Abort our parent thread last, so we can return a failure
2301 * indication if aborting times out.
2303 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2304 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2308 if (!mono_thread_pool_remove_domain_jobs (domain, -1)) {
2309 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2313 /* Finalize all finalizable objects in the doomed appdomain */
2314 if (!mono_domain_finalize (domain, -1)) {
2315 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2319 /* Clear references to our vtables in class->runtime_info.
2320 * We also hold the loader lock because we're going to change
2321 * class->runtime_info.
2324 mono_loader_lock ();
2325 mono_domain_lock (domain);
2328 * We need to make sure that we don't have any remsets
2329 * pointing into static data of the to-be-freed domain because
2330 * at the next collections they would be invalid. So what we
2331 * do is we first zero all static data and then do a minor
2332 * collection. Because all references in the static data will
2333 * now be null we won't do any unnecessary copies and after
2334 * the collection there won't be any more remsets.
2336 for (i = 0; i < domain->class_vtable_array->len; ++i)
2337 zero_static_data (g_ptr_array_index (domain->class_vtable_array, i));
2338 mono_gc_collect (0);
2340 for (i = 0; i < domain->class_vtable_array->len; ++i)
2341 clear_cached_vtable (g_ptr_array_index (domain->class_vtable_array, i));
2342 deregister_reflection_info_roots (domain);
2344 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2346 mono_domain_unlock (domain);
2347 mono_loader_unlock ();
2349 mono_threads_clear_cached_culture (domain);
2351 domain->state = MONO_APPDOMAIN_UNLOADED;
2353 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2355 /* remove from the handle table the items related to this domain */
2356 mono_gchandle_free_domain (domain);
2358 mono_domain_free (domain, FALSE);
2360 mono_gc_collect (mono_gc_max_generation ());
2362 mono_atomic_store_release (&data->done, TRUE);
2363 unload_data_unref (data);
2364 mono_thread_detach (thread);
2368 mono_atomic_store_release (&data->done, TRUE);
2369 unload_data_unref (data);
2370 mono_thread_detach (thread);
2375 * mono_domain_unload:
2376 * @domain: The domain to unload
2378 * Unloads an appdomain. Follows the process outlined in the comment
2379 * for mono_domain_try_unload.
2382 mono_domain_unload (MonoDomain *domain)
2384 MonoObject *exc = NULL;
2385 mono_domain_try_unload (domain, &exc);
2387 mono_raise_exception ((MonoException*)exc);
2391 * mono_domain_unload:
2392 * @domain: The domain to unload
2393 * @exc: Exception information
2395 * Unloads an appdomain. Follows the process outlined in:
2396 * http://blogs.gotdotnet.com/cbrumme
2398 * If doing things the 'right' way is too hard or complex, we do it the
2399 * 'simple' way, which means do everything needed to avoid crashes and
2400 * memory leaks, but not much else.
2402 * It is required to pass a valid reference to the exc argument, upon return
2403 * from this function *exc will be set to the exception thrown, if any.
2405 * If this method is not called from an icall (embedded scenario for instance),
2406 * it must not be called with any managed frames on the stack, since the unload
2407 * process could end up trying to abort the current thread.
2410 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2412 HANDLE thread_handle;
2413 MonoAppDomainState prev_state;
2415 unload_data *thread_data;
2416 MonoNativeThreadId tid;
2417 MonoDomain *caller_domain = mono_domain_get ();
2420 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2422 /* Atomically change our state to UNLOADING */
2423 prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2424 MONO_APPDOMAIN_UNLOADING_START,
2425 MONO_APPDOMAIN_CREATED);
2426 if (prev_state != MONO_APPDOMAIN_CREATED) {
2427 switch (prev_state) {
2428 case MONO_APPDOMAIN_UNLOADING_START:
2429 case MONO_APPDOMAIN_UNLOADING:
2430 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2432 case MONO_APPDOMAIN_UNLOADED:
2433 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2436 g_warning ("Invalid appdomain state %d", prev_state);
2437 g_assert_not_reached ();
2441 mono_domain_set (domain, FALSE);
2442 /* Notify OnDomainUnload listeners */
2443 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2446 mono_runtime_invoke (method, domain->domain, NULL, exc);
2448 /* Roll back the state change */
2449 domain->state = MONO_APPDOMAIN_CREATED;
2450 mono_domain_set (caller_domain, FALSE);
2453 mono_domain_set (caller_domain, FALSE);
2455 thread_data = g_new0 (unload_data, 1);
2456 thread_data->domain = domain;
2457 thread_data->failure_reason = NULL;
2458 thread_data->done = FALSE;
2459 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2461 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2462 domain->state = MONO_APPDOMAIN_UNLOADING;
2464 * First we create a separate thread for unloading, since
2465 * we might have to abort some threads, including the current one.
2467 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2468 if (thread_handle == NULL)
2470 name = g_strdup_printf ("Unload thread for domain %x", domain);
2471 mono_thread_info_set_name (tid, name);
2472 mono_thread_info_resume (tid);
2475 /* Wait for the thread */
2476 while (!thread_data->done && WaitForSingleObjectEx (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2477 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2478 /* The unload thread tries to abort us */
2479 /* The icall wrapper will execute the abort */
2480 CloseHandle (thread_handle);
2481 unload_data_unref (thread_data);
2485 CloseHandle (thread_handle);
2487 if (thread_data->failure_reason) {
2488 /* Roll back the state change */
2489 domain->state = MONO_APPDOMAIN_CREATED;
2491 g_warning ("%s", thread_data->failure_reason);
2493 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2495 g_free (thread_data->failure_reason);
2496 thread_data->failure_reason = NULL;
2499 unload_data_unref (thread_data);