2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
13 #undef ASSEMBLY_LOAD_DEBUG
19 #include <sys/types.h>
21 #ifdef HAVE_SYS_TIME_H
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
35 #include <mono/metadata/gc-internal.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/socket-io.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/gc-internal.h>
45 #include <mono/metadata/mono-gc.h>
46 #include <mono/metadata/marshal.h>
47 #include <mono/metadata/monitor.h>
48 #include <mono/metadata/threadpool.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/utils/mono-uri.h>
58 #include <mono/utils/mono-logger-internal.h>
59 #include <mono/utils/mono-path.h>
60 #include <mono/utils/mono-stdlib.h>
61 #include <mono/utils/mono-io-portability.h>
62 #include <mono/utils/mono-error-internals.h>
63 #include <mono/utils/atomic.h>
64 #include <mono/utils/mono-memory-model.h>
65 #include <mono/utils/mono-threads.h>
71 * This is the version number of the corlib-runtime interface. When
72 * making changes to this interface (by changing the layout
73 * of classes the runtime knows about, changing icall signature or
74 * semantics etc), increment this variable. Also increment the
75 * pair of this variable in mscorlib in:
76 * mcs/class/corlib/System/Environment.cs
78 * Changes which are already detected at runtime, like the addition
79 * of icalls, do not require an increment.
81 #define MONO_CORLIB_VERSION 134
86 int assemblybinding_count;
91 mono_mutex_t mono_delegate_section;
93 static gunichar2 process_guid [36];
94 static gboolean process_guid_set = FALSE;
96 static gboolean no_exec = FALSE;
99 mono_domain_assembly_preload (MonoAssemblyName *aname,
100 gchar **assemblies_path,
103 static MonoAssembly *
104 mono_domain_assembly_search (MonoAssemblyName *aname,
108 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
111 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
113 static MonoAppDomain *
114 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
117 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
119 static MonoLoadFunc load_function = NULL;
122 mono_install_runtime_load (MonoLoadFunc func)
124 load_function = func;
128 mono_runtime_load (const char *filename, const char *runtime_version)
130 g_assert (load_function);
131 return load_function (filename, runtime_version);
135 * mono_runtime_set_no_exec:
137 * Instructs the runtime to operate in static mode, i.e. avoid/do not
138 * allow managed code execution. This is useful for running the AOT
139 * compiler on platforms which allow full-aot execution only. This
140 * should be called before mono_runtime_init ().
143 mono_runtime_set_no_exec (gboolean val)
149 * mono_runtime_get_no_exec:
151 * If true, then the runtime will not allow managed code execution.
154 mono_runtime_get_no_exec (void)
160 create_domain_objects (MonoDomain *domain)
162 MonoDomain *old_domain = mono_domain_get ();
164 MonoVTable *string_vt;
165 MonoClassField *string_empty_fld;
167 if (domain != old_domain) {
168 mono_thread_push_appdomain_ref (domain);
169 mono_domain_set_internal_with_options (domain, FALSE);
173 * Initialize String.Empty. This enables the removal of
174 * the static cctor of the String class.
176 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
177 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
178 g_assert (string_empty_fld);
179 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
182 * Create an instance early since we can't do it when there is no memory.
184 arg = mono_string_new (domain, "Out of memory");
185 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
188 * These two are needed because the signal handlers might be executing on
189 * an alternate stack, and Boehm GC can't handle that.
191 arg = mono_string_new (domain, "A null value was found where an object instance was required");
192 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
193 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
194 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
196 /*The ephemeron tombstone i*/
197 domain->ephemeron_tombstone = mono_object_new (domain, mono_defaults.object_class);
199 if (domain != old_domain) {
200 mono_thread_pop_appdomain_ref ();
201 mono_domain_set_internal_with_options (old_domain, FALSE);
205 * This class is used during exception handling, so initialize it here, to prevent
206 * stack overflows while handling stack overflows.
208 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
213 * @domain: domain returned by mono_init ()
215 * Initialize the core AppDomain: this function will run also some
216 * IL initialization code, so it needs the execution engine to be fully
219 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
220 * we know the entry_assembly.
224 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
225 MonoThreadAttachCB attach_cb)
227 MonoAppDomainSetup *setup;
231 mono_portability_helpers_init ();
233 mono_gc_base_init ();
234 mono_monitor_init ();
235 mono_thread_pool_init ();
236 mono_marshal_init ();
238 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
239 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
240 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
241 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
242 mono_install_assembly_postload_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
243 mono_install_assembly_postload_refonly_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
244 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
245 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
247 mono_thread_init (start_cb, attach_cb);
249 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
250 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, class);
252 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
253 ad = (MonoAppDomain *) mono_object_new_pinned (domain, class);
256 domain->setup = setup;
258 mono_mutex_init_recursive (&mono_delegate_section);
260 mono_thread_attach (domain);
262 mono_type_initialization_init ();
264 if (!mono_runtime_get_no_exec ())
265 create_domain_objects (domain);
267 /* GC init has to happen after thread init */
270 /* contexts use GC handles, so they must be initialized after the GC */
271 mono_context_init (domain);
272 mono_context_set (domain->default_context);
274 #ifndef DISABLE_SOCKETS
275 mono_network_init ();
278 mono_console_init ();
281 mono_locks_tracer_init ();
283 /* mscorlib is loaded before we install the load hook */
284 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
290 mono_get_corlib_version (void)
293 MonoClassField *field;
296 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
297 mono_class_init (klass);
298 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
301 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
303 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
304 return *(gint32*)((gchar*)value + sizeof (MonoObject));
308 * mono_check_corlib_version
310 * Checks that the corlib that is loaded matches the version of this runtime.
312 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
313 * allocated string with the error otherwise.
316 mono_check_corlib_version (void)
318 int version = mono_get_corlib_version ();
319 if (version != MONO_CORLIB_VERSION)
320 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
327 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
329 * Initializes the @domain's default System.Runtime.Remoting's Context.
332 mono_context_init (MonoDomain *domain)
335 MonoAppContext *context;
337 class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
338 context = (MonoAppContext *) mono_object_new_pinned (domain, class);
339 context->domain_id = domain->domain_id;
340 context->context_id = 0;
341 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
342 domain->default_context = context;
346 * mono_runtime_cleanup:
351 * This must not be called while there are still running threads executing
355 mono_runtime_cleanup (MonoDomain *domain)
357 mono_attach_cleanup ();
359 /* This ends up calling any pending pending (for at most 2 seconds) */
362 mono_thread_cleanup ();
364 #ifndef DISABLE_SOCKETS
365 mono_network_cleanup ();
367 mono_marshal_cleanup ();
369 mono_type_initialization_cleanup ();
371 mono_monitor_cleanup ();
374 static MonoDomainFunc quit_function = NULL;
377 mono_install_runtime_cleanup (MonoDomainFunc func)
379 quit_function = func;
385 if (quit_function != NULL)
386 quit_function (mono_get_root_domain (), NULL);
390 * mono_domain_create_appdomain:
391 * @friendly_name: The friendly name of the appdomain to create
392 * @configuration_file: The configuration file to initialize the appdomain with
394 * Returns a MonoDomain initialized with the appdomain
397 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
400 MonoAppDomainSetup *setup;
403 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
404 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
405 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
407 ad = mono_domain_create_appdomain_internal (friendly_name, setup);
409 return mono_domain_from_appdomain (ad);
413 * mono_domain_set_config:
414 * @domain: MonoDomain initialized with the appdomain we want to change
415 * @base_dir: new base directory for the appdomain
416 * @config_file_name: path to the new configuration for the app domain
418 * Used to set the system configuration for an appdomain
420 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
421 * Error Initializing the configuration system. ---> System.ArgumentException:
422 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
425 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
427 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
428 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
431 static MonoAppDomainSetup*
432 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
434 MonoDomain *caller_domain = mono_domain_get ();
435 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
436 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
438 mono_domain_set_internal (domain);
440 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
441 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
442 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
443 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
444 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
445 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
446 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
447 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
448 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
449 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
450 copy->publisher_policy = setup->publisher_policy;
451 copy->path_changed = setup->path_changed;
452 copy->loader_optimization = setup->loader_optimization;
453 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
454 copy->disallow_code_downloads = setup->disallow_code_downloads;
455 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
456 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
457 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
458 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
459 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
461 mono_domain_set_internal (caller_domain);
466 static MonoAppDomain *
467 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
473 char *shadow_location;
475 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
477 /* FIXME: pin all those objects */
478 data = mono_domain_create();
480 ad = (MonoAppDomain *) mono_object_new (data, adclass);
483 data->friendly_name = g_strdup (friendly_name);
485 if (!setup->application_base) {
486 /* Inherit from the root domain since MS.NET does this */
487 MonoDomain *root = mono_get_root_domain ();
488 if (root->setup->application_base)
489 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)));
492 mono_context_init (data);
494 data->setup = copy_app_domain_setup (data, setup);
495 mono_set_private_bin_path_from_config (data);
496 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
498 #ifndef DISABLE_SHADOW_COPY
499 /*FIXME, guard this for when the debugger is not running */
500 shadow_location = get_shadow_assembly_location_base (data, &error);
501 if (!mono_error_ok (&error))
502 mono_error_raise_exception (&error);
503 g_free (shadow_location);
506 create_domain_objects (data);
512 * mono_domain_has_type_resolve:
513 * @domain: application domains being looked up
515 * Returns true if the AppDomain.TypeResolve field has been
519 mono_domain_has_type_resolve (MonoDomain *domain)
521 static MonoClassField *field = NULL;
525 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
529 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
533 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
538 * mono_domain_try_type_resolve:
539 * @domain: application domainwhere the name where the type is going to be resolved
540 * @name: the name of the type to resolve or NULL.
541 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
543 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
544 * the assembly that matches name.
546 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
548 * Returns: A MonoReflectionAssembly or NULL if not found
550 MonoReflectionAssembly *
551 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
555 static MonoMethod *method = NULL;
557 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
559 if (method == NULL) {
560 klass = domain->domain->mbr.obj.vtable->klass;
563 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
564 if (method == NULL) {
565 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
571 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
574 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
578 * mono_domain_owns_vtable_slot:
580 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
583 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
587 mono_domain_lock (domain);
588 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
589 mono_domain_unlock (domain);
596 * @force: force setting.
598 * Set the current appdomain to @domain. If @force is set, set it even
599 * if it is being unloaded.
603 * FALSE if the domain is unloaded
606 mono_domain_set (MonoDomain *domain, gboolean force)
608 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
611 mono_domain_set_internal (domain);
617 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
623 MONO_CHECK_ARG_NULL (name, NULL);
625 g_assert (ad != NULL);
627 g_assert (add != NULL);
629 str = mono_string_to_utf8 (name);
631 mono_domain_lock (add);
633 if (!strcmp (str, "APPBASE"))
634 o = (MonoObject *)add->setup->application_base;
635 else if (!strcmp (str, "APP_CONFIG_FILE"))
636 o = (MonoObject *)add->setup->configuration_file;
637 else if (!strcmp (str, "DYNAMIC_BASE"))
638 o = (MonoObject *)add->setup->dynamic_base;
639 else if (!strcmp (str, "APP_NAME"))
640 o = (MonoObject *)add->setup->application_name;
641 else if (!strcmp (str, "CACHE_BASE"))
642 o = (MonoObject *)add->setup->cache_path;
643 else if (!strcmp (str, "PRIVATE_BINPATH"))
644 o = (MonoObject *)add->setup->private_bin_path;
645 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
646 o = (MonoObject *)add->setup->private_bin_path_probe;
647 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
648 o = (MonoObject *)add->setup->shadow_copy_directories;
649 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
650 o = (MonoObject *)add->setup->shadow_copy_files;
652 o = mono_g_hash_table_lookup (add->env, name);
654 mono_domain_unlock (add);
664 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
668 MONO_CHECK_ARG_NULL (name,);
670 g_assert (ad != NULL);
672 g_assert (add != NULL);
674 mono_domain_lock (add);
676 mono_g_hash_table_insert (add->env, name, data);
678 mono_domain_unlock (add);
682 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
684 g_assert (ad != NULL);
685 g_assert (ad->data != NULL);
687 return ad->data->setup;
691 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
693 g_assert (ad != NULL);
694 g_assert (ad->data != NULL);
696 return mono_string_new (ad->data, ad->data->friendly_name);
700 ves_icall_System_AppDomain_getCurDomain ()
702 MonoDomain *add = mono_domain_get ();
708 ves_icall_System_AppDomain_getRootDomain ()
710 MonoDomain *root = mono_get_root_domain ();
716 get_attribute_value (const gchar **attribute_names,
717 const gchar **attribute_values,
718 const char *att_name)
721 for (n = 0; attribute_names [n] != NULL; n++) {
722 if (strcmp (attribute_names [n], att_name) == 0)
723 return g_strdup (attribute_values [n]);
729 start_element (GMarkupParseContext *context,
730 const gchar *element_name,
731 const gchar **attribute_names,
732 const gchar **attribute_values,
736 RuntimeConfig *runtime_config = user_data;
738 if (strcmp (element_name, "runtime") == 0) {
739 runtime_config->runtime_count++;
743 if (strcmp (element_name, "assemblyBinding") == 0) {
744 runtime_config->assemblybinding_count++;
748 if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
751 if (strcmp (element_name, "probing") != 0)
754 g_free (runtime_config->domain->private_bin_path);
755 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
756 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
757 g_free (runtime_config->domain->private_bin_path);
758 runtime_config->domain->private_bin_path = NULL;
764 end_element (GMarkupParseContext *context,
765 const gchar *element_name,
769 RuntimeConfig *runtime_config = user_data;
770 if (strcmp (element_name, "runtime") == 0)
771 runtime_config->runtime_count--;
772 else if (strcmp (element_name, "assemblyBinding") == 0)
773 runtime_config->assemblybinding_count--;
777 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
779 RuntimeConfig *state = user_data;
781 const gchar *filename;
783 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
784 msg = error && error->message ? error->message : "";
785 g_warning ("Error parsing %s: %s", filename, msg);
788 static const GMarkupParser
798 mono_set_private_bin_path_from_config (MonoDomain *domain)
801 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
803 GMarkupParseContext *context;
804 RuntimeConfig runtime_config;
807 if (!domain || !domain->setup || !domain->setup->configuration_file)
810 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
811 if (!mono_error_ok (&error)) {
812 mono_error_cleanup (&error);
816 config_file_path = mono_portability_find_file (config_file_name, TRUE);
817 if (!config_file_path)
818 config_file_path = config_file_name;
820 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
823 runtime_config.runtime_count = 0;
824 runtime_config.assemblybinding_count = 0;
825 runtime_config.domain = domain;
826 runtime_config.filename = config_file_path;
829 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
830 offset = 3; /* Skip UTF-8 BOM */
832 context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
833 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
834 g_markup_parse_context_end_parse (context, NULL);
835 g_markup_parse_context_free (context);
839 if (config_file_name != config_file_path)
840 g_free (config_file_name);
841 g_free (config_file_path);
845 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
847 #ifdef DISABLE_APPDOMAINS
848 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
851 char *fname = mono_string_to_utf8 (friendly_name);
852 MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
861 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
863 MonoDomain *domain = ad->data;
865 static MonoClass *System_Reflection_Assembly;
869 GPtrArray *assemblies;
871 if (!System_Reflection_Assembly)
872 System_Reflection_Assembly = mono_class_from_name (
873 mono_defaults.corlib, "System.Reflection", "Assembly");
876 * Make a copy of the list of assemblies because we can't hold the assemblies
877 * lock while creating objects etc.
879 assemblies = g_ptr_array_new ();
880 /* Need to skip internal assembly builders created by remoting */
881 mono_domain_assemblies_lock (domain);
882 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
884 if (refonly != ass->ref_only)
886 if (ass->corlib_internal)
888 g_ptr_array_add (assemblies, ass);
890 mono_domain_assemblies_unlock (domain);
892 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
893 for (i = 0; i < assemblies->len; ++i) {
894 ass = g_ptr_array_index (assemblies, i);
895 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
898 g_ptr_array_free (assemblies, TRUE);
903 MonoReflectionAssembly *
904 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
908 MonoBoolean isrefonly;
911 if (mono_runtime_get_no_exec ())
914 g_assert (domain != NULL && fname != NULL);
916 klass = domain->domain->mbr.obj.vtable->klass;
919 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
920 if (method == NULL) {
921 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
925 isrefonly = refonly ? 1 : 0;
927 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
928 params [2] = &isrefonly;
929 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
933 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
936 MonoReflectionAssembly *assembly;
937 MonoDomain *domain = mono_domain_get ();
941 aname_str = mono_stringify_assembly_name (aname);
943 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
944 str = mono_string_new (domain, aname_str);
949 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
953 return assembly->assembly;
959 * LOCKING: assumes assemblies_lock in the domain is already locked.
962 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
966 gboolean destroy_ht = FALSE;
968 if (!ass->aname.name)
972 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
976 /* FIXME: handle lazy loaded assemblies */
977 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
978 g_hash_table_insert (ht, tmp->data, tmp->data);
980 if (!g_hash_table_lookup (ht, ass)) {
981 mono_assembly_addref (ass);
982 g_hash_table_insert (ht, ass, ass);
983 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
984 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);
987 if (ass->image->references) {
988 for (i = 0; ass->image->references [i] != NULL; i++) {
989 if (ass->image->references [i] != REFERENCE_MISSING)
990 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
991 add_assemblies_to_domain (domain, ass->image->references [i], ht);
996 g_hash_table_destroy (ht);
1000 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1002 static MonoClassField *assembly_load_field;
1003 static MonoMethod *assembly_load_method;
1004 MonoDomain *domain = mono_domain_get ();
1005 MonoReflectionAssembly *ref_assembly;
1007 gpointer load_value;
1010 if (!domain->domain)
1011 /* This can happen during startup */
1013 #ifdef ASSEMBLY_LOAD_DEBUG
1014 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1016 klass = domain->domain->mbr.obj.vtable->klass;
1018 mono_domain_assemblies_lock (domain);
1019 add_assemblies_to_domain (domain, assembly, NULL);
1020 mono_domain_assemblies_unlock (domain);
1022 if (assembly_load_field == NULL) {
1023 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1024 g_assert (assembly_load_field);
1027 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1028 if (load_value == NULL) {
1029 /* No events waiting to be triggered */
1033 ref_assembly = mono_assembly_get_object (domain, assembly);
1034 g_assert (ref_assembly);
1036 if (assembly_load_method == NULL) {
1037 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1038 g_assert (assembly_load_method);
1041 *params = ref_assembly;
1042 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1046 * LOCKING: Acquires the domain assemblies lock.
1049 set_domain_search_path (MonoDomain *domain)
1052 MonoAppDomainSetup *setup;
1054 gchar *search_path = NULL;
1057 gchar **pvt_split = NULL;
1058 GError *gerror = NULL;
1059 gint appbaselen = -1;
1062 * We use the low-level domain assemblies lock, since this is called from
1063 * assembly loads hooks, which means this thread might hold the loader lock.
1065 mono_domain_assemblies_lock (domain);
1067 if (!domain->setup) {
1068 mono_domain_assemblies_unlock (domain);
1072 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1073 mono_domain_assemblies_unlock (domain);
1076 setup = domain->setup;
1077 if (!setup->application_base) {
1078 mono_domain_assemblies_unlock (domain);
1079 return; /* Must set application base to get private path working */
1084 if (setup->private_bin_path) {
1085 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1086 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1087 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1088 mono_error_cleanup (&error);
1089 mono_domain_assemblies_unlock (domain);
1094 if (domain->private_bin_path) {
1095 if (search_path == NULL)
1096 search_path = domain->private_bin_path;
1098 gchar *tmp2 = search_path;
1099 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1106 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1107 * directories relative to ApplicationBase separated by semicolons (see
1108 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1109 * The loop below copes with the fact that some Unix applications may use ':' (or
1110 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1111 * ';' for the subsequent split.
1113 * The issue was reported in bug #81446
1116 #ifndef TARGET_WIN32
1119 slen = strlen (search_path);
1120 for (i = 0; i < slen; i++)
1121 if (search_path [i] == ':')
1122 search_path [i] = ';';
1125 pvt_split = g_strsplit (search_path, ";", 1000);
1126 g_free (search_path);
1127 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1132 g_strfreev (pvt_split);
1134 * Don't do this because the first time is called, the domain
1135 * setup is not finished.
1137 * domain->search_path = g_malloc (sizeof (char *));
1138 * domain->search_path [0] = NULL;
1140 mono_domain_assemblies_unlock (domain);
1144 if (domain->search_path)
1145 g_strfreev (domain->search_path);
1147 tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1148 tmp [npaths] = NULL;
1150 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1151 if (!mono_error_ok (&error)) {
1152 mono_error_cleanup (&error);
1153 g_strfreev (pvt_split);
1156 mono_domain_assemblies_unlock (domain);
1160 domain->search_path = tmp;
1162 /* FIXME: is this needed? */
1163 if (strncmp (*tmp, "file://", 7) == 0) {
1169 uri = g_strdup_printf ("file:///%s", uri + 7);
1172 uri = mono_escape_uri_string (tmpuri);
1173 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1179 if (gerror != NULL) {
1180 g_warning ("%s\n", gerror->message);
1181 g_error_free (gerror);
1188 for (i = 1; pvt_split && i < npaths; i++) {
1189 if (g_path_is_absolute (pvt_split [i - 1])) {
1190 tmp [i] = g_strdup (pvt_split [i - 1]);
1192 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1195 if (strchr (tmp [i], '.')) {
1199 reduced = mono_path_canonicalize (tmp [i]);
1200 if (appbaselen == -1)
1201 appbaselen = strlen (tmp [0]);
1203 if (strncmp (tmp [0], reduced, appbaselen)) {
1206 tmp [i] = g_strdup ("");
1216 if (setup->private_bin_path_probe != NULL) {
1218 tmp [0] = g_strdup ("");
1221 domain->setup->path_changed = FALSE;
1223 g_strfreev (pvt_split);
1225 mono_domain_assemblies_unlock (domain);
1228 #ifdef DISABLE_SHADOW_COPY
1230 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1236 mono_make_shadow_copy (const char *filename)
1238 return (char *) filename;
1242 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1244 guint16 *orig, *dest;
1245 gboolean copy_result;
1247 strcpy (src + srclen - tail_len, extension);
1249 if (IS_PORTABILITY_CASE) {
1250 gchar *file = mono_portability_find_file (src, TRUE);
1256 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1260 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1262 strcpy (target + targetlen - tail_len, extension);
1263 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1266 copy_result = CopyFile (orig, dest, FALSE);
1268 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1269 * overwritten when updated in their original locations. */
1271 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1280 get_cstring_hash (const char *str)
1286 if (!str || !str [0])
1291 for (i = 0; i < len; i++) {
1292 h = (h << 5) - h + *p;
1300 * Returned memory is malloc'd. Called must free it
1303 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1305 MonoAppDomainSetup *setup;
1306 char *cache_path, *appname;
1310 mono_error_init (error);
1312 setup = domain->setup;
1313 if (setup->cache_path != NULL && setup->application_name != NULL) {
1314 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1315 if (!mono_error_ok (error))
1317 #ifndef TARGET_WIN32
1320 for (i = strlen (cache_path) - 1; i >= 0; i--)
1321 if (cache_path [i] == '\\')
1322 cache_path [i] = '/';
1326 appname = mono_string_to_utf8_checked (setup->application_name, error);
1327 if (!mono_error_ok (error)) {
1328 g_free (cache_path);
1332 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1334 g_free (cache_path);
1336 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1337 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1344 get_shadow_assembly_location (const char *filename, MonoError *error)
1346 gint32 hash = 0, hash2 = 0;
1348 char path_hash [30];
1349 char *bname = g_path_get_basename (filename);
1350 char *dirname = g_path_get_dirname (filename);
1351 char *location, *tmploc;
1352 MonoDomain *domain = mono_domain_get ();
1354 mono_error_init (error);
1356 hash = get_cstring_hash (bname);
1357 hash2 = get_cstring_hash (dirname);
1358 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1359 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1360 tmploc = get_shadow_assembly_location_base (domain, error);
1361 if (!mono_error_ok (error)) {
1367 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1375 ensure_directory_exists (const char *filename)
1378 gchar *dir_utf8 = g_path_get_dirname (filename);
1380 gunichar2 *dir_utf16 = NULL;
1383 if (!dir_utf8 || !dir_utf8 [0])
1386 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1394 /* make life easy and only use one directory seperator */
1405 while (*p++ != '\\')
1411 p = wcschr (p, '\\');
1414 retval = _wmkdir (dir_utf16);
1415 if (retval != 0 && errno != EEXIST) {
1428 gchar *dir = g_path_get_dirname (filename);
1432 if (!dir || !dir [0]) {
1437 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1447 p = strchr (p, '/');
1450 retval = mkdir (dir, 0777);
1451 if (retval != 0 && errno != EEXIST) {
1466 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1468 struct stat sbuf_dest;
1470 gchar *real_src = mono_portability_find_file (src, TRUE);
1473 stat_src = (gchar*)src;
1475 stat_src = real_src;
1477 if (stat (stat_src, sbuf_src) == -1) {
1478 time_t tnow = time (NULL);
1483 memset (sbuf_src, 0, sizeof (*sbuf_src));
1484 sbuf_src->st_mtime = tnow;
1485 sbuf_src->st_atime = tnow;
1492 if (stat (dest, &sbuf_dest) == -1)
1495 if (sbuf_src->st_size == sbuf_dest.st_size &&
1496 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1503 shadow_copy_create_ini (const char *shadow, const char *filename)
1513 dir_name = g_path_get_dirname (shadow);
1514 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1516 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1521 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1526 handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1527 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1529 if (handle == INVALID_HANDLE_VALUE) {
1533 full_path = mono_path_resolve_symlinks (filename);
1534 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1536 CloseHandle (handle);
1541 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1544 MonoAppDomainSetup *setup;
1547 gchar **directories;
1548 gchar *shadow_status_string;
1550 gboolean shadow_enabled;
1551 gboolean found = FALSE;
1556 setup = domain->setup;
1557 if (setup == NULL || setup->shadow_copy_files == NULL)
1560 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1561 if (!mono_error_ok (&error)) {
1562 mono_error_cleanup (&error);
1565 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1566 g_free (shadow_status_string);
1568 if (!shadow_enabled)
1571 if (setup->shadow_copy_directories == NULL)
1574 /* Is dir_name a shadow_copy destination already? */
1575 base_dir = get_shadow_assembly_location_base (domain, &error);
1576 if (!mono_error_ok (&error)) {
1577 mono_error_cleanup (&error);
1581 if (strstr (dir_name, base_dir)) {
1587 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1588 if (!mono_error_ok (&error)) {
1589 mono_error_cleanup (&error);
1593 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1594 dir_ptr = directories;
1596 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1602 g_strfreev (directories);
1608 This function raises exceptions so it can cause as sorts of nasty stuff if called
1609 while holding a lock.
1610 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1611 or NULL if source file not found.
1612 FIXME bubble up the error instead of raising it here
1615 mono_make_shadow_copy (const char *filename)
1618 gchar *sibling_source, *sibling_target;
1619 gint sibling_source_len, sibling_target_len;
1620 guint16 *orig, *dest;
1623 gboolean copy_result;
1625 struct stat src_sbuf;
1626 struct utimbuf utbuf;
1627 char *dir_name = g_path_get_dirname (filename);
1628 MonoDomain *domain = mono_domain_get ();
1631 set_domain_search_path (domain);
1633 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1635 return (char *) filename;
1638 /* Is dir_name a shadow_copy destination already? */
1639 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1640 if (!mono_error_ok (&error)) {
1641 mono_error_cleanup (&error);
1643 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1644 mono_raise_exception (exc);
1647 if (strstr (dir_name, shadow_dir)) {
1648 g_free (shadow_dir);
1650 return (char *) filename;
1652 g_free (shadow_dir);
1655 shadow = get_shadow_assembly_location (filename, &error);
1656 if (!mono_error_ok (&error)) {
1657 mono_error_cleanup (&error);
1658 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1659 mono_raise_exception (exc);
1662 if (ensure_directory_exists (shadow) == FALSE) {
1664 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1665 mono_raise_exception (exc);
1668 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1669 return (char*) shadow;
1671 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1672 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1675 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1676 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1677 * and not have it runtime error" */
1678 attrs = GetFileAttributes (orig);
1679 if (attrs == INVALID_FILE_ATTRIBUTES) {
1681 return (char *)filename;
1684 copy_result = CopyFile (orig, dest, FALSE);
1686 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1687 * overwritten when updated in their original locations. */
1689 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1694 if (copy_result == FALSE) {
1697 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1698 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1699 return NULL; /* file not found, shadow copy failed */
1701 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1702 mono_raise_exception (exc);
1705 /* attempt to copy .mdb, .config if they exist */
1706 sibling_source = g_strconcat (filename, ".config", NULL);
1707 sibling_source_len = strlen (sibling_source);
1708 sibling_target = g_strconcat (shadow, ".config", NULL);
1709 sibling_target_len = strlen (sibling_target);
1711 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1712 if (copy_result == TRUE)
1713 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1715 g_free (sibling_source);
1716 g_free (sibling_target);
1718 if (copy_result == FALSE) {
1720 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1721 mono_raise_exception (exc);
1724 /* Create a .ini file containing the original assembly location */
1725 if (!shadow_copy_create_ini (shadow, filename)) {
1727 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1728 mono_raise_exception (exc);
1731 utbuf.actime = src_sbuf.st_atime;
1732 utbuf.modtime = src_sbuf.st_mtime;
1733 utime (shadow, &utbuf);
1737 #endif /* DISABLE_SHADOW_COPY */
1740 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1742 if (appdomain == NULL)
1745 return appdomain->data;
1749 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1750 const gchar *path3, const gchar *path4,
1751 gboolean refonly, gboolean is_private)
1754 gboolean found = FALSE;
1757 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1759 if (IS_PORTABILITY_SET) {
1760 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1763 fullpath = new_fullpath;
1767 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1770 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1773 return (*assembly != NULL);
1776 static MonoAssembly *
1777 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1779 MonoAssembly *result = NULL;
1782 const gchar *local_culture;
1784 gboolean is_private = FALSE;
1786 if (!culture || *culture == '\0') {
1789 local_culture = culture;
1792 filename = g_strconcat (name, ".dll", NULL);
1793 len = strlen (filename);
1795 for (path = search_path; *path; path++) {
1796 if (**path == '\0') {
1798 continue; /* Ignore empty ApplicationBase */
1801 /* See test cases in bug #58992 and bug #57710 */
1802 /* 1st try: [culture]/[name].dll (culture may be empty) */
1803 strcpy (filename + len - 4, ".dll");
1804 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1807 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1808 strcpy (filename + len - 4, ".exe");
1809 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1812 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1813 strcpy (filename + len - 4, ".dll");
1814 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1817 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1818 strcpy (filename + len - 4, ".exe");
1819 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1828 * Try loading the assembly from ApplicationBase and PrivateBinPath
1829 * and then from assemblies_path if any.
1830 * LOCKING: This is called from the assembly loading code, which means the caller
1831 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1833 static MonoAssembly *
1834 mono_domain_assembly_preload (MonoAssemblyName *aname,
1835 gchar **assemblies_path,
1838 MonoDomain *domain = mono_domain_get ();
1839 MonoAssembly *result = NULL;
1840 gboolean refonly = GPOINTER_TO_UINT (user_data);
1842 set_domain_search_path (domain);
1844 if (domain->search_path && domain->search_path [0] != NULL) {
1845 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1848 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1849 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1856 * Check whenever a given assembly was already loaded in the current appdomain.
1858 static MonoAssembly *
1859 mono_domain_assembly_search (MonoAssemblyName *aname,
1862 MonoDomain *domain = mono_domain_get ();
1865 gboolean refonly = GPOINTER_TO_UINT (user_data);
1867 mono_domain_assemblies_lock (domain);
1868 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1870 /* Dynamic assemblies can't match here in MS.NET */
1871 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1874 mono_domain_assemblies_unlock (domain);
1877 mono_domain_assemblies_unlock (domain);
1882 MonoReflectionAssembly *
1883 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1885 MonoDomain *domain = mono_domain_get ();
1886 char *name, *filename;
1887 MonoImageOpenStatus status = MONO_IMAGE_OK;
1890 if (fname == NULL) {
1891 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1892 mono_set_pending_exception (exc);
1896 name = filename = mono_string_to_utf8 (fname);
1898 ass = mono_assembly_open_full (filename, &status, refOnly);
1903 if (status == MONO_IMAGE_IMAGE_INVALID)
1904 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1906 exc = mono_get_exception_file_not_found2 (NULL, fname);
1908 mono_set_pending_exception (exc);
1914 return mono_assembly_get_object (domain, ass);
1917 MonoReflectionAssembly *
1918 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1919 MonoArray *raw_assembly,
1920 MonoArray *raw_symbol_store, MonoObject *evidence,
1921 MonoBoolean refonly)
1924 MonoReflectionAssembly *refass = NULL;
1925 MonoDomain *domain = ad->data;
1926 MonoImageOpenStatus status;
1927 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1928 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1931 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1935 if (raw_symbol_store != NULL)
1936 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1938 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1942 mono_image_close (image);
1943 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1947 refass = mono_assembly_get_object (domain, ass);
1948 MONO_OBJECT_SETREF (refass, evidence, evidence);
1952 MonoReflectionAssembly *
1953 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1955 MonoDomain *domain = ad->data;
1956 MonoImageOpenStatus status = MONO_IMAGE_OK;
1958 MonoAssemblyName aname;
1959 MonoReflectionAssembly *refass = NULL;
1963 g_assert (assRef != NULL);
1965 name = mono_string_to_utf8 (assRef);
1966 parsed = mono_assembly_name_parse (name, &aname);
1970 /* This is a parse error... */
1972 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1976 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1977 mono_assembly_name_free (&aname);
1980 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1982 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1991 refass = mono_assembly_get_object (domain, ass);
1993 MONO_OBJECT_SETREF (refass, evidence, evidence);
1998 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2000 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2002 if (NULL == domain) {
2003 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2004 mono_set_pending_exception (exc);
2008 if (domain == mono_get_root_domain ()) {
2009 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2014 * Unloading seems to cause problems when running NUnit/NAnt, hence
2017 if (g_getenv ("MONO_NO_UNLOAD"))
2019 #ifdef __native_client__
2023 mono_domain_unload (domain);
2027 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2029 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2034 return mono_domain_is_unloading (domain);
2038 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2039 MonoReflectionAssembly *refass, MonoArray *args)
2046 image = refass->assembly->image;
2049 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2052 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2055 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2057 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2061 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2063 return ad->data->domain_id;
2067 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2069 MonoDomain *old_domain = mono_domain_get();
2071 if (!mono_domain_set (ad->data, FALSE)) {
2072 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2076 return old_domain->domain;
2080 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2082 MonoDomain *current_domain = mono_domain_get ();
2083 MonoDomain *domain = mono_domain_get_by_id (domainid);
2085 if (!domain || !mono_domain_set (domain, FALSE)) {
2086 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2090 return current_domain->domain;
2094 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2096 mono_thread_push_appdomain_ref (ad->data);
2100 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2102 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2106 * Raise an exception to prevent the managed code from executing a pop
2109 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2113 mono_thread_push_appdomain_ref (domain);
2117 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2119 mono_thread_pop_appdomain_ref ();
2123 ves_icall_System_AppDomain_InternalGetContext ()
2125 return mono_context_get ();
2129 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2131 return mono_domain_get ()->default_context;
2135 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2137 MonoAppContext *old_context = mono_context_get ();
2139 mono_context_set (mc);
2145 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2147 MonoDomain* mono_root_domain = mono_get_root_domain ();
2148 mono_domain_lock (mono_root_domain);
2149 if (process_guid_set) {
2150 mono_domain_unlock (mono_root_domain);
2151 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2153 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2154 process_guid_set = TRUE;
2155 mono_domain_unlock (mono_root_domain);
2160 mono_domain_is_unloading (MonoDomain *domain)
2162 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2169 clear_cached_vtable (MonoVTable *vtable)
2171 MonoClass *klass = vtable->klass;
2172 MonoDomain *domain = vtable->domain;
2173 MonoClassRuntimeInfo *runtime_info;
2176 runtime_info = klass->runtime_info;
2177 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2178 runtime_info->domain_vtables [domain->domain_id] = NULL;
2179 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2180 mono_gc_free_fixed (data);
2183 static G_GNUC_UNUSED void
2184 zero_static_data (MonoVTable *vtable)
2186 MonoClass *klass = vtable->klass;
2189 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2190 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2193 typedef struct unload_data {
2196 char *failure_reason;
2201 unload_data_unref (unload_data *data)
2205 mono_atomic_load_acquire (count, gint32, &data->refcount);
2206 g_assert (count >= 1 && count <= 2);
2211 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2215 deregister_reflection_info_roots_from_list (MonoImage *image)
2217 GSList *list = image->reflection_info_unregister_classes;
2220 MonoClass *class = list->data;
2222 mono_class_free_ref_info (class);
2227 image->reflection_info_unregister_classes = NULL;
2231 deregister_reflection_info_roots (MonoDomain *domain)
2235 mono_domain_assemblies_lock (domain);
2236 for (list = domain->domain_assemblies; list; list = list->next) {
2237 MonoAssembly *assembly = list->data;
2238 MonoImage *image = assembly->image;
2242 * No need to take the image lock here since dynamic images are appdomain bound and
2243 * at this point the mutator is gone. Taking the image lock here would mean
2244 * promoting it from a simple lock to a complex lock, which we better avoid if
2247 if (image_is_dynamic (image))
2248 deregister_reflection_info_roots_from_list (image);
2250 for (i = 0; i < image->module_count; ++i) {
2251 MonoImage *module = image->modules [i];
2252 if (module && image_is_dynamic (module))
2253 deregister_reflection_info_roots_from_list (module);
2256 mono_domain_assemblies_unlock (domain);
2259 static guint32 WINAPI
2260 unload_thread_main (void *arg)
2262 unload_data *data = (unload_data*)arg;
2263 MonoDomain *domain = data->domain;
2267 /* Have to attach to the runtime so shutdown can wait for this thread */
2268 /* Force it to be attached to avoid racing during shutdown. */
2269 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2272 * FIXME: Abort our parent thread last, so we can return a failure
2273 * indication if aborting times out.
2275 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2276 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2280 if (!mono_thread_pool_remove_domain_jobs (domain, -1)) {
2281 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2285 /* Finalize all finalizable objects in the doomed appdomain */
2286 if (!mono_domain_finalize (domain, -1)) {
2287 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2291 /* Clear references to our vtables in class->runtime_info.
2292 * We also hold the loader lock because we're going to change
2293 * class->runtime_info.
2296 mono_loader_lock (); //FIXME why do we need the loader lock here?
2297 mono_domain_lock (domain);
2300 * We need to make sure that we don't have any remsets
2301 * pointing into static data of the to-be-freed domain because
2302 * at the next collections they would be invalid. So what we
2303 * do is we first zero all static data and then do a minor
2304 * collection. Because all references in the static data will
2305 * now be null we won't do any unnecessary copies and after
2306 * the collection there won't be any more remsets.
2308 for (i = 0; i < domain->class_vtable_array->len; ++i)
2309 zero_static_data (g_ptr_array_index (domain->class_vtable_array, i));
2310 mono_gc_collect (0);
2312 for (i = 0; i < domain->class_vtable_array->len; ++i)
2313 clear_cached_vtable (g_ptr_array_index (domain->class_vtable_array, i));
2314 deregister_reflection_info_roots (domain);
2316 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2318 mono_domain_unlock (domain);
2319 mono_loader_unlock ();
2321 mono_threads_clear_cached_culture (domain);
2323 domain->state = MONO_APPDOMAIN_UNLOADED;
2325 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2327 /* remove from the handle table the items related to this domain */
2328 mono_gchandle_free_domain (domain);
2330 mono_domain_free (domain, FALSE);
2332 mono_gc_collect (mono_gc_max_generation ());
2334 mono_atomic_store_release (&data->done, TRUE);
2335 unload_data_unref (data);
2336 mono_thread_detach (thread);
2340 mono_atomic_store_release (&data->done, TRUE);
2341 unload_data_unref (data);
2342 mono_thread_detach (thread);
2347 * mono_domain_unload:
2348 * @domain: The domain to unload
2350 * Unloads an appdomain. Follows the process outlined in the comment
2351 * for mono_domain_try_unload.
2354 mono_domain_unload (MonoDomain *domain)
2356 MonoObject *exc = NULL;
2357 mono_domain_try_unload (domain, &exc);
2359 mono_raise_exception ((MonoException*)exc);
2363 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2367 MONO_PREPARE_BLOCKING
2368 result = WaitForSingleObjectEx (handle, timeout, alertable);
2369 MONO_FINISH_BLOCKING
2375 * mono_domain_unload:
2376 * @domain: The domain to unload
2377 * @exc: Exception information
2379 * Unloads an appdomain. Follows the process outlined in:
2380 * http://blogs.gotdotnet.com/cbrumme
2382 * If doing things the 'right' way is too hard or complex, we do it the
2383 * 'simple' way, which means do everything needed to avoid crashes and
2384 * memory leaks, but not much else.
2386 * It is required to pass a valid reference to the exc argument, upon return
2387 * from this function *exc will be set to the exception thrown, if any.
2389 * If this method is not called from an icall (embedded scenario for instance),
2390 * it must not be called with any managed frames on the stack, since the unload
2391 * process could end up trying to abort the current thread.
2394 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2396 HANDLE thread_handle;
2397 MonoAppDomainState prev_state;
2399 unload_data *thread_data;
2400 MonoNativeThreadId tid;
2401 MonoDomain *caller_domain = mono_domain_get ();
2404 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2406 /* Atomically change our state to UNLOADING */
2407 prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2408 MONO_APPDOMAIN_UNLOADING_START,
2409 MONO_APPDOMAIN_CREATED);
2410 if (prev_state != MONO_APPDOMAIN_CREATED) {
2411 switch (prev_state) {
2412 case MONO_APPDOMAIN_UNLOADING_START:
2413 case MONO_APPDOMAIN_UNLOADING:
2414 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2416 case MONO_APPDOMAIN_UNLOADED:
2417 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2420 g_warning ("Invalid appdomain state %d", prev_state);
2421 g_assert_not_reached ();
2425 mono_domain_set (domain, FALSE);
2426 /* Notify OnDomainUnload listeners */
2427 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2430 mono_runtime_invoke (method, domain->domain, NULL, exc);
2432 /* Roll back the state change */
2433 domain->state = MONO_APPDOMAIN_CREATED;
2434 mono_domain_set (caller_domain, FALSE);
2437 mono_domain_set (caller_domain, FALSE);
2439 thread_data = g_new0 (unload_data, 1);
2440 thread_data->domain = domain;
2441 thread_data->failure_reason = NULL;
2442 thread_data->done = FALSE;
2443 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2445 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2446 domain->state = MONO_APPDOMAIN_UNLOADING;
2448 * First we create a separate thread for unloading, since
2449 * we might have to abort some threads, including the current one.
2451 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2452 if (thread_handle == NULL)
2454 name = g_strdup_printf ("Unload thread for domain %x", domain);
2455 mono_thread_info_set_name (tid, name);
2456 mono_thread_info_resume (tid);
2459 /* Wait for the thread */
2460 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2461 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2462 /* The unload thread tries to abort us */
2463 /* The icall wrapper will execute the abort */
2464 CloseHandle (thread_handle);
2465 unload_data_unref (thread_data);
2469 CloseHandle (thread_handle);
2471 if (thread_data->failure_reason) {
2472 /* Roll back the state change */
2473 domain->state = MONO_APPDOMAIN_CREATED;
2475 g_warning ("%s", thread_data->failure_reason);
2477 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2479 g_free (thread_data->failure_reason);
2480 thread_data->failure_reason = NULL;
2483 unload_data_unref (thread_data);