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);
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)
396 MonoAppDomainSetup *setup;
399 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
400 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), klass);
401 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
403 ad = mono_domain_create_appdomain_internal (friendly_name, setup);
405 return mono_domain_from_appdomain (ad);
409 * mono_domain_set_config:
410 * @domain: MonoDomain initialized with the appdomain we want to change
411 * @base_dir: new base directory for the appdomain
412 * @config_file_name: path to the new configuration for the app domain
414 * Used to set the system configuration for an appdomain
416 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
417 * Error Initializing the configuration system. ---> System.ArgumentException:
418 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
421 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
423 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
424 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
427 static MonoAppDomainSetup*
428 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
430 MonoDomain *caller_domain = mono_domain_get ();
431 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
432 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
434 mono_domain_set_internal (domain);
436 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
437 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
438 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
439 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
440 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
441 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
442 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
443 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
444 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
445 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
446 copy->publisher_policy = setup->publisher_policy;
447 copy->path_changed = setup->path_changed;
448 copy->loader_optimization = setup->loader_optimization;
449 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
450 copy->disallow_code_downloads = setup->disallow_code_downloads;
451 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
452 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
453 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
454 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
455 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
457 mono_domain_set_internal (caller_domain);
462 static MonoAppDomain *
463 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
469 char *shadow_location;
471 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
473 /* FIXME: pin all those objects */
474 data = mono_domain_create();
476 ad = (MonoAppDomain *) mono_object_new (data, adclass);
479 data->friendly_name = g_strdup (friendly_name);
481 mono_profiler_appdomain_name (data, data->friendly_name);
483 if (!setup->application_base) {
484 /* Inherit from the root domain since MS.NET does this */
485 MonoDomain *root = mono_get_root_domain ();
486 if (root->setup->application_base)
487 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)));
490 mono_context_init (data);
492 data->setup = copy_app_domain_setup (data, setup);
493 mono_domain_set_options_from_config (data);
494 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
496 #ifndef DISABLE_SHADOW_COPY
497 /*FIXME, guard this for when the debugger is not running */
498 shadow_location = get_shadow_assembly_location_base (data, &error);
499 if (!mono_error_ok (&error))
500 mono_error_raise_exception (&error);
501 g_free (shadow_location);
504 create_domain_objects (data);
510 * mono_domain_has_type_resolve:
511 * @domain: application domains being looked up
513 * Returns true if the AppDomain.TypeResolve field has been
517 mono_domain_has_type_resolve (MonoDomain *domain)
519 static MonoClassField *field = NULL;
523 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
527 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
531 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
536 * mono_domain_try_type_resolve:
537 * @domain: application domainwhere the name where the type is going to be resolved
538 * @name: the name of the type to resolve or NULL.
539 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
541 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
542 * the assembly that matches name.
544 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
546 * Returns: A MonoReflectionAssembly or NULL if not found
548 MonoReflectionAssembly *
549 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
553 static MonoMethod *method = NULL;
555 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
557 if (method == NULL) {
558 klass = domain->domain->mbr.obj.vtable->klass;
561 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
562 if (method == NULL) {
563 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
569 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
572 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
576 * mono_domain_owns_vtable_slot:
578 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
581 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
585 mono_domain_lock (domain);
586 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
587 mono_domain_unlock (domain);
594 * @force: force setting.
596 * Set the current appdomain to @domain. If @force is set, set it even
597 * if it is being unloaded.
601 * FALSE if the domain is unloaded
604 mono_domain_set (MonoDomain *domain, gboolean force)
606 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
609 mono_domain_set_internal (domain);
615 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
621 MONO_CHECK_ARG_NULL (name, NULL);
627 str = mono_string_to_utf8 (name);
629 mono_domain_lock (add);
631 if (!strcmp (str, "APPBASE"))
632 o = (MonoObject *)add->setup->application_base;
633 else if (!strcmp (str, "APP_CONFIG_FILE"))
634 o = (MonoObject *)add->setup->configuration_file;
635 else if (!strcmp (str, "DYNAMIC_BASE"))
636 o = (MonoObject *)add->setup->dynamic_base;
637 else if (!strcmp (str, "APP_NAME"))
638 o = (MonoObject *)add->setup->application_name;
639 else if (!strcmp (str, "CACHE_BASE"))
640 o = (MonoObject *)add->setup->cache_path;
641 else if (!strcmp (str, "PRIVATE_BINPATH"))
642 o = (MonoObject *)add->setup->private_bin_path;
643 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
644 o = (MonoObject *)add->setup->private_bin_path_probe;
645 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
646 o = (MonoObject *)add->setup->shadow_copy_directories;
647 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
648 o = (MonoObject *)add->setup->shadow_copy_files;
650 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
652 mono_domain_unlock (add);
662 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
666 MONO_CHECK_ARG_NULL (name,);
672 mono_domain_lock (add);
674 mono_g_hash_table_insert (add->env, name, data);
676 mono_domain_unlock (add);
680 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
685 return ad->data->setup;
689 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
694 return mono_string_new (ad->data, ad->data->friendly_name);
698 ves_icall_System_AppDomain_getCurDomain ()
700 MonoDomain *add = mono_domain_get ();
706 ves_icall_System_AppDomain_getRootDomain ()
708 MonoDomain *root = mono_get_root_domain ();
714 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
716 MonoDomain *domain = mono_domain_get ();
718 return domain->throw_unobserved_task_exceptions;
722 get_attribute_value (const gchar **attribute_names,
723 const gchar **attribute_values,
724 const char *att_name)
727 for (n = 0; attribute_names [n] != NULL; n++) {
728 if (strcmp (attribute_names [n], att_name) == 0)
729 return g_strdup (attribute_values [n]);
735 start_element (GMarkupParseContext *context,
736 const gchar *element_name,
737 const gchar **attribute_names,
738 const gchar **attribute_values,
742 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
744 if (strcmp (element_name, "runtime") == 0) {
745 runtime_config->runtime_count++;
749 if (strcmp (element_name, "assemblyBinding") == 0) {
750 runtime_config->assemblybinding_count++;
754 if (runtime_config->runtime_count != 1)
757 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
758 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
760 if (value && g_ascii_strcasecmp (value, "true") == 0)
761 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
764 if (runtime_config->assemblybinding_count != 1)
767 if (strcmp (element_name, "probing") != 0)
770 g_free (runtime_config->domain->private_bin_path);
771 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
772 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
773 g_free (runtime_config->domain->private_bin_path);
774 runtime_config->domain->private_bin_path = NULL;
780 end_element (GMarkupParseContext *context,
781 const gchar *element_name,
785 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
786 if (strcmp (element_name, "runtime") == 0)
787 runtime_config->runtime_count--;
788 else if (strcmp (element_name, "assemblyBinding") == 0)
789 runtime_config->assemblybinding_count--;
793 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
795 RuntimeConfig *state = (RuntimeConfig *)user_data;
797 const gchar *filename;
799 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
800 msg = error && error->message ? error->message : "";
801 g_warning ("Error parsing %s: %s", filename, msg);
804 static const GMarkupParser
814 mono_domain_set_options_from_config (MonoDomain *domain)
817 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
819 GMarkupParseContext *context;
820 RuntimeConfig runtime_config;
823 if (!domain || !domain->setup || !domain->setup->configuration_file)
826 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
827 if (!mono_error_ok (&error)) {
828 mono_error_cleanup (&error);
832 config_file_path = mono_portability_find_file (config_file_name, TRUE);
833 if (!config_file_path)
834 config_file_path = config_file_name;
836 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
839 runtime_config.runtime_count = 0;
840 runtime_config.assemblybinding_count = 0;
841 runtime_config.domain = domain;
842 runtime_config.filename = config_file_path;
845 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
846 offset = 3; /* Skip UTF-8 BOM */
848 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
849 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
850 g_markup_parse_context_end_parse (context, NULL);
851 g_markup_parse_context_free (context);
855 if (config_file_name != config_file_path)
856 g_free (config_file_name);
857 g_free (config_file_path);
861 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
863 #ifdef DISABLE_APPDOMAINS
864 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
867 char *fname = mono_string_to_utf8 (friendly_name);
868 MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
877 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
879 MonoDomain *domain = ad->data;
881 static MonoClass *System_Reflection_Assembly;
885 GPtrArray *assemblies;
887 if (!System_Reflection_Assembly)
888 System_Reflection_Assembly = mono_class_from_name (
889 mono_defaults.corlib, "System.Reflection", "Assembly");
892 * Make a copy of the list of assemblies because we can't hold the assemblies
893 * lock while creating objects etc.
895 assemblies = g_ptr_array_new ();
896 /* Need to skip internal assembly builders created by remoting */
897 mono_domain_assemblies_lock (domain);
898 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
899 ass = (MonoAssembly *)tmp->data;
900 if (refonly != ass->ref_only)
902 if (ass->corlib_internal)
904 g_ptr_array_add (assemblies, ass);
906 mono_domain_assemblies_unlock (domain);
908 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
909 for (i = 0; i < assemblies->len; ++i) {
910 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
911 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
914 g_ptr_array_free (assemblies, TRUE);
919 MonoReflectionAssembly *
920 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
924 MonoBoolean isrefonly;
927 if (mono_runtime_get_no_exec ())
930 g_assert (domain != NULL && fname != NULL);
932 klass = domain->domain->mbr.obj.vtable->klass;
935 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
936 if (method == NULL) {
937 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
941 isrefonly = refonly ? 1 : 0;
943 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
944 params [2] = &isrefonly;
945 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
949 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
952 MonoReflectionAssembly *assembly;
953 MonoDomain *domain = mono_domain_get ();
957 aname_str = mono_stringify_assembly_name (aname);
959 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
960 str = mono_string_new (domain, aname_str);
965 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
969 return assembly->assembly;
975 * LOCKING: assumes assemblies_lock in the domain is already locked.
978 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
982 gboolean destroy_ht = FALSE;
984 if (!ass->aname.name)
988 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
992 /* FIXME: handle lazy loaded assemblies */
993 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
994 g_hash_table_insert (ht, tmp->data, tmp->data);
996 if (!g_hash_table_lookup (ht, ass)) {
997 mono_assembly_addref (ass);
998 g_hash_table_insert (ht, ass, ass);
999 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1000 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);
1003 if (ass->image->references) {
1004 for (i = 0; ass->image->references [i] != NULL; i++) {
1005 if (ass->image->references [i] != REFERENCE_MISSING)
1006 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1007 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1012 g_hash_table_destroy (ht);
1016 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1018 static MonoClassField *assembly_load_field;
1019 static MonoMethod *assembly_load_method;
1020 MonoDomain *domain = mono_domain_get ();
1021 MonoReflectionAssembly *ref_assembly;
1023 gpointer load_value;
1026 if (!domain->domain)
1027 /* This can happen during startup */
1029 #ifdef ASSEMBLY_LOAD_DEBUG
1030 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1032 klass = domain->domain->mbr.obj.vtable->klass;
1034 mono_domain_assemblies_lock (domain);
1035 add_assemblies_to_domain (domain, assembly, NULL);
1036 mono_domain_assemblies_unlock (domain);
1038 if (assembly_load_field == NULL) {
1039 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1040 g_assert (assembly_load_field);
1043 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1044 if (load_value == NULL) {
1045 /* No events waiting to be triggered */
1049 ref_assembly = mono_assembly_get_object (domain, assembly);
1050 g_assert (ref_assembly);
1052 if (assembly_load_method == NULL) {
1053 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1054 g_assert (assembly_load_method);
1057 *params = ref_assembly;
1058 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1062 * LOCKING: Acquires the domain assemblies lock.
1065 set_domain_search_path (MonoDomain *domain)
1068 MonoAppDomainSetup *setup;
1070 gchar *search_path = NULL;
1073 gchar **pvt_split = NULL;
1074 GError *gerror = NULL;
1075 gint appbaselen = -1;
1078 * We use the low-level domain assemblies lock, since this is called from
1079 * assembly loads hooks, which means this thread might hold the loader lock.
1081 mono_domain_assemblies_lock (domain);
1083 if (!domain->setup) {
1084 mono_domain_assemblies_unlock (domain);
1088 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1089 mono_domain_assemblies_unlock (domain);
1092 setup = domain->setup;
1093 if (!setup->application_base) {
1094 mono_domain_assemblies_unlock (domain);
1095 return; /* Must set application base to get private path working */
1100 if (setup->private_bin_path) {
1101 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1102 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1103 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1104 mono_error_cleanup (&error);
1105 mono_domain_assemblies_unlock (domain);
1110 if (domain->private_bin_path) {
1111 if (search_path == NULL)
1112 search_path = domain->private_bin_path;
1114 gchar *tmp2 = search_path;
1115 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1122 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1123 * directories relative to ApplicationBase separated by semicolons (see
1124 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1125 * The loop below copes with the fact that some Unix applications may use ':' (or
1126 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1127 * ';' for the subsequent split.
1129 * The issue was reported in bug #81446
1132 #ifndef TARGET_WIN32
1135 slen = strlen (search_path);
1136 for (i = 0; i < slen; i++)
1137 if (search_path [i] == ':')
1138 search_path [i] = ';';
1141 pvt_split = g_strsplit (search_path, ";", 1000);
1142 g_free (search_path);
1143 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1148 g_strfreev (pvt_split);
1150 * Don't do this because the first time is called, the domain
1151 * setup is not finished.
1153 * domain->search_path = g_malloc (sizeof (char *));
1154 * domain->search_path [0] = NULL;
1156 mono_domain_assemblies_unlock (domain);
1160 if (domain->search_path)
1161 g_strfreev (domain->search_path);
1163 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1164 tmp [npaths] = NULL;
1166 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1167 if (!mono_error_ok (&error)) {
1168 mono_error_cleanup (&error);
1169 g_strfreev (pvt_split);
1172 mono_domain_assemblies_unlock (domain);
1176 domain->search_path = tmp;
1178 /* FIXME: is this needed? */
1179 if (strncmp (*tmp, "file://", 7) == 0) {
1185 uri = g_strdup_printf ("file:///%s", uri + 7);
1188 uri = mono_escape_uri_string (tmpuri);
1189 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1195 if (gerror != NULL) {
1196 g_warning ("%s\n", gerror->message);
1197 g_error_free (gerror);
1204 for (i = 1; pvt_split && i < npaths; i++) {
1205 if (g_path_is_absolute (pvt_split [i - 1])) {
1206 tmp [i] = g_strdup (pvt_split [i - 1]);
1208 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1211 if (strchr (tmp [i], '.')) {
1215 reduced = mono_path_canonicalize (tmp [i]);
1216 if (appbaselen == -1)
1217 appbaselen = strlen (tmp [0]);
1219 if (strncmp (tmp [0], reduced, appbaselen)) {
1222 tmp [i] = g_strdup ("");
1232 if (setup->private_bin_path_probe != NULL) {
1234 tmp [0] = g_strdup ("");
1237 domain->setup->path_changed = FALSE;
1239 g_strfreev (pvt_split);
1241 mono_domain_assemblies_unlock (domain);
1244 #ifdef DISABLE_SHADOW_COPY
1246 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1252 mono_make_shadow_copy (const char *filename)
1254 return (char *) filename;
1258 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1260 guint16 *orig, *dest;
1261 gboolean copy_result;
1263 strcpy (src + srclen - tail_len, extension);
1265 if (IS_PORTABILITY_CASE) {
1266 gchar *file = mono_portability_find_file (src, TRUE);
1272 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1276 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1278 strcpy (target + targetlen - tail_len, extension);
1279 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1282 copy_result = CopyFile (orig, dest, FALSE);
1284 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1285 * overwritten when updated in their original locations. */
1287 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1296 get_cstring_hash (const char *str)
1302 if (!str || !str [0])
1307 for (i = 0; i < len; i++) {
1308 h = (h << 5) - h + *p;
1316 * Returned memory is malloc'd. Called must free it
1319 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1321 MonoAppDomainSetup *setup;
1322 char *cache_path, *appname;
1326 mono_error_init (error);
1328 setup = domain->setup;
1329 if (setup->cache_path != NULL && setup->application_name != NULL) {
1330 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1331 if (!mono_error_ok (error))
1333 #ifndef TARGET_WIN32
1336 for (i = strlen (cache_path) - 1; i >= 0; i--)
1337 if (cache_path [i] == '\\')
1338 cache_path [i] = '/';
1342 appname = mono_string_to_utf8_checked (setup->application_name, error);
1343 if (!mono_error_ok (error)) {
1344 g_free (cache_path);
1348 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1350 g_free (cache_path);
1352 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1353 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1360 get_shadow_assembly_location (const char *filename, MonoError *error)
1362 gint32 hash = 0, hash2 = 0;
1364 char path_hash [30];
1365 char *bname = g_path_get_basename (filename);
1366 char *dirname = g_path_get_dirname (filename);
1367 char *location, *tmploc;
1368 MonoDomain *domain = mono_domain_get ();
1370 mono_error_init (error);
1372 hash = get_cstring_hash (bname);
1373 hash2 = get_cstring_hash (dirname);
1374 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1375 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1376 tmploc = get_shadow_assembly_location_base (domain, error);
1377 if (!mono_error_ok (error)) {
1383 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1391 ensure_directory_exists (const char *filename)
1394 gchar *dir_utf8 = g_path_get_dirname (filename);
1396 gunichar2 *dir_utf16 = NULL;
1399 if (!dir_utf8 || !dir_utf8 [0])
1402 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1410 /* make life easy and only use one directory seperator */
1421 while (*p++ != '\\')
1427 p = wcschr (p, '\\');
1430 retval = _wmkdir (dir_utf16);
1431 if (retval != 0 && errno != EEXIST) {
1444 gchar *dir = g_path_get_dirname (filename);
1448 if (!dir || !dir [0]) {
1453 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1463 p = strchr (p, '/');
1466 retval = mkdir (dir, 0777);
1467 if (retval != 0 && errno != EEXIST) {
1482 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1484 struct stat sbuf_dest;
1486 gchar *real_src = mono_portability_find_file (src, TRUE);
1489 stat_src = (gchar*)src;
1491 stat_src = real_src;
1493 if (stat (stat_src, sbuf_src) == -1) {
1494 time_t tnow = time (NULL);
1499 memset (sbuf_src, 0, sizeof (*sbuf_src));
1500 sbuf_src->st_mtime = tnow;
1501 sbuf_src->st_atime = tnow;
1508 if (stat (dest, &sbuf_dest) == -1)
1511 if (sbuf_src->st_size == sbuf_dest.st_size &&
1512 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1519 shadow_copy_create_ini (const char *shadow, const char *filename)
1529 dir_name = g_path_get_dirname (shadow);
1530 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1532 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1537 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1542 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1543 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1545 if (handle == INVALID_HANDLE_VALUE) {
1549 full_path = mono_path_resolve_symlinks (filename);
1550 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1552 CloseHandle (handle);
1557 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1560 MonoAppDomainSetup *setup;
1563 gchar **directories;
1564 gchar *shadow_status_string;
1566 gboolean shadow_enabled;
1567 gboolean found = FALSE;
1572 setup = domain->setup;
1573 if (setup == NULL || setup->shadow_copy_files == NULL)
1576 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1577 if (!mono_error_ok (&error)) {
1578 mono_error_cleanup (&error);
1581 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1582 g_free (shadow_status_string);
1584 if (!shadow_enabled)
1587 if (setup->shadow_copy_directories == NULL)
1590 /* Is dir_name a shadow_copy destination already? */
1591 base_dir = get_shadow_assembly_location_base (domain, &error);
1592 if (!mono_error_ok (&error)) {
1593 mono_error_cleanup (&error);
1597 if (strstr (dir_name, base_dir)) {
1603 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1604 if (!mono_error_ok (&error)) {
1605 mono_error_cleanup (&error);
1609 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1610 dir_ptr = directories;
1612 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1618 g_strfreev (directories);
1624 This function raises exceptions so it can cause as sorts of nasty stuff if called
1625 while holding a lock.
1626 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1627 or NULL if source file not found.
1628 FIXME bubble up the error instead of raising it here
1631 mono_make_shadow_copy (const char *filename)
1634 gchar *sibling_source, *sibling_target;
1635 gint sibling_source_len, sibling_target_len;
1636 guint16 *orig, *dest;
1639 gboolean copy_result;
1641 struct stat src_sbuf;
1642 struct utimbuf utbuf;
1643 char *dir_name = g_path_get_dirname (filename);
1644 MonoDomain *domain = mono_domain_get ();
1647 set_domain_search_path (domain);
1649 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1651 return (char *) filename;
1654 /* Is dir_name a shadow_copy destination already? */
1655 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1656 if (!mono_error_ok (&error)) {
1657 mono_error_cleanup (&error);
1659 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1660 mono_raise_exception (exc);
1663 if (strstr (dir_name, shadow_dir)) {
1664 g_free (shadow_dir);
1666 return (char *) filename;
1668 g_free (shadow_dir);
1671 shadow = get_shadow_assembly_location (filename, &error);
1672 if (!mono_error_ok (&error)) {
1673 mono_error_cleanup (&error);
1674 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1675 mono_raise_exception (exc);
1678 if (ensure_directory_exists (shadow) == FALSE) {
1680 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1681 mono_raise_exception (exc);
1684 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1685 return (char*) shadow;
1687 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1688 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1691 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1692 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1693 * and not have it runtime error" */
1694 attrs = GetFileAttributes (orig);
1695 if (attrs == INVALID_FILE_ATTRIBUTES) {
1697 return (char *)filename;
1700 copy_result = CopyFile (orig, dest, FALSE);
1702 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1703 * overwritten when updated in their original locations. */
1705 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1710 if (copy_result == FALSE) {
1713 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1714 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1715 return NULL; /* file not found, shadow copy failed */
1717 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1718 mono_raise_exception (exc);
1721 /* attempt to copy .mdb, .config if they exist */
1722 sibling_source = g_strconcat (filename, ".config", NULL);
1723 sibling_source_len = strlen (sibling_source);
1724 sibling_target = g_strconcat (shadow, ".config", NULL);
1725 sibling_target_len = strlen (sibling_target);
1727 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1728 if (copy_result == TRUE)
1729 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1731 g_free (sibling_source);
1732 g_free (sibling_target);
1734 if (copy_result == FALSE) {
1736 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1737 mono_raise_exception (exc);
1740 /* Create a .ini file containing the original assembly location */
1741 if (!shadow_copy_create_ini (shadow, filename)) {
1743 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1744 mono_raise_exception (exc);
1747 utbuf.actime = src_sbuf.st_atime;
1748 utbuf.modtime = src_sbuf.st_mtime;
1749 utime (shadow, &utbuf);
1753 #endif /* DISABLE_SHADOW_COPY */
1756 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1758 if (appdomain == NULL)
1761 return appdomain->data;
1765 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1766 const gchar *path3, const gchar *path4,
1767 gboolean refonly, gboolean is_private)
1770 gboolean found = FALSE;
1773 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1775 if (IS_PORTABILITY_SET) {
1776 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1779 fullpath = new_fullpath;
1783 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1786 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1789 return (*assembly != NULL);
1792 static MonoAssembly *
1793 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1795 MonoAssembly *result = NULL;
1798 const gchar *local_culture;
1800 gboolean is_private = FALSE;
1802 if (!culture || *culture == '\0') {
1805 local_culture = culture;
1808 filename = g_strconcat (name, ".dll", NULL);
1809 len = strlen (filename);
1811 for (path = search_path; *path; path++) {
1812 if (**path == '\0') {
1814 continue; /* Ignore empty ApplicationBase */
1817 /* See test cases in bug #58992 and bug #57710 */
1818 /* 1st try: [culture]/[name].dll (culture may be empty) */
1819 strcpy (filename + len - 4, ".dll");
1820 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1823 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1824 strcpy (filename + len - 4, ".exe");
1825 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1828 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1829 strcpy (filename + len - 4, ".dll");
1830 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1833 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1834 strcpy (filename + len - 4, ".exe");
1835 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1844 * Try loading the assembly from ApplicationBase and PrivateBinPath
1845 * and then from assemblies_path if any.
1846 * LOCKING: This is called from the assembly loading code, which means the caller
1847 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1849 static MonoAssembly *
1850 mono_domain_assembly_preload (MonoAssemblyName *aname,
1851 gchar **assemblies_path,
1854 MonoDomain *domain = mono_domain_get ();
1855 MonoAssembly *result = NULL;
1856 gboolean refonly = GPOINTER_TO_UINT (user_data);
1858 set_domain_search_path (domain);
1860 if (domain->search_path && domain->search_path [0] != NULL) {
1861 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1864 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1865 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1872 * Check whenever a given assembly was already loaded in the current appdomain.
1874 static MonoAssembly *
1875 mono_domain_assembly_search (MonoAssemblyName *aname,
1878 MonoDomain *domain = mono_domain_get ();
1881 gboolean refonly = GPOINTER_TO_UINT (user_data);
1883 mono_domain_assemblies_lock (domain);
1884 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1885 ass = (MonoAssembly *)tmp->data;
1886 /* Dynamic assemblies can't match here in MS.NET */
1887 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1890 mono_domain_assemblies_unlock (domain);
1893 mono_domain_assemblies_unlock (domain);
1898 MonoReflectionAssembly *
1899 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1901 MonoDomain *domain = mono_domain_get ();
1902 char *name, *filename;
1903 MonoImageOpenStatus status = MONO_IMAGE_OK;
1906 if (fname == NULL) {
1907 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1908 mono_set_pending_exception (exc);
1912 name = filename = mono_string_to_utf8 (fname);
1914 ass = mono_assembly_open_full (filename, &status, refOnly);
1919 if (status == MONO_IMAGE_IMAGE_INVALID)
1920 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1922 exc = mono_get_exception_file_not_found2 (NULL, fname);
1924 mono_set_pending_exception (exc);
1930 return mono_assembly_get_object (domain, ass);
1933 MonoReflectionAssembly *
1934 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1935 MonoArray *raw_assembly,
1936 MonoArray *raw_symbol_store, MonoObject *evidence,
1937 MonoBoolean refonly)
1940 MonoReflectionAssembly *refass = NULL;
1941 MonoDomain *domain = ad->data;
1942 MonoImageOpenStatus status;
1943 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1944 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1947 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1951 if (raw_symbol_store != NULL)
1952 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1954 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1958 mono_image_close (image);
1959 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1963 refass = mono_assembly_get_object (domain, ass);
1964 MONO_OBJECT_SETREF (refass, evidence, evidence);
1968 MonoReflectionAssembly *
1969 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1971 MonoDomain *domain = ad->data;
1972 MonoImageOpenStatus status = MONO_IMAGE_OK;
1974 MonoAssemblyName aname;
1975 MonoReflectionAssembly *refass = NULL;
1981 name = mono_string_to_utf8 (assRef);
1982 parsed = mono_assembly_name_parse (name, &aname);
1986 /* This is a parse error... */
1988 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1992 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1993 mono_assembly_name_free (&aname);
1996 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1998 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2007 refass = mono_assembly_get_object (domain, ass);
2009 MONO_OBJECT_SETREF (refass, evidence, evidence);
2014 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2016 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2018 if (NULL == domain) {
2019 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2020 mono_set_pending_exception (exc);
2024 if (domain == mono_get_root_domain ()) {
2025 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2030 * Unloading seems to cause problems when running NUnit/NAnt, hence
2033 if (g_getenv ("MONO_NO_UNLOAD"))
2035 #ifdef __native_client__
2039 mono_domain_unload (domain);
2043 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2045 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2050 return mono_domain_is_unloading (domain);
2054 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2056 mono_unhandled_exception ((MonoObject*) exc);
2060 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2061 MonoReflectionAssembly *refass, MonoArray *args)
2068 image = refass->assembly->image;
2071 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2074 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2077 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2079 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2083 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2085 return ad->data->domain_id;
2089 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2091 MonoDomain *old_domain = mono_domain_get();
2093 if (!mono_domain_set (ad->data, FALSE)) {
2094 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2098 return old_domain->domain;
2102 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2104 MonoDomain *current_domain = mono_domain_get ();
2105 MonoDomain *domain = mono_domain_get_by_id (domainid);
2107 if (!domain || !mono_domain_set (domain, FALSE)) {
2108 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2112 return current_domain->domain;
2116 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2118 mono_thread_push_appdomain_ref (ad->data);
2122 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2124 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2128 * Raise an exception to prevent the managed code from executing a pop
2131 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2135 mono_thread_push_appdomain_ref (domain);
2139 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2141 mono_thread_pop_appdomain_ref ();
2145 ves_icall_System_AppDomain_InternalGetContext ()
2147 return mono_context_get ();
2151 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2153 return mono_domain_get ()->default_context;
2157 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2159 MonoAppContext *old_context = mono_context_get ();
2161 mono_context_set (mc);
2167 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2169 MonoDomain* mono_root_domain = mono_get_root_domain ();
2170 mono_domain_lock (mono_root_domain);
2171 if (process_guid_set) {
2172 mono_domain_unlock (mono_root_domain);
2173 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2175 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2176 process_guid_set = TRUE;
2177 mono_domain_unlock (mono_root_domain);
2182 mono_domain_is_unloading (MonoDomain *domain)
2184 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2191 clear_cached_vtable (MonoVTable *vtable)
2193 MonoClass *klass = vtable->klass;
2194 MonoDomain *domain = vtable->domain;
2195 MonoClassRuntimeInfo *runtime_info;
2198 runtime_info = klass->runtime_info;
2199 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2200 runtime_info->domain_vtables [domain->domain_id] = NULL;
2201 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2202 mono_gc_free_fixed (data);
2205 static G_GNUC_UNUSED void
2206 zero_static_data (MonoVTable *vtable)
2208 MonoClass *klass = vtable->klass;
2211 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2212 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2215 typedef struct unload_data {
2218 char *failure_reason;
2223 unload_data_unref (unload_data *data)
2227 mono_atomic_load_acquire (count, gint32, &data->refcount);
2228 g_assert (count >= 1 && count <= 2);
2233 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2237 deregister_reflection_info_roots_from_list (MonoImage *image)
2239 GSList *list = image->reflection_info_unregister_classes;
2242 MonoClass *klass = (MonoClass *)list->data;
2244 mono_class_free_ref_info (klass);
2249 image->reflection_info_unregister_classes = NULL;
2253 deregister_reflection_info_roots (MonoDomain *domain)
2257 mono_domain_assemblies_lock (domain);
2258 for (list = domain->domain_assemblies; list; list = list->next) {
2259 MonoAssembly *assembly = (MonoAssembly *)list->data;
2260 MonoImage *image = assembly->image;
2264 * No need to take the image lock here since dynamic images are appdomain bound and
2265 * at this point the mutator is gone. Taking the image lock here would mean
2266 * promoting it from a simple lock to a complex lock, which we better avoid if
2269 if (image_is_dynamic (image))
2270 deregister_reflection_info_roots_from_list (image);
2272 for (i = 0; i < image->module_count; ++i) {
2273 MonoImage *module = image->modules [i];
2274 if (module && image_is_dynamic (module))
2275 deregister_reflection_info_roots_from_list (module);
2278 mono_domain_assemblies_unlock (domain);
2281 static guint32 WINAPI
2282 unload_thread_main (void *arg)
2284 unload_data *data = (unload_data*)arg;
2285 MonoDomain *domain = data->domain;
2289 /* Have to attach to the runtime so shutdown can wait for this thread */
2290 /* Force it to be attached to avoid racing during shutdown. */
2291 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2294 * FIXME: Abort our parent thread last, so we can return a failure
2295 * indication if aborting times out.
2297 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2298 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2302 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2303 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2307 /* Finalize all finalizable objects in the doomed appdomain */
2308 if (!mono_domain_finalize (domain, -1)) {
2309 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2313 /* Clear references to our vtables in class->runtime_info.
2314 * We also hold the loader lock because we're going to change
2315 * class->runtime_info.
2318 mono_loader_lock (); //FIXME why do we need the loader lock here?
2319 mono_domain_lock (domain);
2322 * We need to make sure that we don't have any remsets
2323 * pointing into static data of the to-be-freed domain because
2324 * at the next collections they would be invalid. So what we
2325 * do is we first zero all static data and then do a minor
2326 * collection. Because all references in the static data will
2327 * now be null we won't do any unnecessary copies and after
2328 * the collection there won't be any more remsets.
2330 for (i = 0; i < domain->class_vtable_array->len; ++i)
2331 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2332 mono_gc_collect (0);
2334 for (i = 0; i < domain->class_vtable_array->len; ++i)
2335 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2336 deregister_reflection_info_roots (domain);
2338 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2340 mono_domain_unlock (domain);
2341 mono_loader_unlock ();
2343 mono_threads_clear_cached_culture (domain);
2345 domain->state = MONO_APPDOMAIN_UNLOADED;
2347 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2349 /* remove from the handle table the items related to this domain */
2350 mono_gchandle_free_domain (domain);
2352 mono_domain_free (domain, FALSE);
2354 mono_gc_collect (mono_gc_max_generation ());
2356 mono_atomic_store_release (&data->done, TRUE);
2357 unload_data_unref (data);
2358 mono_thread_detach (thread);
2362 mono_atomic_store_release (&data->done, TRUE);
2363 unload_data_unref (data);
2364 mono_thread_detach (thread);
2369 * mono_domain_unload:
2370 * @domain: The domain to unload
2372 * Unloads an appdomain. Follows the process outlined in the comment
2373 * for mono_domain_try_unload.
2376 mono_domain_unload (MonoDomain *domain)
2378 MonoObject *exc = NULL;
2379 mono_domain_try_unload (domain, &exc);
2381 mono_raise_exception ((MonoException*)exc);
2385 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2389 MONO_PREPARE_BLOCKING;
2390 result = WaitForSingleObjectEx (handle, timeout, alertable);
2391 MONO_FINISH_BLOCKING;
2397 * mono_domain_unload:
2398 * @domain: The domain to unload
2399 * @exc: Exception information
2401 * Unloads an appdomain. Follows the process outlined in:
2402 * http://blogs.gotdotnet.com/cbrumme
2404 * If doing things the 'right' way is too hard or complex, we do it the
2405 * 'simple' way, which means do everything needed to avoid crashes and
2406 * memory leaks, but not much else.
2408 * It is required to pass a valid reference to the exc argument, upon return
2409 * from this function *exc will be set to the exception thrown, if any.
2411 * If this method is not called from an icall (embedded scenario for instance),
2412 * it must not be called with any managed frames on the stack, since the unload
2413 * process could end up trying to abort the current thread.
2416 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2418 HANDLE thread_handle;
2419 MonoAppDomainState prev_state;
2421 unload_data *thread_data;
2422 MonoNativeThreadId tid;
2423 MonoDomain *caller_domain = mono_domain_get ();
2426 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2428 /* Atomically change our state to UNLOADING */
2429 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2430 MONO_APPDOMAIN_UNLOADING_START,
2431 MONO_APPDOMAIN_CREATED);
2432 if (prev_state != MONO_APPDOMAIN_CREATED) {
2433 switch (prev_state) {
2434 case MONO_APPDOMAIN_UNLOADING_START:
2435 case MONO_APPDOMAIN_UNLOADING:
2436 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2438 case MONO_APPDOMAIN_UNLOADED:
2439 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2442 g_warning ("Invalid appdomain state %d", prev_state);
2443 g_assert_not_reached ();
2447 mono_domain_set (domain, FALSE);
2448 /* Notify OnDomainUnload listeners */
2449 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2452 mono_runtime_invoke (method, domain->domain, NULL, exc);
2454 /* Roll back the state change */
2455 domain->state = MONO_APPDOMAIN_CREATED;
2456 mono_domain_set (caller_domain, FALSE);
2459 mono_domain_set (caller_domain, FALSE);
2461 thread_data = g_new0 (unload_data, 1);
2462 thread_data->domain = domain;
2463 thread_data->failure_reason = NULL;
2464 thread_data->done = FALSE;
2465 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2467 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2468 domain->state = MONO_APPDOMAIN_UNLOADING;
2470 * First we create a separate thread for unloading, since
2471 * we might have to abort some threads, including the current one.
2473 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2474 if (thread_handle == NULL)
2476 name = g_strdup_printf ("Unload thread for domain %x", domain);
2477 mono_thread_info_set_name (tid, name);
2478 mono_thread_info_resume (tid);
2481 /* Wait for the thread */
2482 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2483 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2484 /* The unload thread tries to abort us */
2485 /* The icall wrapper will execute the abort */
2486 CloseHandle (thread_handle);
2487 unload_data_unref (thread_data);
2491 CloseHandle (thread_handle);
2493 if (thread_data->failure_reason) {
2494 /* Roll back the state change */
2495 domain->state = MONO_APPDOMAIN_CREATED;
2497 g_warning ("%s", thread_data->failure_reason);
2499 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2501 g_free (thread_data->failure_reason);
2502 thread_data->failure_reason = NULL;
2505 unload_data_unref (thread_data);