2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
13 #undef ASSEMBLY_LOAD_DEBUG
19 #include <sys/types.h>
21 #ifdef HAVE_SYS_TIME_H
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
35 #include <mono/metadata/gc-internals.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/threadpool-ms.h>
43 #include <mono/metadata/socket-io.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/gc-internals.h>
46 #include <mono/metadata/mono-gc.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/monitor.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/utils/mono-uri.h>
59 #include <mono/utils/mono-logger-internals.h>
60 #include <mono/utils/mono-path.h>
61 #include <mono/utils/mono-stdlib.h>
62 #include <mono/utils/mono-io-portability.h>
63 #include <mono/utils/mono-error-internals.h>
64 #include <mono/utils/atomic.h>
65 #include <mono/utils/mono-memory-model.h>
66 #include <mono/utils/mono-threads.h>
72 * This is the version number of the corlib-runtime interface. When
73 * making changes to this interface (by changing the layout
74 * of classes the runtime knows about, changing icall signature or
75 * semantics etc), increment this variable. Also increment the
76 * pair of this variable in mscorlib in:
77 * mcs/class/corlib/System/Environment.cs
79 * Changes which are already detected at runtime, like the addition
80 * of icalls, do not require an increment.
82 #define MONO_CORLIB_VERSION 140
87 int assemblybinding_count;
92 static gunichar2 process_guid [36];
93 static gboolean process_guid_set = FALSE;
95 static gboolean no_exec = FALSE;
98 mono_domain_assembly_preload (MonoAssemblyName *aname,
99 gchar **assemblies_path,
102 static MonoAssembly *
103 mono_domain_assembly_search (MonoAssemblyName *aname,
107 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
110 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
112 static MonoAppDomain *
113 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
116 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
118 static MonoLoadFunc load_function = NULL;
121 mono_install_runtime_load (MonoLoadFunc func)
123 load_function = func;
127 mono_runtime_load (const char *filename, const char *runtime_version)
129 g_assert (load_function);
130 return load_function (filename, runtime_version);
134 * mono_runtime_set_no_exec:
136 * Instructs the runtime to operate in static mode, i.e. avoid/do not
137 * allow managed code execution. This is useful for running the AOT
138 * compiler on platforms which allow full-aot execution only. This
139 * should be called before mono_runtime_init ().
142 mono_runtime_set_no_exec (gboolean val)
148 * mono_runtime_get_no_exec:
150 * If true, then the runtime will not allow managed code execution.
153 mono_runtime_get_no_exec (void)
159 create_domain_objects (MonoDomain *domain)
161 MonoDomain *old_domain = mono_domain_get ();
163 MonoVTable *string_vt;
164 MonoClassField *string_empty_fld;
166 if (domain != old_domain) {
167 mono_thread_push_appdomain_ref (domain);
168 mono_domain_set_internal_with_options (domain, FALSE);
172 * Initialize String.Empty. This enables the removal of
173 * the static cctor of the String class.
175 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
176 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
177 g_assert (string_empty_fld);
178 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
181 * Create an instance early since we can't do it when there is no memory.
183 arg = mono_string_new (domain, "Out of memory");
184 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
187 * These two are needed because the signal handlers might be executing on
188 * an alternate stack, and Boehm GC can't handle that.
190 arg = mono_string_new (domain, "A null value was found where an object instance was required");
191 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
192 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
193 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
195 /*The ephemeron tombstone i*/
196 domain->ephemeron_tombstone = mono_object_new (domain, mono_defaults.object_class);
198 if (domain != old_domain) {
199 mono_thread_pop_appdomain_ref ();
200 mono_domain_set_internal_with_options (old_domain, FALSE);
204 * This class is used during exception handling, so initialize it here, to prevent
205 * stack overflows while handling stack overflows.
207 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
212 * @domain: domain returned by mono_init ()
214 * Initialize the core AppDomain: this function will run also some
215 * IL initialization code, so it needs the execution engine to be fully
218 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
219 * we know the entry_assembly.
223 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
224 MonoThreadAttachCB attach_cb)
226 MonoAppDomainSetup *setup;
230 mono_portability_helpers_init ();
232 mono_gc_base_init ();
233 mono_monitor_init ();
234 mono_marshal_init ();
236 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
237 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
238 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
239 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
240 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
241 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
242 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
243 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
245 mono_thread_init (start_cb, attach_cb);
247 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
248 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass);
250 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
251 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass);
254 domain->setup = setup;
256 mono_thread_attach (domain);
258 mono_type_initialization_init ();
260 if (!mono_runtime_get_no_exec ())
261 create_domain_objects (domain);
263 /* GC init has to happen after thread init */
266 /* contexts use GC handles, so they must be initialized after the GC */
267 mono_context_init (domain);
268 mono_context_set (domain->default_context);
270 #ifndef DISABLE_SOCKETS
271 mono_network_init ();
274 mono_console_init ();
277 mono_locks_tracer_init ();
279 /* mscorlib is loaded before we install the load hook */
280 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
286 mono_get_corlib_version (void)
289 MonoClassField *field;
292 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
293 mono_class_init (klass);
294 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
297 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
299 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
300 return *(gint32*)((gchar*)value + sizeof (MonoObject));
304 * mono_check_corlib_version
306 * Checks that the corlib that is loaded matches the version of this runtime.
308 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
309 * allocated string with the error otherwise.
312 mono_check_corlib_version (void)
314 int version = mono_get_corlib_version ();
315 if (version != MONO_CORLIB_VERSION)
316 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
323 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
325 * Initializes the @domain's default System.Runtime.Remoting's Context.
328 mono_context_init (MonoDomain *domain)
331 MonoAppContext *context;
333 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
334 context = (MonoAppContext *) mono_object_new_pinned (domain, klass);
335 context->domain_id = domain->domain_id;
336 context->context_id = 0;
337 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
338 domain->default_context = context;
342 * mono_runtime_cleanup:
347 * This must not be called while there are still running threads executing
351 mono_runtime_cleanup (MonoDomain *domain)
353 mono_attach_cleanup ();
355 /* This ends up calling any pending pending (for at most 2 seconds) */
358 mono_thread_cleanup ();
360 #ifndef DISABLE_SOCKETS
361 mono_network_cleanup ();
363 mono_marshal_cleanup ();
365 mono_type_initialization_cleanup ();
367 mono_monitor_cleanup ();
370 static MonoDomainFunc quit_function = NULL;
373 mono_install_runtime_cleanup (MonoDomainFunc func)
375 quit_function = func;
381 if (quit_function != NULL)
382 quit_function (mono_get_root_domain (), NULL);
386 * mono_domain_create_appdomain:
387 * @friendly_name: The friendly name of the appdomain to create
388 * @configuration_file: The configuration file to initialize the appdomain with
390 * Returns a MonoDomain initialized with the appdomain
393 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
397 MonoAppDomainSetup *setup;
400 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
401 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), klass);
402 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
404 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
405 mono_error_raise_exception (&error); /* FIXME don't raise here */
407 return mono_domain_from_appdomain (ad);
411 * mono_domain_set_config:
412 * @domain: MonoDomain initialized with the appdomain we want to change
413 * @base_dir: new base directory for the appdomain
414 * @config_file_name: path to the new configuration for the app domain
416 * Used to set the system configuration for an appdomain
418 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
419 * Error Initializing the configuration system. ---> System.ArgumentException:
420 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
423 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
425 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
426 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
429 static MonoAppDomainSetup*
430 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
432 MonoDomain *caller_domain = mono_domain_get ();
433 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
434 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
436 mono_domain_set_internal (domain);
438 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
439 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
440 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
441 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
442 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
443 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
444 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
445 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
446 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
447 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
448 copy->publisher_policy = setup->publisher_policy;
449 copy->path_changed = setup->path_changed;
450 copy->loader_optimization = setup->loader_optimization;
451 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
452 copy->disallow_code_downloads = setup->disallow_code_downloads;
453 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
454 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
455 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
456 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
457 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
459 mono_domain_set_internal (caller_domain);
464 static MonoAppDomain *
465 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
470 char *shadow_location;
472 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
474 /* FIXME: pin all those objects */
475 data = mono_domain_create();
477 ad = (MonoAppDomain *) mono_object_new (data, adclass);
480 data->friendly_name = g_strdup (friendly_name);
482 mono_profiler_appdomain_name (data, data->friendly_name);
484 if (!setup->application_base) {
485 /* Inherit from the root domain since MS.NET does this */
486 MonoDomain *root = mono_get_root_domain ();
487 if (root->setup->application_base)
488 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)));
491 mono_context_init (data);
493 data->setup = copy_app_domain_setup (data, setup);
494 mono_domain_set_options_from_config (data);
495 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
497 #ifndef DISABLE_SHADOW_COPY
498 /*FIXME, guard this for when the debugger is not running */
499 shadow_location = get_shadow_assembly_location_base (data, error);
500 if (!mono_error_ok (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);
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 = (MonoObject *)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,);
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)
687 return ad->data->setup;
691 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
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 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
718 MonoDomain *domain = mono_domain_get ();
720 return domain->throw_unobserved_task_exceptions;
724 get_attribute_value (const gchar **attribute_names,
725 const gchar **attribute_values,
726 const char *att_name)
729 for (n = 0; attribute_names [n] != NULL; n++) {
730 if (strcmp (attribute_names [n], att_name) == 0)
731 return g_strdup (attribute_values [n]);
737 start_element (GMarkupParseContext *context,
738 const gchar *element_name,
739 const gchar **attribute_names,
740 const gchar **attribute_values,
744 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
746 if (strcmp (element_name, "runtime") == 0) {
747 runtime_config->runtime_count++;
751 if (strcmp (element_name, "assemblyBinding") == 0) {
752 runtime_config->assemblybinding_count++;
756 if (runtime_config->runtime_count != 1)
759 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
760 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
762 if (value && g_ascii_strcasecmp (value, "true") == 0)
763 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
766 if (runtime_config->assemblybinding_count != 1)
769 if (strcmp (element_name, "probing") != 0)
772 g_free (runtime_config->domain->private_bin_path);
773 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
774 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
775 g_free (runtime_config->domain->private_bin_path);
776 runtime_config->domain->private_bin_path = NULL;
782 end_element (GMarkupParseContext *context,
783 const gchar *element_name,
787 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
788 if (strcmp (element_name, "runtime") == 0)
789 runtime_config->runtime_count--;
790 else if (strcmp (element_name, "assemblyBinding") == 0)
791 runtime_config->assemblybinding_count--;
795 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
797 RuntimeConfig *state = (RuntimeConfig *)user_data;
799 const gchar *filename;
801 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
802 msg = error && error->message ? error->message : "";
803 g_warning ("Error parsing %s: %s", filename, msg);
806 static const GMarkupParser
816 mono_domain_set_options_from_config (MonoDomain *domain)
819 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
821 GMarkupParseContext *context;
822 RuntimeConfig runtime_config;
825 if (!domain || !domain->setup || !domain->setup->configuration_file)
828 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
829 if (!mono_error_ok (&error)) {
830 mono_error_cleanup (&error);
834 config_file_path = mono_portability_find_file (config_file_name, TRUE);
835 if (!config_file_path)
836 config_file_path = config_file_name;
838 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
841 runtime_config.runtime_count = 0;
842 runtime_config.assemblybinding_count = 0;
843 runtime_config.domain = domain;
844 runtime_config.filename = config_file_path;
847 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
848 offset = 3; /* Skip UTF-8 BOM */
850 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
851 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
852 g_markup_parse_context_end_parse (context, NULL);
853 g_markup_parse_context_free (context);
857 if (config_file_name != config_file_path)
858 g_free (config_file_name);
859 g_free (config_file_path);
863 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
865 #ifdef DISABLE_APPDOMAINS
866 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
873 fname = mono_string_to_utf8 (friendly_name);
874 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
878 mono_error_raise_exception (&error);
885 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
887 MonoDomain *domain = ad->data;
889 static MonoClass *System_Reflection_Assembly;
893 GPtrArray *assemblies;
895 if (!System_Reflection_Assembly)
896 System_Reflection_Assembly = mono_class_from_name (
897 mono_defaults.corlib, "System.Reflection", "Assembly");
900 * Make a copy of the list of assemblies because we can't hold the assemblies
901 * lock while creating objects etc.
903 assemblies = g_ptr_array_new ();
904 /* Need to skip internal assembly builders created by remoting */
905 mono_domain_assemblies_lock (domain);
906 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
907 ass = (MonoAssembly *)tmp->data;
908 if (refonly != ass->ref_only)
910 if (ass->corlib_internal)
912 g_ptr_array_add (assemblies, ass);
914 mono_domain_assemblies_unlock (domain);
916 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
917 for (i = 0; i < assemblies->len; ++i) {
918 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
919 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
922 g_ptr_array_free (assemblies, TRUE);
927 MonoReflectionAssembly *
928 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
932 MonoBoolean isrefonly;
935 if (mono_runtime_get_no_exec ())
938 g_assert (domain != NULL && fname != NULL);
940 klass = domain->domain->mbr.obj.vtable->klass;
943 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
944 if (method == NULL) {
945 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
949 isrefonly = refonly ? 1 : 0;
951 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
952 params [2] = &isrefonly;
953 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
957 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
960 MonoReflectionAssembly *assembly;
961 MonoDomain *domain = mono_domain_get ();
965 aname_str = mono_stringify_assembly_name (aname);
967 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
968 str = mono_string_new (domain, aname_str);
973 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
977 return assembly->assembly;
983 * LOCKING: assumes assemblies_lock in the domain is already locked.
986 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
990 gboolean destroy_ht = FALSE;
992 if (!ass->aname.name)
996 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1000 /* FIXME: handle lazy loaded assemblies */
1001 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1002 g_hash_table_insert (ht, tmp->data, tmp->data);
1004 if (!g_hash_table_lookup (ht, ass)) {
1005 mono_assembly_addref (ass);
1006 g_hash_table_insert (ht, ass, ass);
1007 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1008 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);
1011 if (ass->image->references) {
1012 for (i = 0; ass->image->references [i] != NULL; i++) {
1013 if (ass->image->references [i] != REFERENCE_MISSING)
1014 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1015 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1020 g_hash_table_destroy (ht);
1024 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1026 static MonoClassField *assembly_load_field;
1027 static MonoMethod *assembly_load_method;
1028 MonoDomain *domain = mono_domain_get ();
1029 MonoReflectionAssembly *ref_assembly;
1031 gpointer load_value;
1034 if (!domain->domain)
1035 /* This can happen during startup */
1037 #ifdef ASSEMBLY_LOAD_DEBUG
1038 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1040 klass = domain->domain->mbr.obj.vtable->klass;
1042 mono_domain_assemblies_lock (domain);
1043 add_assemblies_to_domain (domain, assembly, NULL);
1044 mono_domain_assemblies_unlock (domain);
1046 if (assembly_load_field == NULL) {
1047 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1048 g_assert (assembly_load_field);
1051 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1052 if (load_value == NULL) {
1053 /* No events waiting to be triggered */
1057 ref_assembly = mono_assembly_get_object (domain, assembly);
1058 g_assert (ref_assembly);
1060 if (assembly_load_method == NULL) {
1061 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1062 g_assert (assembly_load_method);
1065 *params = ref_assembly;
1066 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1070 * LOCKING: Acquires the domain assemblies lock.
1073 set_domain_search_path (MonoDomain *domain)
1076 MonoAppDomainSetup *setup;
1078 gchar *search_path = NULL;
1081 gchar **pvt_split = NULL;
1082 GError *gerror = NULL;
1083 gint appbaselen = -1;
1086 * We use the low-level domain assemblies lock, since this is called from
1087 * assembly loads hooks, which means this thread might hold the loader lock.
1089 mono_domain_assemblies_lock (domain);
1091 if (!domain->setup) {
1092 mono_domain_assemblies_unlock (domain);
1096 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1097 mono_domain_assemblies_unlock (domain);
1100 setup = domain->setup;
1101 if (!setup->application_base) {
1102 mono_domain_assemblies_unlock (domain);
1103 return; /* Must set application base to get private path working */
1108 if (setup->private_bin_path) {
1109 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1110 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1111 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1112 mono_error_cleanup (&error);
1113 mono_domain_assemblies_unlock (domain);
1118 if (domain->private_bin_path) {
1119 if (search_path == NULL)
1120 search_path = domain->private_bin_path;
1122 gchar *tmp2 = search_path;
1123 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1130 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1131 * directories relative to ApplicationBase separated by semicolons (see
1132 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1133 * The loop below copes with the fact that some Unix applications may use ':' (or
1134 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1135 * ';' for the subsequent split.
1137 * The issue was reported in bug #81446
1140 #ifndef TARGET_WIN32
1143 slen = strlen (search_path);
1144 for (i = 0; i < slen; i++)
1145 if (search_path [i] == ':')
1146 search_path [i] = ';';
1149 pvt_split = g_strsplit (search_path, ";", 1000);
1150 g_free (search_path);
1151 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1156 g_strfreev (pvt_split);
1158 * Don't do this because the first time is called, the domain
1159 * setup is not finished.
1161 * domain->search_path = g_malloc (sizeof (char *));
1162 * domain->search_path [0] = NULL;
1164 mono_domain_assemblies_unlock (domain);
1168 if (domain->search_path)
1169 g_strfreev (domain->search_path);
1171 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1172 tmp [npaths] = NULL;
1174 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1175 if (!mono_error_ok (&error)) {
1176 mono_error_cleanup (&error);
1177 g_strfreev (pvt_split);
1180 mono_domain_assemblies_unlock (domain);
1184 domain->search_path = tmp;
1186 /* FIXME: is this needed? */
1187 if (strncmp (*tmp, "file://", 7) == 0) {
1193 uri = g_strdup_printf ("file:///%s", uri + 7);
1196 uri = mono_escape_uri_string (tmpuri);
1197 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1203 if (gerror != NULL) {
1204 g_warning ("%s\n", gerror->message);
1205 g_error_free (gerror);
1212 for (i = 1; pvt_split && i < npaths; i++) {
1213 if (g_path_is_absolute (pvt_split [i - 1])) {
1214 tmp [i] = g_strdup (pvt_split [i - 1]);
1216 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1219 if (strchr (tmp [i], '.')) {
1223 reduced = mono_path_canonicalize (tmp [i]);
1224 if (appbaselen == -1)
1225 appbaselen = strlen (tmp [0]);
1227 if (strncmp (tmp [0], reduced, appbaselen)) {
1230 tmp [i] = g_strdup ("");
1240 if (setup->private_bin_path_probe != NULL) {
1242 tmp [0] = g_strdup ("");
1245 domain->setup->path_changed = FALSE;
1247 g_strfreev (pvt_split);
1249 mono_domain_assemblies_unlock (domain);
1252 #ifdef DISABLE_SHADOW_COPY
1254 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1260 mono_make_shadow_copy (const char *filename, MonoError *error)
1262 mono_error_init (error);
1263 return (char *) filename;
1267 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1269 guint16 *orig, *dest;
1270 gboolean copy_result;
1272 strcpy (src + srclen - tail_len, extension);
1274 if (IS_PORTABILITY_CASE) {
1275 gchar *file = mono_portability_find_file (src, TRUE);
1281 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1285 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1287 strcpy (target + targetlen - tail_len, extension);
1288 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1291 copy_result = CopyFile (orig, dest, FALSE);
1293 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1294 * overwritten when updated in their original locations. */
1296 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1305 get_cstring_hash (const char *str)
1311 if (!str || !str [0])
1316 for (i = 0; i < len; i++) {
1317 h = (h << 5) - h + *p;
1325 * Returned memory is malloc'd. Called must free it
1328 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1330 MonoAppDomainSetup *setup;
1331 char *cache_path, *appname;
1335 mono_error_init (error);
1337 setup = domain->setup;
1338 if (setup->cache_path != NULL && setup->application_name != NULL) {
1339 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1340 if (!mono_error_ok (error))
1342 #ifndef TARGET_WIN32
1345 for (i = strlen (cache_path) - 1; i >= 0; i--)
1346 if (cache_path [i] == '\\')
1347 cache_path [i] = '/';
1351 appname = mono_string_to_utf8_checked (setup->application_name, error);
1352 if (!mono_error_ok (error)) {
1353 g_free (cache_path);
1357 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1359 g_free (cache_path);
1361 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1362 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1369 get_shadow_assembly_location (const char *filename, MonoError *error)
1371 gint32 hash = 0, hash2 = 0;
1373 char path_hash [30];
1374 char *bname = g_path_get_basename (filename);
1375 char *dirname = g_path_get_dirname (filename);
1376 char *location, *tmploc;
1377 MonoDomain *domain = mono_domain_get ();
1379 mono_error_init (error);
1381 hash = get_cstring_hash (bname);
1382 hash2 = get_cstring_hash (dirname);
1383 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1384 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1385 tmploc = get_shadow_assembly_location_base (domain, error);
1386 if (!mono_error_ok (error)) {
1392 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1400 ensure_directory_exists (const char *filename)
1403 gchar *dir_utf8 = g_path_get_dirname (filename);
1405 gunichar2 *dir_utf16 = NULL;
1408 if (!dir_utf8 || !dir_utf8 [0])
1411 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1419 /* make life easy and only use one directory seperator */
1430 while (*p++ != '\\')
1436 p = wcschr (p, '\\');
1439 retval = _wmkdir (dir_utf16);
1440 if (retval != 0 && errno != EEXIST) {
1453 gchar *dir = g_path_get_dirname (filename);
1457 if (!dir || !dir [0]) {
1462 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1472 p = strchr (p, '/');
1475 retval = mkdir (dir, 0777);
1476 if (retval != 0 && errno != EEXIST) {
1491 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1493 struct stat sbuf_dest;
1495 gchar *real_src = mono_portability_find_file (src, TRUE);
1498 stat_src = (gchar*)src;
1500 stat_src = real_src;
1502 if (stat (stat_src, sbuf_src) == -1) {
1503 time_t tnow = time (NULL);
1508 memset (sbuf_src, 0, sizeof (*sbuf_src));
1509 sbuf_src->st_mtime = tnow;
1510 sbuf_src->st_atime = tnow;
1517 if (stat (dest, &sbuf_dest) == -1)
1520 if (sbuf_src->st_size == sbuf_dest.st_size &&
1521 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1528 shadow_copy_create_ini (const char *shadow, const char *filename)
1538 dir_name = g_path_get_dirname (shadow);
1539 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1541 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1546 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1551 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1552 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1554 if (handle == INVALID_HANDLE_VALUE) {
1558 full_path = mono_path_resolve_symlinks (filename);
1559 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1561 CloseHandle (handle);
1566 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1569 MonoAppDomainSetup *setup;
1572 gchar **directories;
1573 gchar *shadow_status_string;
1575 gboolean shadow_enabled;
1576 gboolean found = FALSE;
1581 setup = domain->setup;
1582 if (setup == NULL || setup->shadow_copy_files == NULL)
1585 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1586 if (!mono_error_ok (&error)) {
1587 mono_error_cleanup (&error);
1590 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1591 g_free (shadow_status_string);
1593 if (!shadow_enabled)
1596 if (setup->shadow_copy_directories == NULL)
1599 /* Is dir_name a shadow_copy destination already? */
1600 base_dir = get_shadow_assembly_location_base (domain, &error);
1601 if (!mono_error_ok (&error)) {
1602 mono_error_cleanup (&error);
1606 if (strstr (dir_name, base_dir)) {
1612 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1613 if (!mono_error_ok (&error)) {
1614 mono_error_cleanup (&error);
1618 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1619 dir_ptr = directories;
1621 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1627 g_strfreev (directories);
1633 This function raises exceptions so it can cause as sorts of nasty stuff if called
1634 while holding a lock.
1635 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1636 or NULL if source file not found.
1637 FIXME bubble up the error instead of raising it here
1640 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1643 gchar *sibling_source, *sibling_target;
1644 gint sibling_source_len, sibling_target_len;
1645 guint16 *orig, *dest;
1648 gboolean copy_result;
1649 struct stat src_sbuf;
1650 struct utimbuf utbuf;
1651 char *dir_name = g_path_get_dirname (filename);
1652 MonoDomain *domain = mono_domain_get ();
1655 mono_error_init (oerror);
1657 set_domain_search_path (domain);
1659 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1661 return (char *) filename;
1664 /* Is dir_name a shadow_copy destination already? */
1665 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1666 if (!mono_error_ok (&error)) {
1667 mono_error_cleanup (&error);
1669 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1673 if (strstr (dir_name, shadow_dir)) {
1674 g_free (shadow_dir);
1676 return (char *) filename;
1678 g_free (shadow_dir);
1681 shadow = get_shadow_assembly_location (filename, &error);
1682 if (!mono_error_ok (&error)) {
1683 mono_error_cleanup (&error);
1684 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1688 if (ensure_directory_exists (shadow) == FALSE) {
1690 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1694 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1695 return (char*) shadow;
1697 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1698 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1701 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1702 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1703 * and not have it runtime error" */
1704 attrs = GetFileAttributes (orig);
1705 if (attrs == INVALID_FILE_ATTRIBUTES) {
1707 return (char *)filename;
1710 copy_result = CopyFile (orig, dest, FALSE);
1712 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1713 * overwritten when updated in their original locations. */
1715 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1720 if (copy_result == FALSE) {
1723 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1724 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1725 return NULL; /* file not found, shadow copy failed */
1727 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1731 /* attempt to copy .mdb, .config if they exist */
1732 sibling_source = g_strconcat (filename, ".config", NULL);
1733 sibling_source_len = strlen (sibling_source);
1734 sibling_target = g_strconcat (shadow, ".config", NULL);
1735 sibling_target_len = strlen (sibling_target);
1737 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1738 if (copy_result == TRUE)
1739 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1741 g_free (sibling_source);
1742 g_free (sibling_target);
1744 if (copy_result == FALSE) {
1746 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1750 /* Create a .ini file containing the original assembly location */
1751 if (!shadow_copy_create_ini (shadow, filename)) {
1753 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1757 utbuf.actime = src_sbuf.st_atime;
1758 utbuf.modtime = src_sbuf.st_mtime;
1759 utime (shadow, &utbuf);
1763 #endif /* DISABLE_SHADOW_COPY */
1766 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1768 if (appdomain == NULL)
1771 return appdomain->data;
1775 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1776 const gchar *path3, const gchar *path4,
1777 gboolean refonly, gboolean is_private)
1780 gboolean found = FALSE;
1783 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1785 if (IS_PORTABILITY_SET) {
1786 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1789 fullpath = new_fullpath;
1793 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1796 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1799 return (*assembly != NULL);
1802 static MonoAssembly *
1803 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1805 MonoAssembly *result = NULL;
1808 const gchar *local_culture;
1810 gboolean is_private = FALSE;
1812 if (!culture || *culture == '\0') {
1815 local_culture = culture;
1818 filename = g_strconcat (name, ".dll", NULL);
1819 len = strlen (filename);
1821 for (path = search_path; *path; path++) {
1822 if (**path == '\0') {
1824 continue; /* Ignore empty ApplicationBase */
1827 /* See test cases in bug #58992 and bug #57710 */
1828 /* 1st try: [culture]/[name].dll (culture may be empty) */
1829 strcpy (filename + len - 4, ".dll");
1830 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1833 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1834 strcpy (filename + len - 4, ".exe");
1835 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1838 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1839 strcpy (filename + len - 4, ".dll");
1840 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1843 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1844 strcpy (filename + len - 4, ".exe");
1845 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1854 * Try loading the assembly from ApplicationBase and PrivateBinPath
1855 * and then from assemblies_path if any.
1856 * LOCKING: This is called from the assembly loading code, which means the caller
1857 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1859 static MonoAssembly *
1860 mono_domain_assembly_preload (MonoAssemblyName *aname,
1861 gchar **assemblies_path,
1864 MonoDomain *domain = mono_domain_get ();
1865 MonoAssembly *result = NULL;
1866 gboolean refonly = GPOINTER_TO_UINT (user_data);
1868 set_domain_search_path (domain);
1870 if (domain->search_path && domain->search_path [0] != NULL) {
1871 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1874 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1875 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1882 * Check whenever a given assembly was already loaded in the current appdomain.
1884 static MonoAssembly *
1885 mono_domain_assembly_search (MonoAssemblyName *aname,
1888 MonoDomain *domain = mono_domain_get ();
1891 gboolean refonly = GPOINTER_TO_UINT (user_data);
1893 mono_domain_assemblies_lock (domain);
1894 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1895 ass = (MonoAssembly *)tmp->data;
1896 /* Dynamic assemblies can't match here in MS.NET */
1897 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1900 mono_domain_assemblies_unlock (domain);
1903 mono_domain_assemblies_unlock (domain);
1908 MonoReflectionAssembly *
1909 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1911 MonoDomain *domain = mono_domain_get ();
1912 char *name, *filename;
1913 MonoImageOpenStatus status = MONO_IMAGE_OK;
1916 if (fname == NULL) {
1917 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1918 mono_set_pending_exception (exc);
1922 name = filename = mono_string_to_utf8 (fname);
1924 ass = mono_assembly_open_full (filename, &status, refOnly);
1929 if (status == MONO_IMAGE_IMAGE_INVALID)
1930 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1932 exc = mono_get_exception_file_not_found2 (NULL, fname);
1934 mono_set_pending_exception (exc);
1940 return mono_assembly_get_object (domain, ass);
1943 MonoReflectionAssembly *
1944 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1945 MonoArray *raw_assembly,
1946 MonoArray *raw_symbol_store, MonoObject *evidence,
1947 MonoBoolean refonly)
1950 MonoReflectionAssembly *refass = NULL;
1951 MonoDomain *domain = ad->data;
1952 MonoImageOpenStatus status;
1953 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1954 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1957 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1961 if (raw_symbol_store != NULL)
1962 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1964 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1968 mono_image_close (image);
1969 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1973 refass = mono_assembly_get_object (domain, ass);
1974 MONO_OBJECT_SETREF (refass, evidence, evidence);
1978 MonoReflectionAssembly *
1979 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1981 MonoDomain *domain = ad->data;
1982 MonoImageOpenStatus status = MONO_IMAGE_OK;
1984 MonoAssemblyName aname;
1985 MonoReflectionAssembly *refass = NULL;
1991 name = mono_string_to_utf8 (assRef);
1992 parsed = mono_assembly_name_parse (name, &aname);
1996 /* This is a parse error... */
1998 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2002 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2003 mono_assembly_name_free (&aname);
2006 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2008 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2017 refass = mono_assembly_get_object (domain, ass);
2019 MONO_OBJECT_SETREF (refass, evidence, evidence);
2024 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2026 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2028 if (NULL == domain) {
2029 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2030 mono_set_pending_exception (exc);
2034 if (domain == mono_get_root_domain ()) {
2035 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2040 * Unloading seems to cause problems when running NUnit/NAnt, hence
2043 if (g_getenv ("MONO_NO_UNLOAD"))
2045 #ifdef __native_client__
2049 mono_domain_unload (domain);
2053 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2055 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2060 return mono_domain_is_unloading (domain);
2064 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2066 mono_unhandled_exception ((MonoObject*) exc);
2070 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2071 MonoReflectionAssembly *refass, MonoArray *args)
2078 image = refass->assembly->image;
2081 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2084 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2087 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2089 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2093 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2095 return ad->data->domain_id;
2099 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2101 MonoDomain *old_domain = mono_domain_get();
2103 if (!mono_domain_set (ad->data, FALSE)) {
2104 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2108 return old_domain->domain;
2112 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2114 MonoDomain *current_domain = mono_domain_get ();
2115 MonoDomain *domain = mono_domain_get_by_id (domainid);
2117 if (!domain || !mono_domain_set (domain, FALSE)) {
2118 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2122 return current_domain->domain;
2126 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2128 mono_thread_push_appdomain_ref (ad->data);
2132 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2134 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2138 * Raise an exception to prevent the managed code from executing a pop
2141 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2145 mono_thread_push_appdomain_ref (domain);
2149 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2151 mono_thread_pop_appdomain_ref ();
2155 ves_icall_System_AppDomain_InternalGetContext ()
2157 return mono_context_get ();
2161 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2163 return mono_domain_get ()->default_context;
2167 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2169 MonoAppContext *old_context = mono_context_get ();
2171 mono_context_set (mc);
2177 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2179 MonoDomain* mono_root_domain = mono_get_root_domain ();
2180 mono_domain_lock (mono_root_domain);
2181 if (process_guid_set) {
2182 mono_domain_unlock (mono_root_domain);
2183 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2185 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2186 process_guid_set = TRUE;
2187 mono_domain_unlock (mono_root_domain);
2192 mono_domain_is_unloading (MonoDomain *domain)
2194 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2201 clear_cached_vtable (MonoVTable *vtable)
2203 MonoClass *klass = vtable->klass;
2204 MonoDomain *domain = vtable->domain;
2205 MonoClassRuntimeInfo *runtime_info;
2208 runtime_info = klass->runtime_info;
2209 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2210 runtime_info->domain_vtables [domain->domain_id] = NULL;
2211 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2212 mono_gc_free_fixed (data);
2215 static G_GNUC_UNUSED void
2216 zero_static_data (MonoVTable *vtable)
2218 MonoClass *klass = vtable->klass;
2221 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2222 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2225 typedef struct unload_data {
2228 char *failure_reason;
2233 unload_data_unref (unload_data *data)
2237 mono_atomic_load_acquire (count, gint32, &data->refcount);
2238 g_assert (count >= 1 && count <= 2);
2243 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2247 deregister_reflection_info_roots_from_list (MonoImage *image)
2249 GSList *list = image->reflection_info_unregister_classes;
2252 MonoClass *klass = (MonoClass *)list->data;
2254 mono_class_free_ref_info (klass);
2259 image->reflection_info_unregister_classes = NULL;
2263 deregister_reflection_info_roots (MonoDomain *domain)
2267 mono_domain_assemblies_lock (domain);
2268 for (list = domain->domain_assemblies; list; list = list->next) {
2269 MonoAssembly *assembly = (MonoAssembly *)list->data;
2270 MonoImage *image = assembly->image;
2274 * No need to take the image lock here since dynamic images are appdomain bound and
2275 * at this point the mutator is gone. Taking the image lock here would mean
2276 * promoting it from a simple lock to a complex lock, which we better avoid if
2279 if (image_is_dynamic (image))
2280 deregister_reflection_info_roots_from_list (image);
2282 for (i = 0; i < image->module_count; ++i) {
2283 MonoImage *module = image->modules [i];
2284 if (module && image_is_dynamic (module))
2285 deregister_reflection_info_roots_from_list (module);
2288 mono_domain_assemblies_unlock (domain);
2291 static guint32 WINAPI
2292 unload_thread_main (void *arg)
2294 unload_data *data = (unload_data*)arg;
2295 MonoDomain *domain = data->domain;
2299 /* Have to attach to the runtime so shutdown can wait for this thread */
2300 /* Force it to be attached to avoid racing during shutdown. */
2301 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2304 * FIXME: Abort our parent thread last, so we can return a failure
2305 * indication if aborting times out.
2307 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2308 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2312 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2313 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2317 /* Finalize all finalizable objects in the doomed appdomain */
2318 if (!mono_domain_finalize (domain, -1)) {
2319 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2323 /* Clear references to our vtables in class->runtime_info.
2324 * We also hold the loader lock because we're going to change
2325 * class->runtime_info.
2328 mono_loader_lock (); //FIXME why do we need the loader lock here?
2329 mono_domain_lock (domain);
2332 * We need to make sure that we don't have any remsets
2333 * pointing into static data of the to-be-freed domain because
2334 * at the next collections they would be invalid. So what we
2335 * do is we first zero all static data and then do a minor
2336 * collection. Because all references in the static data will
2337 * now be null we won't do any unnecessary copies and after
2338 * the collection there won't be any more remsets.
2340 for (i = 0; i < domain->class_vtable_array->len; ++i)
2341 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2342 mono_gc_collect (0);
2344 for (i = 0; i < domain->class_vtable_array->len; ++i)
2345 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2346 deregister_reflection_info_roots (domain);
2348 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2350 mono_domain_unlock (domain);
2351 mono_loader_unlock ();
2353 mono_threads_clear_cached_culture (domain);
2355 domain->state = MONO_APPDOMAIN_UNLOADED;
2357 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2359 /* remove from the handle table the items related to this domain */
2360 mono_gchandle_free_domain (domain);
2362 mono_domain_free (domain, FALSE);
2364 mono_gc_collect (mono_gc_max_generation ());
2366 mono_atomic_store_release (&data->done, TRUE);
2367 unload_data_unref (data);
2368 mono_thread_detach (thread);
2372 mono_atomic_store_release (&data->done, TRUE);
2373 unload_data_unref (data);
2374 mono_thread_detach (thread);
2379 * mono_domain_unload:
2380 * @domain: The domain to unload
2382 * Unloads an appdomain. Follows the process outlined in the comment
2383 * for mono_domain_try_unload.
2386 mono_domain_unload (MonoDomain *domain)
2388 MonoObject *exc = NULL;
2389 mono_domain_try_unload (domain, &exc);
2391 mono_raise_exception ((MonoException*)exc);
2395 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2399 MONO_PREPARE_BLOCKING;
2400 result = WaitForSingleObjectEx (handle, timeout, alertable);
2401 MONO_FINISH_BLOCKING;
2407 * mono_domain_unload:
2408 * @domain: The domain to unload
2409 * @exc: Exception information
2411 * Unloads an appdomain. Follows the process outlined in:
2412 * http://blogs.gotdotnet.com/cbrumme
2414 * If doing things the 'right' way is too hard or complex, we do it the
2415 * 'simple' way, which means do everything needed to avoid crashes and
2416 * memory leaks, but not much else.
2418 * It is required to pass a valid reference to the exc argument, upon return
2419 * from this function *exc will be set to the exception thrown, if any.
2421 * If this method is not called from an icall (embedded scenario for instance),
2422 * it must not be called with any managed frames on the stack, since the unload
2423 * process could end up trying to abort the current thread.
2426 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2428 HANDLE thread_handle;
2429 MonoAppDomainState prev_state;
2431 unload_data *thread_data;
2432 MonoNativeThreadId tid;
2433 MonoDomain *caller_domain = mono_domain_get ();
2436 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2438 /* Atomically change our state to UNLOADING */
2439 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2440 MONO_APPDOMAIN_UNLOADING_START,
2441 MONO_APPDOMAIN_CREATED);
2442 if (prev_state != MONO_APPDOMAIN_CREATED) {
2443 switch (prev_state) {
2444 case MONO_APPDOMAIN_UNLOADING_START:
2445 case MONO_APPDOMAIN_UNLOADING:
2446 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2448 case MONO_APPDOMAIN_UNLOADED:
2449 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2452 g_warning ("Invalid appdomain state %d", prev_state);
2453 g_assert_not_reached ();
2457 mono_domain_set (domain, FALSE);
2458 /* Notify OnDomainUnload listeners */
2459 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2462 mono_runtime_invoke (method, domain->domain, NULL, exc);
2464 /* Roll back the state change */
2465 domain->state = MONO_APPDOMAIN_CREATED;
2466 mono_domain_set (caller_domain, FALSE);
2469 mono_domain_set (caller_domain, FALSE);
2471 thread_data = g_new0 (unload_data, 1);
2472 thread_data->domain = domain;
2473 thread_data->failure_reason = NULL;
2474 thread_data->done = FALSE;
2475 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2477 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2478 domain->state = MONO_APPDOMAIN_UNLOADING;
2480 * First we create a separate thread for unloading, since
2481 * we might have to abort some threads, including the current one.
2483 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2484 if (thread_handle == NULL)
2486 name = g_strdup_printf ("Unload thread for domain %x", domain);
2487 mono_thread_info_set_name (tid, name);
2488 mono_thread_info_resume (tid);
2491 /* Wait for the thread */
2492 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2493 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2494 /* The unload thread tries to abort us */
2495 /* The icall wrapper will execute the abort */
2496 CloseHandle (thread_handle);
2497 unload_data_unref (thread_data);
2501 CloseHandle (thread_handle);
2503 if (thread_data->failure_reason) {
2504 /* Roll back the state change */
2505 domain->state = MONO_APPDOMAIN_CREATED;
2507 g_warning ("%s", thread_data->failure_reason);
2509 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2511 g_free (thread_data->failure_reason);
2512 thread_data->failure_reason = NULL;
2515 unload_data_unref (thread_data);