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/metadata/reflection-internals.h>
59 #include <mono/utils/mono-uri.h>
60 #include <mono/utils/mono-logger-internals.h>
61 #include <mono/utils/mono-path.h>
62 #include <mono/utils/mono-stdlib.h>
63 #include <mono/utils/mono-io-portability.h>
64 #include <mono/utils/mono-error-internals.h>
65 #include <mono/utils/atomic.h>
66 #include <mono/utils/mono-memory-model.h>
67 #include <mono/utils/mono-threads.h>
73 * This is the version number of the corlib-runtime interface. When
74 * making changes to this interface (by changing the layout
75 * of classes the runtime knows about, changing icall signature or
76 * semantics etc), increment this variable. Also increment the
77 * pair of this variable in mscorlib in:
78 * mcs/class/corlib/System/Environment.cs
80 * Changes which are already detected at runtime, like the addition
81 * of icalls, do not require an increment.
83 #define MONO_CORLIB_VERSION 143
88 int assemblybinding_count;
93 static gunichar2 process_guid [36];
94 static gboolean process_guid_set = FALSE;
96 static gboolean no_exec = FALSE;
99 mono_domain_assembly_preload (MonoAssemblyName *aname,
100 gchar **assemblies_path,
103 static MonoAssembly *
104 mono_domain_assembly_search (MonoAssemblyName *aname,
108 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
111 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
113 static MonoAppDomain *
114 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
117 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
119 static MonoLoadFunc load_function = NULL;
121 /* Lazy class loading functions */
122 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
125 mono_install_runtime_load (MonoLoadFunc func)
127 load_function = func;
131 mono_runtime_load (const char *filename, const char *runtime_version)
133 g_assert (load_function);
134 return load_function (filename, runtime_version);
138 * mono_runtime_set_no_exec:
140 * Instructs the runtime to operate in static mode, i.e. avoid/do not
141 * allow managed code execution. This is useful for running the AOT
142 * compiler on platforms which allow full-aot execution only. This
143 * should be called before mono_runtime_init ().
146 mono_runtime_set_no_exec (gboolean val)
152 * mono_runtime_get_no_exec:
154 * If true, then the runtime will not allow managed code execution.
157 mono_runtime_get_no_exec (void)
163 create_domain_objects (MonoDomain *domain)
166 MonoDomain *old_domain = mono_domain_get ();
168 MonoVTable *string_vt;
169 MonoClassField *string_empty_fld;
171 if (domain != old_domain) {
172 mono_thread_push_appdomain_ref (domain);
173 mono_domain_set_internal_with_options (domain, FALSE);
177 * Initialize String.Empty. This enables the removal of
178 * the static cctor of the String class.
180 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
181 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
182 g_assert (string_empty_fld);
183 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
184 mono_error_assert_ok (&error);
185 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
188 * Create an instance early since we can't do it when there is no memory.
190 arg = mono_string_new (domain, "Out of memory");
191 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
194 * These two are needed because the signal handlers might be executing on
195 * an alternate stack, and Boehm GC can't handle that.
197 arg = mono_string_new (domain, "A null value was found where an object instance was required");
198 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
199 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
200 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
202 /*The ephemeron tombstone i*/
203 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
204 mono_error_assert_ok (&error);
206 if (domain != old_domain) {
207 mono_thread_pop_appdomain_ref ();
208 mono_domain_set_internal_with_options (old_domain, FALSE);
212 * This class is used during exception handling, so initialize it here, to prevent
213 * stack overflows while handling stack overflows.
215 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
220 * @domain: domain returned by mono_init ()
222 * Initialize the core AppDomain: this function will run also some
223 * IL initialization code, so it needs the execution engine to be fully
226 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
227 * we know the entry_assembly.
231 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
234 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
235 mono_error_cleanup (&error);
239 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
241 MonoAppDomainSetup *setup;
245 mono_error_init (error);
247 mono_portability_helpers_init ();
249 mono_gc_base_init ();
250 mono_monitor_init ();
251 mono_marshal_init ();
253 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
254 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
255 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
256 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
257 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
258 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
259 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
261 mono_thread_init (start_cb, attach_cb);
263 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
264 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
265 return_if_nok (error);
267 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
269 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
270 return_if_nok (error);
274 domain->setup = setup;
276 mono_thread_attach (domain);
278 mono_type_initialization_init ();
280 if (!mono_runtime_get_no_exec ())
281 create_domain_objects (domain);
283 /* GC init has to happen after thread init */
286 /* contexts use GC handles, so they must be initialized after the GC */
287 mono_context_init_checked (domain, error);
288 return_if_nok (error);
289 mono_context_set (domain->default_context);
291 #ifndef DISABLE_SOCKETS
292 mono_network_init ();
295 mono_console_init ();
298 mono_locks_tracer_init ();
300 /* mscorlib is loaded before we install the load hook */
301 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
307 mono_get_corlib_version (void)
311 MonoClassField *field;
314 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
315 mono_class_init (klass);
316 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
319 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
321 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
322 mono_error_raise_exception (&error); /* FIXME don't raise here */
323 return *(gint32*)((gchar*)value + sizeof (MonoObject));
327 * mono_check_corlib_version
329 * Checks that the corlib that is loaded matches the version of this runtime.
331 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
332 * allocated string with the error otherwise.
335 mono_check_corlib_version (void)
337 int version = mono_get_corlib_version ();
338 if (version != MONO_CORLIB_VERSION)
339 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
346 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
348 * Initializes the @domain's default System.Runtime.Remoting's Context.
351 mono_context_init (MonoDomain *domain)
354 mono_context_init_checked (domain, &error);
355 mono_error_cleanup (&error);
359 mono_context_init_checked (MonoDomain *domain, MonoError *error)
362 MonoAppContext *context;
364 mono_error_init (error);
366 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
367 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
368 return_if_nok (error);
370 context->domain_id = domain->domain_id;
371 context->context_id = 0;
372 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
373 domain->default_context = context;
377 * mono_runtime_cleanup:
382 * This must not be called while there are still running threads executing
386 mono_runtime_cleanup (MonoDomain *domain)
388 mono_attach_cleanup ();
390 /* This ends up calling any pending pending (for at most 2 seconds) */
393 mono_thread_cleanup ();
395 #ifndef DISABLE_SOCKETS
396 mono_network_cleanup ();
398 mono_marshal_cleanup ();
400 mono_type_initialization_cleanup ();
402 mono_monitor_cleanup ();
405 static MonoDomainFunc quit_function = NULL;
408 mono_install_runtime_cleanup (MonoDomainFunc func)
410 quit_function = func;
416 if (quit_function != NULL)
417 quit_function (mono_get_root_domain (), NULL);
421 * mono_domain_create_appdomain:
422 * @friendly_name: The friendly name of the appdomain to create
423 * @configuration_file: The configuration file to initialize the appdomain with
425 * Returns a MonoDomain initialized with the appdomain
428 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
432 MonoAppDomainSetup *setup;
435 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
436 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
437 mono_error_raise_exception (&error); /* FIXME don't raise here */
438 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
440 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
441 mono_error_raise_exception (&error); /* FIXME don't raise here */
443 return mono_domain_from_appdomain (ad);
447 * mono_domain_set_config:
448 * @domain: MonoDomain initialized with the appdomain we want to change
449 * @base_dir: new base directory for the appdomain
450 * @config_file_name: path to the new configuration for the app domain
452 * Used to set the system configuration for an appdomain
454 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
455 * Error Initializing the configuration system. ---> System.ArgumentException:
456 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
459 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
461 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
462 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
465 static MonoAppDomainSetup*
466 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
468 MonoDomain *caller_domain;
469 MonoClass *ads_class;
470 MonoAppDomainSetup *copy;
472 mono_error_init (error);
474 caller_domain = mono_domain_get ();
475 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
477 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
478 return_val_if_nok (error, NULL);
480 mono_domain_set_internal (domain);
482 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
483 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
484 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
485 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
486 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
487 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
488 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
489 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
490 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
491 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
492 copy->publisher_policy = setup->publisher_policy;
493 copy->path_changed = setup->path_changed;
494 copy->loader_optimization = setup->loader_optimization;
495 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
496 copy->disallow_code_downloads = setup->disallow_code_downloads;
497 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
498 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
499 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
500 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
501 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
503 mono_domain_set_internal (caller_domain);
508 static MonoAppDomain *
509 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
514 char *shadow_location;
516 mono_error_init (error);
518 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
520 /* FIXME: pin all those objects */
521 data = mono_domain_create();
523 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
524 return_val_if_nok (error, NULL);
527 data->friendly_name = g_strdup (friendly_name);
529 mono_profiler_appdomain_name (data, data->friendly_name);
531 if (!setup->application_base) {
532 /* Inherit from the root domain since MS.NET does this */
533 MonoDomain *root = mono_get_root_domain ();
534 if (root->setup->application_base) {
535 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
536 mono_error_assert_ok (error); /* FIXME don't swallow the error */
537 MONO_OBJECT_SETREF (setup, application_base, s);
541 mono_context_init_checked (data, error);
542 return_val_if_nok (error, NULL);
544 data->setup = copy_app_domain_setup (data, setup, error);
545 if (!mono_error_ok (error)) {
546 g_free (data->friendly_name);
550 mono_domain_set_options_from_config (data);
551 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
553 #ifndef DISABLE_SHADOW_COPY
554 /*FIXME, guard this for when the debugger is not running */
555 shadow_location = get_shadow_assembly_location_base (data, error);
556 if (!mono_error_ok (error)) {
557 g_free (data->friendly_name);
561 g_free (shadow_location);
564 create_domain_objects (data);
570 * mono_domain_has_type_resolve:
571 * @domain: application domains being looked up
573 * Returns: TRUE if the AppDomain.TypeResolve field has been
577 mono_domain_has_type_resolve (MonoDomain *domain)
579 static MonoClassField *field = NULL;
583 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
587 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
591 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
596 * mono_domain_try_type_resolve:
597 * @domain: application domainwhere the name where the type is going to be resolved
598 * @name: the name of the type to resolve or NULL.
599 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
601 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
602 * the assembly that matches name.
604 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
606 * Returns: A MonoReflectionAssembly or NULL if not found
608 MonoReflectionAssembly *
609 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
612 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
613 mono_error_cleanup (&error);
618 MonoReflectionAssembly *
619 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
621 static MonoMethod *method = NULL;
622 MonoReflectionAssembly *ret;
626 mono_error_init (error);
628 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
630 if (method == NULL) {
631 klass = domain->domain->mbr.obj.vtable->klass;
634 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
635 if (method == NULL) {
636 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
642 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
646 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
647 return_val_if_nok (error, NULL);
653 * mono_domain_owns_vtable_slot:
655 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
658 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
662 mono_domain_lock (domain);
663 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
664 mono_domain_unlock (domain);
671 * @force: force setting.
673 * Set the current appdomain to @domain. If @force is set, set it even
674 * if it is being unloaded.
678 * FALSE if the domain is unloaded
681 mono_domain_set (MonoDomain *domain, gboolean force)
683 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
686 mono_domain_set_internal (domain);
692 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
698 MONO_CHECK_ARG_NULL (name, NULL);
704 str = mono_string_to_utf8 (name);
706 mono_domain_lock (add);
708 if (!strcmp (str, "APPBASE"))
709 o = (MonoObject *)add->setup->application_base;
710 else if (!strcmp (str, "APP_CONFIG_FILE"))
711 o = (MonoObject *)add->setup->configuration_file;
712 else if (!strcmp (str, "DYNAMIC_BASE"))
713 o = (MonoObject *)add->setup->dynamic_base;
714 else if (!strcmp (str, "APP_NAME"))
715 o = (MonoObject *)add->setup->application_name;
716 else if (!strcmp (str, "CACHE_BASE"))
717 o = (MonoObject *)add->setup->cache_path;
718 else if (!strcmp (str, "PRIVATE_BINPATH"))
719 o = (MonoObject *)add->setup->private_bin_path;
720 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
721 o = (MonoObject *)add->setup->private_bin_path_probe;
722 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
723 o = (MonoObject *)add->setup->shadow_copy_directories;
724 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
725 o = (MonoObject *)add->setup->shadow_copy_files;
727 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
729 mono_domain_unlock (add);
739 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
743 MONO_CHECK_ARG_NULL (name,);
749 mono_domain_lock (add);
751 mono_g_hash_table_insert (add->env, name, data);
753 mono_domain_unlock (add);
757 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
762 return ad->data->setup;
766 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
771 return mono_string_new (ad->data, ad->data->friendly_name);
775 ves_icall_System_AppDomain_getCurDomain ()
777 MonoDomain *add = mono_domain_get ();
783 ves_icall_System_AppDomain_getRootDomain ()
785 MonoDomain *root = mono_get_root_domain ();
791 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
793 MonoDomain *domain = mono_domain_get ();
795 return domain->throw_unobserved_task_exceptions;
799 get_attribute_value (const gchar **attribute_names,
800 const gchar **attribute_values,
801 const char *att_name)
804 for (n = 0; attribute_names [n] != NULL; n++) {
805 if (strcmp (attribute_names [n], att_name) == 0)
806 return g_strdup (attribute_values [n]);
812 start_element (GMarkupParseContext *context,
813 const gchar *element_name,
814 const gchar **attribute_names,
815 const gchar **attribute_values,
819 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
821 if (strcmp (element_name, "runtime") == 0) {
822 runtime_config->runtime_count++;
826 if (strcmp (element_name, "assemblyBinding") == 0) {
827 runtime_config->assemblybinding_count++;
831 if (runtime_config->runtime_count != 1)
834 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
835 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
837 if (value && g_ascii_strcasecmp (value, "true") == 0)
838 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
841 if (runtime_config->assemblybinding_count != 1)
844 if (strcmp (element_name, "probing") != 0)
847 g_free (runtime_config->domain->private_bin_path);
848 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
849 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
850 g_free (runtime_config->domain->private_bin_path);
851 runtime_config->domain->private_bin_path = NULL;
857 end_element (GMarkupParseContext *context,
858 const gchar *element_name,
862 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
863 if (strcmp (element_name, "runtime") == 0)
864 runtime_config->runtime_count--;
865 else if (strcmp (element_name, "assemblyBinding") == 0)
866 runtime_config->assemblybinding_count--;
870 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
872 RuntimeConfig *state = (RuntimeConfig *)user_data;
874 const gchar *filename;
876 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
877 msg = error && error->message ? error->message : "";
878 g_warning ("Error parsing %s: %s", filename, msg);
881 static const GMarkupParser
891 mono_domain_set_options_from_config (MonoDomain *domain)
894 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
896 GMarkupParseContext *context;
897 RuntimeConfig runtime_config;
900 if (!domain || !domain->setup || !domain->setup->configuration_file)
903 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
904 if (!mono_error_ok (&error)) {
905 mono_error_cleanup (&error);
909 config_file_path = mono_portability_find_file (config_file_name, TRUE);
910 if (!config_file_path)
911 config_file_path = config_file_name;
913 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
916 runtime_config.runtime_count = 0;
917 runtime_config.assemblybinding_count = 0;
918 runtime_config.domain = domain;
919 runtime_config.filename = config_file_path;
922 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
923 offset = 3; /* Skip UTF-8 BOM */
925 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
926 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
927 g_markup_parse_context_end_parse (context, NULL);
928 g_markup_parse_context_free (context);
932 if (config_file_name != config_file_path)
933 g_free (config_file_name);
934 g_free (config_file_path);
938 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
940 #ifdef DISABLE_APPDOMAINS
941 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
948 fname = mono_string_to_utf8 (friendly_name);
949 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
953 mono_error_raise_exception (&error);
960 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
963 MonoDomain *domain = ad->data;
968 GPtrArray *assemblies;
970 mono_error_init (&error);
973 * Make a copy of the list of assemblies because we can't hold the assemblies
974 * lock while creating objects etc.
976 assemblies = g_ptr_array_new ();
977 /* Need to skip internal assembly builders created by remoting */
978 mono_domain_assemblies_lock (domain);
979 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
980 ass = (MonoAssembly *)tmp->data;
981 if (refonly != ass->ref_only)
983 if (ass->corlib_internal)
985 g_ptr_array_add (assemblies, ass);
987 mono_domain_assemblies_unlock (domain);
989 res = mono_array_new (domain, mono_class_get_assembly_class (), assemblies->len);
990 for (i = 0; i < assemblies->len; ++i) {
991 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
992 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
993 if (!mono_error_ok (&error))
995 mono_array_setref (res, i, ass_obj);
999 g_ptr_array_free (assemblies, TRUE);
1000 if (!mono_error_ok (&error))
1001 mono_error_set_pending_exception (&error);
1005 MonoReflectionAssembly *
1006 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1008 MonoReflectionAssembly *ret;
1011 MonoBoolean isrefonly;
1012 gpointer params [3];
1014 mono_error_init (error);
1016 if (mono_runtime_get_no_exec ())
1019 g_assert (domain != NULL && fname != NULL);
1021 klass = domain->domain->mbr.obj.vtable->klass;
1024 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1025 if (method == NULL) {
1026 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1030 isrefonly = refonly ? 1 : 0;
1033 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1034 return_val_if_nok (error, NULL);
1037 params [2] = &isrefonly;
1039 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1040 return_val_if_nok (error, NULL);
1046 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1050 MonoReflectionAssembly *assembly;
1051 MonoDomain *domain = mono_domain_get ();
1055 aname_str = mono_stringify_assembly_name (aname);
1057 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1058 str = mono_string_new (domain, aname_str);
1064 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1065 if (!mono_error_ok (&error)) {
1067 mono_error_raise_exception (&error); /* FIXME don't raise here */
1073 return assembly->assembly;
1079 * LOCKING: assumes assemblies_lock in the domain is already locked.
1082 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1086 gboolean destroy_ht = FALSE;
1088 if (!ass->aname.name)
1092 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1096 /* FIXME: handle lazy loaded assemblies */
1097 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1098 g_hash_table_insert (ht, tmp->data, tmp->data);
1100 if (!g_hash_table_lookup (ht, ass)) {
1101 mono_assembly_addref (ass);
1102 g_hash_table_insert (ht, ass, ass);
1103 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1104 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);
1107 if (ass->image->references) {
1108 for (i = 0; ass->image->references [i] != NULL; i++) {
1109 if (ass->image->references [i] != REFERENCE_MISSING)
1110 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1111 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1116 g_hash_table_destroy (ht);
1120 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1122 static MonoClassField *assembly_load_field;
1123 static MonoMethod *assembly_load_method;
1125 MonoDomain *domain = mono_domain_get ();
1126 MonoReflectionAssembly *ref_assembly;
1128 gpointer load_value;
1131 if (!domain->domain)
1132 /* This can happen during startup */
1134 #ifdef ASSEMBLY_LOAD_DEBUG
1135 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1137 klass = domain->domain->mbr.obj.vtable->klass;
1139 mono_domain_assemblies_lock (domain);
1140 add_assemblies_to_domain (domain, assembly, NULL);
1141 mono_domain_assemblies_unlock (domain);
1143 if (assembly_load_field == NULL) {
1144 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1145 g_assert (assembly_load_field);
1148 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1149 if (load_value == NULL) {
1150 /* No events waiting to be triggered */
1154 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1155 mono_error_assert_ok (&error);
1157 if (assembly_load_method == NULL) {
1158 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1159 g_assert (assembly_load_method);
1162 *params = ref_assembly;
1164 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1165 mono_error_raise_exception (&error); /* FIXME don't raise here */
1169 * LOCKING: Acquires the domain assemblies lock.
1172 set_domain_search_path (MonoDomain *domain)
1175 MonoAppDomainSetup *setup;
1177 gchar *search_path = NULL;
1180 gchar **pvt_split = NULL;
1181 GError *gerror = NULL;
1182 gint appbaselen = -1;
1185 * We use the low-level domain assemblies lock, since this is called from
1186 * assembly loads hooks, which means this thread might hold the loader lock.
1188 mono_domain_assemblies_lock (domain);
1190 if (!domain->setup) {
1191 mono_domain_assemblies_unlock (domain);
1195 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1196 mono_domain_assemblies_unlock (domain);
1199 setup = domain->setup;
1200 if (!setup->application_base) {
1201 mono_domain_assemblies_unlock (domain);
1202 return; /* Must set application base to get private path working */
1207 if (setup->private_bin_path) {
1208 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1209 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1210 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1211 mono_error_cleanup (&error);
1212 mono_domain_assemblies_unlock (domain);
1217 if (domain->private_bin_path) {
1218 if (search_path == NULL)
1219 search_path = domain->private_bin_path;
1221 gchar *tmp2 = search_path;
1222 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1229 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1230 * directories relative to ApplicationBase separated by semicolons (see
1231 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1232 * The loop below copes with the fact that some Unix applications may use ':' (or
1233 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1234 * ';' for the subsequent split.
1236 * The issue was reported in bug #81446
1239 #ifndef TARGET_WIN32
1242 slen = strlen (search_path);
1243 for (i = 0; i < slen; i++)
1244 if (search_path [i] == ':')
1245 search_path [i] = ';';
1248 pvt_split = g_strsplit (search_path, ";", 1000);
1249 g_free (search_path);
1250 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1255 g_strfreev (pvt_split);
1257 * Don't do this because the first time is called, the domain
1258 * setup is not finished.
1260 * domain->search_path = g_malloc (sizeof (char *));
1261 * domain->search_path [0] = NULL;
1263 mono_domain_assemblies_unlock (domain);
1267 if (domain->search_path)
1268 g_strfreev (domain->search_path);
1270 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1271 tmp [npaths] = NULL;
1273 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1274 if (!mono_error_ok (&error)) {
1275 mono_error_cleanup (&error);
1276 g_strfreev (pvt_split);
1279 mono_domain_assemblies_unlock (domain);
1283 domain->search_path = tmp;
1285 /* FIXME: is this needed? */
1286 if (strncmp (*tmp, "file://", 7) == 0) {
1292 uri = g_strdup_printf ("file:///%s", uri + 7);
1295 uri = mono_escape_uri_string (tmpuri);
1296 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1302 if (gerror != NULL) {
1303 g_warning ("%s\n", gerror->message);
1304 g_error_free (gerror);
1311 for (i = 1; pvt_split && i < npaths; i++) {
1312 if (g_path_is_absolute (pvt_split [i - 1])) {
1313 tmp [i] = g_strdup (pvt_split [i - 1]);
1315 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1318 if (strchr (tmp [i], '.')) {
1322 reduced = mono_path_canonicalize (tmp [i]);
1323 if (appbaselen == -1)
1324 appbaselen = strlen (tmp [0]);
1326 if (strncmp (tmp [0], reduced, appbaselen)) {
1329 tmp [i] = g_strdup ("");
1339 if (setup->private_bin_path_probe != NULL) {
1341 tmp [0] = g_strdup ("");
1344 domain->setup->path_changed = FALSE;
1346 g_strfreev (pvt_split);
1348 mono_domain_assemblies_unlock (domain);
1351 #ifdef DISABLE_SHADOW_COPY
1353 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1359 mono_make_shadow_copy (const char *filename, MonoError *error)
1361 mono_error_init (error);
1362 return (char *) filename;
1366 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1368 guint16 *orig, *dest;
1369 gboolean copy_result;
1371 strcpy (src + srclen - tail_len, extension);
1373 if (IS_PORTABILITY_CASE) {
1374 gchar *file = mono_portability_find_file (src, TRUE);
1380 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1384 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1386 strcpy (target + targetlen - tail_len, extension);
1387 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1390 copy_result = CopyFile (orig, dest, FALSE);
1392 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1393 * overwritten when updated in their original locations. */
1395 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1404 get_cstring_hash (const char *str)
1410 if (!str || !str [0])
1415 for (i = 0; i < len; i++) {
1416 h = (h << 5) - h + *p;
1424 * Returned memory is malloc'd. Called must free it
1427 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1429 MonoAppDomainSetup *setup;
1430 char *cache_path, *appname;
1434 mono_error_init (error);
1436 setup = domain->setup;
1437 if (setup->cache_path != NULL && setup->application_name != NULL) {
1438 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1439 return_val_if_nok (error, NULL);
1441 #ifndef TARGET_WIN32
1444 for (i = strlen (cache_path) - 1; i >= 0; i--)
1445 if (cache_path [i] == '\\')
1446 cache_path [i] = '/';
1450 appname = mono_string_to_utf8_checked (setup->application_name, error);
1451 if (!mono_error_ok (error)) {
1452 g_free (cache_path);
1456 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1458 g_free (cache_path);
1460 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1461 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1468 get_shadow_assembly_location (const char *filename, MonoError *error)
1470 gint32 hash = 0, hash2 = 0;
1472 char path_hash [30];
1473 char *bname = g_path_get_basename (filename);
1474 char *dirname = g_path_get_dirname (filename);
1475 char *location, *tmploc;
1476 MonoDomain *domain = mono_domain_get ();
1478 mono_error_init (error);
1480 hash = get_cstring_hash (bname);
1481 hash2 = get_cstring_hash (dirname);
1482 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1483 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1484 tmploc = get_shadow_assembly_location_base (domain, error);
1485 if (!mono_error_ok (error)) {
1491 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1499 ensure_directory_exists (const char *filename)
1502 gchar *dir_utf8 = g_path_get_dirname (filename);
1504 gunichar2 *dir_utf16 = NULL;
1507 if (!dir_utf8 || !dir_utf8 [0])
1510 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1518 /* make life easy and only use one directory seperator */
1529 while (*p++ != '\\')
1535 p = wcschr (p, '\\');
1538 retval = _wmkdir (dir_utf16);
1539 if (retval != 0 && errno != EEXIST) {
1552 gchar *dir = g_path_get_dirname (filename);
1556 if (!dir || !dir [0]) {
1561 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1571 p = strchr (p, '/');
1574 retval = mkdir (dir, 0777);
1575 if (retval != 0 && errno != EEXIST) {
1590 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1592 struct stat sbuf_dest;
1594 gchar *real_src = mono_portability_find_file (src, TRUE);
1597 stat_src = (gchar*)src;
1599 stat_src = real_src;
1601 if (stat (stat_src, sbuf_src) == -1) {
1602 time_t tnow = time (NULL);
1607 memset (sbuf_src, 0, sizeof (*sbuf_src));
1608 sbuf_src->st_mtime = tnow;
1609 sbuf_src->st_atime = tnow;
1616 if (stat (dest, &sbuf_dest) == -1)
1619 if (sbuf_src->st_size == sbuf_dest.st_size &&
1620 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1627 shadow_copy_create_ini (const char *shadow, const char *filename)
1637 dir_name = g_path_get_dirname (shadow);
1638 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1640 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1645 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1650 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1651 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1653 if (handle == INVALID_HANDLE_VALUE) {
1657 full_path = mono_path_resolve_symlinks (filename);
1658 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1660 CloseHandle (handle);
1665 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1668 MonoAppDomainSetup *setup;
1671 gchar **directories;
1672 gchar *shadow_status_string;
1674 gboolean shadow_enabled;
1675 gboolean found = FALSE;
1680 setup = domain->setup;
1681 if (setup == NULL || setup->shadow_copy_files == NULL)
1684 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1685 if (!mono_error_ok (&error)) {
1686 mono_error_cleanup (&error);
1689 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1690 g_free (shadow_status_string);
1692 if (!shadow_enabled)
1695 if (setup->shadow_copy_directories == NULL)
1698 /* Is dir_name a shadow_copy destination already? */
1699 base_dir = get_shadow_assembly_location_base (domain, &error);
1700 if (!mono_error_ok (&error)) {
1701 mono_error_cleanup (&error);
1705 if (strstr (dir_name, base_dir)) {
1711 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1712 if (!mono_error_ok (&error)) {
1713 mono_error_cleanup (&error);
1717 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1718 dir_ptr = directories;
1720 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1726 g_strfreev (directories);
1732 This function raises exceptions so it can cause as sorts of nasty stuff if called
1733 while holding a lock.
1734 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1735 or NULL if source file not found.
1736 FIXME bubble up the error instead of raising it here
1739 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1742 gchar *sibling_source, *sibling_target;
1743 gint sibling_source_len, sibling_target_len;
1744 guint16 *orig, *dest;
1747 gboolean copy_result;
1748 struct stat src_sbuf;
1749 struct utimbuf utbuf;
1750 char *dir_name = g_path_get_dirname (filename);
1751 MonoDomain *domain = mono_domain_get ();
1754 mono_error_init (oerror);
1756 set_domain_search_path (domain);
1758 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1760 return (char *) filename;
1763 /* Is dir_name a shadow_copy destination already? */
1764 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1765 if (!mono_error_ok (&error)) {
1766 mono_error_cleanup (&error);
1768 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1772 if (strstr (dir_name, shadow_dir)) {
1773 g_free (shadow_dir);
1775 return (char *) filename;
1777 g_free (shadow_dir);
1780 shadow = get_shadow_assembly_location (filename, &error);
1781 if (!mono_error_ok (&error)) {
1782 mono_error_cleanup (&error);
1783 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1787 if (ensure_directory_exists (shadow) == FALSE) {
1789 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1793 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1794 return (char*) shadow;
1796 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1797 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1800 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1801 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1802 * and not have it runtime error" */
1803 attrs = GetFileAttributes (orig);
1804 if (attrs == INVALID_FILE_ATTRIBUTES) {
1806 return (char *)filename;
1809 copy_result = CopyFile (orig, dest, FALSE);
1811 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1812 * overwritten when updated in their original locations. */
1814 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1819 if (copy_result == FALSE) {
1822 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1823 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1824 return NULL; /* file not found, shadow copy failed */
1826 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1830 /* attempt to copy .mdb, .config if they exist */
1831 sibling_source = g_strconcat (filename, ".config", NULL);
1832 sibling_source_len = strlen (sibling_source);
1833 sibling_target = g_strconcat (shadow, ".config", NULL);
1834 sibling_target_len = strlen (sibling_target);
1836 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1837 if (copy_result == TRUE)
1838 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1840 g_free (sibling_source);
1841 g_free (sibling_target);
1843 if (copy_result == FALSE) {
1845 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1849 /* Create a .ini file containing the original assembly location */
1850 if (!shadow_copy_create_ini (shadow, filename)) {
1852 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1856 utbuf.actime = src_sbuf.st_atime;
1857 utbuf.modtime = src_sbuf.st_mtime;
1858 utime (shadow, &utbuf);
1862 #endif /* DISABLE_SHADOW_COPY */
1865 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1867 if (appdomain == NULL)
1870 return appdomain->data;
1874 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1875 const gchar *path3, const gchar *path4,
1876 gboolean refonly, gboolean is_private)
1879 gboolean found = FALSE;
1882 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1884 if (IS_PORTABILITY_SET) {
1885 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1888 fullpath = new_fullpath;
1892 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1895 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1898 return (*assembly != NULL);
1901 static MonoAssembly *
1902 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1904 MonoAssembly *result = NULL;
1907 const gchar *local_culture;
1909 gboolean is_private = FALSE;
1911 if (!culture || *culture == '\0') {
1914 local_culture = culture;
1917 filename = g_strconcat (name, ".dll", NULL);
1918 len = strlen (filename);
1920 for (path = search_path; *path; path++) {
1921 if (**path == '\0') {
1923 continue; /* Ignore empty ApplicationBase */
1926 /* See test cases in bug #58992 and bug #57710 */
1927 /* 1st try: [culture]/[name].dll (culture may be empty) */
1928 strcpy (filename + len - 4, ".dll");
1929 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1932 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1933 strcpy (filename + len - 4, ".exe");
1934 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1937 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1938 strcpy (filename + len - 4, ".dll");
1939 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1942 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1943 strcpy (filename + len - 4, ".exe");
1944 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1953 * Try loading the assembly from ApplicationBase and PrivateBinPath
1954 * and then from assemblies_path if any.
1955 * LOCKING: This is called from the assembly loading code, which means the caller
1956 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1958 static MonoAssembly *
1959 mono_domain_assembly_preload (MonoAssemblyName *aname,
1960 gchar **assemblies_path,
1963 MonoDomain *domain = mono_domain_get ();
1964 MonoAssembly *result = NULL;
1965 gboolean refonly = GPOINTER_TO_UINT (user_data);
1967 set_domain_search_path (domain);
1969 if (domain->search_path && domain->search_path [0] != NULL) {
1970 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1973 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1974 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1981 * Check whenever a given assembly was already loaded in the current appdomain.
1983 static MonoAssembly *
1984 mono_domain_assembly_search (MonoAssemblyName *aname,
1987 MonoDomain *domain = mono_domain_get ();
1990 gboolean refonly = GPOINTER_TO_UINT (user_data);
1992 mono_domain_assemblies_lock (domain);
1993 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1994 ass = (MonoAssembly *)tmp->data;
1995 /* Dynamic assemblies can't match here in MS.NET */
1996 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1999 mono_domain_assemblies_unlock (domain);
2002 mono_domain_assemblies_unlock (domain);
2007 MonoReflectionAssembly *
2008 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2011 MonoReflectionAssembly *result;
2012 MonoDomain *domain = mono_domain_get ();
2013 char *name, *filename;
2014 MonoImageOpenStatus status = MONO_IMAGE_OK;
2017 if (fname == NULL) {
2018 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2019 mono_set_pending_exception (exc);
2023 name = filename = mono_string_to_utf8 (fname);
2025 ass = mono_assembly_open_full (filename, &status, refOnly);
2030 if (status == MONO_IMAGE_IMAGE_INVALID)
2031 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2033 exc = mono_get_exception_file_not_found2 (NULL, fname);
2035 mono_set_pending_exception (exc);
2041 result = mono_assembly_get_object_checked (domain, ass, &error);
2043 mono_error_set_pending_exception (&error);
2047 MonoReflectionAssembly *
2048 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2049 MonoArray *raw_assembly,
2050 MonoArray *raw_symbol_store, MonoObject *evidence,
2051 MonoBoolean refonly)
2055 MonoReflectionAssembly *refass = NULL;
2056 MonoDomain *domain = ad->data;
2057 MonoImageOpenStatus status;
2058 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2059 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2062 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2066 if (raw_symbol_store != NULL)
2067 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2069 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2073 mono_image_close (image);
2074 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2078 refass = mono_assembly_get_object_checked (domain, ass, &error);
2080 mono_error_set_pending_exception (&error);
2082 MONO_OBJECT_SETREF (refass, evidence, evidence);
2086 MonoReflectionAssembly *
2087 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2090 MonoDomain *domain = ad->data;
2091 MonoImageOpenStatus status = MONO_IMAGE_OK;
2093 MonoAssemblyName aname;
2094 MonoReflectionAssembly *refass = NULL;
2100 name = mono_string_to_utf8 (assRef);
2101 parsed = mono_assembly_name_parse (name, &aname);
2105 /* This is a parse error... */
2107 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2108 if (!mono_error_ok (&error)) {
2109 mono_error_set_pending_exception (&error);
2116 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2117 mono_assembly_name_free (&aname);
2120 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2122 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2123 if (!mono_error_ok (&error)) {
2124 mono_error_set_pending_exception (&error);
2136 refass = mono_assembly_get_object_checked (domain, ass, &error);
2139 mono_error_set_pending_exception (&error);
2141 MONO_OBJECT_SETREF (refass, evidence, evidence);
2146 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2148 MonoException *exc = NULL;
2149 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2151 if (NULL == domain) {
2152 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2153 mono_set_pending_exception (exc);
2157 if (domain == mono_get_root_domain ()) {
2158 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2163 * Unloading seems to cause problems when running NUnit/NAnt, hence
2166 if (g_getenv ("MONO_NO_UNLOAD"))
2168 #ifdef __native_client__
2172 mono_domain_try_unload (domain, (MonoObject**)&exc);
2174 mono_set_pending_exception (exc);
2178 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2180 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2185 return mono_domain_is_unloading (domain);
2189 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2191 mono_unhandled_exception ((MonoObject*) exc);
2195 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2196 MonoReflectionAssembly *refass, MonoArray *args)
2203 image = refass->assembly->image;
2206 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2209 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2212 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2214 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2218 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2220 return ad->data->domain_id;
2224 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2226 MonoDomain *old_domain = mono_domain_get();
2228 if (!mono_domain_set (ad->data, FALSE)) {
2229 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2233 return old_domain->domain;
2237 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2239 MonoDomain *current_domain = mono_domain_get ();
2240 MonoDomain *domain = mono_domain_get_by_id (domainid);
2242 if (!domain || !mono_domain_set (domain, FALSE)) {
2243 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2247 return current_domain->domain;
2251 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2253 mono_thread_push_appdomain_ref (ad->data);
2257 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2259 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2263 * Raise an exception to prevent the managed code from executing a pop
2266 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2270 mono_thread_push_appdomain_ref (domain);
2274 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2276 mono_thread_pop_appdomain_ref ();
2280 ves_icall_System_AppDomain_InternalGetContext ()
2282 return mono_context_get ();
2286 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2288 return mono_domain_get ()->default_context;
2292 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2294 MonoAppContext *old_context = mono_context_get ();
2296 mono_context_set (mc);
2302 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2304 MonoDomain* mono_root_domain = mono_get_root_domain ();
2305 mono_domain_lock (mono_root_domain);
2306 if (process_guid_set) {
2307 mono_domain_unlock (mono_root_domain);
2309 MonoString *res = NULL;
2310 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2311 mono_error_raise_exception (&error);
2314 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2315 process_guid_set = TRUE;
2316 mono_domain_unlock (mono_root_domain);
2321 mono_domain_is_unloading (MonoDomain *domain)
2323 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2330 clear_cached_vtable (MonoVTable *vtable)
2332 MonoClass *klass = vtable->klass;
2333 MonoDomain *domain = vtable->domain;
2334 MonoClassRuntimeInfo *runtime_info;
2337 runtime_info = klass->runtime_info;
2338 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2339 runtime_info->domain_vtables [domain->domain_id] = NULL;
2340 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2341 mono_gc_free_fixed (data);
2344 static G_GNUC_UNUSED void
2345 zero_static_data (MonoVTable *vtable)
2347 MonoClass *klass = vtable->klass;
2350 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2351 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2354 typedef struct unload_data {
2357 char *failure_reason;
2362 unload_data_unref (unload_data *data)
2366 mono_atomic_load_acquire (count, gint32, &data->refcount);
2367 g_assert (count >= 1 && count <= 2);
2372 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2376 deregister_reflection_info_roots_from_list (MonoImage *image)
2378 GSList *list = image->reflection_info_unregister_classes;
2381 MonoClass *klass = (MonoClass *)list->data;
2383 mono_class_free_ref_info (klass);
2388 image->reflection_info_unregister_classes = NULL;
2392 deregister_reflection_info_roots (MonoDomain *domain)
2396 mono_domain_assemblies_lock (domain);
2397 for (list = domain->domain_assemblies; list; list = list->next) {
2398 MonoAssembly *assembly = (MonoAssembly *)list->data;
2399 MonoImage *image = assembly->image;
2403 * No need to take the image lock here since dynamic images are appdomain bound and
2404 * at this point the mutator is gone. Taking the image lock here would mean
2405 * promoting it from a simple lock to a complex lock, which we better avoid if
2408 if (image_is_dynamic (image))
2409 deregister_reflection_info_roots_from_list (image);
2411 for (i = 0; i < image->module_count; ++i) {
2412 MonoImage *module = image->modules [i];
2413 if (module && image_is_dynamic (module))
2414 deregister_reflection_info_roots_from_list (module);
2417 mono_domain_assemblies_unlock (domain);
2420 static guint32 WINAPI
2421 unload_thread_main (void *arg)
2424 unload_data *data = (unload_data*)arg;
2425 MonoDomain *domain = data->domain;
2429 /* Have to attach to the runtime so shutdown can wait for this thread */
2430 /* Force it to be attached to avoid racing during shutdown. */
2431 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2432 mono_error_raise_exception (&error); /* FIXME don't raise here */
2435 * FIXME: Abort our parent thread last, so we can return a failure
2436 * indication if aborting times out.
2438 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2439 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2443 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2444 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2448 /* Finalize all finalizable objects in the doomed appdomain */
2449 if (!mono_domain_finalize (domain, -1)) {
2450 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2454 /* Clear references to our vtables in class->runtime_info.
2455 * We also hold the loader lock because we're going to change
2456 * class->runtime_info.
2459 mono_loader_lock (); //FIXME why do we need the loader lock here?
2460 mono_domain_lock (domain);
2463 * We need to make sure that we don't have any remsets
2464 * pointing into static data of the to-be-freed domain because
2465 * at the next collections they would be invalid. So what we
2466 * do is we first zero all static data and then do a minor
2467 * collection. Because all references in the static data will
2468 * now be null we won't do any unnecessary copies and after
2469 * the collection there won't be any more remsets.
2471 for (i = 0; i < domain->class_vtable_array->len; ++i)
2472 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2473 mono_gc_collect (0);
2475 for (i = 0; i < domain->class_vtable_array->len; ++i)
2476 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2477 deregister_reflection_info_roots (domain);
2479 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2481 mono_domain_unlock (domain);
2482 mono_loader_unlock ();
2484 mono_threads_clear_cached_culture (domain);
2486 domain->state = MONO_APPDOMAIN_UNLOADED;
2488 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2490 /* remove from the handle table the items related to this domain */
2491 mono_gchandle_free_domain (domain);
2493 mono_domain_free (domain, FALSE);
2495 mono_gc_collect (mono_gc_max_generation ());
2497 mono_atomic_store_release (&data->done, TRUE);
2498 unload_data_unref (data);
2499 mono_thread_detach (thread);
2503 mono_atomic_store_release (&data->done, TRUE);
2504 unload_data_unref (data);
2505 mono_thread_detach (thread);
2510 * mono_domain_unload:
2511 * @domain: The domain to unload
2513 * Unloads an appdomain. Follows the process outlined in the comment
2514 * for mono_domain_try_unload.
2517 mono_domain_unload (MonoDomain *domain)
2519 MonoObject *exc = NULL;
2520 mono_domain_try_unload (domain, &exc);
2524 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2528 MONO_PREPARE_BLOCKING;
2529 result = WaitForSingleObjectEx (handle, timeout, alertable);
2530 MONO_FINISH_BLOCKING;
2536 * mono_domain_unload:
2537 * @domain: The domain to unload
2538 * @exc: Exception information
2540 * Unloads an appdomain. Follows the process outlined in:
2541 * http://blogs.gotdotnet.com/cbrumme
2543 * If doing things the 'right' way is too hard or complex, we do it the
2544 * 'simple' way, which means do everything needed to avoid crashes and
2545 * memory leaks, but not much else.
2547 * It is required to pass a valid reference to the exc argument, upon return
2548 * from this function *exc will be set to the exception thrown, if any.
2550 * If this method is not called from an icall (embedded scenario for instance),
2551 * it must not be called with any managed frames on the stack, since the unload
2552 * process could end up trying to abort the current thread.
2555 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2558 HANDLE thread_handle;
2559 MonoAppDomainState prev_state;
2561 unload_data *thread_data;
2562 MonoNativeThreadId tid;
2563 MonoDomain *caller_domain = mono_domain_get ();
2566 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2568 /* Atomically change our state to UNLOADING */
2569 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2570 MONO_APPDOMAIN_UNLOADING_START,
2571 MONO_APPDOMAIN_CREATED);
2572 if (prev_state != MONO_APPDOMAIN_CREATED) {
2573 switch (prev_state) {
2574 case MONO_APPDOMAIN_UNLOADING_START:
2575 case MONO_APPDOMAIN_UNLOADING:
2576 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2578 case MONO_APPDOMAIN_UNLOADED:
2579 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2582 g_warning ("Invalid appdomain state %d", prev_state);
2583 g_assert_not_reached ();
2587 mono_domain_set (domain, FALSE);
2588 /* Notify OnDomainUnload listeners */
2589 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2592 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2594 if (!mono_error_ok (&error)) {
2596 mono_error_cleanup (&error);
2598 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2602 /* Roll back the state change */
2603 domain->state = MONO_APPDOMAIN_CREATED;
2604 mono_domain_set (caller_domain, FALSE);
2607 mono_domain_set (caller_domain, FALSE);
2609 thread_data = g_new0 (unload_data, 1);
2610 thread_data->domain = domain;
2611 thread_data->failure_reason = NULL;
2612 thread_data->done = FALSE;
2613 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2615 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2616 domain->state = MONO_APPDOMAIN_UNLOADING;
2618 * First we create a separate thread for unloading, since
2619 * we might have to abort some threads, including the current one.
2621 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2622 if (thread_handle == NULL)
2624 name = g_strdup_printf ("Unload thread for domain %x", domain);
2625 mono_thread_info_set_name (tid, name);
2626 mono_thread_info_resume (tid);
2629 /* Wait for the thread */
2630 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2631 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2632 /* The unload thread tries to abort us */
2633 /* The icall wrapper will execute the abort */
2634 CloseHandle (thread_handle);
2635 unload_data_unref (thread_data);
2639 CloseHandle (thread_handle);
2641 if (thread_data->failure_reason) {
2642 /* Roll back the state change */
2643 domain->state = MONO_APPDOMAIN_CREATED;
2645 g_warning ("%s", thread_data->failure_reason);
2647 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2649 g_free (thread_data->failure_reason);
2650 thread_data->failure_reason = NULL;
2653 unload_data_unref (thread_data);