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;
1650 struct stat src_sbuf;
1651 struct utimbuf utbuf;
1652 char *dir_name = g_path_get_dirname (filename);
1653 MonoDomain *domain = mono_domain_get ();
1656 mono_error_init (oerror);
1658 set_domain_search_path (domain);
1660 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1662 return (char *) filename;
1665 /* Is dir_name a shadow_copy destination already? */
1666 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1667 if (!mono_error_ok (&error)) {
1668 mono_error_cleanup (&error);
1670 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1674 if (strstr (dir_name, shadow_dir)) {
1675 g_free (shadow_dir);
1677 return (char *) filename;
1679 g_free (shadow_dir);
1682 shadow = get_shadow_assembly_location (filename, &error);
1683 if (!mono_error_ok (&error)) {
1684 mono_error_cleanup (&error);
1685 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1689 if (ensure_directory_exists (shadow) == FALSE) {
1691 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1695 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1696 return (char*) shadow;
1698 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1699 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1702 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1703 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1704 * and not have it runtime error" */
1705 attrs = GetFileAttributes (orig);
1706 if (attrs == INVALID_FILE_ATTRIBUTES) {
1708 return (char *)filename;
1711 copy_result = CopyFile (orig, dest, FALSE);
1713 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1714 * overwritten when updated in their original locations. */
1716 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1721 if (copy_result == FALSE) {
1724 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1725 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1726 return NULL; /* file not found, shadow copy failed */
1728 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1732 /* attempt to copy .mdb, .config if they exist */
1733 sibling_source = g_strconcat (filename, ".config", NULL);
1734 sibling_source_len = strlen (sibling_source);
1735 sibling_target = g_strconcat (shadow, ".config", NULL);
1736 sibling_target_len = strlen (sibling_target);
1738 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1739 if (copy_result == TRUE)
1740 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1742 g_free (sibling_source);
1743 g_free (sibling_target);
1745 if (copy_result == FALSE) {
1747 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1751 /* Create a .ini file containing the original assembly location */
1752 if (!shadow_copy_create_ini (shadow, filename)) {
1754 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1758 utbuf.actime = src_sbuf.st_atime;
1759 utbuf.modtime = src_sbuf.st_mtime;
1760 utime (shadow, &utbuf);
1764 #endif /* DISABLE_SHADOW_COPY */
1767 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1769 if (appdomain == NULL)
1772 return appdomain->data;
1776 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1777 const gchar *path3, const gchar *path4,
1778 gboolean refonly, gboolean is_private)
1781 gboolean found = FALSE;
1784 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1786 if (IS_PORTABILITY_SET) {
1787 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1790 fullpath = new_fullpath;
1794 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1797 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1800 return (*assembly != NULL);
1803 static MonoAssembly *
1804 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1806 MonoAssembly *result = NULL;
1809 const gchar *local_culture;
1811 gboolean is_private = FALSE;
1813 if (!culture || *culture == '\0') {
1816 local_culture = culture;
1819 filename = g_strconcat (name, ".dll", NULL);
1820 len = strlen (filename);
1822 for (path = search_path; *path; path++) {
1823 if (**path == '\0') {
1825 continue; /* Ignore empty ApplicationBase */
1828 /* See test cases in bug #58992 and bug #57710 */
1829 /* 1st try: [culture]/[name].dll (culture may be empty) */
1830 strcpy (filename + len - 4, ".dll");
1831 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1834 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1835 strcpy (filename + len - 4, ".exe");
1836 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1839 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1840 strcpy (filename + len - 4, ".dll");
1841 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1844 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1845 strcpy (filename + len - 4, ".exe");
1846 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1855 * Try loading the assembly from ApplicationBase and PrivateBinPath
1856 * and then from assemblies_path if any.
1857 * LOCKING: This is called from the assembly loading code, which means the caller
1858 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1860 static MonoAssembly *
1861 mono_domain_assembly_preload (MonoAssemblyName *aname,
1862 gchar **assemblies_path,
1865 MonoDomain *domain = mono_domain_get ();
1866 MonoAssembly *result = NULL;
1867 gboolean refonly = GPOINTER_TO_UINT (user_data);
1869 set_domain_search_path (domain);
1871 if (domain->search_path && domain->search_path [0] != NULL) {
1872 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1875 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1876 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1883 * Check whenever a given assembly was already loaded in the current appdomain.
1885 static MonoAssembly *
1886 mono_domain_assembly_search (MonoAssemblyName *aname,
1889 MonoDomain *domain = mono_domain_get ();
1892 gboolean refonly = GPOINTER_TO_UINT (user_data);
1894 mono_domain_assemblies_lock (domain);
1895 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1896 ass = (MonoAssembly *)tmp->data;
1897 /* Dynamic assemblies can't match here in MS.NET */
1898 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1901 mono_domain_assemblies_unlock (domain);
1904 mono_domain_assemblies_unlock (domain);
1909 MonoReflectionAssembly *
1910 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1912 MonoDomain *domain = mono_domain_get ();
1913 char *name, *filename;
1914 MonoImageOpenStatus status = MONO_IMAGE_OK;
1917 if (fname == NULL) {
1918 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1919 mono_set_pending_exception (exc);
1923 name = filename = mono_string_to_utf8 (fname);
1925 ass = mono_assembly_open_full (filename, &status, refOnly);
1930 if (status == MONO_IMAGE_IMAGE_INVALID)
1931 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1933 exc = mono_get_exception_file_not_found2 (NULL, fname);
1935 mono_set_pending_exception (exc);
1941 return mono_assembly_get_object (domain, ass);
1944 MonoReflectionAssembly *
1945 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1946 MonoArray *raw_assembly,
1947 MonoArray *raw_symbol_store, MonoObject *evidence,
1948 MonoBoolean refonly)
1951 MonoReflectionAssembly *refass = NULL;
1952 MonoDomain *domain = ad->data;
1953 MonoImageOpenStatus status;
1954 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1955 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1958 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1962 if (raw_symbol_store != NULL)
1963 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1965 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1969 mono_image_close (image);
1970 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1974 refass = mono_assembly_get_object (domain, ass);
1975 MONO_OBJECT_SETREF (refass, evidence, evidence);
1979 MonoReflectionAssembly *
1980 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1982 MonoDomain *domain = ad->data;
1983 MonoImageOpenStatus status = MONO_IMAGE_OK;
1985 MonoAssemblyName aname;
1986 MonoReflectionAssembly *refass = NULL;
1992 name = mono_string_to_utf8 (assRef);
1993 parsed = mono_assembly_name_parse (name, &aname);
1997 /* This is a parse error... */
1999 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2003 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2004 mono_assembly_name_free (&aname);
2007 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2009 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2018 refass = mono_assembly_get_object (domain, ass);
2020 MONO_OBJECT_SETREF (refass, evidence, evidence);
2025 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2027 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2029 if (NULL == domain) {
2030 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2031 mono_set_pending_exception (exc);
2035 if (domain == mono_get_root_domain ()) {
2036 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2041 * Unloading seems to cause problems when running NUnit/NAnt, hence
2044 if (g_getenv ("MONO_NO_UNLOAD"))
2046 #ifdef __native_client__
2050 mono_domain_unload (domain);
2054 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2056 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2061 return mono_domain_is_unloading (domain);
2065 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2067 mono_unhandled_exception ((MonoObject*) exc);
2071 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2072 MonoReflectionAssembly *refass, MonoArray *args)
2079 image = refass->assembly->image;
2082 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2085 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2088 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2090 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2094 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2096 return ad->data->domain_id;
2100 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2102 MonoDomain *old_domain = mono_domain_get();
2104 if (!mono_domain_set (ad->data, FALSE)) {
2105 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2109 return old_domain->domain;
2113 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2115 MonoDomain *current_domain = mono_domain_get ();
2116 MonoDomain *domain = mono_domain_get_by_id (domainid);
2118 if (!domain || !mono_domain_set (domain, FALSE)) {
2119 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2123 return current_domain->domain;
2127 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2129 mono_thread_push_appdomain_ref (ad->data);
2133 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2135 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2139 * Raise an exception to prevent the managed code from executing a pop
2142 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2146 mono_thread_push_appdomain_ref (domain);
2150 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2152 mono_thread_pop_appdomain_ref ();
2156 ves_icall_System_AppDomain_InternalGetContext ()
2158 return mono_context_get ();
2162 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2164 return mono_domain_get ()->default_context;
2168 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2170 MonoAppContext *old_context = mono_context_get ();
2172 mono_context_set (mc);
2178 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2180 MonoDomain* mono_root_domain = mono_get_root_domain ();
2181 mono_domain_lock (mono_root_domain);
2182 if (process_guid_set) {
2183 mono_domain_unlock (mono_root_domain);
2184 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2186 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2187 process_guid_set = TRUE;
2188 mono_domain_unlock (mono_root_domain);
2193 mono_domain_is_unloading (MonoDomain *domain)
2195 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2202 clear_cached_vtable (MonoVTable *vtable)
2204 MonoClass *klass = vtable->klass;
2205 MonoDomain *domain = vtable->domain;
2206 MonoClassRuntimeInfo *runtime_info;
2209 runtime_info = klass->runtime_info;
2210 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2211 runtime_info->domain_vtables [domain->domain_id] = NULL;
2212 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2213 mono_gc_free_fixed (data);
2216 static G_GNUC_UNUSED void
2217 zero_static_data (MonoVTable *vtable)
2219 MonoClass *klass = vtable->klass;
2222 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2223 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2226 typedef struct unload_data {
2229 char *failure_reason;
2234 unload_data_unref (unload_data *data)
2238 mono_atomic_load_acquire (count, gint32, &data->refcount);
2239 g_assert (count >= 1 && count <= 2);
2244 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2248 deregister_reflection_info_roots_from_list (MonoImage *image)
2250 GSList *list = image->reflection_info_unregister_classes;
2253 MonoClass *klass = (MonoClass *)list->data;
2255 mono_class_free_ref_info (klass);
2260 image->reflection_info_unregister_classes = NULL;
2264 deregister_reflection_info_roots (MonoDomain *domain)
2268 mono_domain_assemblies_lock (domain);
2269 for (list = domain->domain_assemblies; list; list = list->next) {
2270 MonoAssembly *assembly = (MonoAssembly *)list->data;
2271 MonoImage *image = assembly->image;
2275 * No need to take the image lock here since dynamic images are appdomain bound and
2276 * at this point the mutator is gone. Taking the image lock here would mean
2277 * promoting it from a simple lock to a complex lock, which we better avoid if
2280 if (image_is_dynamic (image))
2281 deregister_reflection_info_roots_from_list (image);
2283 for (i = 0; i < image->module_count; ++i) {
2284 MonoImage *module = image->modules [i];
2285 if (module && image_is_dynamic (module))
2286 deregister_reflection_info_roots_from_list (module);
2289 mono_domain_assemblies_unlock (domain);
2292 static guint32 WINAPI
2293 unload_thread_main (void *arg)
2295 unload_data *data = (unload_data*)arg;
2296 MonoDomain *domain = data->domain;
2300 /* Have to attach to the runtime so shutdown can wait for this thread */
2301 /* Force it to be attached to avoid racing during shutdown. */
2302 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2305 * FIXME: Abort our parent thread last, so we can return a failure
2306 * indication if aborting times out.
2308 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2309 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2313 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2314 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2318 /* Finalize all finalizable objects in the doomed appdomain */
2319 if (!mono_domain_finalize (domain, -1)) {
2320 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2324 /* Clear references to our vtables in class->runtime_info.
2325 * We also hold the loader lock because we're going to change
2326 * class->runtime_info.
2329 mono_loader_lock (); //FIXME why do we need the loader lock here?
2330 mono_domain_lock (domain);
2333 * We need to make sure that we don't have any remsets
2334 * pointing into static data of the to-be-freed domain because
2335 * at the next collections they would be invalid. So what we
2336 * do is we first zero all static data and then do a minor
2337 * collection. Because all references in the static data will
2338 * now be null we won't do any unnecessary copies and after
2339 * the collection there won't be any more remsets.
2341 for (i = 0; i < domain->class_vtable_array->len; ++i)
2342 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2343 mono_gc_collect (0);
2345 for (i = 0; i < domain->class_vtable_array->len; ++i)
2346 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2347 deregister_reflection_info_roots (domain);
2349 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2351 mono_domain_unlock (domain);
2352 mono_loader_unlock ();
2354 mono_threads_clear_cached_culture (domain);
2356 domain->state = MONO_APPDOMAIN_UNLOADED;
2358 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2360 /* remove from the handle table the items related to this domain */
2361 mono_gchandle_free_domain (domain);
2363 mono_domain_free (domain, FALSE);
2365 mono_gc_collect (mono_gc_max_generation ());
2367 mono_atomic_store_release (&data->done, TRUE);
2368 unload_data_unref (data);
2369 mono_thread_detach (thread);
2373 mono_atomic_store_release (&data->done, TRUE);
2374 unload_data_unref (data);
2375 mono_thread_detach (thread);
2380 * mono_domain_unload:
2381 * @domain: The domain to unload
2383 * Unloads an appdomain. Follows the process outlined in the comment
2384 * for mono_domain_try_unload.
2387 mono_domain_unload (MonoDomain *domain)
2389 MonoObject *exc = NULL;
2390 mono_domain_try_unload (domain, &exc);
2392 mono_raise_exception ((MonoException*)exc);
2396 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2400 MONO_PREPARE_BLOCKING;
2401 result = WaitForSingleObjectEx (handle, timeout, alertable);
2402 MONO_FINISH_BLOCKING;
2408 * mono_domain_unload:
2409 * @domain: The domain to unload
2410 * @exc: Exception information
2412 * Unloads an appdomain. Follows the process outlined in:
2413 * http://blogs.gotdotnet.com/cbrumme
2415 * If doing things the 'right' way is too hard or complex, we do it the
2416 * 'simple' way, which means do everything needed to avoid crashes and
2417 * memory leaks, but not much else.
2419 * It is required to pass a valid reference to the exc argument, upon return
2420 * from this function *exc will be set to the exception thrown, if any.
2422 * If this method is not called from an icall (embedded scenario for instance),
2423 * it must not be called with any managed frames on the stack, since the unload
2424 * process could end up trying to abort the current thread.
2427 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2429 HANDLE thread_handle;
2430 MonoAppDomainState prev_state;
2432 unload_data *thread_data;
2433 MonoNativeThreadId tid;
2434 MonoDomain *caller_domain = mono_domain_get ();
2437 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2439 /* Atomically change our state to UNLOADING */
2440 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2441 MONO_APPDOMAIN_UNLOADING_START,
2442 MONO_APPDOMAIN_CREATED);
2443 if (prev_state != MONO_APPDOMAIN_CREATED) {
2444 switch (prev_state) {
2445 case MONO_APPDOMAIN_UNLOADING_START:
2446 case MONO_APPDOMAIN_UNLOADING:
2447 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2449 case MONO_APPDOMAIN_UNLOADED:
2450 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2453 g_warning ("Invalid appdomain state %d", prev_state);
2454 g_assert_not_reached ();
2458 mono_domain_set (domain, FALSE);
2459 /* Notify OnDomainUnload listeners */
2460 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2463 mono_runtime_invoke (method, domain->domain, NULL, exc);
2465 /* Roll back the state change */
2466 domain->state = MONO_APPDOMAIN_CREATED;
2467 mono_domain_set (caller_domain, FALSE);
2470 mono_domain_set (caller_domain, FALSE);
2472 thread_data = g_new0 (unload_data, 1);
2473 thread_data->domain = domain;
2474 thread_data->failure_reason = NULL;
2475 thread_data->done = FALSE;
2476 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2478 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2479 domain->state = MONO_APPDOMAIN_UNLOADING;
2481 * First we create a separate thread for unloading, since
2482 * we might have to abort some threads, including the current one.
2484 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2485 if (thread_handle == NULL)
2487 name = g_strdup_printf ("Unload thread for domain %x", domain);
2488 mono_thread_info_set_name (tid, name);
2489 mono_thread_info_resume (tid);
2492 /* Wait for the thread */
2493 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2494 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2495 /* The unload thread tries to abort us */
2496 /* The icall wrapper will execute the abort */
2497 CloseHandle (thread_handle);
2498 unload_data_unref (thread_data);
2502 CloseHandle (thread_handle);
2504 if (thread_data->failure_reason) {
2505 /* Roll back the state change */
2506 domain->state = MONO_APPDOMAIN_CREATED;
2508 g_warning ("%s", thread_data->failure_reason);
2510 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2512 g_free (thread_data->failure_reason);
2513 thread_data->failure_reason = NULL;
2516 unload_data_unref (thread_data);