2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
13 #undef ASSEMBLY_LOAD_DEBUG
19 #include <sys/types.h>
21 #ifdef HAVE_SYS_TIME_H
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
35 #include <mono/metadata/gc-internals.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/threadpool-ms.h>
43 #include <mono/metadata/socket-io.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/gc-internals.h>
46 #include <mono/metadata/mono-gc.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/monitor.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/utils/mono-uri.h>
59 #include <mono/utils/mono-logger-internals.h>
60 #include <mono/utils/mono-path.h>
61 #include <mono/utils/mono-stdlib.h>
62 #include <mono/utils/mono-io-portability.h>
63 #include <mono/utils/mono-error-internals.h>
64 #include <mono/utils/atomic.h>
65 #include <mono/utils/mono-memory-model.h>
66 #include <mono/utils/mono-threads.h>
72 * This is the version number of the corlib-runtime interface. When
73 * making changes to this interface (by changing the layout
74 * of classes the runtime knows about, changing icall signature or
75 * semantics etc), increment this variable. Also increment the
76 * pair of this variable in mscorlib in:
77 * mcs/class/corlib/System/Environment.cs
79 * Changes which are already detected at runtime, like the addition
80 * of icalls, do not require an increment.
82 #define MONO_CORLIB_VERSION 139
87 int assemblybinding_count;
92 static gunichar2 process_guid [36];
93 static gboolean process_guid_set = FALSE;
95 static gboolean no_exec = FALSE;
98 mono_domain_assembly_preload (MonoAssemblyName *aname,
99 gchar **assemblies_path,
102 static MonoAssembly *
103 mono_domain_assembly_search (MonoAssemblyName *aname,
107 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
110 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
112 static MonoAppDomain *
113 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
116 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
118 static MonoLoadFunc load_function = NULL;
121 mono_install_runtime_load (MonoLoadFunc func)
123 load_function = func;
127 mono_runtime_load (const char *filename, const char *runtime_version)
129 g_assert (load_function);
130 return load_function (filename, runtime_version);
134 * mono_runtime_set_no_exec:
136 * Instructs the runtime to operate in static mode, i.e. avoid/do not
137 * allow managed code execution. This is useful for running the AOT
138 * compiler on platforms which allow full-aot execution only. This
139 * should be called before mono_runtime_init ().
142 mono_runtime_set_no_exec (gboolean val)
148 * mono_runtime_get_no_exec:
150 * If true, then the runtime will not allow managed code execution.
153 mono_runtime_get_no_exec (void)
159 create_domain_objects (MonoDomain *domain)
161 MonoDomain *old_domain = mono_domain_get ();
163 MonoVTable *string_vt;
164 MonoClassField *string_empty_fld;
166 if (domain != old_domain) {
167 mono_thread_push_appdomain_ref (domain);
168 mono_domain_set_internal_with_options (domain, FALSE);
172 * Initialize String.Empty. This enables the removal of
173 * the static cctor of the String class.
175 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
176 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
177 g_assert (string_empty_fld);
178 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
181 * Create an instance early since we can't do it when there is no memory.
183 arg = mono_string_new (domain, "Out of memory");
184 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
187 * These two are needed because the signal handlers might be executing on
188 * an alternate stack, and Boehm GC can't handle that.
190 arg = mono_string_new (domain, "A null value was found where an object instance was required");
191 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
192 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
193 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
195 /*The ephemeron tombstone i*/
196 domain->ephemeron_tombstone = mono_object_new (domain, mono_defaults.object_class);
198 if (domain != old_domain) {
199 mono_thread_pop_appdomain_ref ();
200 mono_domain_set_internal_with_options (old_domain, FALSE);
204 * This class is used during exception handling, so initialize it here, to prevent
205 * stack overflows while handling stack overflows.
207 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
212 * @domain: domain returned by mono_init ()
214 * Initialize the core AppDomain: this function will run also some
215 * IL initialization code, so it needs the execution engine to be fully
218 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
219 * we know the entry_assembly.
223 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
224 MonoThreadAttachCB attach_cb)
226 MonoAppDomainSetup *setup;
230 mono_portability_helpers_init ();
232 mono_gc_base_init ();
233 mono_monitor_init ();
234 mono_marshal_init ();
236 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
237 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
238 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
239 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
240 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
241 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
242 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
243 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
245 mono_thread_init (start_cb, attach_cb);
247 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
248 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass);
250 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
251 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass);
254 domain->setup = setup;
256 mono_thread_attach (domain);
258 mono_type_initialization_init ();
260 if (!mono_runtime_get_no_exec ())
261 create_domain_objects (domain);
263 /* GC init has to happen after thread init */
266 /* contexts use GC handles, so they must be initialized after the GC */
267 mono_context_init (domain);
268 mono_context_set (domain->default_context);
270 #ifndef DISABLE_SOCKETS
271 mono_network_init ();
274 mono_console_init ();
277 mono_locks_tracer_init ();
279 /* mscorlib is loaded before we install the load hook */
280 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
286 mono_get_corlib_version (void)
289 MonoClassField *field;
292 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
293 mono_class_init (klass);
294 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
297 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
299 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
300 return *(gint32*)((gchar*)value + sizeof (MonoObject));
304 * mono_check_corlib_version
306 * Checks that the corlib that is loaded matches the version of this runtime.
308 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
309 * allocated string with the error otherwise.
312 mono_check_corlib_version (void)
314 int version = mono_get_corlib_version ();
315 if (version != MONO_CORLIB_VERSION)
316 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
323 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
325 * Initializes the @domain's default System.Runtime.Remoting's Context.
328 mono_context_init (MonoDomain *domain)
331 MonoAppContext *context;
333 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
334 context = (MonoAppContext *) mono_object_new_pinned (domain, klass);
335 context->domain_id = domain->domain_id;
336 context->context_id = 0;
337 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
338 domain->default_context = context;
342 * mono_runtime_cleanup:
347 * This must not be called while there are still running threads executing
351 mono_runtime_cleanup (MonoDomain *domain)
353 mono_attach_cleanup ();
355 /* This ends up calling any pending pending (for at most 2 seconds) */
358 mono_thread_cleanup ();
360 #ifndef DISABLE_SOCKETS
361 mono_network_cleanup ();
363 mono_marshal_cleanup ();
365 mono_type_initialization_cleanup ();
367 mono_monitor_cleanup ();
370 static MonoDomainFunc quit_function = NULL;
373 mono_install_runtime_cleanup (MonoDomainFunc func)
375 quit_function = func;
381 if (quit_function != NULL)
382 quit_function (mono_get_root_domain (), NULL);
386 * mono_domain_create_appdomain:
387 * @friendly_name: The friendly name of the appdomain to create
388 * @configuration_file: The configuration file to initialize the appdomain with
390 * Returns a MonoDomain initialized with the appdomain
393 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
396 MonoAppDomainSetup *setup;
399 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
400 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), klass);
401 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
403 ad = mono_domain_create_appdomain_internal (friendly_name, setup);
405 return mono_domain_from_appdomain (ad);
409 * mono_domain_set_config:
410 * @domain: MonoDomain initialized with the appdomain we want to change
411 * @base_dir: new base directory for the appdomain
412 * @config_file_name: path to the new configuration for the app domain
414 * Used to set the system configuration for an appdomain
416 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
417 * Error Initializing the configuration system. ---> System.ArgumentException:
418 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
421 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
423 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
424 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
427 static MonoAppDomainSetup*
428 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
430 MonoDomain *caller_domain = mono_domain_get ();
431 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
432 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
434 mono_domain_set_internal (domain);
436 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
437 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
438 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
439 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
440 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
441 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
442 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
443 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
444 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
445 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
446 copy->publisher_policy = setup->publisher_policy;
447 copy->path_changed = setup->path_changed;
448 copy->loader_optimization = setup->loader_optimization;
449 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
450 copy->disallow_code_downloads = setup->disallow_code_downloads;
451 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
452 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
453 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
454 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
455 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
457 mono_domain_set_internal (caller_domain);
462 static MonoAppDomain *
463 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
469 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 mono_profiler_appdomain_name (data, data->friendly_name);
483 if (!setup->application_base) {
484 /* Inherit from the root domain since MS.NET does this */
485 MonoDomain *root = mono_get_root_domain ();
486 if (root->setup->application_base)
487 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)));
490 mono_context_init (data);
492 data->setup = copy_app_domain_setup (data, setup);
493 mono_set_private_bin_path_from_config (data);
494 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
496 #ifndef DISABLE_SHADOW_COPY
497 /*FIXME, guard this for when the debugger is not running */
498 shadow_location = get_shadow_assembly_location_base (data, &error);
499 if (!mono_error_ok (&error))
500 mono_error_raise_exception (&error);
501 g_free (shadow_location);
504 create_domain_objects (data);
510 * mono_domain_has_type_resolve:
511 * @domain: application domains being looked up
513 * Returns true if the AppDomain.TypeResolve field has been
517 mono_domain_has_type_resolve (MonoDomain *domain)
519 static MonoClassField *field = NULL;
523 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
527 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
531 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
536 * mono_domain_try_type_resolve:
537 * @domain: application domainwhere the name where the type is going to be resolved
538 * @name: the name of the type to resolve or NULL.
539 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
541 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
542 * the assembly that matches name.
544 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
546 * Returns: A MonoReflectionAssembly or NULL if not found
548 MonoReflectionAssembly *
549 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
553 static MonoMethod *method = NULL;
555 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
557 if (method == NULL) {
558 klass = domain->domain->mbr.obj.vtable->klass;
561 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
562 if (method == NULL) {
563 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
569 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
572 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
576 * mono_domain_owns_vtable_slot:
578 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
581 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
585 mono_domain_lock (domain);
586 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
587 mono_domain_unlock (domain);
594 * @force: force setting.
596 * Set the current appdomain to @domain. If @force is set, set it even
597 * if it is being unloaded.
601 * FALSE if the domain is unloaded
604 mono_domain_set (MonoDomain *domain, gboolean force)
606 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
609 mono_domain_set_internal (domain);
615 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
621 MONO_CHECK_ARG_NULL (name, NULL);
627 str = mono_string_to_utf8 (name);
629 mono_domain_lock (add);
631 if (!strcmp (str, "APPBASE"))
632 o = (MonoObject *)add->setup->application_base;
633 else if (!strcmp (str, "APP_CONFIG_FILE"))
634 o = (MonoObject *)add->setup->configuration_file;
635 else if (!strcmp (str, "DYNAMIC_BASE"))
636 o = (MonoObject *)add->setup->dynamic_base;
637 else if (!strcmp (str, "APP_NAME"))
638 o = (MonoObject *)add->setup->application_name;
639 else if (!strcmp (str, "CACHE_BASE"))
640 o = (MonoObject *)add->setup->cache_path;
641 else if (!strcmp (str, "PRIVATE_BINPATH"))
642 o = (MonoObject *)add->setup->private_bin_path;
643 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
644 o = (MonoObject *)add->setup->private_bin_path_probe;
645 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
646 o = (MonoObject *)add->setup->shadow_copy_directories;
647 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
648 o = (MonoObject *)add->setup->shadow_copy_files;
650 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
652 mono_domain_unlock (add);
662 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
666 MONO_CHECK_ARG_NULL (name,);
672 mono_domain_lock (add);
674 mono_g_hash_table_insert (add->env, name, data);
676 mono_domain_unlock (add);
680 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
685 return ad->data->setup;
689 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
694 return mono_string_new (ad->data, ad->data->friendly_name);
698 ves_icall_System_AppDomain_getCurDomain ()
700 MonoDomain *add = mono_domain_get ();
706 ves_icall_System_AppDomain_getRootDomain ()
708 MonoDomain *root = mono_get_root_domain ();
714 get_attribute_value (const gchar **attribute_names,
715 const gchar **attribute_values,
716 const char *att_name)
719 for (n = 0; attribute_names [n] != NULL; n++) {
720 if (strcmp (attribute_names [n], att_name) == 0)
721 return g_strdup (attribute_values [n]);
727 start_element (GMarkupParseContext *context,
728 const gchar *element_name,
729 const gchar **attribute_names,
730 const gchar **attribute_values,
734 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
736 if (strcmp (element_name, "runtime") == 0) {
737 runtime_config->runtime_count++;
741 if (strcmp (element_name, "assemblyBinding") == 0) {
742 runtime_config->assemblybinding_count++;
746 if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
749 if (strcmp (element_name, "probing") != 0)
752 g_free (runtime_config->domain->private_bin_path);
753 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
754 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
755 g_free (runtime_config->domain->private_bin_path);
756 runtime_config->domain->private_bin_path = NULL;
762 end_element (GMarkupParseContext *context,
763 const gchar *element_name,
767 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
768 if (strcmp (element_name, "runtime") == 0)
769 runtime_config->runtime_count--;
770 else if (strcmp (element_name, "assemblyBinding") == 0)
771 runtime_config->assemblybinding_count--;
775 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
777 RuntimeConfig *state = (RuntimeConfig *)user_data;
779 const gchar *filename;
781 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
782 msg = error && error->message ? error->message : "";
783 g_warning ("Error parsing %s: %s", filename, msg);
786 static const GMarkupParser
796 mono_set_private_bin_path_from_config (MonoDomain *domain)
799 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
801 GMarkupParseContext *context;
802 RuntimeConfig runtime_config;
805 if (!domain || !domain->setup || !domain->setup->configuration_file)
808 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
809 if (!mono_error_ok (&error)) {
810 mono_error_cleanup (&error);
814 config_file_path = mono_portability_find_file (config_file_name, TRUE);
815 if (!config_file_path)
816 config_file_path = config_file_name;
818 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
821 runtime_config.runtime_count = 0;
822 runtime_config.assemblybinding_count = 0;
823 runtime_config.domain = domain;
824 runtime_config.filename = config_file_path;
827 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
828 offset = 3; /* Skip UTF-8 BOM */
830 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
831 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
832 g_markup_parse_context_end_parse (context, NULL);
833 g_markup_parse_context_free (context);
837 if (config_file_name != config_file_path)
838 g_free (config_file_name);
839 g_free (config_file_path);
843 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
845 #ifdef DISABLE_APPDOMAINS
846 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
849 char *fname = mono_string_to_utf8 (friendly_name);
850 MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
859 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
861 MonoDomain *domain = ad->data;
863 static MonoClass *System_Reflection_Assembly;
867 GPtrArray *assemblies;
869 if (!System_Reflection_Assembly)
870 System_Reflection_Assembly = mono_class_from_name (
871 mono_defaults.corlib, "System.Reflection", "Assembly");
874 * Make a copy of the list of assemblies because we can't hold the assemblies
875 * lock while creating objects etc.
877 assemblies = g_ptr_array_new ();
878 /* Need to skip internal assembly builders created by remoting */
879 mono_domain_assemblies_lock (domain);
880 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
881 ass = (MonoAssembly *)tmp->data;
882 if (refonly != ass->ref_only)
884 if (ass->corlib_internal)
886 g_ptr_array_add (assemblies, ass);
888 mono_domain_assemblies_unlock (domain);
890 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
891 for (i = 0; i < assemblies->len; ++i) {
892 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
893 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
896 g_ptr_array_free (assemblies, TRUE);
901 MonoReflectionAssembly *
902 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
906 MonoBoolean isrefonly;
909 if (mono_runtime_get_no_exec ())
912 g_assert (domain != NULL && fname != NULL);
914 klass = domain->domain->mbr.obj.vtable->klass;
917 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
918 if (method == NULL) {
919 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
923 isrefonly = refonly ? 1 : 0;
925 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
926 params [2] = &isrefonly;
927 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
931 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
934 MonoReflectionAssembly *assembly;
935 MonoDomain *domain = mono_domain_get ();
939 aname_str = mono_stringify_assembly_name (aname);
941 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
942 str = mono_string_new (domain, aname_str);
947 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
951 return assembly->assembly;
957 * LOCKING: assumes assemblies_lock in the domain is already locked.
960 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
964 gboolean destroy_ht = FALSE;
966 if (!ass->aname.name)
970 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
974 /* FIXME: handle lazy loaded assemblies */
975 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
976 g_hash_table_insert (ht, tmp->data, tmp->data);
978 if (!g_hash_table_lookup (ht, ass)) {
979 mono_assembly_addref (ass);
980 g_hash_table_insert (ht, ass, ass);
981 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
982 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);
985 if (ass->image->references) {
986 for (i = 0; ass->image->references [i] != NULL; i++) {
987 if (ass->image->references [i] != REFERENCE_MISSING)
988 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
989 add_assemblies_to_domain (domain, ass->image->references [i], ht);
994 g_hash_table_destroy (ht);
998 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1000 static MonoClassField *assembly_load_field;
1001 static MonoMethod *assembly_load_method;
1002 MonoDomain *domain = mono_domain_get ();
1003 MonoReflectionAssembly *ref_assembly;
1005 gpointer load_value;
1008 if (!domain->domain)
1009 /* This can happen during startup */
1011 #ifdef ASSEMBLY_LOAD_DEBUG
1012 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1014 klass = domain->domain->mbr.obj.vtable->klass;
1016 mono_domain_assemblies_lock (domain);
1017 add_assemblies_to_domain (domain, assembly, NULL);
1018 mono_domain_assemblies_unlock (domain);
1020 if (assembly_load_field == NULL) {
1021 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1022 g_assert (assembly_load_field);
1025 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1026 if (load_value == NULL) {
1027 /* No events waiting to be triggered */
1031 ref_assembly = mono_assembly_get_object (domain, assembly);
1032 g_assert (ref_assembly);
1034 if (assembly_load_method == NULL) {
1035 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1036 g_assert (assembly_load_method);
1039 *params = ref_assembly;
1040 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1044 * LOCKING: Acquires the domain assemblies lock.
1047 set_domain_search_path (MonoDomain *domain)
1050 MonoAppDomainSetup *setup;
1052 gchar *search_path = NULL;
1055 gchar **pvt_split = NULL;
1056 GError *gerror = NULL;
1057 gint appbaselen = -1;
1060 * We use the low-level domain assemblies lock, since this is called from
1061 * assembly loads hooks, which means this thread might hold the loader lock.
1063 mono_domain_assemblies_lock (domain);
1065 if (!domain->setup) {
1066 mono_domain_assemblies_unlock (domain);
1070 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1071 mono_domain_assemblies_unlock (domain);
1074 setup = domain->setup;
1075 if (!setup->application_base) {
1076 mono_domain_assemblies_unlock (domain);
1077 return; /* Must set application base to get private path working */
1082 if (setup->private_bin_path) {
1083 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1084 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1085 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1086 mono_error_cleanup (&error);
1087 mono_domain_assemblies_unlock (domain);
1092 if (domain->private_bin_path) {
1093 if (search_path == NULL)
1094 search_path = domain->private_bin_path;
1096 gchar *tmp2 = search_path;
1097 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1104 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1105 * directories relative to ApplicationBase separated by semicolons (see
1106 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1107 * The loop below copes with the fact that some Unix applications may use ':' (or
1108 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1109 * ';' for the subsequent split.
1111 * The issue was reported in bug #81446
1114 #ifndef TARGET_WIN32
1117 slen = strlen (search_path);
1118 for (i = 0; i < slen; i++)
1119 if (search_path [i] == ':')
1120 search_path [i] = ';';
1123 pvt_split = g_strsplit (search_path, ";", 1000);
1124 g_free (search_path);
1125 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1130 g_strfreev (pvt_split);
1132 * Don't do this because the first time is called, the domain
1133 * setup is not finished.
1135 * domain->search_path = g_malloc (sizeof (char *));
1136 * domain->search_path [0] = NULL;
1138 mono_domain_assemblies_unlock (domain);
1142 if (domain->search_path)
1143 g_strfreev (domain->search_path);
1145 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1146 tmp [npaths] = NULL;
1148 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1149 if (!mono_error_ok (&error)) {
1150 mono_error_cleanup (&error);
1151 g_strfreev (pvt_split);
1154 mono_domain_assemblies_unlock (domain);
1158 domain->search_path = tmp;
1160 /* FIXME: is this needed? */
1161 if (strncmp (*tmp, "file://", 7) == 0) {
1167 uri = g_strdup_printf ("file:///%s", uri + 7);
1170 uri = mono_escape_uri_string (tmpuri);
1171 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1177 if (gerror != NULL) {
1178 g_warning ("%s\n", gerror->message);
1179 g_error_free (gerror);
1186 for (i = 1; pvt_split && i < npaths; i++) {
1187 if (g_path_is_absolute (pvt_split [i - 1])) {
1188 tmp [i] = g_strdup (pvt_split [i - 1]);
1190 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1193 if (strchr (tmp [i], '.')) {
1197 reduced = mono_path_canonicalize (tmp [i]);
1198 if (appbaselen == -1)
1199 appbaselen = strlen (tmp [0]);
1201 if (strncmp (tmp [0], reduced, appbaselen)) {
1204 tmp [i] = g_strdup ("");
1214 if (setup->private_bin_path_probe != NULL) {
1216 tmp [0] = g_strdup ("");
1219 domain->setup->path_changed = FALSE;
1221 g_strfreev (pvt_split);
1223 mono_domain_assemblies_unlock (domain);
1226 #ifdef DISABLE_SHADOW_COPY
1228 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1234 mono_make_shadow_copy (const char *filename)
1236 return (char *) filename;
1240 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1242 guint16 *orig, *dest;
1243 gboolean copy_result;
1245 strcpy (src + srclen - tail_len, extension);
1247 if (IS_PORTABILITY_CASE) {
1248 gchar *file = mono_portability_find_file (src, TRUE);
1254 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1258 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1260 strcpy (target + targetlen - tail_len, extension);
1261 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1264 copy_result = CopyFile (orig, dest, FALSE);
1266 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1267 * overwritten when updated in their original locations. */
1269 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1278 get_cstring_hash (const char *str)
1284 if (!str || !str [0])
1289 for (i = 0; i < len; i++) {
1290 h = (h << 5) - h + *p;
1298 * Returned memory is malloc'd. Called must free it
1301 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1303 MonoAppDomainSetup *setup;
1304 char *cache_path, *appname;
1308 mono_error_init (error);
1310 setup = domain->setup;
1311 if (setup->cache_path != NULL && setup->application_name != NULL) {
1312 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1313 if (!mono_error_ok (error))
1315 #ifndef TARGET_WIN32
1318 for (i = strlen (cache_path) - 1; i >= 0; i--)
1319 if (cache_path [i] == '\\')
1320 cache_path [i] = '/';
1324 appname = mono_string_to_utf8_checked (setup->application_name, error);
1325 if (!mono_error_ok (error)) {
1326 g_free (cache_path);
1330 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1332 g_free (cache_path);
1334 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1335 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1342 get_shadow_assembly_location (const char *filename, MonoError *error)
1344 gint32 hash = 0, hash2 = 0;
1346 char path_hash [30];
1347 char *bname = g_path_get_basename (filename);
1348 char *dirname = g_path_get_dirname (filename);
1349 char *location, *tmploc;
1350 MonoDomain *domain = mono_domain_get ();
1352 mono_error_init (error);
1354 hash = get_cstring_hash (bname);
1355 hash2 = get_cstring_hash (dirname);
1356 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1357 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1358 tmploc = get_shadow_assembly_location_base (domain, error);
1359 if (!mono_error_ok (error)) {
1365 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1373 ensure_directory_exists (const char *filename)
1376 gchar *dir_utf8 = g_path_get_dirname (filename);
1378 gunichar2 *dir_utf16 = NULL;
1381 if (!dir_utf8 || !dir_utf8 [0])
1384 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1392 /* make life easy and only use one directory seperator */
1403 while (*p++ != '\\')
1409 p = wcschr (p, '\\');
1412 retval = _wmkdir (dir_utf16);
1413 if (retval != 0 && errno != EEXIST) {
1426 gchar *dir = g_path_get_dirname (filename);
1430 if (!dir || !dir [0]) {
1435 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1445 p = strchr (p, '/');
1448 retval = mkdir (dir, 0777);
1449 if (retval != 0 && errno != EEXIST) {
1464 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1466 struct stat sbuf_dest;
1468 gchar *real_src = mono_portability_find_file (src, TRUE);
1471 stat_src = (gchar*)src;
1473 stat_src = real_src;
1475 if (stat (stat_src, sbuf_src) == -1) {
1476 time_t tnow = time (NULL);
1481 memset (sbuf_src, 0, sizeof (*sbuf_src));
1482 sbuf_src->st_mtime = tnow;
1483 sbuf_src->st_atime = tnow;
1490 if (stat (dest, &sbuf_dest) == -1)
1493 if (sbuf_src->st_size == sbuf_dest.st_size &&
1494 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1501 shadow_copy_create_ini (const char *shadow, const char *filename)
1511 dir_name = g_path_get_dirname (shadow);
1512 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1514 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1519 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1524 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1525 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1527 if (handle == INVALID_HANDLE_VALUE) {
1531 full_path = mono_path_resolve_symlinks (filename);
1532 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1534 CloseHandle (handle);
1539 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1542 MonoAppDomainSetup *setup;
1545 gchar **directories;
1546 gchar *shadow_status_string;
1548 gboolean shadow_enabled;
1549 gboolean found = FALSE;
1554 setup = domain->setup;
1555 if (setup == NULL || setup->shadow_copy_files == NULL)
1558 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1559 if (!mono_error_ok (&error)) {
1560 mono_error_cleanup (&error);
1563 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1564 g_free (shadow_status_string);
1566 if (!shadow_enabled)
1569 if (setup->shadow_copy_directories == NULL)
1572 /* Is dir_name a shadow_copy destination already? */
1573 base_dir = get_shadow_assembly_location_base (domain, &error);
1574 if (!mono_error_ok (&error)) {
1575 mono_error_cleanup (&error);
1579 if (strstr (dir_name, base_dir)) {
1585 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1586 if (!mono_error_ok (&error)) {
1587 mono_error_cleanup (&error);
1591 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1592 dir_ptr = directories;
1594 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1600 g_strfreev (directories);
1606 This function raises exceptions so it can cause as sorts of nasty stuff if called
1607 while holding a lock.
1608 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1609 or NULL if source file not found.
1610 FIXME bubble up the error instead of raising it here
1613 mono_make_shadow_copy (const char *filename)
1616 gchar *sibling_source, *sibling_target;
1617 gint sibling_source_len, sibling_target_len;
1618 guint16 *orig, *dest;
1621 gboolean copy_result;
1623 struct stat src_sbuf;
1624 struct utimbuf utbuf;
1625 char *dir_name = g_path_get_dirname (filename);
1626 MonoDomain *domain = mono_domain_get ();
1629 set_domain_search_path (domain);
1631 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1633 return (char *) filename;
1636 /* Is dir_name a shadow_copy destination already? */
1637 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1638 if (!mono_error_ok (&error)) {
1639 mono_error_cleanup (&error);
1641 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1642 mono_raise_exception (exc);
1645 if (strstr (dir_name, shadow_dir)) {
1646 g_free (shadow_dir);
1648 return (char *) filename;
1650 g_free (shadow_dir);
1653 shadow = get_shadow_assembly_location (filename, &error);
1654 if (!mono_error_ok (&error)) {
1655 mono_error_cleanup (&error);
1656 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1657 mono_raise_exception (exc);
1660 if (ensure_directory_exists (shadow) == FALSE) {
1662 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1663 mono_raise_exception (exc);
1666 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1667 return (char*) shadow;
1669 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1670 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1673 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1674 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1675 * and not have it runtime error" */
1676 attrs = GetFileAttributes (orig);
1677 if (attrs == INVALID_FILE_ATTRIBUTES) {
1679 return (char *)filename;
1682 copy_result = CopyFile (orig, dest, FALSE);
1684 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1685 * overwritten when updated in their original locations. */
1687 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1692 if (copy_result == FALSE) {
1695 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1696 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1697 return NULL; /* file not found, shadow copy failed */
1699 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1700 mono_raise_exception (exc);
1703 /* attempt to copy .mdb, .config if they exist */
1704 sibling_source = g_strconcat (filename, ".config", NULL);
1705 sibling_source_len = strlen (sibling_source);
1706 sibling_target = g_strconcat (shadow, ".config", NULL);
1707 sibling_target_len = strlen (sibling_target);
1709 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1710 if (copy_result == TRUE)
1711 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1713 g_free (sibling_source);
1714 g_free (sibling_target);
1716 if (copy_result == FALSE) {
1718 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1719 mono_raise_exception (exc);
1722 /* Create a .ini file containing the original assembly location */
1723 if (!shadow_copy_create_ini (shadow, filename)) {
1725 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1726 mono_raise_exception (exc);
1729 utbuf.actime = src_sbuf.st_atime;
1730 utbuf.modtime = src_sbuf.st_mtime;
1731 utime (shadow, &utbuf);
1735 #endif /* DISABLE_SHADOW_COPY */
1738 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1740 if (appdomain == NULL)
1743 return appdomain->data;
1747 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1748 const gchar *path3, const gchar *path4,
1749 gboolean refonly, gboolean is_private)
1752 gboolean found = FALSE;
1755 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1757 if (IS_PORTABILITY_SET) {
1758 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1761 fullpath = new_fullpath;
1765 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1768 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1771 return (*assembly != NULL);
1774 static MonoAssembly *
1775 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1777 MonoAssembly *result = NULL;
1780 const gchar *local_culture;
1782 gboolean is_private = FALSE;
1784 if (!culture || *culture == '\0') {
1787 local_culture = culture;
1790 filename = g_strconcat (name, ".dll", NULL);
1791 len = strlen (filename);
1793 for (path = search_path; *path; path++) {
1794 if (**path == '\0') {
1796 continue; /* Ignore empty ApplicationBase */
1799 /* See test cases in bug #58992 and bug #57710 */
1800 /* 1st try: [culture]/[name].dll (culture may be empty) */
1801 strcpy (filename + len - 4, ".dll");
1802 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1805 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1806 strcpy (filename + len - 4, ".exe");
1807 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1810 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1811 strcpy (filename + len - 4, ".dll");
1812 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1815 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1816 strcpy (filename + len - 4, ".exe");
1817 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1826 * Try loading the assembly from ApplicationBase and PrivateBinPath
1827 * and then from assemblies_path if any.
1828 * LOCKING: This is called from the assembly loading code, which means the caller
1829 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1831 static MonoAssembly *
1832 mono_domain_assembly_preload (MonoAssemblyName *aname,
1833 gchar **assemblies_path,
1836 MonoDomain *domain = mono_domain_get ();
1837 MonoAssembly *result = NULL;
1838 gboolean refonly = GPOINTER_TO_UINT (user_data);
1840 set_domain_search_path (domain);
1842 if (domain->search_path && domain->search_path [0] != NULL) {
1843 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1846 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1847 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1854 * Check whenever a given assembly was already loaded in the current appdomain.
1856 static MonoAssembly *
1857 mono_domain_assembly_search (MonoAssemblyName *aname,
1860 MonoDomain *domain = mono_domain_get ();
1863 gboolean refonly = GPOINTER_TO_UINT (user_data);
1865 mono_domain_assemblies_lock (domain);
1866 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1867 ass = (MonoAssembly *)tmp->data;
1868 /* Dynamic assemblies can't match here in MS.NET */
1869 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1872 mono_domain_assemblies_unlock (domain);
1875 mono_domain_assemblies_unlock (domain);
1880 MonoReflectionAssembly *
1881 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1883 MonoDomain *domain = mono_domain_get ();
1884 char *name, *filename;
1885 MonoImageOpenStatus status = MONO_IMAGE_OK;
1888 if (fname == NULL) {
1889 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1890 mono_set_pending_exception (exc);
1894 name = filename = mono_string_to_utf8 (fname);
1896 ass = mono_assembly_open_full (filename, &status, refOnly);
1901 if (status == MONO_IMAGE_IMAGE_INVALID)
1902 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1904 exc = mono_get_exception_file_not_found2 (NULL, fname);
1906 mono_set_pending_exception (exc);
1912 return mono_assembly_get_object (domain, ass);
1915 MonoReflectionAssembly *
1916 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1917 MonoArray *raw_assembly,
1918 MonoArray *raw_symbol_store, MonoObject *evidence,
1919 MonoBoolean refonly)
1922 MonoReflectionAssembly *refass = NULL;
1923 MonoDomain *domain = ad->data;
1924 MonoImageOpenStatus status;
1925 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1926 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1929 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1933 if (raw_symbol_store != NULL)
1934 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1936 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1940 mono_image_close (image);
1941 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1945 refass = mono_assembly_get_object (domain, ass);
1946 MONO_OBJECT_SETREF (refass, evidence, evidence);
1950 MonoReflectionAssembly *
1951 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1953 MonoDomain *domain = ad->data;
1954 MonoImageOpenStatus status = MONO_IMAGE_OK;
1956 MonoAssemblyName aname;
1957 MonoReflectionAssembly *refass = NULL;
1963 name = mono_string_to_utf8 (assRef);
1964 parsed = mono_assembly_name_parse (name, &aname);
1968 /* This is a parse error... */
1970 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1974 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1975 mono_assembly_name_free (&aname);
1978 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1980 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1989 refass = mono_assembly_get_object (domain, ass);
1991 MONO_OBJECT_SETREF (refass, evidence, evidence);
1996 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
1998 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2000 if (NULL == domain) {
2001 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2002 mono_set_pending_exception (exc);
2006 if (domain == mono_get_root_domain ()) {
2007 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2012 * Unloading seems to cause problems when running NUnit/NAnt, hence
2015 if (g_getenv ("MONO_NO_UNLOAD"))
2017 #ifdef __native_client__
2021 mono_domain_unload (domain);
2025 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2027 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2032 return mono_domain_is_unloading (domain);
2036 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2038 mono_unhandled_exception ((MonoObject*) exc);
2042 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2043 MonoReflectionAssembly *refass, MonoArray *args)
2050 image = refass->assembly->image;
2053 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2056 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2059 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2061 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2065 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2067 return ad->data->domain_id;
2071 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2073 MonoDomain *old_domain = mono_domain_get();
2075 if (!mono_domain_set (ad->data, FALSE)) {
2076 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2080 return old_domain->domain;
2084 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2086 MonoDomain *current_domain = mono_domain_get ();
2087 MonoDomain *domain = mono_domain_get_by_id (domainid);
2089 if (!domain || !mono_domain_set (domain, FALSE)) {
2090 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2094 return current_domain->domain;
2098 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2100 mono_thread_push_appdomain_ref (ad->data);
2104 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2106 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2110 * Raise an exception to prevent the managed code from executing a pop
2113 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2117 mono_thread_push_appdomain_ref (domain);
2121 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2123 mono_thread_pop_appdomain_ref ();
2127 ves_icall_System_AppDomain_InternalGetContext ()
2129 return mono_context_get ();
2133 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2135 return mono_domain_get ()->default_context;
2139 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2141 MonoAppContext *old_context = mono_context_get ();
2143 mono_context_set (mc);
2149 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2151 MonoDomain* mono_root_domain = mono_get_root_domain ();
2152 mono_domain_lock (mono_root_domain);
2153 if (process_guid_set) {
2154 mono_domain_unlock (mono_root_domain);
2155 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2157 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2158 process_guid_set = TRUE;
2159 mono_domain_unlock (mono_root_domain);
2164 mono_domain_is_unloading (MonoDomain *domain)
2166 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2173 clear_cached_vtable (MonoVTable *vtable)
2175 MonoClass *klass = vtable->klass;
2176 MonoDomain *domain = vtable->domain;
2177 MonoClassRuntimeInfo *runtime_info;
2180 runtime_info = klass->runtime_info;
2181 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2182 runtime_info->domain_vtables [domain->domain_id] = NULL;
2183 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2184 mono_gc_free_fixed (data);
2187 static G_GNUC_UNUSED void
2188 zero_static_data (MonoVTable *vtable)
2190 MonoClass *klass = vtable->klass;
2193 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2194 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2197 typedef struct unload_data {
2200 char *failure_reason;
2205 unload_data_unref (unload_data *data)
2209 mono_atomic_load_acquire (count, gint32, &data->refcount);
2210 g_assert (count >= 1 && count <= 2);
2215 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2219 deregister_reflection_info_roots_from_list (MonoImage *image)
2221 GSList *list = image->reflection_info_unregister_classes;
2224 MonoClass *klass = (MonoClass *)list->data;
2226 mono_class_free_ref_info (klass);
2231 image->reflection_info_unregister_classes = NULL;
2235 deregister_reflection_info_roots (MonoDomain *domain)
2239 mono_domain_assemblies_lock (domain);
2240 for (list = domain->domain_assemblies; list; list = list->next) {
2241 MonoAssembly *assembly = (MonoAssembly *)list->data;
2242 MonoImage *image = assembly->image;
2246 * No need to take the image lock here since dynamic images are appdomain bound and
2247 * at this point the mutator is gone. Taking the image lock here would mean
2248 * promoting it from a simple lock to a complex lock, which we better avoid if
2251 if (image_is_dynamic (image))
2252 deregister_reflection_info_roots_from_list (image);
2254 for (i = 0; i < image->module_count; ++i) {
2255 MonoImage *module = image->modules [i];
2256 if (module && image_is_dynamic (module))
2257 deregister_reflection_info_roots_from_list (module);
2260 mono_domain_assemblies_unlock (domain);
2263 static guint32 WINAPI
2264 unload_thread_main (void *arg)
2266 unload_data *data = (unload_data*)arg;
2267 MonoDomain *domain = data->domain;
2271 /* Have to attach to the runtime so shutdown can wait for this thread */
2272 /* Force it to be attached to avoid racing during shutdown. */
2273 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2276 * FIXME: Abort our parent thread last, so we can return a failure
2277 * indication if aborting times out.
2279 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2280 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2284 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2285 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2289 /* Finalize all finalizable objects in the doomed appdomain */
2290 if (!mono_domain_finalize (domain, -1)) {
2291 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2295 /* Clear references to our vtables in class->runtime_info.
2296 * We also hold the loader lock because we're going to change
2297 * class->runtime_info.
2300 mono_loader_lock (); //FIXME why do we need the loader lock here?
2301 mono_domain_lock (domain);
2304 * We need to make sure that we don't have any remsets
2305 * pointing into static data of the to-be-freed domain because
2306 * at the next collections they would be invalid. So what we
2307 * do is we first zero all static data and then do a minor
2308 * collection. Because all references in the static data will
2309 * now be null we won't do any unnecessary copies and after
2310 * the collection there won't be any more remsets.
2312 for (i = 0; i < domain->class_vtable_array->len; ++i)
2313 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2314 mono_gc_collect (0);
2316 for (i = 0; i < domain->class_vtable_array->len; ++i)
2317 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2318 deregister_reflection_info_roots (domain);
2320 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2322 mono_domain_unlock (domain);
2323 mono_loader_unlock ();
2325 mono_threads_clear_cached_culture (domain);
2327 domain->state = MONO_APPDOMAIN_UNLOADED;
2329 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2331 /* remove from the handle table the items related to this domain */
2332 mono_gchandle_free_domain (domain);
2334 mono_domain_free (domain, FALSE);
2336 mono_gc_collect (mono_gc_max_generation ());
2338 mono_atomic_store_release (&data->done, TRUE);
2339 unload_data_unref (data);
2340 mono_thread_detach (thread);
2344 mono_atomic_store_release (&data->done, TRUE);
2345 unload_data_unref (data);
2346 mono_thread_detach (thread);
2351 * mono_domain_unload:
2352 * @domain: The domain to unload
2354 * Unloads an appdomain. Follows the process outlined in the comment
2355 * for mono_domain_try_unload.
2358 mono_domain_unload (MonoDomain *domain)
2360 MonoObject *exc = NULL;
2361 mono_domain_try_unload (domain, &exc);
2363 mono_raise_exception ((MonoException*)exc);
2367 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2371 MONO_PREPARE_BLOCKING;
2372 result = WaitForSingleObjectEx (handle, timeout, alertable);
2373 MONO_FINISH_BLOCKING;
2379 * mono_domain_unload:
2380 * @domain: The domain to unload
2381 * @exc: Exception information
2383 * Unloads an appdomain. Follows the process outlined in:
2384 * http://blogs.gotdotnet.com/cbrumme
2386 * If doing things the 'right' way is too hard or complex, we do it the
2387 * 'simple' way, which means do everything needed to avoid crashes and
2388 * memory leaks, but not much else.
2390 * It is required to pass a valid reference to the exc argument, upon return
2391 * from this function *exc will be set to the exception thrown, if any.
2393 * If this method is not called from an icall (embedded scenario for instance),
2394 * it must not be called with any managed frames on the stack, since the unload
2395 * process could end up trying to abort the current thread.
2398 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2400 HANDLE thread_handle;
2401 MonoAppDomainState prev_state;
2403 unload_data *thread_data;
2404 MonoNativeThreadId tid;
2405 MonoDomain *caller_domain = mono_domain_get ();
2408 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2410 /* Atomically change our state to UNLOADING */
2411 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2412 MONO_APPDOMAIN_UNLOADING_START,
2413 MONO_APPDOMAIN_CREATED);
2414 if (prev_state != MONO_APPDOMAIN_CREATED) {
2415 switch (prev_state) {
2416 case MONO_APPDOMAIN_UNLOADING_START:
2417 case MONO_APPDOMAIN_UNLOADING:
2418 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2420 case MONO_APPDOMAIN_UNLOADED:
2421 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2424 g_warning ("Invalid appdomain state %d", prev_state);
2425 g_assert_not_reached ();
2429 mono_domain_set (domain, FALSE);
2430 /* Notify OnDomainUnload listeners */
2431 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2434 mono_runtime_invoke (method, domain->domain, NULL, exc);
2436 /* Roll back the state change */
2437 domain->state = MONO_APPDOMAIN_CREATED;
2438 mono_domain_set (caller_domain, FALSE);
2441 mono_domain_set (caller_domain, FALSE);
2443 thread_data = g_new0 (unload_data, 1);
2444 thread_data->domain = domain;
2445 thread_data->failure_reason = NULL;
2446 thread_data->done = FALSE;
2447 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2449 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2450 domain->state = MONO_APPDOMAIN_UNLOADING;
2452 * First we create a separate thread for unloading, since
2453 * we might have to abort some threads, including the current one.
2455 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2456 if (thread_handle == NULL)
2458 name = g_strdup_printf ("Unload thread for domain %x", domain);
2459 mono_thread_info_set_name (tid, name);
2460 mono_thread_info_resume (tid);
2463 /* Wait for the thread */
2464 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2465 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2466 /* The unload thread tries to abort us */
2467 /* The icall wrapper will execute the abort */
2468 CloseHandle (thread_handle);
2469 unload_data_unref (thread_data);
2473 CloseHandle (thread_handle);
2475 if (thread_data->failure_reason) {
2476 /* Roll back the state change */
2477 domain->state = MONO_APPDOMAIN_CREATED;
2479 g_warning ("%s", thread_data->failure_reason);
2481 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2483 g_free (thread_data->failure_reason);
2484 thread_data->failure_reason = NULL;
2487 unload_data_unref (thread_data);