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)
227 MonoAppDomainSetup *setup;
231 mono_portability_helpers_init ();
233 mono_gc_base_init ();
234 mono_monitor_init ();
235 mono_marshal_init ();
237 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
238 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
239 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
240 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
241 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
242 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
243 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
244 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
246 mono_thread_init (start_cb, attach_cb);
248 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
249 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, &error);
250 mono_error_raise_exception (&error); /* FIXME don't raise here */
252 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
253 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, &error);
254 mono_error_raise_exception (&error); /* FIXME don't raise here */
257 domain->setup = setup;
259 mono_thread_attach (domain);
261 mono_type_initialization_init ();
263 if (!mono_runtime_get_no_exec ())
264 create_domain_objects (domain);
266 /* GC init has to happen after thread init */
269 /* contexts use GC handles, so they must be initialized after the GC */
270 mono_context_init (domain);
271 mono_context_set (domain->default_context);
273 #ifndef DISABLE_SOCKETS
274 mono_network_init ();
277 mono_console_init ();
280 mono_locks_tracer_init ();
282 /* mscorlib is loaded before we install the load hook */
283 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
289 mono_get_corlib_version (void)
292 MonoClassField *field;
295 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
296 mono_class_init (klass);
297 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
300 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
302 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
303 return *(gint32*)((gchar*)value + sizeof (MonoObject));
307 * mono_check_corlib_version
309 * Checks that the corlib that is loaded matches the version of this runtime.
311 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
312 * allocated string with the error otherwise.
315 mono_check_corlib_version (void)
317 int version = mono_get_corlib_version ();
318 if (version != MONO_CORLIB_VERSION)
319 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
326 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
328 * Initializes the @domain's default System.Runtime.Remoting's Context.
331 mono_context_init (MonoDomain *domain)
335 MonoAppContext *context;
337 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
338 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, &error);
339 mono_error_raise_exception (&error); /* FIXME don't raise here */
340 context->domain_id = domain->domain_id;
341 context->context_id = 0;
342 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
343 domain->default_context = context;
347 * mono_runtime_cleanup:
352 * This must not be called while there are still running threads executing
356 mono_runtime_cleanup (MonoDomain *domain)
358 mono_attach_cleanup ();
360 /* This ends up calling any pending pending (for at most 2 seconds) */
363 mono_thread_cleanup ();
365 #ifndef DISABLE_SOCKETS
366 mono_network_cleanup ();
368 mono_marshal_cleanup ();
370 mono_type_initialization_cleanup ();
372 mono_monitor_cleanup ();
375 static MonoDomainFunc quit_function = NULL;
378 mono_install_runtime_cleanup (MonoDomainFunc func)
380 quit_function = func;
386 if (quit_function != NULL)
387 quit_function (mono_get_root_domain (), NULL);
391 * mono_domain_create_appdomain:
392 * @friendly_name: The friendly name of the appdomain to create
393 * @configuration_file: The configuration file to initialize the appdomain with
395 * Returns a MonoDomain initialized with the appdomain
398 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
402 MonoAppDomainSetup *setup;
405 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
406 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), klass);
407 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
409 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
410 mono_error_raise_exception (&error); /* FIXME don't raise here */
412 return mono_domain_from_appdomain (ad);
416 * mono_domain_set_config:
417 * @domain: MonoDomain initialized with the appdomain we want to change
418 * @base_dir: new base directory for the appdomain
419 * @config_file_name: path to the new configuration for the app domain
421 * Used to set the system configuration for an appdomain
423 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
424 * Error Initializing the configuration system. ---> System.ArgumentException:
425 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
428 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
430 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
431 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
434 static MonoAppDomainSetup*
435 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
437 MonoDomain *caller_domain = mono_domain_get ();
438 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
439 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
441 mono_domain_set_internal (domain);
443 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
444 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
445 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
446 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
447 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
448 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
449 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
450 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
451 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
452 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
453 copy->publisher_policy = setup->publisher_policy;
454 copy->path_changed = setup->path_changed;
455 copy->loader_optimization = setup->loader_optimization;
456 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
457 copy->disallow_code_downloads = setup->disallow_code_downloads;
458 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
459 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
460 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
461 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
462 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
464 mono_domain_set_internal (caller_domain);
469 static MonoAppDomain *
470 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
475 char *shadow_location;
477 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
479 /* FIXME: pin all those objects */
480 data = mono_domain_create();
482 ad = (MonoAppDomain *) mono_object_new (data, adclass);
485 data->friendly_name = g_strdup (friendly_name);
487 mono_profiler_appdomain_name (data, data->friendly_name);
489 if (!setup->application_base) {
490 /* Inherit from the root domain since MS.NET does this */
491 MonoDomain *root = mono_get_root_domain ();
492 if (root->setup->application_base)
493 MONO_OBJECT_SETREF (setup, application_base, mono_string_new_utf16 (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base)));
496 mono_context_init (data);
498 data->setup = copy_app_domain_setup (data, setup);
499 mono_domain_set_options_from_config (data);
500 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
502 #ifndef DISABLE_SHADOW_COPY
503 /*FIXME, guard this for when the debugger is not running */
504 shadow_location = get_shadow_assembly_location_base (data, error);
505 if (!mono_error_ok (error))
508 g_free (shadow_location);
511 create_domain_objects (data);
517 * mono_domain_has_type_resolve:
518 * @domain: application domains being looked up
520 * Returns true if the AppDomain.TypeResolve field has been
524 mono_domain_has_type_resolve (MonoDomain *domain)
526 static MonoClassField *field = NULL;
530 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
534 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
538 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
543 * mono_domain_try_type_resolve:
544 * @domain: application domainwhere the name where the type is going to be resolved
545 * @name: the name of the type to resolve or NULL.
546 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
548 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
549 * the assembly that matches name.
551 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
553 * Returns: A MonoReflectionAssembly or NULL if not found
555 MonoReflectionAssembly *
556 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
560 static MonoMethod *method = NULL;
562 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
564 if (method == NULL) {
565 klass = domain->domain->mbr.obj.vtable->klass;
568 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
569 if (method == NULL) {
570 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
576 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
579 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
583 * mono_domain_owns_vtable_slot:
585 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
588 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
592 mono_domain_lock (domain);
593 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
594 mono_domain_unlock (domain);
601 * @force: force setting.
603 * Set the current appdomain to @domain. If @force is set, set it even
604 * if it is being unloaded.
608 * FALSE if the domain is unloaded
611 mono_domain_set (MonoDomain *domain, gboolean force)
613 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
616 mono_domain_set_internal (domain);
622 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
628 MONO_CHECK_ARG_NULL (name, NULL);
634 str = mono_string_to_utf8 (name);
636 mono_domain_lock (add);
638 if (!strcmp (str, "APPBASE"))
639 o = (MonoObject *)add->setup->application_base;
640 else if (!strcmp (str, "APP_CONFIG_FILE"))
641 o = (MonoObject *)add->setup->configuration_file;
642 else if (!strcmp (str, "DYNAMIC_BASE"))
643 o = (MonoObject *)add->setup->dynamic_base;
644 else if (!strcmp (str, "APP_NAME"))
645 o = (MonoObject *)add->setup->application_name;
646 else if (!strcmp (str, "CACHE_BASE"))
647 o = (MonoObject *)add->setup->cache_path;
648 else if (!strcmp (str, "PRIVATE_BINPATH"))
649 o = (MonoObject *)add->setup->private_bin_path;
650 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
651 o = (MonoObject *)add->setup->private_bin_path_probe;
652 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
653 o = (MonoObject *)add->setup->shadow_copy_directories;
654 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
655 o = (MonoObject *)add->setup->shadow_copy_files;
657 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
659 mono_domain_unlock (add);
669 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
673 MONO_CHECK_ARG_NULL (name,);
679 mono_domain_lock (add);
681 mono_g_hash_table_insert (add->env, name, data);
683 mono_domain_unlock (add);
687 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
692 return ad->data->setup;
696 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
701 return mono_string_new (ad->data, ad->data->friendly_name);
705 ves_icall_System_AppDomain_getCurDomain ()
707 MonoDomain *add = mono_domain_get ();
713 ves_icall_System_AppDomain_getRootDomain ()
715 MonoDomain *root = mono_get_root_domain ();
721 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
723 MonoDomain *domain = mono_domain_get ();
725 return domain->throw_unobserved_task_exceptions;
729 get_attribute_value (const gchar **attribute_names,
730 const gchar **attribute_values,
731 const char *att_name)
734 for (n = 0; attribute_names [n] != NULL; n++) {
735 if (strcmp (attribute_names [n], att_name) == 0)
736 return g_strdup (attribute_values [n]);
742 start_element (GMarkupParseContext *context,
743 const gchar *element_name,
744 const gchar **attribute_names,
745 const gchar **attribute_values,
749 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
751 if (strcmp (element_name, "runtime") == 0) {
752 runtime_config->runtime_count++;
756 if (strcmp (element_name, "assemblyBinding") == 0) {
757 runtime_config->assemblybinding_count++;
761 if (runtime_config->runtime_count != 1)
764 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
765 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
767 if (value && g_ascii_strcasecmp (value, "true") == 0)
768 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
771 if (runtime_config->assemblybinding_count != 1)
774 if (strcmp (element_name, "probing") != 0)
777 g_free (runtime_config->domain->private_bin_path);
778 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
779 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
780 g_free (runtime_config->domain->private_bin_path);
781 runtime_config->domain->private_bin_path = NULL;
787 end_element (GMarkupParseContext *context,
788 const gchar *element_name,
792 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
793 if (strcmp (element_name, "runtime") == 0)
794 runtime_config->runtime_count--;
795 else if (strcmp (element_name, "assemblyBinding") == 0)
796 runtime_config->assemblybinding_count--;
800 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
802 RuntimeConfig *state = (RuntimeConfig *)user_data;
804 const gchar *filename;
806 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
807 msg = error && error->message ? error->message : "";
808 g_warning ("Error parsing %s: %s", filename, msg);
811 static const GMarkupParser
821 mono_domain_set_options_from_config (MonoDomain *domain)
824 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
826 GMarkupParseContext *context;
827 RuntimeConfig runtime_config;
830 if (!domain || !domain->setup || !domain->setup->configuration_file)
833 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
834 if (!mono_error_ok (&error)) {
835 mono_error_cleanup (&error);
839 config_file_path = mono_portability_find_file (config_file_name, TRUE);
840 if (!config_file_path)
841 config_file_path = config_file_name;
843 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
846 runtime_config.runtime_count = 0;
847 runtime_config.assemblybinding_count = 0;
848 runtime_config.domain = domain;
849 runtime_config.filename = config_file_path;
852 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
853 offset = 3; /* Skip UTF-8 BOM */
855 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
856 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
857 g_markup_parse_context_end_parse (context, NULL);
858 g_markup_parse_context_free (context);
862 if (config_file_name != config_file_path)
863 g_free (config_file_name);
864 g_free (config_file_path);
868 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
870 #ifdef DISABLE_APPDOMAINS
871 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
878 fname = mono_string_to_utf8 (friendly_name);
879 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
883 mono_error_raise_exception (&error);
890 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
892 MonoDomain *domain = ad->data;
894 static MonoClass *System_Reflection_Assembly;
898 GPtrArray *assemblies;
900 if (!System_Reflection_Assembly)
901 System_Reflection_Assembly = mono_class_from_name (
902 mono_defaults.corlib, "System.Reflection", "Assembly");
905 * Make a copy of the list of assemblies because we can't hold the assemblies
906 * lock while creating objects etc.
908 assemblies = g_ptr_array_new ();
909 /* Need to skip internal assembly builders created by remoting */
910 mono_domain_assemblies_lock (domain);
911 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
912 ass = (MonoAssembly *)tmp->data;
913 if (refonly != ass->ref_only)
915 if (ass->corlib_internal)
917 g_ptr_array_add (assemblies, ass);
919 mono_domain_assemblies_unlock (domain);
921 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
922 for (i = 0; i < assemblies->len; ++i) {
923 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
924 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
927 g_ptr_array_free (assemblies, TRUE);
932 MonoReflectionAssembly *
933 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
937 MonoBoolean isrefonly;
940 if (mono_runtime_get_no_exec ())
943 g_assert (domain != NULL && fname != NULL);
945 klass = domain->domain->mbr.obj.vtable->klass;
948 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
949 if (method == NULL) {
950 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
954 isrefonly = refonly ? 1 : 0;
956 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
957 params [2] = &isrefonly;
958 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
962 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
965 MonoReflectionAssembly *assembly;
966 MonoDomain *domain = mono_domain_get ();
970 aname_str = mono_stringify_assembly_name (aname);
972 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
973 str = mono_string_new (domain, aname_str);
978 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
982 return assembly->assembly;
988 * LOCKING: assumes assemblies_lock in the domain is already locked.
991 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
995 gboolean destroy_ht = FALSE;
997 if (!ass->aname.name)
1001 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1005 /* FIXME: handle lazy loaded assemblies */
1006 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1007 g_hash_table_insert (ht, tmp->data, tmp->data);
1009 if (!g_hash_table_lookup (ht, ass)) {
1010 mono_assembly_addref (ass);
1011 g_hash_table_insert (ht, ass, ass);
1012 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1013 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);
1016 if (ass->image->references) {
1017 for (i = 0; ass->image->references [i] != NULL; i++) {
1018 if (ass->image->references [i] != REFERENCE_MISSING)
1019 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1020 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1025 g_hash_table_destroy (ht);
1029 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1031 static MonoClassField *assembly_load_field;
1032 static MonoMethod *assembly_load_method;
1033 MonoDomain *domain = mono_domain_get ();
1034 MonoReflectionAssembly *ref_assembly;
1036 gpointer load_value;
1039 if (!domain->domain)
1040 /* This can happen during startup */
1042 #ifdef ASSEMBLY_LOAD_DEBUG
1043 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1045 klass = domain->domain->mbr.obj.vtable->klass;
1047 mono_domain_assemblies_lock (domain);
1048 add_assemblies_to_domain (domain, assembly, NULL);
1049 mono_domain_assemblies_unlock (domain);
1051 if (assembly_load_field == NULL) {
1052 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1053 g_assert (assembly_load_field);
1056 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1057 if (load_value == NULL) {
1058 /* No events waiting to be triggered */
1062 ref_assembly = mono_assembly_get_object (domain, assembly);
1063 g_assert (ref_assembly);
1065 if (assembly_load_method == NULL) {
1066 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1067 g_assert (assembly_load_method);
1070 *params = ref_assembly;
1071 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1075 * LOCKING: Acquires the domain assemblies lock.
1078 set_domain_search_path (MonoDomain *domain)
1081 MonoAppDomainSetup *setup;
1083 gchar *search_path = NULL;
1086 gchar **pvt_split = NULL;
1087 GError *gerror = NULL;
1088 gint appbaselen = -1;
1091 * We use the low-level domain assemblies lock, since this is called from
1092 * assembly loads hooks, which means this thread might hold the loader lock.
1094 mono_domain_assemblies_lock (domain);
1096 if (!domain->setup) {
1097 mono_domain_assemblies_unlock (domain);
1101 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1102 mono_domain_assemblies_unlock (domain);
1105 setup = domain->setup;
1106 if (!setup->application_base) {
1107 mono_domain_assemblies_unlock (domain);
1108 return; /* Must set application base to get private path working */
1113 if (setup->private_bin_path) {
1114 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1115 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1116 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1117 mono_error_cleanup (&error);
1118 mono_domain_assemblies_unlock (domain);
1123 if (domain->private_bin_path) {
1124 if (search_path == NULL)
1125 search_path = domain->private_bin_path;
1127 gchar *tmp2 = search_path;
1128 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1135 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1136 * directories relative to ApplicationBase separated by semicolons (see
1137 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1138 * The loop below copes with the fact that some Unix applications may use ':' (or
1139 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1140 * ';' for the subsequent split.
1142 * The issue was reported in bug #81446
1145 #ifndef TARGET_WIN32
1148 slen = strlen (search_path);
1149 for (i = 0; i < slen; i++)
1150 if (search_path [i] == ':')
1151 search_path [i] = ';';
1154 pvt_split = g_strsplit (search_path, ";", 1000);
1155 g_free (search_path);
1156 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1161 g_strfreev (pvt_split);
1163 * Don't do this because the first time is called, the domain
1164 * setup is not finished.
1166 * domain->search_path = g_malloc (sizeof (char *));
1167 * domain->search_path [0] = NULL;
1169 mono_domain_assemblies_unlock (domain);
1173 if (domain->search_path)
1174 g_strfreev (domain->search_path);
1176 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1177 tmp [npaths] = NULL;
1179 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1180 if (!mono_error_ok (&error)) {
1181 mono_error_cleanup (&error);
1182 g_strfreev (pvt_split);
1185 mono_domain_assemblies_unlock (domain);
1189 domain->search_path = tmp;
1191 /* FIXME: is this needed? */
1192 if (strncmp (*tmp, "file://", 7) == 0) {
1198 uri = g_strdup_printf ("file:///%s", uri + 7);
1201 uri = mono_escape_uri_string (tmpuri);
1202 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1208 if (gerror != NULL) {
1209 g_warning ("%s\n", gerror->message);
1210 g_error_free (gerror);
1217 for (i = 1; pvt_split && i < npaths; i++) {
1218 if (g_path_is_absolute (pvt_split [i - 1])) {
1219 tmp [i] = g_strdup (pvt_split [i - 1]);
1221 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1224 if (strchr (tmp [i], '.')) {
1228 reduced = mono_path_canonicalize (tmp [i]);
1229 if (appbaselen == -1)
1230 appbaselen = strlen (tmp [0]);
1232 if (strncmp (tmp [0], reduced, appbaselen)) {
1235 tmp [i] = g_strdup ("");
1245 if (setup->private_bin_path_probe != NULL) {
1247 tmp [0] = g_strdup ("");
1250 domain->setup->path_changed = FALSE;
1252 g_strfreev (pvt_split);
1254 mono_domain_assemblies_unlock (domain);
1257 #ifdef DISABLE_SHADOW_COPY
1259 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1265 mono_make_shadow_copy (const char *filename, MonoError *error)
1267 mono_error_init (error);
1268 return (char *) filename;
1272 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1274 guint16 *orig, *dest;
1275 gboolean copy_result;
1277 strcpy (src + srclen - tail_len, extension);
1279 if (IS_PORTABILITY_CASE) {
1280 gchar *file = mono_portability_find_file (src, TRUE);
1286 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1290 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1292 strcpy (target + targetlen - tail_len, extension);
1293 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1296 copy_result = CopyFile (orig, dest, FALSE);
1298 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1299 * overwritten when updated in their original locations. */
1301 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1310 get_cstring_hash (const char *str)
1316 if (!str || !str [0])
1321 for (i = 0; i < len; i++) {
1322 h = (h << 5) - h + *p;
1330 * Returned memory is malloc'd. Called must free it
1333 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1335 MonoAppDomainSetup *setup;
1336 char *cache_path, *appname;
1340 mono_error_init (error);
1342 setup = domain->setup;
1343 if (setup->cache_path != NULL && setup->application_name != NULL) {
1344 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1345 if (!mono_error_ok (error))
1347 #ifndef TARGET_WIN32
1350 for (i = strlen (cache_path) - 1; i >= 0; i--)
1351 if (cache_path [i] == '\\')
1352 cache_path [i] = '/';
1356 appname = mono_string_to_utf8_checked (setup->application_name, error);
1357 if (!mono_error_ok (error)) {
1358 g_free (cache_path);
1362 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1364 g_free (cache_path);
1366 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1367 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1374 get_shadow_assembly_location (const char *filename, MonoError *error)
1376 gint32 hash = 0, hash2 = 0;
1378 char path_hash [30];
1379 char *bname = g_path_get_basename (filename);
1380 char *dirname = g_path_get_dirname (filename);
1381 char *location, *tmploc;
1382 MonoDomain *domain = mono_domain_get ();
1384 mono_error_init (error);
1386 hash = get_cstring_hash (bname);
1387 hash2 = get_cstring_hash (dirname);
1388 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1389 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1390 tmploc = get_shadow_assembly_location_base (domain, error);
1391 if (!mono_error_ok (error)) {
1397 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1405 ensure_directory_exists (const char *filename)
1408 gchar *dir_utf8 = g_path_get_dirname (filename);
1410 gunichar2 *dir_utf16 = NULL;
1413 if (!dir_utf8 || !dir_utf8 [0])
1416 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1424 /* make life easy and only use one directory seperator */
1435 while (*p++ != '\\')
1441 p = wcschr (p, '\\');
1444 retval = _wmkdir (dir_utf16);
1445 if (retval != 0 && errno != EEXIST) {
1458 gchar *dir = g_path_get_dirname (filename);
1462 if (!dir || !dir [0]) {
1467 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1477 p = strchr (p, '/');
1480 retval = mkdir (dir, 0777);
1481 if (retval != 0 && errno != EEXIST) {
1496 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1498 struct stat sbuf_dest;
1500 gchar *real_src = mono_portability_find_file (src, TRUE);
1503 stat_src = (gchar*)src;
1505 stat_src = real_src;
1507 if (stat (stat_src, sbuf_src) == -1) {
1508 time_t tnow = time (NULL);
1513 memset (sbuf_src, 0, sizeof (*sbuf_src));
1514 sbuf_src->st_mtime = tnow;
1515 sbuf_src->st_atime = tnow;
1522 if (stat (dest, &sbuf_dest) == -1)
1525 if (sbuf_src->st_size == sbuf_dest.st_size &&
1526 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1533 shadow_copy_create_ini (const char *shadow, const char *filename)
1543 dir_name = g_path_get_dirname (shadow);
1544 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1546 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1551 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1556 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1557 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1559 if (handle == INVALID_HANDLE_VALUE) {
1563 full_path = mono_path_resolve_symlinks (filename);
1564 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1566 CloseHandle (handle);
1571 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1574 MonoAppDomainSetup *setup;
1577 gchar **directories;
1578 gchar *shadow_status_string;
1580 gboolean shadow_enabled;
1581 gboolean found = FALSE;
1586 setup = domain->setup;
1587 if (setup == NULL || setup->shadow_copy_files == NULL)
1590 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1591 if (!mono_error_ok (&error)) {
1592 mono_error_cleanup (&error);
1595 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1596 g_free (shadow_status_string);
1598 if (!shadow_enabled)
1601 if (setup->shadow_copy_directories == NULL)
1604 /* Is dir_name a shadow_copy destination already? */
1605 base_dir = get_shadow_assembly_location_base (domain, &error);
1606 if (!mono_error_ok (&error)) {
1607 mono_error_cleanup (&error);
1611 if (strstr (dir_name, base_dir)) {
1617 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1618 if (!mono_error_ok (&error)) {
1619 mono_error_cleanup (&error);
1623 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1624 dir_ptr = directories;
1626 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1632 g_strfreev (directories);
1638 This function raises exceptions so it can cause as sorts of nasty stuff if called
1639 while holding a lock.
1640 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1641 or NULL if source file not found.
1642 FIXME bubble up the error instead of raising it here
1645 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1648 gchar *sibling_source, *sibling_target;
1649 gint sibling_source_len, sibling_target_len;
1650 guint16 *orig, *dest;
1653 gboolean copy_result;
1654 struct stat src_sbuf;
1655 struct utimbuf utbuf;
1656 char *dir_name = g_path_get_dirname (filename);
1657 MonoDomain *domain = mono_domain_get ();
1660 mono_error_init (oerror);
1662 set_domain_search_path (domain);
1664 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1666 return (char *) filename;
1669 /* Is dir_name a shadow_copy destination already? */
1670 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1671 if (!mono_error_ok (&error)) {
1672 mono_error_cleanup (&error);
1674 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1678 if (strstr (dir_name, shadow_dir)) {
1679 g_free (shadow_dir);
1681 return (char *) filename;
1683 g_free (shadow_dir);
1686 shadow = get_shadow_assembly_location (filename, &error);
1687 if (!mono_error_ok (&error)) {
1688 mono_error_cleanup (&error);
1689 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1693 if (ensure_directory_exists (shadow) == FALSE) {
1695 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1699 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1700 return (char*) shadow;
1702 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1703 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1706 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1707 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1708 * and not have it runtime error" */
1709 attrs = GetFileAttributes (orig);
1710 if (attrs == INVALID_FILE_ATTRIBUTES) {
1712 return (char *)filename;
1715 copy_result = CopyFile (orig, dest, FALSE);
1717 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1718 * overwritten when updated in their original locations. */
1720 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1725 if (copy_result == FALSE) {
1728 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1729 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1730 return NULL; /* file not found, shadow copy failed */
1732 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1736 /* attempt to copy .mdb, .config if they exist */
1737 sibling_source = g_strconcat (filename, ".config", NULL);
1738 sibling_source_len = strlen (sibling_source);
1739 sibling_target = g_strconcat (shadow, ".config", NULL);
1740 sibling_target_len = strlen (sibling_target);
1742 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1743 if (copy_result == TRUE)
1744 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1746 g_free (sibling_source);
1747 g_free (sibling_target);
1749 if (copy_result == FALSE) {
1751 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1755 /* Create a .ini file containing the original assembly location */
1756 if (!shadow_copy_create_ini (shadow, filename)) {
1758 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1762 utbuf.actime = src_sbuf.st_atime;
1763 utbuf.modtime = src_sbuf.st_mtime;
1764 utime (shadow, &utbuf);
1768 #endif /* DISABLE_SHADOW_COPY */
1771 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1773 if (appdomain == NULL)
1776 return appdomain->data;
1780 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1781 const gchar *path3, const gchar *path4,
1782 gboolean refonly, gboolean is_private)
1785 gboolean found = FALSE;
1788 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1790 if (IS_PORTABILITY_SET) {
1791 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1794 fullpath = new_fullpath;
1798 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1801 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1804 return (*assembly != NULL);
1807 static MonoAssembly *
1808 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1810 MonoAssembly *result = NULL;
1813 const gchar *local_culture;
1815 gboolean is_private = FALSE;
1817 if (!culture || *culture == '\0') {
1820 local_culture = culture;
1823 filename = g_strconcat (name, ".dll", NULL);
1824 len = strlen (filename);
1826 for (path = search_path; *path; path++) {
1827 if (**path == '\0') {
1829 continue; /* Ignore empty ApplicationBase */
1832 /* See test cases in bug #58992 and bug #57710 */
1833 /* 1st try: [culture]/[name].dll (culture may be empty) */
1834 strcpy (filename + len - 4, ".dll");
1835 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1838 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1839 strcpy (filename + len - 4, ".exe");
1840 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1843 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1844 strcpy (filename + len - 4, ".dll");
1845 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1848 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1849 strcpy (filename + len - 4, ".exe");
1850 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1859 * Try loading the assembly from ApplicationBase and PrivateBinPath
1860 * and then from assemblies_path if any.
1861 * LOCKING: This is called from the assembly loading code, which means the caller
1862 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1864 static MonoAssembly *
1865 mono_domain_assembly_preload (MonoAssemblyName *aname,
1866 gchar **assemblies_path,
1869 MonoDomain *domain = mono_domain_get ();
1870 MonoAssembly *result = NULL;
1871 gboolean refonly = GPOINTER_TO_UINT (user_data);
1873 set_domain_search_path (domain);
1875 if (domain->search_path && domain->search_path [0] != NULL) {
1876 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1879 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1880 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1887 * Check whenever a given assembly was already loaded in the current appdomain.
1889 static MonoAssembly *
1890 mono_domain_assembly_search (MonoAssemblyName *aname,
1893 MonoDomain *domain = mono_domain_get ();
1896 gboolean refonly = GPOINTER_TO_UINT (user_data);
1898 mono_domain_assemblies_lock (domain);
1899 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1900 ass = (MonoAssembly *)tmp->data;
1901 /* Dynamic assemblies can't match here in MS.NET */
1902 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1905 mono_domain_assemblies_unlock (domain);
1908 mono_domain_assemblies_unlock (domain);
1913 MonoReflectionAssembly *
1914 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1916 MonoDomain *domain = mono_domain_get ();
1917 char *name, *filename;
1918 MonoImageOpenStatus status = MONO_IMAGE_OK;
1921 if (fname == NULL) {
1922 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1923 mono_set_pending_exception (exc);
1927 name = filename = mono_string_to_utf8 (fname);
1929 ass = mono_assembly_open_full (filename, &status, refOnly);
1934 if (status == MONO_IMAGE_IMAGE_INVALID)
1935 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1937 exc = mono_get_exception_file_not_found2 (NULL, fname);
1939 mono_set_pending_exception (exc);
1945 return mono_assembly_get_object (domain, ass);
1948 MonoReflectionAssembly *
1949 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1950 MonoArray *raw_assembly,
1951 MonoArray *raw_symbol_store, MonoObject *evidence,
1952 MonoBoolean refonly)
1955 MonoReflectionAssembly *refass = NULL;
1956 MonoDomain *domain = ad->data;
1957 MonoImageOpenStatus status;
1958 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1959 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1962 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1966 if (raw_symbol_store != NULL)
1967 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1969 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1973 mono_image_close (image);
1974 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1978 refass = mono_assembly_get_object (domain, ass);
1979 MONO_OBJECT_SETREF (refass, evidence, evidence);
1983 MonoReflectionAssembly *
1984 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1986 MonoDomain *domain = ad->data;
1987 MonoImageOpenStatus status = MONO_IMAGE_OK;
1989 MonoAssemblyName aname;
1990 MonoReflectionAssembly *refass = NULL;
1996 name = mono_string_to_utf8 (assRef);
1997 parsed = mono_assembly_name_parse (name, &aname);
2001 /* This is a parse error... */
2003 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2007 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2008 mono_assembly_name_free (&aname);
2011 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2013 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2022 refass = mono_assembly_get_object (domain, ass);
2024 MONO_OBJECT_SETREF (refass, evidence, evidence);
2029 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2031 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2033 if (NULL == domain) {
2034 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2035 mono_set_pending_exception (exc);
2039 if (domain == mono_get_root_domain ()) {
2040 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2045 * Unloading seems to cause problems when running NUnit/NAnt, hence
2048 if (g_getenv ("MONO_NO_UNLOAD"))
2050 #ifdef __native_client__
2054 mono_domain_unload (domain);
2058 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2060 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2065 return mono_domain_is_unloading (domain);
2069 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2071 mono_unhandled_exception ((MonoObject*) exc);
2075 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2076 MonoReflectionAssembly *refass, MonoArray *args)
2083 image = refass->assembly->image;
2086 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2089 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2092 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2094 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2098 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2100 return ad->data->domain_id;
2104 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2106 MonoDomain *old_domain = mono_domain_get();
2108 if (!mono_domain_set (ad->data, FALSE)) {
2109 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2113 return old_domain->domain;
2117 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2119 MonoDomain *current_domain = mono_domain_get ();
2120 MonoDomain *domain = mono_domain_get_by_id (domainid);
2122 if (!domain || !mono_domain_set (domain, FALSE)) {
2123 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2127 return current_domain->domain;
2131 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2133 mono_thread_push_appdomain_ref (ad->data);
2137 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2139 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2143 * Raise an exception to prevent the managed code from executing a pop
2146 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2150 mono_thread_push_appdomain_ref (domain);
2154 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2156 mono_thread_pop_appdomain_ref ();
2160 ves_icall_System_AppDomain_InternalGetContext ()
2162 return mono_context_get ();
2166 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2168 return mono_domain_get ()->default_context;
2172 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2174 MonoAppContext *old_context = mono_context_get ();
2176 mono_context_set (mc);
2182 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2184 MonoDomain* mono_root_domain = mono_get_root_domain ();
2185 mono_domain_lock (mono_root_domain);
2186 if (process_guid_set) {
2187 mono_domain_unlock (mono_root_domain);
2188 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2190 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2191 process_guid_set = TRUE;
2192 mono_domain_unlock (mono_root_domain);
2197 mono_domain_is_unloading (MonoDomain *domain)
2199 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2206 clear_cached_vtable (MonoVTable *vtable)
2208 MonoClass *klass = vtable->klass;
2209 MonoDomain *domain = vtable->domain;
2210 MonoClassRuntimeInfo *runtime_info;
2213 runtime_info = klass->runtime_info;
2214 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2215 runtime_info->domain_vtables [domain->domain_id] = NULL;
2216 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2217 mono_gc_free_fixed (data);
2220 static G_GNUC_UNUSED void
2221 zero_static_data (MonoVTable *vtable)
2223 MonoClass *klass = vtable->klass;
2226 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2227 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2230 typedef struct unload_data {
2233 char *failure_reason;
2238 unload_data_unref (unload_data *data)
2242 mono_atomic_load_acquire (count, gint32, &data->refcount);
2243 g_assert (count >= 1 && count <= 2);
2248 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2252 deregister_reflection_info_roots_from_list (MonoImage *image)
2254 GSList *list = image->reflection_info_unregister_classes;
2257 MonoClass *klass = (MonoClass *)list->data;
2259 mono_class_free_ref_info (klass);
2264 image->reflection_info_unregister_classes = NULL;
2268 deregister_reflection_info_roots (MonoDomain *domain)
2272 mono_domain_assemblies_lock (domain);
2273 for (list = domain->domain_assemblies; list; list = list->next) {
2274 MonoAssembly *assembly = (MonoAssembly *)list->data;
2275 MonoImage *image = assembly->image;
2279 * No need to take the image lock here since dynamic images are appdomain bound and
2280 * at this point the mutator is gone. Taking the image lock here would mean
2281 * promoting it from a simple lock to a complex lock, which we better avoid if
2284 if (image_is_dynamic (image))
2285 deregister_reflection_info_roots_from_list (image);
2287 for (i = 0; i < image->module_count; ++i) {
2288 MonoImage *module = image->modules [i];
2289 if (module && image_is_dynamic (module))
2290 deregister_reflection_info_roots_from_list (module);
2293 mono_domain_assemblies_unlock (domain);
2296 static guint32 WINAPI
2297 unload_thread_main (void *arg)
2300 unload_data *data = (unload_data*)arg;
2301 MonoDomain *domain = data->domain;
2305 /* Have to attach to the runtime so shutdown can wait for this thread */
2306 /* Force it to be attached to avoid racing during shutdown. */
2307 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2308 mono_error_raise_exception (&error); /* FIXME don't raise here */
2311 * FIXME: Abort our parent thread last, so we can return a failure
2312 * indication if aborting times out.
2314 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2315 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2319 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2320 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2324 /* Finalize all finalizable objects in the doomed appdomain */
2325 if (!mono_domain_finalize (domain, -1)) {
2326 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2330 /* Clear references to our vtables in class->runtime_info.
2331 * We also hold the loader lock because we're going to change
2332 * class->runtime_info.
2335 mono_loader_lock (); //FIXME why do we need the loader lock here?
2336 mono_domain_lock (domain);
2339 * We need to make sure that we don't have any remsets
2340 * pointing into static data of the to-be-freed domain because
2341 * at the next collections they would be invalid. So what we
2342 * do is we first zero all static data and then do a minor
2343 * collection. Because all references in the static data will
2344 * now be null we won't do any unnecessary copies and after
2345 * the collection there won't be any more remsets.
2347 for (i = 0; i < domain->class_vtable_array->len; ++i)
2348 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2349 mono_gc_collect (0);
2351 for (i = 0; i < domain->class_vtable_array->len; ++i)
2352 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2353 deregister_reflection_info_roots (domain);
2355 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2357 mono_domain_unlock (domain);
2358 mono_loader_unlock ();
2360 mono_threads_clear_cached_culture (domain);
2362 domain->state = MONO_APPDOMAIN_UNLOADED;
2364 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2366 /* remove from the handle table the items related to this domain */
2367 mono_gchandle_free_domain (domain);
2369 mono_domain_free (domain, FALSE);
2371 mono_gc_collect (mono_gc_max_generation ());
2373 mono_atomic_store_release (&data->done, TRUE);
2374 unload_data_unref (data);
2375 mono_thread_detach (thread);
2379 mono_atomic_store_release (&data->done, TRUE);
2380 unload_data_unref (data);
2381 mono_thread_detach (thread);
2386 * mono_domain_unload:
2387 * @domain: The domain to unload
2389 * Unloads an appdomain. Follows the process outlined in the comment
2390 * for mono_domain_try_unload.
2393 mono_domain_unload (MonoDomain *domain)
2395 MonoObject *exc = NULL;
2396 mono_domain_try_unload (domain, &exc);
2398 mono_raise_exception ((MonoException*)exc);
2402 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2406 MONO_PREPARE_BLOCKING;
2407 result = WaitForSingleObjectEx (handle, timeout, alertable);
2408 MONO_FINISH_BLOCKING;
2414 * mono_domain_unload:
2415 * @domain: The domain to unload
2416 * @exc: Exception information
2418 * Unloads an appdomain. Follows the process outlined in:
2419 * http://blogs.gotdotnet.com/cbrumme
2421 * If doing things the 'right' way is too hard or complex, we do it the
2422 * 'simple' way, which means do everything needed to avoid crashes and
2423 * memory leaks, but not much else.
2425 * It is required to pass a valid reference to the exc argument, upon return
2426 * from this function *exc will be set to the exception thrown, if any.
2428 * If this method is not called from an icall (embedded scenario for instance),
2429 * it must not be called with any managed frames on the stack, since the unload
2430 * process could end up trying to abort the current thread.
2433 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2435 HANDLE thread_handle;
2436 MonoAppDomainState prev_state;
2438 unload_data *thread_data;
2439 MonoNativeThreadId tid;
2440 MonoDomain *caller_domain = mono_domain_get ();
2443 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2445 /* Atomically change our state to UNLOADING */
2446 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2447 MONO_APPDOMAIN_UNLOADING_START,
2448 MONO_APPDOMAIN_CREATED);
2449 if (prev_state != MONO_APPDOMAIN_CREATED) {
2450 switch (prev_state) {
2451 case MONO_APPDOMAIN_UNLOADING_START:
2452 case MONO_APPDOMAIN_UNLOADING:
2453 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2455 case MONO_APPDOMAIN_UNLOADED:
2456 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2459 g_warning ("Invalid appdomain state %d", prev_state);
2460 g_assert_not_reached ();
2464 mono_domain_set (domain, FALSE);
2465 /* Notify OnDomainUnload listeners */
2466 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2469 mono_runtime_invoke (method, domain->domain, NULL, exc);
2471 /* Roll back the state change */
2472 domain->state = MONO_APPDOMAIN_CREATED;
2473 mono_domain_set (caller_domain, FALSE);
2476 mono_domain_set (caller_domain, FALSE);
2478 thread_data = g_new0 (unload_data, 1);
2479 thread_data->domain = domain;
2480 thread_data->failure_reason = NULL;
2481 thread_data->done = FALSE;
2482 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2484 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2485 domain->state = MONO_APPDOMAIN_UNLOADING;
2487 * First we create a separate thread for unloading, since
2488 * we might have to abort some threads, including the current one.
2490 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2491 if (thread_handle == NULL)
2493 name = g_strdup_printf ("Unload thread for domain %x", domain);
2494 mono_thread_info_set_name (tid, name);
2495 mono_thread_info_resume (tid);
2498 /* Wait for the thread */
2499 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2500 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2501 /* The unload thread tries to abort us */
2502 /* The icall wrapper will execute the abort */
2503 CloseHandle (thread_handle);
2504 unload_data_unref (thread_data);
2508 CloseHandle (thread_handle);
2510 if (thread_data->failure_reason) {
2511 /* Roll back the state change */
2512 domain->state = MONO_APPDOMAIN_CREATED;
2514 g_warning ("%s", thread_data->failure_reason);
2516 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2518 g_free (thread_data->failure_reason);
2519 thread_data->failure_reason = NULL;
2522 unload_data_unref (thread_data);