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 131
86 int assemblybinding_count;
91 mono_mutex_t mono_delegate_section;
93 mono_mutex_t mono_strtod_mutex;
95 static gunichar2 process_guid [36];
96 static gboolean process_guid_set = FALSE;
98 static gboolean no_exec = FALSE;
100 static MonoAssembly *
101 mono_domain_assembly_preload (MonoAssemblyName *aname,
102 gchar **assemblies_path,
105 static MonoAssembly *
106 mono_domain_assembly_search (MonoAssemblyName *aname,
110 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
113 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
115 static MonoAppDomain *
116 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
119 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
121 static MonoLoadFunc load_function = NULL;
124 mono_install_runtime_load (MonoLoadFunc func)
126 load_function = func;
130 mono_runtime_load (const char *filename, const char *runtime_version)
132 g_assert (load_function);
133 return load_function (filename, runtime_version);
137 * mono_runtime_set_no_exec:
139 * Instructs the runtime to operate in static mode, i.e. avoid/do not
140 * allow managed code execution. This is useful for running the AOT
141 * compiler on platforms which allow full-aot execution only. This
142 * should be called before mono_runtime_init ().
145 mono_runtime_set_no_exec (gboolean val)
151 * mono_runtime_get_no_exec:
153 * If true, then the runtime will not allow managed code execution.
156 mono_runtime_get_no_exec (void)
162 create_domain_objects (MonoDomain *domain)
164 MonoDomain *old_domain = mono_domain_get ();
166 MonoVTable *string_vt;
167 MonoClassField *string_empty_fld;
169 if (domain != old_domain) {
170 mono_thread_push_appdomain_ref (domain);
171 mono_domain_set_internal_with_options (domain, FALSE);
175 * Initialize String.Empty. This enables the removal of
176 * the static cctor of the String class.
178 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
179 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
180 g_assert (string_empty_fld);
181 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
184 * Create an instance early since we can't do it when there is no memory.
186 arg = mono_string_new (domain, "Out of memory");
187 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
190 * These two are needed because the signal handlers might be executing on
191 * an alternate stack, and Boehm GC can't handle that.
193 arg = mono_string_new (domain, "A null value was found where an object instance was required");
194 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
195 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
196 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
198 /*The ephemeron tombstone i*/
199 domain->ephemeron_tombstone = mono_object_new (domain, mono_defaults.object_class);
201 if (domain != old_domain) {
202 mono_thread_pop_appdomain_ref ();
203 mono_domain_set_internal_with_options (old_domain, FALSE);
207 * This class is used during exception handling, so initialize it here, to prevent
208 * stack overflows while handling stack overflows.
210 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
215 * @domain: domain returned by mono_init ()
217 * Initialize the core AppDomain: this function will run also some
218 * IL initialization code, so it needs the execution engine to be fully
221 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
222 * we know the entry_assembly.
226 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
227 MonoThreadAttachCB attach_cb)
229 MonoAppDomainSetup *setup;
233 mono_portability_helpers_init ();
235 mono_gc_base_init ();
236 mono_monitor_init ();
237 mono_thread_pool_init ();
238 mono_marshal_init ();
240 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
241 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
242 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
243 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
244 mono_install_assembly_postload_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
245 mono_install_assembly_postload_refonly_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
246 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
247 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
249 mono_thread_init (start_cb, attach_cb);
251 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
252 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, class);
254 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
255 ad = (MonoAppDomain *) mono_object_new_pinned (domain, class);
258 domain->setup = setup;
260 mono_mutex_init_recursive (&mono_delegate_section);
262 mono_mutex_init_recursive (&mono_strtod_mutex);
264 mono_thread_attach (domain);
266 mono_type_initialization_init ();
268 if (!mono_runtime_get_no_exec ())
269 create_domain_objects (domain);
271 /* GC init has to happen after thread init */
274 /* contexts use GC handles, so they must be initialized after the GC */
275 mono_context_init (domain);
276 mono_context_set (domain->default_context);
278 #ifndef DISABLE_SOCKETS
279 mono_network_init ();
282 mono_console_init ();
285 mono_locks_tracer_init ();
287 /* mscorlib is loaded before we install the load hook */
288 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
294 mono_get_corlib_version (void)
297 MonoClassField *field;
300 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
301 mono_class_init (klass);
302 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
305 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
307 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
308 return *(gint32*)((gchar*)value + sizeof (MonoObject));
312 * mono_check_corlib_version
314 * Checks that the corlib that is loaded matches the version of this runtime.
316 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
317 * allocated string with the error otherwise.
320 mono_check_corlib_version (void)
322 int version = mono_get_corlib_version ();
323 if (version != MONO_CORLIB_VERSION)
324 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
331 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
333 * Initializes the @domain's default System.Runtime.Remoting's Context.
336 mono_context_init (MonoDomain *domain)
339 MonoAppContext *context;
341 class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
342 context = (MonoAppContext *) mono_object_new_pinned (domain, class);
343 context->domain_id = domain->domain_id;
344 context->context_id = 0;
345 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
346 domain->default_context = context;
350 * mono_runtime_cleanup:
355 * This must not be called while there are still running threads executing
359 mono_runtime_cleanup (MonoDomain *domain)
361 mono_attach_cleanup ();
363 /* This ends up calling any pending pending (for at most 2 seconds) */
366 mono_thread_cleanup ();
368 #ifndef DISABLE_SOCKETS
369 mono_network_cleanup ();
371 mono_marshal_cleanup ();
373 mono_type_initialization_cleanup ();
375 mono_monitor_cleanup ();
378 static MonoDomainFunc quit_function = NULL;
381 mono_install_runtime_cleanup (MonoDomainFunc func)
383 quit_function = func;
389 if (quit_function != NULL)
390 quit_function (mono_get_root_domain (), NULL);
394 * mono_domain_create_appdomain:
395 * @friendly_name: The friendly name of the appdomain to create
396 * @configuration_file: The configuration file to initialize the appdomain with
398 * Returns a MonoDomain initialized with the appdomain
401 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
404 MonoAppDomainSetup *setup;
407 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
408 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
409 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
411 ad = mono_domain_create_appdomain_internal (friendly_name, setup);
413 return mono_domain_from_appdomain (ad);
417 * mono_domain_set_config:
418 * @domain: MonoDomain initialized with the appdomain we want to change
419 * @base_dir: new base directory for the appdomain
420 * @config_file_name: path to the new configuration for the app domain
422 * Used to set the system configuration for an appdomain
424 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
425 * Error Initializing the configuration system. ---> System.ArgumentException:
426 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
429 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
431 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
432 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
435 static MonoAppDomainSetup*
436 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
438 MonoDomain *caller_domain = mono_domain_get ();
439 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
440 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
442 mono_domain_set_internal (domain);
444 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
445 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
446 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
447 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
448 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
449 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
450 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
451 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
452 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
453 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
454 copy->publisher_policy = setup->publisher_policy;
455 copy->path_changed = setup->path_changed;
456 copy->loader_optimization = setup->loader_optimization;
457 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
458 copy->disallow_code_downloads = setup->disallow_code_downloads;
459 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
460 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
461 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
462 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
463 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
465 mono_domain_set_internal (caller_domain);
470 static MonoAppDomain *
471 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
477 char *shadow_location;
479 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
481 /* FIXME: pin all those objects */
482 data = mono_domain_create();
484 ad = (MonoAppDomain *) mono_object_new (data, adclass);
487 data->friendly_name = g_strdup (friendly_name);
489 if (!setup->application_base) {
490 /* Inherit from the root domain since MS.NET does this */
491 MonoDomain *root = mono_get_root_domain ();
492 if (root->setup->application_base)
493 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)));
496 mono_context_init (data);
498 data->setup = copy_app_domain_setup (data, setup);
499 mono_set_private_bin_path_from_config (data);
500 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
502 #ifndef DISABLE_SHADOW_COPY
503 /*FIXME, guard this for when the debugger is not running */
504 shadow_location = get_shadow_assembly_location_base (data, &error);
505 if (!mono_error_ok (&error))
506 mono_error_raise_exception (&error);
507 g_free (shadow_location);
510 create_domain_objects (data);
516 * mono_domain_has_type_resolve:
517 * @domain: application domains being looked up
519 * Returns true if the AppDomain.TypeResolve field has been
523 mono_domain_has_type_resolve (MonoDomain *domain)
525 static MonoClassField *field = NULL;
529 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
533 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
537 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
542 * mono_domain_try_type_resolve:
543 * @domain: application domainwhere the name where the type is going to be resolved
544 * @name: the name of the type to resolve or NULL.
545 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
547 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
548 * the assembly that matches name.
550 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
552 * Returns: A MonoReflectionAssembly or NULL if not found
554 MonoReflectionAssembly *
555 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
559 static MonoMethod *method = NULL;
561 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
563 if (method == NULL) {
564 klass = domain->domain->mbr.obj.vtable->klass;
567 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
568 if (method == NULL) {
569 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
575 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
578 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
582 * mono_domain_owns_vtable_slot:
584 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
587 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
591 mono_domain_lock (domain);
592 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
593 mono_domain_unlock (domain);
600 * @force: force setting.
602 * Set the current appdomain to @domain. If @force is set, set it even
603 * if it is being unloaded.
607 * FALSE if the domain is unloaded
610 mono_domain_set (MonoDomain *domain, gboolean force)
612 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
615 mono_domain_set_internal (domain);
621 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
627 MONO_CHECK_ARG_NULL (name, NULL);
629 g_assert (ad != NULL);
631 g_assert (add != NULL);
633 str = mono_string_to_utf8 (name);
635 mono_domain_lock (add);
637 if (!strcmp (str, "APPBASE"))
638 o = (MonoObject *)add->setup->application_base;
639 else if (!strcmp (str, "APP_CONFIG_FILE"))
640 o = (MonoObject *)add->setup->configuration_file;
641 else if (!strcmp (str, "DYNAMIC_BASE"))
642 o = (MonoObject *)add->setup->dynamic_base;
643 else if (!strcmp (str, "APP_NAME"))
644 o = (MonoObject *)add->setup->application_name;
645 else if (!strcmp (str, "CACHE_BASE"))
646 o = (MonoObject *)add->setup->cache_path;
647 else if (!strcmp (str, "PRIVATE_BINPATH"))
648 o = (MonoObject *)add->setup->private_bin_path;
649 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
650 o = (MonoObject *)add->setup->private_bin_path_probe;
651 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
652 o = (MonoObject *)add->setup->shadow_copy_directories;
653 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
654 o = (MonoObject *)add->setup->shadow_copy_files;
656 o = mono_g_hash_table_lookup (add->env, name);
658 mono_domain_unlock (add);
668 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
672 MONO_CHECK_ARG_NULL (name,);
674 g_assert (ad != NULL);
676 g_assert (add != NULL);
678 mono_domain_lock (add);
680 mono_g_hash_table_insert (add->env, name, data);
682 mono_domain_unlock (add);
686 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
688 g_assert (ad != NULL);
689 g_assert (ad->data != NULL);
691 return ad->data->setup;
695 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
697 g_assert (ad != NULL);
698 g_assert (ad->data != NULL);
700 return mono_string_new (ad->data, ad->data->friendly_name);
704 ves_icall_System_AppDomain_getCurDomain ()
706 MonoDomain *add = mono_domain_get ();
712 ves_icall_System_AppDomain_getRootDomain ()
714 MonoDomain *root = mono_get_root_domain ();
720 get_attribute_value (const gchar **attribute_names,
721 const gchar **attribute_values,
722 const char *att_name)
725 for (n = 0; attribute_names [n] != NULL; n++) {
726 if (strcmp (attribute_names [n], att_name) == 0)
727 return g_strdup (attribute_values [n]);
733 start_element (GMarkupParseContext *context,
734 const gchar *element_name,
735 const gchar **attribute_names,
736 const gchar **attribute_values,
740 RuntimeConfig *runtime_config = user_data;
742 if (strcmp (element_name, "runtime") == 0) {
743 runtime_config->runtime_count++;
747 if (strcmp (element_name, "assemblyBinding") == 0) {
748 runtime_config->assemblybinding_count++;
752 if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
755 if (strcmp (element_name, "probing") != 0)
758 g_free (runtime_config->domain->private_bin_path);
759 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
760 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
761 g_free (runtime_config->domain->private_bin_path);
762 runtime_config->domain->private_bin_path = NULL;
768 end_element (GMarkupParseContext *context,
769 const gchar *element_name,
773 RuntimeConfig *runtime_config = user_data;
774 if (strcmp (element_name, "runtime") == 0)
775 runtime_config->runtime_count--;
776 else if (strcmp (element_name, "assemblyBinding") == 0)
777 runtime_config->assemblybinding_count--;
781 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
783 RuntimeConfig *state = user_data;
785 const gchar *filename;
787 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
788 msg = error && error->message ? error->message : "";
789 g_warning ("Error parsing %s: %s", filename, msg);
792 static const GMarkupParser
802 mono_set_private_bin_path_from_config (MonoDomain *domain)
805 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
807 GMarkupParseContext *context;
808 RuntimeConfig runtime_config;
811 if (!domain || !domain->setup || !domain->setup->configuration_file)
814 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
815 if (!mono_error_ok (&error)) {
816 mono_error_cleanup (&error);
820 config_file_path = mono_portability_find_file (config_file_name, TRUE);
821 if (!config_file_path)
822 config_file_path = config_file_name;
824 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
827 runtime_config.runtime_count = 0;
828 runtime_config.assemblybinding_count = 0;
829 runtime_config.domain = domain;
830 runtime_config.filename = config_file_path;
833 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
834 offset = 3; /* Skip UTF-8 BOM */
836 context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
837 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
838 g_markup_parse_context_end_parse (context, NULL);
839 g_markup_parse_context_free (context);
843 if (config_file_name != config_file_path)
844 g_free (config_file_name);
845 g_free (config_file_path);
849 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
851 #ifdef DISABLE_APPDOMAINS
852 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
855 char *fname = mono_string_to_utf8 (friendly_name);
856 MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
865 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
867 MonoDomain *domain = ad->data;
869 static MonoClass *System_Reflection_Assembly;
873 GPtrArray *assemblies;
875 if (!System_Reflection_Assembly)
876 System_Reflection_Assembly = mono_class_from_name (
877 mono_defaults.corlib, "System.Reflection", "Assembly");
880 * Make a copy of the list of assemblies because we can't hold the assemblies
881 * lock while creating objects etc.
883 assemblies = g_ptr_array_new ();
884 /* Need to skip internal assembly builders created by remoting */
885 mono_domain_assemblies_lock (domain);
886 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
888 if (refonly != ass->ref_only)
890 if (ass->corlib_internal)
892 g_ptr_array_add (assemblies, ass);
894 mono_domain_assemblies_unlock (domain);
896 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
897 for (i = 0; i < assemblies->len; ++i) {
898 ass = g_ptr_array_index (assemblies, i);
899 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
902 g_ptr_array_free (assemblies, TRUE);
907 MonoReflectionAssembly *
908 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
912 MonoBoolean isrefonly;
915 if (mono_runtime_get_no_exec ())
918 g_assert (domain != NULL && fname != NULL);
920 klass = domain->domain->mbr.obj.vtable->klass;
923 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
924 if (method == NULL) {
925 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
929 isrefonly = refonly ? 1 : 0;
931 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
932 params [2] = &isrefonly;
933 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
937 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
940 MonoReflectionAssembly *assembly;
941 MonoDomain *domain = mono_domain_get ();
945 aname_str = mono_stringify_assembly_name (aname);
947 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
948 str = mono_string_new (domain, aname_str);
953 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
957 return assembly->assembly;
963 * LOCKING: assumes assemblies_lock in the domain is already locked.
966 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
970 gboolean destroy_ht = FALSE;
972 if (!ass->aname.name)
976 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
980 /* FIXME: handle lazy loaded assemblies */
981 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
982 g_hash_table_insert (ht, tmp->data, tmp->data);
984 if (!g_hash_table_lookup (ht, ass)) {
985 mono_assembly_addref (ass);
986 g_hash_table_insert (ht, ass, ass);
987 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
988 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);
991 if (ass->image->references) {
992 for (i = 0; ass->image->references [i] != NULL; i++) {
993 if (ass->image->references [i] != REFERENCE_MISSING)
994 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
995 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1000 g_hash_table_destroy (ht);
1004 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1006 static MonoClassField *assembly_load_field;
1007 static MonoMethod *assembly_load_method;
1008 MonoDomain *domain = mono_domain_get ();
1009 MonoReflectionAssembly *ref_assembly;
1011 gpointer load_value;
1014 if (!domain->domain)
1015 /* This can happen during startup */
1017 #ifdef ASSEMBLY_LOAD_DEBUG
1018 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1020 klass = domain->domain->mbr.obj.vtable->klass;
1022 mono_domain_assemblies_lock (domain);
1023 add_assemblies_to_domain (domain, assembly, NULL);
1024 mono_domain_assemblies_unlock (domain);
1026 if (assembly_load_field == NULL) {
1027 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1028 g_assert (assembly_load_field);
1031 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1032 if (load_value == NULL) {
1033 /* No events waiting to be triggered */
1037 ref_assembly = mono_assembly_get_object (domain, assembly);
1038 g_assert (ref_assembly);
1040 if (assembly_load_method == NULL) {
1041 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1042 g_assert (assembly_load_method);
1045 *params = ref_assembly;
1046 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1050 * LOCKING: Acquires the domain assemblies lock.
1053 set_domain_search_path (MonoDomain *domain)
1056 MonoAppDomainSetup *setup;
1058 gchar *search_path = NULL;
1061 gchar **pvt_split = NULL;
1062 GError *gerror = NULL;
1063 gint appbaselen = -1;
1066 * We use the low-level domain assemblies lock, since this is called from
1067 * assembly loads hooks, which means this thread might hold the loader lock.
1069 mono_domain_assemblies_lock (domain);
1071 if (!domain->setup) {
1072 mono_domain_assemblies_unlock (domain);
1076 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1077 mono_domain_assemblies_unlock (domain);
1080 setup = domain->setup;
1081 if (!setup->application_base) {
1082 mono_domain_assemblies_unlock (domain);
1083 return; /* Must set application base to get private path working */
1088 if (setup->private_bin_path) {
1089 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1090 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1091 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1092 mono_error_cleanup (&error);
1093 mono_domain_assemblies_unlock (domain);
1098 if (domain->private_bin_path) {
1099 if (search_path == NULL)
1100 search_path = domain->private_bin_path;
1102 gchar *tmp2 = search_path;
1103 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1110 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1111 * directories relative to ApplicationBase separated by semicolons (see
1112 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1113 * The loop below copes with the fact that some Unix applications may use ':' (or
1114 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1115 * ';' for the subsequent split.
1117 * The issue was reported in bug #81446
1120 #ifndef TARGET_WIN32
1123 slen = strlen (search_path);
1124 for (i = 0; i < slen; i++)
1125 if (search_path [i] == ':')
1126 search_path [i] = ';';
1129 pvt_split = g_strsplit (search_path, ";", 1000);
1130 g_free (search_path);
1131 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1136 g_strfreev (pvt_split);
1138 * Don't do this because the first time is called, the domain
1139 * setup is not finished.
1141 * domain->search_path = g_malloc (sizeof (char *));
1142 * domain->search_path [0] = NULL;
1144 mono_domain_assemblies_unlock (domain);
1148 if (domain->search_path)
1149 g_strfreev (domain->search_path);
1151 tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1152 tmp [npaths] = NULL;
1154 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1155 if (!mono_error_ok (&error)) {
1156 mono_error_cleanup (&error);
1157 g_strfreev (pvt_split);
1160 mono_domain_assemblies_unlock (domain);
1164 domain->search_path = tmp;
1166 /* FIXME: is this needed? */
1167 if (strncmp (*tmp, "file://", 7) == 0) {
1173 uri = g_strdup_printf ("file:///%s", uri + 7);
1176 uri = mono_escape_uri_string (tmpuri);
1177 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1183 if (gerror != NULL) {
1184 g_warning ("%s\n", gerror->message);
1185 g_error_free (gerror);
1192 for (i = 1; pvt_split && i < npaths; i++) {
1193 if (g_path_is_absolute (pvt_split [i - 1])) {
1194 tmp [i] = g_strdup (pvt_split [i - 1]);
1196 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1199 if (strchr (tmp [i], '.')) {
1203 reduced = mono_path_canonicalize (tmp [i]);
1204 if (appbaselen == -1)
1205 appbaselen = strlen (tmp [0]);
1207 if (strncmp (tmp [0], reduced, appbaselen)) {
1210 tmp [i] = g_strdup ("");
1220 if (setup->private_bin_path_probe != NULL) {
1222 tmp [0] = g_strdup ("");
1225 domain->setup->path_changed = FALSE;
1227 g_strfreev (pvt_split);
1229 mono_domain_assemblies_unlock (domain);
1232 #ifdef DISABLE_SHADOW_COPY
1234 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1240 mono_make_shadow_copy (const char *filename)
1242 return (char *) filename;
1246 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1248 guint16 *orig, *dest;
1249 gboolean copy_result;
1251 strcpy (src + srclen - tail_len, extension);
1253 if (IS_PORTABILITY_CASE) {
1254 gchar *file = mono_portability_find_file (src, TRUE);
1260 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1264 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1266 strcpy (target + targetlen - tail_len, extension);
1267 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1270 copy_result = CopyFile (orig, dest, FALSE);
1272 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1273 * overwritten when updated in their original locations. */
1275 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1284 get_cstring_hash (const char *str)
1290 if (!str || !str [0])
1295 for (i = 0; i < len; i++) {
1296 h = (h << 5) - h + *p;
1304 * Returned memory is malloc'd. Called must free it
1307 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1309 MonoAppDomainSetup *setup;
1310 char *cache_path, *appname;
1314 mono_error_init (error);
1316 setup = domain->setup;
1317 if (setup->cache_path != NULL && setup->application_name != NULL) {
1318 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1319 if (!mono_error_ok (error))
1321 #ifndef TARGET_WIN32
1324 for (i = strlen (cache_path) - 1; i >= 0; i--)
1325 if (cache_path [i] == '\\')
1326 cache_path [i] = '/';
1330 appname = mono_string_to_utf8_checked (setup->application_name, error);
1331 if (!mono_error_ok (error)) {
1332 g_free (cache_path);
1336 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1338 g_free (cache_path);
1340 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1341 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1348 get_shadow_assembly_location (const char *filename, MonoError *error)
1350 gint32 hash = 0, hash2 = 0;
1352 char path_hash [30];
1353 char *bname = g_path_get_basename (filename);
1354 char *dirname = g_path_get_dirname (filename);
1355 char *location, *tmploc;
1356 MonoDomain *domain = mono_domain_get ();
1358 mono_error_init (error);
1360 hash = get_cstring_hash (bname);
1361 hash2 = get_cstring_hash (dirname);
1362 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1363 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1364 tmploc = get_shadow_assembly_location_base (domain, error);
1365 if (!mono_error_ok (error)) {
1371 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1379 ensure_directory_exists (const char *filename)
1382 gchar *dir_utf8 = g_path_get_dirname (filename);
1384 gunichar2 *dir_utf16 = NULL;
1387 if (!dir_utf8 || !dir_utf8 [0])
1390 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1398 /* make life easy and only use one directory seperator */
1409 while (*p++ != '\\')
1415 p = wcschr (p, '\\');
1418 retval = _wmkdir (dir_utf16);
1419 if (retval != 0 && errno != EEXIST) {
1432 gchar *dir = g_path_get_dirname (filename);
1436 if (!dir || !dir [0]) {
1441 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1451 p = strchr (p, '/');
1454 retval = mkdir (dir, 0777);
1455 if (retval != 0 && errno != EEXIST) {
1470 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1472 struct stat sbuf_dest;
1474 gchar *real_src = mono_portability_find_file (src, TRUE);
1477 stat_src = (gchar*)src;
1479 stat_src = real_src;
1481 if (stat (stat_src, sbuf_src) == -1) {
1482 time_t tnow = time (NULL);
1487 memset (sbuf_src, 0, sizeof (*sbuf_src));
1488 sbuf_src->st_mtime = tnow;
1489 sbuf_src->st_atime = tnow;
1496 if (stat (dest, &sbuf_dest) == -1)
1499 if (sbuf_src->st_size == sbuf_dest.st_size &&
1500 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1507 shadow_copy_create_ini (const char *shadow, const char *filename)
1517 dir_name = g_path_get_dirname (shadow);
1518 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1520 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1525 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1530 handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1531 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1533 if (handle == INVALID_HANDLE_VALUE) {
1537 full_path = mono_path_resolve_symlinks (filename);
1538 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1540 CloseHandle (handle);
1545 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1548 MonoAppDomainSetup *setup;
1551 gchar **directories;
1552 gchar *shadow_status_string;
1554 gboolean shadow_enabled;
1555 gboolean found = FALSE;
1560 setup = domain->setup;
1561 if (setup == NULL || setup->shadow_copy_files == NULL)
1564 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1565 if (!mono_error_ok (&error)) {
1566 mono_error_cleanup (&error);
1569 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1570 g_free (shadow_status_string);
1572 if (!shadow_enabled)
1575 if (setup->shadow_copy_directories == NULL)
1578 /* Is dir_name a shadow_copy destination already? */
1579 base_dir = get_shadow_assembly_location_base (domain, &error);
1580 if (!mono_error_ok (&error)) {
1581 mono_error_cleanup (&error);
1585 if (strstr (dir_name, base_dir)) {
1591 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1592 if (!mono_error_ok (&error)) {
1593 mono_error_cleanup (&error);
1597 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1598 dir_ptr = directories;
1600 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1606 g_strfreev (directories);
1612 This function raises exceptions so it can cause as sorts of nasty stuff if called
1613 while holding a lock.
1614 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1615 or NULL if source file not found.
1616 FIXME bubble up the error instead of raising it here
1619 mono_make_shadow_copy (const char *filename)
1622 gchar *sibling_source, *sibling_target;
1623 gint sibling_source_len, sibling_target_len;
1624 guint16 *orig, *dest;
1627 gboolean copy_result;
1629 struct stat src_sbuf;
1630 struct utimbuf utbuf;
1631 char *dir_name = g_path_get_dirname (filename);
1632 MonoDomain *domain = mono_domain_get ();
1635 set_domain_search_path (domain);
1637 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1639 return (char *) filename;
1642 /* Is dir_name a shadow_copy destination already? */
1643 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1644 if (!mono_error_ok (&error)) {
1645 mono_error_cleanup (&error);
1647 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1648 mono_raise_exception (exc);
1651 if (strstr (dir_name, shadow_dir)) {
1652 g_free (shadow_dir);
1654 return (char *) filename;
1656 g_free (shadow_dir);
1659 shadow = get_shadow_assembly_location (filename, &error);
1660 if (!mono_error_ok (&error)) {
1661 mono_error_cleanup (&error);
1662 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1663 mono_raise_exception (exc);
1666 if (ensure_directory_exists (shadow) == FALSE) {
1668 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1669 mono_raise_exception (exc);
1672 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1673 return (char*) shadow;
1675 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1676 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1679 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1680 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1681 * and not have it runtime error" */
1682 attrs = GetFileAttributes (orig);
1683 if (attrs == INVALID_FILE_ATTRIBUTES) {
1685 return (char *)filename;
1688 copy_result = CopyFile (orig, dest, FALSE);
1690 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1691 * overwritten when updated in their original locations. */
1693 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1698 if (copy_result == FALSE) {
1701 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1702 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1703 return NULL; /* file not found, shadow copy failed */
1705 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1706 mono_raise_exception (exc);
1709 /* attempt to copy .mdb, .config if they exist */
1710 sibling_source = g_strconcat (filename, ".config", NULL);
1711 sibling_source_len = strlen (sibling_source);
1712 sibling_target = g_strconcat (shadow, ".config", NULL);
1713 sibling_target_len = strlen (sibling_target);
1715 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1716 if (copy_result == TRUE)
1717 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1719 g_free (sibling_source);
1720 g_free (sibling_target);
1722 if (copy_result == FALSE) {
1724 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1725 mono_raise_exception (exc);
1728 /* Create a .ini file containing the original assembly location */
1729 if (!shadow_copy_create_ini (shadow, filename)) {
1731 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1732 mono_raise_exception (exc);
1735 utbuf.actime = src_sbuf.st_atime;
1736 utbuf.modtime = src_sbuf.st_mtime;
1737 utime (shadow, &utbuf);
1741 #endif /* DISABLE_SHADOW_COPY */
1744 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1746 if (appdomain == NULL)
1749 return appdomain->data;
1753 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1754 const gchar *path3, const gchar *path4,
1755 gboolean refonly, gboolean is_private)
1758 gboolean found = FALSE;
1761 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1763 if (IS_PORTABILITY_SET) {
1764 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1767 fullpath = new_fullpath;
1771 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1774 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1777 return (*assembly != NULL);
1780 static MonoAssembly *
1781 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1783 MonoAssembly *result = NULL;
1786 const gchar *local_culture;
1788 gboolean is_private = FALSE;
1790 if (!culture || *culture == '\0') {
1793 local_culture = culture;
1796 filename = g_strconcat (name, ".dll", NULL);
1797 len = strlen (filename);
1799 for (path = search_path; *path; path++) {
1800 if (**path == '\0') {
1802 continue; /* Ignore empty ApplicationBase */
1805 /* See test cases in bug #58992 and bug #57710 */
1806 /* 1st try: [culture]/[name].dll (culture may be empty) */
1807 strcpy (filename + len - 4, ".dll");
1808 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1811 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1812 strcpy (filename + len - 4, ".exe");
1813 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1816 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1817 strcpy (filename + len - 4, ".dll");
1818 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1821 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1822 strcpy (filename + len - 4, ".exe");
1823 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1832 * Try loading the assembly from ApplicationBase and PrivateBinPath
1833 * and then from assemblies_path if any.
1834 * LOCKING: This is called from the assembly loading code, which means the caller
1835 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1837 static MonoAssembly *
1838 mono_domain_assembly_preload (MonoAssemblyName *aname,
1839 gchar **assemblies_path,
1842 MonoDomain *domain = mono_domain_get ();
1843 MonoAssembly *result = NULL;
1844 gboolean refonly = GPOINTER_TO_UINT (user_data);
1846 set_domain_search_path (domain);
1848 if (domain->search_path && domain->search_path [0] != NULL) {
1849 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1852 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1853 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1860 * Check whenever a given assembly was already loaded in the current appdomain.
1862 static MonoAssembly *
1863 mono_domain_assembly_search (MonoAssemblyName *aname,
1866 MonoDomain *domain = mono_domain_get ();
1869 gboolean refonly = GPOINTER_TO_UINT (user_data);
1871 mono_domain_assemblies_lock (domain);
1872 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1874 /* Dynamic assemblies can't match here in MS.NET */
1875 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1878 mono_domain_assemblies_unlock (domain);
1881 mono_domain_assemblies_unlock (domain);
1886 MonoReflectionAssembly *
1887 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1889 MonoDomain *domain = mono_domain_get ();
1890 char *name, *filename;
1891 MonoImageOpenStatus status = MONO_IMAGE_OK;
1894 if (fname == NULL) {
1895 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1896 mono_set_pending_exception (exc);
1900 name = filename = mono_string_to_utf8 (fname);
1902 ass = mono_assembly_open_full (filename, &status, refOnly);
1907 if (status == MONO_IMAGE_IMAGE_INVALID)
1908 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1910 exc = mono_get_exception_file_not_found2 (NULL, fname);
1912 mono_set_pending_exception (exc);
1918 return mono_assembly_get_object (domain, ass);
1921 MonoReflectionAssembly *
1922 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1923 MonoArray *raw_assembly,
1924 MonoArray *raw_symbol_store, MonoObject *evidence,
1925 MonoBoolean refonly)
1928 MonoReflectionAssembly *refass = NULL;
1929 MonoDomain *domain = ad->data;
1930 MonoImageOpenStatus status;
1931 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1932 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1935 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1939 if (raw_symbol_store != NULL)
1940 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1942 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1946 mono_image_close (image);
1947 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1951 refass = mono_assembly_get_object (domain, ass);
1952 MONO_OBJECT_SETREF (refass, evidence, evidence);
1956 MonoReflectionAssembly *
1957 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1959 MonoDomain *domain = ad->data;
1960 MonoImageOpenStatus status = MONO_IMAGE_OK;
1962 MonoAssemblyName aname;
1963 MonoReflectionAssembly *refass = NULL;
1967 g_assert (assRef != NULL);
1969 name = mono_string_to_utf8 (assRef);
1970 parsed = mono_assembly_name_parse (name, &aname);
1974 /* This is a parse error... */
1976 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1980 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1981 mono_assembly_name_free (&aname);
1984 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1986 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1995 refass = mono_assembly_get_object (domain, ass);
1997 MONO_OBJECT_SETREF (refass, evidence, evidence);
2002 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2004 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2006 if (NULL == domain) {
2007 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2008 mono_set_pending_exception (exc);
2012 if (domain == mono_get_root_domain ()) {
2013 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2018 * Unloading seems to cause problems when running NUnit/NAnt, hence
2021 if (g_getenv ("MONO_NO_UNLOAD"))
2023 #ifdef __native_client__
2027 mono_domain_unload (domain);
2031 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2033 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2038 return mono_domain_is_unloading (domain);
2042 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2043 MonoReflectionAssembly *refass, MonoArray *args)
2050 image = refass->assembly->image;
2053 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2056 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2059 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2061 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2065 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2067 return ad->data->domain_id;
2071 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2073 MonoDomain *old_domain = mono_domain_get();
2075 if (!mono_domain_set (ad->data, FALSE)) {
2076 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2080 return old_domain->domain;
2084 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2086 MonoDomain *current_domain = mono_domain_get ();
2087 MonoDomain *domain = mono_domain_get_by_id (domainid);
2089 if (!domain || !mono_domain_set (domain, FALSE)) {
2090 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2094 return current_domain->domain;
2098 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2100 mono_thread_push_appdomain_ref (ad->data);
2104 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2106 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2110 * Raise an exception to prevent the managed code from executing a pop
2113 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2117 mono_thread_push_appdomain_ref (domain);
2121 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2123 mono_thread_pop_appdomain_ref ();
2127 ves_icall_System_AppDomain_InternalGetContext ()
2129 return mono_context_get ();
2133 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2135 return mono_domain_get ()->default_context;
2139 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2141 MonoAppContext *old_context = mono_context_get ();
2143 mono_context_set (mc);
2149 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2151 MonoDomain* mono_root_domain = mono_get_root_domain ();
2152 mono_domain_lock (mono_root_domain);
2153 if (process_guid_set) {
2154 mono_domain_unlock (mono_root_domain);
2155 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2157 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2158 process_guid_set = TRUE;
2159 mono_domain_unlock (mono_root_domain);
2164 mono_domain_is_unloading (MonoDomain *domain)
2166 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2173 clear_cached_vtable (MonoVTable *vtable)
2175 MonoClass *klass = vtable->klass;
2176 MonoDomain *domain = vtable->domain;
2177 MonoClassRuntimeInfo *runtime_info;
2180 runtime_info = klass->runtime_info;
2181 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2182 runtime_info->domain_vtables [domain->domain_id] = NULL;
2183 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2184 mono_gc_free_fixed (data);
2187 static G_GNUC_UNUSED void
2188 zero_static_data (MonoVTable *vtable)
2190 MonoClass *klass = vtable->klass;
2193 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2194 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2197 typedef struct unload_data {
2200 char *failure_reason;
2205 unload_data_unref (unload_data *data)
2209 mono_atomic_load_acquire (count, gint32, &data->refcount);
2210 g_assert (count >= 1 && count <= 2);
2215 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2219 deregister_reflection_info_roots_from_list (MonoImage *image)
2221 GSList *list = image->reflection_info_unregister_classes;
2224 MonoClass *class = list->data;
2226 mono_class_free_ref_info (class);
2231 image->reflection_info_unregister_classes = NULL;
2235 deregister_reflection_info_roots (MonoDomain *domain)
2239 mono_domain_assemblies_lock (domain);
2240 for (list = domain->domain_assemblies; list; list = list->next) {
2241 MonoAssembly *assembly = list->data;
2242 MonoImage *image = assembly->image;
2246 * No need to take the image lock here since dynamic images are appdomain bound and
2247 * at this point the mutator is gone. Taking the image lock here would mean
2248 * promoting it from a simple lock to a complex lock, which we better avoid if
2251 if (image_is_dynamic (image))
2252 deregister_reflection_info_roots_from_list (image);
2254 for (i = 0; i < image->module_count; ++i) {
2255 MonoImage *module = image->modules [i];
2256 if (module && image_is_dynamic (module))
2257 deregister_reflection_info_roots_from_list (module);
2260 mono_domain_assemblies_unlock (domain);
2263 static guint32 WINAPI
2264 unload_thread_main (void *arg)
2266 unload_data *data = (unload_data*)arg;
2267 MonoDomain *domain = data->domain;
2271 /* Have to attach to the runtime so shutdown can wait for this thread */
2272 /* Force it to be attached to avoid racing during shutdown. */
2273 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2276 * FIXME: Abort our parent thread last, so we can return a failure
2277 * indication if aborting times out.
2279 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2280 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2284 if (!mono_thread_pool_remove_domain_jobs (domain, -1)) {
2285 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2289 /* Finalize all finalizable objects in the doomed appdomain */
2290 if (!mono_domain_finalize (domain, -1)) {
2291 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2295 /* Clear references to our vtables in class->runtime_info.
2296 * We also hold the loader lock because we're going to change
2297 * class->runtime_info.
2300 mono_loader_lock (); //FIXME why do we need the loader lock here?
2301 mono_domain_lock (domain);
2304 * We need to make sure that we don't have any remsets
2305 * pointing into static data of the to-be-freed domain because
2306 * at the next collections they would be invalid. So what we
2307 * do is we first zero all static data and then do a minor
2308 * collection. Because all references in the static data will
2309 * now be null we won't do any unnecessary copies and after
2310 * the collection there won't be any more remsets.
2312 for (i = 0; i < domain->class_vtable_array->len; ++i)
2313 zero_static_data (g_ptr_array_index (domain->class_vtable_array, i));
2314 mono_gc_collect (0);
2316 for (i = 0; i < domain->class_vtable_array->len; ++i)
2317 clear_cached_vtable (g_ptr_array_index (domain->class_vtable_array, i));
2318 deregister_reflection_info_roots (domain);
2320 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2322 mono_domain_unlock (domain);
2323 mono_loader_unlock ();
2325 mono_threads_clear_cached_culture (domain);
2327 domain->state = MONO_APPDOMAIN_UNLOADED;
2329 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2331 /* remove from the handle table the items related to this domain */
2332 mono_gchandle_free_domain (domain);
2334 mono_domain_free (domain, FALSE);
2336 mono_gc_collect (mono_gc_max_generation ());
2338 mono_atomic_store_release (&data->done, TRUE);
2339 unload_data_unref (data);
2340 mono_thread_detach (thread);
2344 mono_atomic_store_release (&data->done, TRUE);
2345 unload_data_unref (data);
2346 mono_thread_detach (thread);
2351 * mono_domain_unload:
2352 * @domain: The domain to unload
2354 * Unloads an appdomain. Follows the process outlined in the comment
2355 * for mono_domain_try_unload.
2358 mono_domain_unload (MonoDomain *domain)
2360 MonoObject *exc = NULL;
2361 mono_domain_try_unload (domain, &exc);
2363 mono_raise_exception ((MonoException*)exc);
2367 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2371 MONO_PREPARE_BLOCKING
2372 result = WaitForSingleObjectEx (handle, timeout, alertable);
2373 MONO_FINISH_BLOCKING
2379 * mono_domain_unload:
2380 * @domain: The domain to unload
2381 * @exc: Exception information
2383 * Unloads an appdomain. Follows the process outlined in:
2384 * http://blogs.gotdotnet.com/cbrumme
2386 * If doing things the 'right' way is too hard or complex, we do it the
2387 * 'simple' way, which means do everything needed to avoid crashes and
2388 * memory leaks, but not much else.
2390 * It is required to pass a valid reference to the exc argument, upon return
2391 * from this function *exc will be set to the exception thrown, if any.
2393 * If this method is not called from an icall (embedded scenario for instance),
2394 * it must not be called with any managed frames on the stack, since the unload
2395 * process could end up trying to abort the current thread.
2398 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2400 HANDLE thread_handle;
2401 MonoAppDomainState prev_state;
2403 unload_data *thread_data;
2404 MonoNativeThreadId tid;
2405 MonoDomain *caller_domain = mono_domain_get ();
2408 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2410 /* Atomically change our state to UNLOADING */
2411 prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2412 MONO_APPDOMAIN_UNLOADING_START,
2413 MONO_APPDOMAIN_CREATED);
2414 if (prev_state != MONO_APPDOMAIN_CREATED) {
2415 switch (prev_state) {
2416 case MONO_APPDOMAIN_UNLOADING_START:
2417 case MONO_APPDOMAIN_UNLOADING:
2418 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2420 case MONO_APPDOMAIN_UNLOADED:
2421 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2424 g_warning ("Invalid appdomain state %d", prev_state);
2425 g_assert_not_reached ();
2429 mono_domain_set (domain, FALSE);
2430 /* Notify OnDomainUnload listeners */
2431 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2434 mono_runtime_invoke (method, domain->domain, NULL, exc);
2436 /* Roll back the state change */
2437 domain->state = MONO_APPDOMAIN_CREATED;
2438 mono_domain_set (caller_domain, FALSE);
2441 mono_domain_set (caller_domain, FALSE);
2443 thread_data = g_new0 (unload_data, 1);
2444 thread_data->domain = domain;
2445 thread_data->failure_reason = NULL;
2446 thread_data->done = FALSE;
2447 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2449 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2450 domain->state = MONO_APPDOMAIN_UNLOADING;
2452 * First we create a separate thread for unloading, since
2453 * we might have to abort some threads, including the current one.
2455 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2456 if (thread_handle == NULL)
2458 name = g_strdup_printf ("Unload thread for domain %x", domain);
2459 mono_thread_info_set_name (tid, name);
2460 mono_thread_info_resume (tid);
2463 /* Wait for the thread */
2464 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2465 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2466 /* The unload thread tries to abort us */
2467 /* The icall wrapper will execute the abort */
2468 CloseHandle (thread_handle);
2469 unload_data_unref (thread_data);
2473 CloseHandle (thread_handle);
2475 if (thread_data->failure_reason) {
2476 /* Roll back the state change */
2477 domain->state = MONO_APPDOMAIN_CREATED;
2479 g_warning ("%s", thread_data->failure_reason);
2481 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2483 g_free (thread_data->failure_reason);
2484 thread_data->failure_reason = NULL;
2487 unload_data_unref (thread_data);