2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
13 #undef ASSEMBLY_LOAD_DEBUG
19 #include <sys/types.h>
21 #ifdef HAVE_SYS_TIME_H
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
35 #include <mono/metadata/gc-internal.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/threadpool-ms.h>
43 #include <mono/metadata/socket-io.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/gc-internal.h>
46 #include <mono/metadata/mono-gc.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/monitor.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/utils/mono-uri.h>
59 #include <mono/utils/mono-logger-internal.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 136
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 ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
241 mono_install_assembly_postload_refonly_search_hook ((void*)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 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
248 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, class);
250 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
251 ad = (MonoAppDomain *) mono_object_new_pinned (domain, class);
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 class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
334 context = (MonoAppContext *) mono_object_new_pinned (domain, class);
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 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
400 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
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 = 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 = 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 = 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 = 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, 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) {
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 = 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 = 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 = 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) {
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_ExecuteAssembly (MonoAppDomain *ad,
2037 MonoReflectionAssembly *refass, MonoArray *args)
2044 image = refass->assembly->image;
2047 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2050 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2053 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2055 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2059 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2061 return ad->data->domain_id;
2065 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2067 MonoDomain *old_domain = mono_domain_get();
2069 if (!mono_domain_set (ad->data, FALSE)) {
2070 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2074 return old_domain->domain;
2078 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2080 MonoDomain *current_domain = mono_domain_get ();
2081 MonoDomain *domain = mono_domain_get_by_id (domainid);
2083 if (!domain || !mono_domain_set (domain, FALSE)) {
2084 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2088 return current_domain->domain;
2092 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2094 mono_thread_push_appdomain_ref (ad->data);
2098 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2100 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2104 * Raise an exception to prevent the managed code from executing a pop
2107 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2111 mono_thread_push_appdomain_ref (domain);
2115 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2117 mono_thread_pop_appdomain_ref ();
2121 ves_icall_System_AppDomain_InternalGetContext ()
2123 return mono_context_get ();
2127 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2129 return mono_domain_get ()->default_context;
2133 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2135 MonoAppContext *old_context = mono_context_get ();
2137 mono_context_set (mc);
2143 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2145 MonoDomain* mono_root_domain = mono_get_root_domain ();
2146 mono_domain_lock (mono_root_domain);
2147 if (process_guid_set) {
2148 mono_domain_unlock (mono_root_domain);
2149 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2151 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2152 process_guid_set = TRUE;
2153 mono_domain_unlock (mono_root_domain);
2158 mono_domain_is_unloading (MonoDomain *domain)
2160 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2167 clear_cached_vtable (MonoVTable *vtable)
2169 MonoClass *klass = vtable->klass;
2170 MonoDomain *domain = vtable->domain;
2171 MonoClassRuntimeInfo *runtime_info;
2174 runtime_info = klass->runtime_info;
2175 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2176 runtime_info->domain_vtables [domain->domain_id] = NULL;
2177 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2178 mono_gc_free_fixed (data);
2181 static G_GNUC_UNUSED void
2182 zero_static_data (MonoVTable *vtable)
2184 MonoClass *klass = vtable->klass;
2187 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2188 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2191 typedef struct unload_data {
2194 char *failure_reason;
2199 unload_data_unref (unload_data *data)
2203 mono_atomic_load_acquire (count, gint32, &data->refcount);
2204 g_assert (count >= 1 && count <= 2);
2209 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2213 deregister_reflection_info_roots_from_list (MonoImage *image)
2215 GSList *list = image->reflection_info_unregister_classes;
2218 MonoClass *class = list->data;
2220 mono_class_free_ref_info (class);
2225 image->reflection_info_unregister_classes = NULL;
2229 deregister_reflection_info_roots (MonoDomain *domain)
2233 mono_domain_assemblies_lock (domain);
2234 for (list = domain->domain_assemblies; list; list = list->next) {
2235 MonoAssembly *assembly = list->data;
2236 MonoImage *image = assembly->image;
2240 * No need to take the image lock here since dynamic images are appdomain bound and
2241 * at this point the mutator is gone. Taking the image lock here would mean
2242 * promoting it from a simple lock to a complex lock, which we better avoid if
2245 if (image_is_dynamic (image))
2246 deregister_reflection_info_roots_from_list (image);
2248 for (i = 0; i < image->module_count; ++i) {
2249 MonoImage *module = image->modules [i];
2250 if (module && image_is_dynamic (module))
2251 deregister_reflection_info_roots_from_list (module);
2254 mono_domain_assemblies_unlock (domain);
2257 static guint32 WINAPI
2258 unload_thread_main (void *arg)
2260 unload_data *data = (unload_data*)arg;
2261 MonoDomain *domain = data->domain;
2265 /* Have to attach to the runtime so shutdown can wait for this thread */
2266 /* Force it to be attached to avoid racing during shutdown. */
2267 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2270 * FIXME: Abort our parent thread last, so we can return a failure
2271 * indication if aborting times out.
2273 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2274 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2278 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2279 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2283 /* Finalize all finalizable objects in the doomed appdomain */
2284 if (!mono_domain_finalize (domain, -1)) {
2285 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2289 /* Clear references to our vtables in class->runtime_info.
2290 * We also hold the loader lock because we're going to change
2291 * class->runtime_info.
2294 mono_loader_lock (); //FIXME why do we need the loader lock here?
2295 mono_domain_lock (domain);
2298 * We need to make sure that we don't have any remsets
2299 * pointing into static data of the to-be-freed domain because
2300 * at the next collections they would be invalid. So what we
2301 * do is we first zero all static data and then do a minor
2302 * collection. Because all references in the static data will
2303 * now be null we won't do any unnecessary copies and after
2304 * the collection there won't be any more remsets.
2306 for (i = 0; i < domain->class_vtable_array->len; ++i)
2307 zero_static_data (g_ptr_array_index (domain->class_vtable_array, i));
2308 mono_gc_collect (0);
2310 for (i = 0; i < domain->class_vtable_array->len; ++i)
2311 clear_cached_vtable (g_ptr_array_index (domain->class_vtable_array, i));
2312 deregister_reflection_info_roots (domain);
2314 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2316 mono_domain_unlock (domain);
2317 mono_loader_unlock ();
2319 mono_threads_clear_cached_culture (domain);
2321 domain->state = MONO_APPDOMAIN_UNLOADED;
2323 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2325 /* remove from the handle table the items related to this domain */
2326 mono_gchandle_free_domain (domain);
2328 mono_domain_free (domain, FALSE);
2330 mono_gc_collect (mono_gc_max_generation ());
2332 mono_atomic_store_release (&data->done, TRUE);
2333 unload_data_unref (data);
2334 mono_thread_detach (thread);
2338 mono_atomic_store_release (&data->done, TRUE);
2339 unload_data_unref (data);
2340 mono_thread_detach (thread);
2345 * mono_domain_unload:
2346 * @domain: The domain to unload
2348 * Unloads an appdomain. Follows the process outlined in the comment
2349 * for mono_domain_try_unload.
2352 mono_domain_unload (MonoDomain *domain)
2354 MonoObject *exc = NULL;
2355 mono_domain_try_unload (domain, &exc);
2357 mono_raise_exception ((MonoException*)exc);
2361 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2365 MONO_PREPARE_BLOCKING;
2366 result = WaitForSingleObjectEx (handle, timeout, alertable);
2367 MONO_FINISH_BLOCKING;
2373 * mono_domain_unload:
2374 * @domain: The domain to unload
2375 * @exc: Exception information
2377 * Unloads an appdomain. Follows the process outlined in:
2378 * http://blogs.gotdotnet.com/cbrumme
2380 * If doing things the 'right' way is too hard or complex, we do it the
2381 * 'simple' way, which means do everything needed to avoid crashes and
2382 * memory leaks, but not much else.
2384 * It is required to pass a valid reference to the exc argument, upon return
2385 * from this function *exc will be set to the exception thrown, if any.
2387 * If this method is not called from an icall (embedded scenario for instance),
2388 * it must not be called with any managed frames on the stack, since the unload
2389 * process could end up trying to abort the current thread.
2392 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2394 HANDLE thread_handle;
2395 MonoAppDomainState prev_state;
2397 unload_data *thread_data;
2398 MonoNativeThreadId tid;
2399 MonoDomain *caller_domain = mono_domain_get ();
2402 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2404 /* Atomically change our state to UNLOADING */
2405 prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2406 MONO_APPDOMAIN_UNLOADING_START,
2407 MONO_APPDOMAIN_CREATED);
2408 if (prev_state != MONO_APPDOMAIN_CREATED) {
2409 switch (prev_state) {
2410 case MONO_APPDOMAIN_UNLOADING_START:
2411 case MONO_APPDOMAIN_UNLOADING:
2412 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2414 case MONO_APPDOMAIN_UNLOADED:
2415 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2418 g_warning ("Invalid appdomain state %d", prev_state);
2419 g_assert_not_reached ();
2423 mono_domain_set (domain, FALSE);
2424 /* Notify OnDomainUnload listeners */
2425 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2428 mono_runtime_invoke (method, domain->domain, NULL, exc);
2430 /* Roll back the state change */
2431 domain->state = MONO_APPDOMAIN_CREATED;
2432 mono_domain_set (caller_domain, FALSE);
2435 mono_domain_set (caller_domain, FALSE);
2437 thread_data = g_new0 (unload_data, 1);
2438 thread_data->domain = domain;
2439 thread_data->failure_reason = NULL;
2440 thread_data->done = FALSE;
2441 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2443 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2444 domain->state = MONO_APPDOMAIN_UNLOADING;
2446 * First we create a separate thread for unloading, since
2447 * we might have to abort some threads, including the current one.
2449 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2450 if (thread_handle == NULL)
2452 name = g_strdup_printf ("Unload thread for domain %x", domain);
2453 mono_thread_info_set_name (tid, name);
2454 mono_thread_info_resume (tid);
2457 /* Wait for the thread */
2458 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2459 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2460 /* The unload thread tries to abort us */
2461 /* The icall wrapper will execute the abort */
2462 CloseHandle (thread_handle);
2463 unload_data_unref (thread_data);
2467 CloseHandle (thread_handle);
2469 if (thread_data->failure_reason) {
2470 /* Roll back the state change */
2471 domain->state = MONO_APPDOMAIN_CREATED;
2473 g_warning ("%s", thread_data->failure_reason);
2475 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2477 g_free (thread_data->failure_reason);
2478 thread_data->failure_reason = NULL;
2481 unload_data_unref (thread_data);