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 142
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;
122 mono_install_runtime_load (MonoLoadFunc func)
124 load_function = func;
128 mono_runtime_load (const char *filename, const char *runtime_version)
130 g_assert (load_function);
131 return load_function (filename, runtime_version);
135 * mono_runtime_set_no_exec:
137 * Instructs the runtime to operate in static mode, i.e. avoid/do not
138 * allow managed code execution. This is useful for running the AOT
139 * compiler on platforms which allow full-aot execution only. This
140 * should be called before mono_runtime_init ().
143 mono_runtime_set_no_exec (gboolean val)
149 * mono_runtime_get_no_exec:
151 * If true, then the runtime will not allow managed code execution.
154 mono_runtime_get_no_exec (void)
160 create_domain_objects (MonoDomain *domain)
163 MonoDomain *old_domain = mono_domain_get ();
165 MonoVTable *string_vt;
166 MonoClassField *string_empty_fld;
168 if (domain != old_domain) {
169 mono_thread_push_appdomain_ref (domain);
170 mono_domain_set_internal_with_options (domain, FALSE);
174 * Initialize String.Empty. This enables the removal of
175 * the static cctor of the String class.
177 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
178 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
179 g_assert (string_empty_fld);
180 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
183 * Create an instance early since we can't do it when there is no memory.
185 arg = mono_string_new (domain, "Out of memory");
186 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
189 * These two are needed because the signal handlers might be executing on
190 * an alternate stack, and Boehm GC can't handle that.
192 arg = mono_string_new (domain, "A null value was found where an object instance was required");
193 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
194 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
195 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
197 /*The ephemeron tombstone i*/
198 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
199 mono_error_assert_ok (&error);
201 if (domain != old_domain) {
202 mono_thread_pop_appdomain_ref ();
203 mono_domain_set_internal_with_options (old_domain, FALSE);
207 * This class is used during exception handling, so initialize it here, to prevent
208 * stack overflows while handling stack overflows.
210 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
215 * @domain: domain returned by mono_init ()
217 * Initialize the core AppDomain: this function will run also some
218 * IL initialization code, so it needs the execution engine to be fully
221 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
222 * we know the entry_assembly.
226 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
227 MonoThreadAttachCB attach_cb)
230 MonoAppDomainSetup *setup;
234 mono_portability_helpers_init ();
236 mono_gc_base_init ();
237 mono_monitor_init ();
238 mono_marshal_init ();
240 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
241 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
242 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
243 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
244 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
245 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
246 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
247 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
249 mono_thread_init (start_cb, attach_cb);
251 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
252 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, &error);
253 mono_error_raise_exception (&error); /* FIXME don't raise here */
255 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
256 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, &error);
257 mono_error_raise_exception (&error); /* FIXME don't raise here */
260 domain->setup = setup;
262 mono_thread_attach (domain);
264 mono_type_initialization_init ();
266 if (!mono_runtime_get_no_exec ())
267 create_domain_objects (domain);
269 /* GC init has to happen after thread init */
272 /* contexts use GC handles, so they must be initialized after the GC */
273 mono_context_init (domain);
274 mono_context_set (domain->default_context);
276 #ifndef DISABLE_SOCKETS
277 mono_network_init ();
280 mono_console_init ();
283 mono_locks_tracer_init ();
285 /* mscorlib is loaded before we install the load hook */
286 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
292 mono_get_corlib_version (void)
295 MonoClassField *field;
298 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
299 mono_class_init (klass);
300 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
303 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
305 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
306 return *(gint32*)((gchar*)value + sizeof (MonoObject));
310 * mono_check_corlib_version
312 * Checks that the corlib that is loaded matches the version of this runtime.
314 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
315 * allocated string with the error otherwise.
318 mono_check_corlib_version (void)
320 int version = mono_get_corlib_version ();
321 if (version != MONO_CORLIB_VERSION)
322 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
329 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
331 * Initializes the @domain's default System.Runtime.Remoting's Context.
334 mono_context_init (MonoDomain *domain)
338 MonoAppContext *context;
340 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
341 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, &error);
342 mono_error_raise_exception (&error); /* FIXME don't raise here */
343 context->domain_id = domain->domain_id;
344 context->context_id = 0;
345 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
346 domain->default_context = context;
350 * mono_runtime_cleanup:
355 * This must not be called while there are still running threads executing
359 mono_runtime_cleanup (MonoDomain *domain)
361 mono_attach_cleanup ();
363 /* This ends up calling any pending pending (for at most 2 seconds) */
366 mono_thread_cleanup ();
368 #ifndef DISABLE_SOCKETS
369 mono_network_cleanup ();
371 mono_marshal_cleanup ();
373 mono_type_initialization_cleanup ();
375 mono_monitor_cleanup ();
378 static MonoDomainFunc quit_function = NULL;
381 mono_install_runtime_cleanup (MonoDomainFunc func)
383 quit_function = func;
389 if (quit_function != NULL)
390 quit_function (mono_get_root_domain (), NULL);
394 * mono_domain_create_appdomain:
395 * @friendly_name: The friendly name of the appdomain to create
396 * @configuration_file: The configuration file to initialize the appdomain with
398 * Returns a MonoDomain initialized with the appdomain
401 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
405 MonoAppDomainSetup *setup;
408 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
409 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
410 mono_error_raise_exception (&error); /* FIXME don't raise here */
411 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
413 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
414 mono_error_raise_exception (&error); /* FIXME don't raise here */
416 return mono_domain_from_appdomain (ad);
420 * mono_domain_set_config:
421 * @domain: MonoDomain initialized with the appdomain we want to change
422 * @base_dir: new base directory for the appdomain
423 * @config_file_name: path to the new configuration for the app domain
425 * Used to set the system configuration for an appdomain
427 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
428 * Error Initializing the configuration system. ---> System.ArgumentException:
429 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
432 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
434 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
435 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
438 static MonoAppDomainSetup*
439 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
441 MonoDomain *caller_domain;
442 MonoClass *ads_class;
443 MonoAppDomainSetup *copy;
445 mono_error_init (error);
447 caller_domain = mono_domain_get ();
448 ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
450 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
451 return_val_if_nok (error, NULL);
453 mono_domain_set_internal (domain);
455 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
456 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
457 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
458 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
459 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
460 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
461 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
462 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
463 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
464 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
465 copy->publisher_policy = setup->publisher_policy;
466 copy->path_changed = setup->path_changed;
467 copy->loader_optimization = setup->loader_optimization;
468 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
469 copy->disallow_code_downloads = setup->disallow_code_downloads;
470 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
471 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
472 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
473 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
474 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
476 mono_domain_set_internal (caller_domain);
481 static MonoAppDomain *
482 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
487 char *shadow_location;
489 mono_error_init (error);
491 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
493 /* FIXME: pin all those objects */
494 data = mono_domain_create();
496 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
497 return_val_if_nok (error, NULL);
500 data->friendly_name = g_strdup (friendly_name);
502 mono_profiler_appdomain_name (data, data->friendly_name);
504 if (!setup->application_base) {
505 /* Inherit from the root domain since MS.NET does this */
506 MonoDomain *root = mono_get_root_domain ();
507 if (root->setup->application_base) {
508 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
509 mono_error_assert_ok (error); /* FIXME don't swallow the error */
510 MONO_OBJECT_SETREF (setup, application_base, s);
514 mono_context_init (data);
516 data->setup = copy_app_domain_setup (data, setup, error);
517 if (!mono_error_ok (error)) {
518 g_free (data->friendly_name);
522 mono_domain_set_options_from_config (data);
523 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
525 #ifndef DISABLE_SHADOW_COPY
526 /*FIXME, guard this for when the debugger is not running */
527 shadow_location = get_shadow_assembly_location_base (data, error);
528 if (!mono_error_ok (error)) {
529 g_free (data->friendly_name);
533 g_free (shadow_location);
536 create_domain_objects (data);
542 * mono_domain_has_type_resolve:
543 * @domain: application domains being looked up
545 * Returns: TRUE if the AppDomain.TypeResolve field has been
549 mono_domain_has_type_resolve (MonoDomain *domain)
551 static MonoClassField *field = NULL;
555 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
559 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
563 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
568 * mono_domain_try_type_resolve:
569 * @domain: application domainwhere the name where the type is going to be resolved
570 * @name: the name of the type to resolve or NULL.
571 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
573 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
574 * the assembly that matches name.
576 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
578 * Returns: A MonoReflectionAssembly or NULL if not found
580 MonoReflectionAssembly *
581 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
584 MonoReflectionAssembly *ret;
587 static MonoMethod *method = NULL;
589 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
591 if (method == NULL) {
592 klass = domain->domain->mbr.obj.vtable->klass;
595 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
596 if (method == NULL) {
597 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
603 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
607 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, &error);
608 mono_error_raise_exception (&error); /* FIXME don't raise here */
614 * mono_domain_owns_vtable_slot:
616 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
619 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
623 mono_domain_lock (domain);
624 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
625 mono_domain_unlock (domain);
632 * @force: force setting.
634 * Set the current appdomain to @domain. If @force is set, set it even
635 * if it is being unloaded.
639 * FALSE if the domain is unloaded
642 mono_domain_set (MonoDomain *domain, gboolean force)
644 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
647 mono_domain_set_internal (domain);
653 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
659 MONO_CHECK_ARG_NULL (name, NULL);
665 str = mono_string_to_utf8 (name);
667 mono_domain_lock (add);
669 if (!strcmp (str, "APPBASE"))
670 o = (MonoObject *)add->setup->application_base;
671 else if (!strcmp (str, "APP_CONFIG_FILE"))
672 o = (MonoObject *)add->setup->configuration_file;
673 else if (!strcmp (str, "DYNAMIC_BASE"))
674 o = (MonoObject *)add->setup->dynamic_base;
675 else if (!strcmp (str, "APP_NAME"))
676 o = (MonoObject *)add->setup->application_name;
677 else if (!strcmp (str, "CACHE_BASE"))
678 o = (MonoObject *)add->setup->cache_path;
679 else if (!strcmp (str, "PRIVATE_BINPATH"))
680 o = (MonoObject *)add->setup->private_bin_path;
681 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
682 o = (MonoObject *)add->setup->private_bin_path_probe;
683 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
684 o = (MonoObject *)add->setup->shadow_copy_directories;
685 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
686 o = (MonoObject *)add->setup->shadow_copy_files;
688 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
690 mono_domain_unlock (add);
700 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
704 MONO_CHECK_ARG_NULL (name,);
710 mono_domain_lock (add);
712 mono_g_hash_table_insert (add->env, name, data);
714 mono_domain_unlock (add);
718 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
723 return ad->data->setup;
727 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
732 return mono_string_new (ad->data, ad->data->friendly_name);
736 ves_icall_System_AppDomain_getCurDomain ()
738 MonoDomain *add = mono_domain_get ();
744 ves_icall_System_AppDomain_getRootDomain ()
746 MonoDomain *root = mono_get_root_domain ();
752 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
754 MonoDomain *domain = mono_domain_get ();
756 return domain->throw_unobserved_task_exceptions;
760 get_attribute_value (const gchar **attribute_names,
761 const gchar **attribute_values,
762 const char *att_name)
765 for (n = 0; attribute_names [n] != NULL; n++) {
766 if (strcmp (attribute_names [n], att_name) == 0)
767 return g_strdup (attribute_values [n]);
773 start_element (GMarkupParseContext *context,
774 const gchar *element_name,
775 const gchar **attribute_names,
776 const gchar **attribute_values,
780 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
782 if (strcmp (element_name, "runtime") == 0) {
783 runtime_config->runtime_count++;
787 if (strcmp (element_name, "assemblyBinding") == 0) {
788 runtime_config->assemblybinding_count++;
792 if (runtime_config->runtime_count != 1)
795 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
796 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
798 if (value && g_ascii_strcasecmp (value, "true") == 0)
799 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
802 if (runtime_config->assemblybinding_count != 1)
805 if (strcmp (element_name, "probing") != 0)
808 g_free (runtime_config->domain->private_bin_path);
809 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
810 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
811 g_free (runtime_config->domain->private_bin_path);
812 runtime_config->domain->private_bin_path = NULL;
818 end_element (GMarkupParseContext *context,
819 const gchar *element_name,
823 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
824 if (strcmp (element_name, "runtime") == 0)
825 runtime_config->runtime_count--;
826 else if (strcmp (element_name, "assemblyBinding") == 0)
827 runtime_config->assemblybinding_count--;
831 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
833 RuntimeConfig *state = (RuntimeConfig *)user_data;
835 const gchar *filename;
837 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
838 msg = error && error->message ? error->message : "";
839 g_warning ("Error parsing %s: %s", filename, msg);
842 static const GMarkupParser
852 mono_domain_set_options_from_config (MonoDomain *domain)
855 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
857 GMarkupParseContext *context;
858 RuntimeConfig runtime_config;
861 if (!domain || !domain->setup || !domain->setup->configuration_file)
864 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
865 if (!mono_error_ok (&error)) {
866 mono_error_cleanup (&error);
870 config_file_path = mono_portability_find_file (config_file_name, TRUE);
871 if (!config_file_path)
872 config_file_path = config_file_name;
874 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
877 runtime_config.runtime_count = 0;
878 runtime_config.assemblybinding_count = 0;
879 runtime_config.domain = domain;
880 runtime_config.filename = config_file_path;
883 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
884 offset = 3; /* Skip UTF-8 BOM */
886 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
887 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
888 g_markup_parse_context_end_parse (context, NULL);
889 g_markup_parse_context_free (context);
893 if (config_file_name != config_file_path)
894 g_free (config_file_name);
895 g_free (config_file_path);
899 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
901 #ifdef DISABLE_APPDOMAINS
902 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
909 fname = mono_string_to_utf8 (friendly_name);
910 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
914 mono_error_raise_exception (&error);
921 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
924 MonoDomain *domain = ad->data;
926 static MonoClass *System_Reflection_Assembly;
930 GPtrArray *assemblies;
932 mono_error_init (&error);
934 if (!System_Reflection_Assembly)
935 System_Reflection_Assembly = mono_class_from_name (
936 mono_defaults.corlib, "System.Reflection", "Assembly");
939 * Make a copy of the list of assemblies because we can't hold the assemblies
940 * lock while creating objects etc.
942 assemblies = g_ptr_array_new ();
943 /* Need to skip internal assembly builders created by remoting */
944 mono_domain_assemblies_lock (domain);
945 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
946 ass = (MonoAssembly *)tmp->data;
947 if (refonly != ass->ref_only)
949 if (ass->corlib_internal)
951 g_ptr_array_add (assemblies, ass);
953 mono_domain_assemblies_unlock (domain);
955 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
956 for (i = 0; i < assemblies->len; ++i) {
957 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
958 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
959 if (!mono_error_ok (&error))
961 mono_array_setref (res, i, ass_obj);
965 g_ptr_array_free (assemblies, TRUE);
966 if (!mono_error_ok (&error))
967 mono_error_set_pending_exception (&error);
971 MonoReflectionAssembly *
972 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
974 MonoReflectionAssembly *ret;
977 MonoBoolean isrefonly;
980 mono_error_init (error);
982 if (mono_runtime_get_no_exec ())
985 g_assert (domain != NULL && fname != NULL);
987 klass = domain->domain->mbr.obj.vtable->klass;
990 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
991 if (method == NULL) {
992 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
996 isrefonly = refonly ? 1 : 0;
999 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1000 return_val_if_nok (error, NULL);
1003 params [2] = &isrefonly;
1005 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1006 return_val_if_nok (error, NULL);
1012 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1016 MonoReflectionAssembly *assembly;
1017 MonoDomain *domain = mono_domain_get ();
1021 aname_str = mono_stringify_assembly_name (aname);
1023 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1024 str = mono_string_new (domain, aname_str);
1030 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1031 if (!mono_error_ok (&error)) {
1033 mono_error_raise_exception (&error); /* FIXME don't raise here */
1039 return assembly->assembly;
1045 * LOCKING: assumes assemblies_lock in the domain is already locked.
1048 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1052 gboolean destroy_ht = FALSE;
1054 if (!ass->aname.name)
1058 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1062 /* FIXME: handle lazy loaded assemblies */
1063 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1064 g_hash_table_insert (ht, tmp->data, tmp->data);
1066 if (!g_hash_table_lookup (ht, ass)) {
1067 mono_assembly_addref (ass);
1068 g_hash_table_insert (ht, ass, ass);
1069 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1070 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);
1073 if (ass->image->references) {
1074 for (i = 0; ass->image->references [i] != NULL; i++) {
1075 if (ass->image->references [i] != REFERENCE_MISSING)
1076 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1077 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1082 g_hash_table_destroy (ht);
1086 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1088 static MonoClassField *assembly_load_field;
1089 static MonoMethod *assembly_load_method;
1091 MonoDomain *domain = mono_domain_get ();
1092 MonoReflectionAssembly *ref_assembly;
1094 gpointer load_value;
1097 if (!domain->domain)
1098 /* This can happen during startup */
1100 #ifdef ASSEMBLY_LOAD_DEBUG
1101 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1103 klass = domain->domain->mbr.obj.vtable->klass;
1105 mono_domain_assemblies_lock (domain);
1106 add_assemblies_to_domain (domain, assembly, NULL);
1107 mono_domain_assemblies_unlock (domain);
1109 if (assembly_load_field == NULL) {
1110 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1111 g_assert (assembly_load_field);
1114 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1115 if (load_value == NULL) {
1116 /* No events waiting to be triggered */
1120 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1121 mono_error_assert_ok (&error);
1123 if (assembly_load_method == NULL) {
1124 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1125 g_assert (assembly_load_method);
1128 *params = ref_assembly;
1130 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1131 mono_error_raise_exception (&error); /* FIXME don't raise here */
1135 * LOCKING: Acquires the domain assemblies lock.
1138 set_domain_search_path (MonoDomain *domain)
1141 MonoAppDomainSetup *setup;
1143 gchar *search_path = NULL;
1146 gchar **pvt_split = NULL;
1147 GError *gerror = NULL;
1148 gint appbaselen = -1;
1151 * We use the low-level domain assemblies lock, since this is called from
1152 * assembly loads hooks, which means this thread might hold the loader lock.
1154 mono_domain_assemblies_lock (domain);
1156 if (!domain->setup) {
1157 mono_domain_assemblies_unlock (domain);
1161 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1162 mono_domain_assemblies_unlock (domain);
1165 setup = domain->setup;
1166 if (!setup->application_base) {
1167 mono_domain_assemblies_unlock (domain);
1168 return; /* Must set application base to get private path working */
1173 if (setup->private_bin_path) {
1174 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1175 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1176 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1177 mono_error_cleanup (&error);
1178 mono_domain_assemblies_unlock (domain);
1183 if (domain->private_bin_path) {
1184 if (search_path == NULL)
1185 search_path = domain->private_bin_path;
1187 gchar *tmp2 = search_path;
1188 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1195 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1196 * directories relative to ApplicationBase separated by semicolons (see
1197 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1198 * The loop below copes with the fact that some Unix applications may use ':' (or
1199 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1200 * ';' for the subsequent split.
1202 * The issue was reported in bug #81446
1205 #ifndef TARGET_WIN32
1208 slen = strlen (search_path);
1209 for (i = 0; i < slen; i++)
1210 if (search_path [i] == ':')
1211 search_path [i] = ';';
1214 pvt_split = g_strsplit (search_path, ";", 1000);
1215 g_free (search_path);
1216 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1221 g_strfreev (pvt_split);
1223 * Don't do this because the first time is called, the domain
1224 * setup is not finished.
1226 * domain->search_path = g_malloc (sizeof (char *));
1227 * domain->search_path [0] = NULL;
1229 mono_domain_assemblies_unlock (domain);
1233 if (domain->search_path)
1234 g_strfreev (domain->search_path);
1236 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1237 tmp [npaths] = NULL;
1239 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1240 if (!mono_error_ok (&error)) {
1241 mono_error_cleanup (&error);
1242 g_strfreev (pvt_split);
1245 mono_domain_assemblies_unlock (domain);
1249 domain->search_path = tmp;
1251 /* FIXME: is this needed? */
1252 if (strncmp (*tmp, "file://", 7) == 0) {
1258 uri = g_strdup_printf ("file:///%s", uri + 7);
1261 uri = mono_escape_uri_string (tmpuri);
1262 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1268 if (gerror != NULL) {
1269 g_warning ("%s\n", gerror->message);
1270 g_error_free (gerror);
1277 for (i = 1; pvt_split && i < npaths; i++) {
1278 if (g_path_is_absolute (pvt_split [i - 1])) {
1279 tmp [i] = g_strdup (pvt_split [i - 1]);
1281 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1284 if (strchr (tmp [i], '.')) {
1288 reduced = mono_path_canonicalize (tmp [i]);
1289 if (appbaselen == -1)
1290 appbaselen = strlen (tmp [0]);
1292 if (strncmp (tmp [0], reduced, appbaselen)) {
1295 tmp [i] = g_strdup ("");
1305 if (setup->private_bin_path_probe != NULL) {
1307 tmp [0] = g_strdup ("");
1310 domain->setup->path_changed = FALSE;
1312 g_strfreev (pvt_split);
1314 mono_domain_assemblies_unlock (domain);
1317 #ifdef DISABLE_SHADOW_COPY
1319 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1325 mono_make_shadow_copy (const char *filename, MonoError *error)
1327 mono_error_init (error);
1328 return (char *) filename;
1332 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1334 guint16 *orig, *dest;
1335 gboolean copy_result;
1337 strcpy (src + srclen - tail_len, extension);
1339 if (IS_PORTABILITY_CASE) {
1340 gchar *file = mono_portability_find_file (src, TRUE);
1346 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1350 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1352 strcpy (target + targetlen - tail_len, extension);
1353 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1356 copy_result = CopyFile (orig, dest, FALSE);
1358 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1359 * overwritten when updated in their original locations. */
1361 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1370 get_cstring_hash (const char *str)
1376 if (!str || !str [0])
1381 for (i = 0; i < len; i++) {
1382 h = (h << 5) - h + *p;
1390 * Returned memory is malloc'd. Called must free it
1393 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1395 MonoAppDomainSetup *setup;
1396 char *cache_path, *appname;
1400 mono_error_init (error);
1402 setup = domain->setup;
1403 if (setup->cache_path != NULL && setup->application_name != NULL) {
1404 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1405 return_val_if_nok (error, NULL);
1407 #ifndef TARGET_WIN32
1410 for (i = strlen (cache_path) - 1; i >= 0; i--)
1411 if (cache_path [i] == '\\')
1412 cache_path [i] = '/';
1416 appname = mono_string_to_utf8_checked (setup->application_name, error);
1417 if (!mono_error_ok (error)) {
1418 g_free (cache_path);
1422 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1424 g_free (cache_path);
1426 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1427 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1434 get_shadow_assembly_location (const char *filename, MonoError *error)
1436 gint32 hash = 0, hash2 = 0;
1438 char path_hash [30];
1439 char *bname = g_path_get_basename (filename);
1440 char *dirname = g_path_get_dirname (filename);
1441 char *location, *tmploc;
1442 MonoDomain *domain = mono_domain_get ();
1444 mono_error_init (error);
1446 hash = get_cstring_hash (bname);
1447 hash2 = get_cstring_hash (dirname);
1448 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1449 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1450 tmploc = get_shadow_assembly_location_base (domain, error);
1451 if (!mono_error_ok (error)) {
1457 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1465 ensure_directory_exists (const char *filename)
1468 gchar *dir_utf8 = g_path_get_dirname (filename);
1470 gunichar2 *dir_utf16 = NULL;
1473 if (!dir_utf8 || !dir_utf8 [0])
1476 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1484 /* make life easy and only use one directory seperator */
1495 while (*p++ != '\\')
1501 p = wcschr (p, '\\');
1504 retval = _wmkdir (dir_utf16);
1505 if (retval != 0 && errno != EEXIST) {
1518 gchar *dir = g_path_get_dirname (filename);
1522 if (!dir || !dir [0]) {
1527 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1537 p = strchr (p, '/');
1540 retval = mkdir (dir, 0777);
1541 if (retval != 0 && errno != EEXIST) {
1556 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1558 struct stat sbuf_dest;
1560 gchar *real_src = mono_portability_find_file (src, TRUE);
1563 stat_src = (gchar*)src;
1565 stat_src = real_src;
1567 if (stat (stat_src, sbuf_src) == -1) {
1568 time_t tnow = time (NULL);
1573 memset (sbuf_src, 0, sizeof (*sbuf_src));
1574 sbuf_src->st_mtime = tnow;
1575 sbuf_src->st_atime = tnow;
1582 if (stat (dest, &sbuf_dest) == -1)
1585 if (sbuf_src->st_size == sbuf_dest.st_size &&
1586 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1593 shadow_copy_create_ini (const char *shadow, const char *filename)
1603 dir_name = g_path_get_dirname (shadow);
1604 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1606 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1611 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1616 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1617 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1619 if (handle == INVALID_HANDLE_VALUE) {
1623 full_path = mono_path_resolve_symlinks (filename);
1624 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1626 CloseHandle (handle);
1631 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1634 MonoAppDomainSetup *setup;
1637 gchar **directories;
1638 gchar *shadow_status_string;
1640 gboolean shadow_enabled;
1641 gboolean found = FALSE;
1646 setup = domain->setup;
1647 if (setup == NULL || setup->shadow_copy_files == NULL)
1650 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1651 if (!mono_error_ok (&error)) {
1652 mono_error_cleanup (&error);
1655 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1656 g_free (shadow_status_string);
1658 if (!shadow_enabled)
1661 if (setup->shadow_copy_directories == NULL)
1664 /* Is dir_name a shadow_copy destination already? */
1665 base_dir = get_shadow_assembly_location_base (domain, &error);
1666 if (!mono_error_ok (&error)) {
1667 mono_error_cleanup (&error);
1671 if (strstr (dir_name, base_dir)) {
1677 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1678 if (!mono_error_ok (&error)) {
1679 mono_error_cleanup (&error);
1683 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1684 dir_ptr = directories;
1686 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1692 g_strfreev (directories);
1698 This function raises exceptions so it can cause as sorts of nasty stuff if called
1699 while holding a lock.
1700 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1701 or NULL if source file not found.
1702 FIXME bubble up the error instead of raising it here
1705 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1708 gchar *sibling_source, *sibling_target;
1709 gint sibling_source_len, sibling_target_len;
1710 guint16 *orig, *dest;
1713 gboolean copy_result;
1714 struct stat src_sbuf;
1715 struct utimbuf utbuf;
1716 char *dir_name = g_path_get_dirname (filename);
1717 MonoDomain *domain = mono_domain_get ();
1720 mono_error_init (oerror);
1722 set_domain_search_path (domain);
1724 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1726 return (char *) filename;
1729 /* Is dir_name a shadow_copy destination already? */
1730 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1731 if (!mono_error_ok (&error)) {
1732 mono_error_cleanup (&error);
1734 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1738 if (strstr (dir_name, shadow_dir)) {
1739 g_free (shadow_dir);
1741 return (char *) filename;
1743 g_free (shadow_dir);
1746 shadow = get_shadow_assembly_location (filename, &error);
1747 if (!mono_error_ok (&error)) {
1748 mono_error_cleanup (&error);
1749 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1753 if (ensure_directory_exists (shadow) == FALSE) {
1755 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1759 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1760 return (char*) shadow;
1762 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1763 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1766 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1767 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1768 * and not have it runtime error" */
1769 attrs = GetFileAttributes (orig);
1770 if (attrs == INVALID_FILE_ATTRIBUTES) {
1772 return (char *)filename;
1775 copy_result = CopyFile (orig, dest, FALSE);
1777 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1778 * overwritten when updated in their original locations. */
1780 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1785 if (copy_result == FALSE) {
1788 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1789 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1790 return NULL; /* file not found, shadow copy failed */
1792 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1796 /* attempt to copy .mdb, .config if they exist */
1797 sibling_source = g_strconcat (filename, ".config", NULL);
1798 sibling_source_len = strlen (sibling_source);
1799 sibling_target = g_strconcat (shadow, ".config", NULL);
1800 sibling_target_len = strlen (sibling_target);
1802 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1803 if (copy_result == TRUE)
1804 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1806 g_free (sibling_source);
1807 g_free (sibling_target);
1809 if (copy_result == FALSE) {
1811 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1815 /* Create a .ini file containing the original assembly location */
1816 if (!shadow_copy_create_ini (shadow, filename)) {
1818 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1822 utbuf.actime = src_sbuf.st_atime;
1823 utbuf.modtime = src_sbuf.st_mtime;
1824 utime (shadow, &utbuf);
1828 #endif /* DISABLE_SHADOW_COPY */
1831 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1833 if (appdomain == NULL)
1836 return appdomain->data;
1840 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1841 const gchar *path3, const gchar *path4,
1842 gboolean refonly, gboolean is_private)
1845 gboolean found = FALSE;
1848 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1850 if (IS_PORTABILITY_SET) {
1851 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1854 fullpath = new_fullpath;
1858 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1861 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1864 return (*assembly != NULL);
1867 static MonoAssembly *
1868 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1870 MonoAssembly *result = NULL;
1873 const gchar *local_culture;
1875 gboolean is_private = FALSE;
1877 if (!culture || *culture == '\0') {
1880 local_culture = culture;
1883 filename = g_strconcat (name, ".dll", NULL);
1884 len = strlen (filename);
1886 for (path = search_path; *path; path++) {
1887 if (**path == '\0') {
1889 continue; /* Ignore empty ApplicationBase */
1892 /* See test cases in bug #58992 and bug #57710 */
1893 /* 1st try: [culture]/[name].dll (culture may be empty) */
1894 strcpy (filename + len - 4, ".dll");
1895 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1898 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1899 strcpy (filename + len - 4, ".exe");
1900 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1903 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1904 strcpy (filename + len - 4, ".dll");
1905 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1908 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1909 strcpy (filename + len - 4, ".exe");
1910 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1919 * Try loading the assembly from ApplicationBase and PrivateBinPath
1920 * and then from assemblies_path if any.
1921 * LOCKING: This is called from the assembly loading code, which means the caller
1922 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1924 static MonoAssembly *
1925 mono_domain_assembly_preload (MonoAssemblyName *aname,
1926 gchar **assemblies_path,
1929 MonoDomain *domain = mono_domain_get ();
1930 MonoAssembly *result = NULL;
1931 gboolean refonly = GPOINTER_TO_UINT (user_data);
1933 set_domain_search_path (domain);
1935 if (domain->search_path && domain->search_path [0] != NULL) {
1936 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1939 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1940 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1947 * Check whenever a given assembly was already loaded in the current appdomain.
1949 static MonoAssembly *
1950 mono_domain_assembly_search (MonoAssemblyName *aname,
1953 MonoDomain *domain = mono_domain_get ();
1956 gboolean refonly = GPOINTER_TO_UINT (user_data);
1958 mono_domain_assemblies_lock (domain);
1959 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1960 ass = (MonoAssembly *)tmp->data;
1961 /* Dynamic assemblies can't match here in MS.NET */
1962 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1965 mono_domain_assemblies_unlock (domain);
1968 mono_domain_assemblies_unlock (domain);
1973 MonoReflectionAssembly *
1974 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1977 MonoReflectionAssembly *result;
1978 MonoDomain *domain = mono_domain_get ();
1979 char *name, *filename;
1980 MonoImageOpenStatus status = MONO_IMAGE_OK;
1983 if (fname == NULL) {
1984 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1985 mono_set_pending_exception (exc);
1989 name = filename = mono_string_to_utf8 (fname);
1991 ass = mono_assembly_open_full (filename, &status, refOnly);
1996 if (status == MONO_IMAGE_IMAGE_INVALID)
1997 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1999 exc = mono_get_exception_file_not_found2 (NULL, fname);
2001 mono_set_pending_exception (exc);
2007 result = mono_assembly_get_object_checked (domain, ass, &error);
2009 mono_error_set_pending_exception (&error);
2013 MonoReflectionAssembly *
2014 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2015 MonoArray *raw_assembly,
2016 MonoArray *raw_symbol_store, MonoObject *evidence,
2017 MonoBoolean refonly)
2021 MonoReflectionAssembly *refass = NULL;
2022 MonoDomain *domain = ad->data;
2023 MonoImageOpenStatus status;
2024 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2025 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2028 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2032 if (raw_symbol_store != NULL)
2033 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2035 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2039 mono_image_close (image);
2040 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2044 refass = mono_assembly_get_object_checked (domain, ass, &error);
2046 mono_error_set_pending_exception (&error);
2048 MONO_OBJECT_SETREF (refass, evidence, evidence);
2052 MonoReflectionAssembly *
2053 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2056 MonoDomain *domain = ad->data;
2057 MonoImageOpenStatus status = MONO_IMAGE_OK;
2059 MonoAssemblyName aname;
2060 MonoReflectionAssembly *refass = NULL;
2066 name = mono_string_to_utf8 (assRef);
2067 parsed = mono_assembly_name_parse (name, &aname);
2071 /* This is a parse error... */
2073 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2074 if (!mono_error_ok (&error)) {
2075 mono_error_set_pending_exception (&error);
2082 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2083 mono_assembly_name_free (&aname);
2086 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2088 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2089 if (!mono_error_ok (&error)) {
2090 mono_error_set_pending_exception (&error);
2102 refass = mono_assembly_get_object_checked (domain, ass, &error);
2105 mono_error_set_pending_exception (&error);
2107 MONO_OBJECT_SETREF (refass, evidence, evidence);
2112 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2114 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2116 if (NULL == domain) {
2117 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2118 mono_set_pending_exception (exc);
2122 if (domain == mono_get_root_domain ()) {
2123 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2128 * Unloading seems to cause problems when running NUnit/NAnt, hence
2131 if (g_getenv ("MONO_NO_UNLOAD"))
2133 #ifdef __native_client__
2137 mono_domain_unload (domain);
2141 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2143 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2148 return mono_domain_is_unloading (domain);
2152 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2154 mono_unhandled_exception ((MonoObject*) exc);
2158 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2159 MonoReflectionAssembly *refass, MonoArray *args)
2166 image = refass->assembly->image;
2169 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2172 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2175 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2177 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2181 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2183 return ad->data->domain_id;
2187 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2189 MonoDomain *old_domain = mono_domain_get();
2191 if (!mono_domain_set (ad->data, FALSE)) {
2192 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2196 return old_domain->domain;
2200 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2202 MonoDomain *current_domain = mono_domain_get ();
2203 MonoDomain *domain = mono_domain_get_by_id (domainid);
2205 if (!domain || !mono_domain_set (domain, FALSE)) {
2206 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2210 return current_domain->domain;
2214 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2216 mono_thread_push_appdomain_ref (ad->data);
2220 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2222 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2226 * Raise an exception to prevent the managed code from executing a pop
2229 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2233 mono_thread_push_appdomain_ref (domain);
2237 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2239 mono_thread_pop_appdomain_ref ();
2243 ves_icall_System_AppDomain_InternalGetContext ()
2245 return mono_context_get ();
2249 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2251 return mono_domain_get ()->default_context;
2255 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2257 MonoAppContext *old_context = mono_context_get ();
2259 mono_context_set (mc);
2265 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2267 MonoDomain* mono_root_domain = mono_get_root_domain ();
2268 mono_domain_lock (mono_root_domain);
2269 if (process_guid_set) {
2270 mono_domain_unlock (mono_root_domain);
2272 MonoString *res = NULL;
2273 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2274 mono_error_raise_exception (&error);
2277 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2278 process_guid_set = TRUE;
2279 mono_domain_unlock (mono_root_domain);
2284 mono_domain_is_unloading (MonoDomain *domain)
2286 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2293 clear_cached_vtable (MonoVTable *vtable)
2295 MonoClass *klass = vtable->klass;
2296 MonoDomain *domain = vtable->domain;
2297 MonoClassRuntimeInfo *runtime_info;
2300 runtime_info = klass->runtime_info;
2301 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2302 runtime_info->domain_vtables [domain->domain_id] = NULL;
2303 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2304 mono_gc_free_fixed (data);
2307 static G_GNUC_UNUSED void
2308 zero_static_data (MonoVTable *vtable)
2310 MonoClass *klass = vtable->klass;
2313 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2314 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2317 typedef struct unload_data {
2320 char *failure_reason;
2325 unload_data_unref (unload_data *data)
2329 mono_atomic_load_acquire (count, gint32, &data->refcount);
2330 g_assert (count >= 1 && count <= 2);
2335 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2339 deregister_reflection_info_roots_from_list (MonoImage *image)
2341 GSList *list = image->reflection_info_unregister_classes;
2344 MonoClass *klass = (MonoClass *)list->data;
2346 mono_class_free_ref_info (klass);
2351 image->reflection_info_unregister_classes = NULL;
2355 deregister_reflection_info_roots (MonoDomain *domain)
2359 mono_domain_assemblies_lock (domain);
2360 for (list = domain->domain_assemblies; list; list = list->next) {
2361 MonoAssembly *assembly = (MonoAssembly *)list->data;
2362 MonoImage *image = assembly->image;
2366 * No need to take the image lock here since dynamic images are appdomain bound and
2367 * at this point the mutator is gone. Taking the image lock here would mean
2368 * promoting it from a simple lock to a complex lock, which we better avoid if
2371 if (image_is_dynamic (image))
2372 deregister_reflection_info_roots_from_list (image);
2374 for (i = 0; i < image->module_count; ++i) {
2375 MonoImage *module = image->modules [i];
2376 if (module && image_is_dynamic (module))
2377 deregister_reflection_info_roots_from_list (module);
2380 mono_domain_assemblies_unlock (domain);
2383 static guint32 WINAPI
2384 unload_thread_main (void *arg)
2387 unload_data *data = (unload_data*)arg;
2388 MonoDomain *domain = data->domain;
2392 /* Have to attach to the runtime so shutdown can wait for this thread */
2393 /* Force it to be attached to avoid racing during shutdown. */
2394 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2395 mono_error_raise_exception (&error); /* FIXME don't raise here */
2398 * FIXME: Abort our parent thread last, so we can return a failure
2399 * indication if aborting times out.
2401 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2402 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2406 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2407 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2411 /* Finalize all finalizable objects in the doomed appdomain */
2412 if (!mono_domain_finalize (domain, -1)) {
2413 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2417 /* Clear references to our vtables in class->runtime_info.
2418 * We also hold the loader lock because we're going to change
2419 * class->runtime_info.
2422 mono_loader_lock (); //FIXME why do we need the loader lock here?
2423 mono_domain_lock (domain);
2426 * We need to make sure that we don't have any remsets
2427 * pointing into static data of the to-be-freed domain because
2428 * at the next collections they would be invalid. So what we
2429 * do is we first zero all static data and then do a minor
2430 * collection. Because all references in the static data will
2431 * now be null we won't do any unnecessary copies and after
2432 * the collection there won't be any more remsets.
2434 for (i = 0; i < domain->class_vtable_array->len; ++i)
2435 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2436 mono_gc_collect (0);
2438 for (i = 0; i < domain->class_vtable_array->len; ++i)
2439 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2440 deregister_reflection_info_roots (domain);
2442 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2444 mono_domain_unlock (domain);
2445 mono_loader_unlock ();
2447 mono_threads_clear_cached_culture (domain);
2449 domain->state = MONO_APPDOMAIN_UNLOADED;
2451 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2453 /* remove from the handle table the items related to this domain */
2454 mono_gchandle_free_domain (domain);
2456 mono_domain_free (domain, FALSE);
2458 mono_gc_collect (mono_gc_max_generation ());
2460 mono_atomic_store_release (&data->done, TRUE);
2461 unload_data_unref (data);
2462 mono_thread_detach (thread);
2466 mono_atomic_store_release (&data->done, TRUE);
2467 unload_data_unref (data);
2468 mono_thread_detach (thread);
2473 * mono_domain_unload:
2474 * @domain: The domain to unload
2476 * Unloads an appdomain. Follows the process outlined in the comment
2477 * for mono_domain_try_unload.
2480 mono_domain_unload (MonoDomain *domain)
2482 MonoObject *exc = NULL;
2483 mono_domain_try_unload (domain, &exc);
2485 mono_raise_exception ((MonoException*)exc);
2489 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2493 MONO_PREPARE_BLOCKING;
2494 result = WaitForSingleObjectEx (handle, timeout, alertable);
2495 MONO_FINISH_BLOCKING;
2501 * mono_domain_unload:
2502 * @domain: The domain to unload
2503 * @exc: Exception information
2505 * Unloads an appdomain. Follows the process outlined in:
2506 * http://blogs.gotdotnet.com/cbrumme
2508 * If doing things the 'right' way is too hard or complex, we do it the
2509 * 'simple' way, which means do everything needed to avoid crashes and
2510 * memory leaks, but not much else.
2512 * It is required to pass a valid reference to the exc argument, upon return
2513 * from this function *exc will be set to the exception thrown, if any.
2515 * If this method is not called from an icall (embedded scenario for instance),
2516 * it must not be called with any managed frames on the stack, since the unload
2517 * process could end up trying to abort the current thread.
2520 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2523 HANDLE thread_handle;
2524 MonoAppDomainState prev_state;
2526 unload_data *thread_data;
2527 MonoNativeThreadId tid;
2528 MonoDomain *caller_domain = mono_domain_get ();
2531 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2533 /* Atomically change our state to UNLOADING */
2534 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2535 MONO_APPDOMAIN_UNLOADING_START,
2536 MONO_APPDOMAIN_CREATED);
2537 if (prev_state != MONO_APPDOMAIN_CREATED) {
2538 switch (prev_state) {
2539 case MONO_APPDOMAIN_UNLOADING_START:
2540 case MONO_APPDOMAIN_UNLOADING:
2541 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2543 case MONO_APPDOMAIN_UNLOADED:
2544 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2547 g_warning ("Invalid appdomain state %d", prev_state);
2548 g_assert_not_reached ();
2552 mono_domain_set (domain, FALSE);
2553 /* Notify OnDomainUnload listeners */
2554 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2557 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2559 if (!mono_error_ok (&error)) {
2561 mono_error_cleanup (&error);
2563 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2567 /* Roll back the state change */
2568 domain->state = MONO_APPDOMAIN_CREATED;
2569 mono_domain_set (caller_domain, FALSE);
2572 mono_domain_set (caller_domain, FALSE);
2574 thread_data = g_new0 (unload_data, 1);
2575 thread_data->domain = domain;
2576 thread_data->failure_reason = NULL;
2577 thread_data->done = FALSE;
2578 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2580 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2581 domain->state = MONO_APPDOMAIN_UNLOADING;
2583 * First we create a separate thread for unloading, since
2584 * we might have to abort some threads, including the current one.
2586 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2587 if (thread_handle == NULL)
2589 name = g_strdup_printf ("Unload thread for domain %x", domain);
2590 mono_thread_info_set_name (tid, name);
2591 mono_thread_info_resume (tid);
2594 /* Wait for the thread */
2595 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2596 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2597 /* The unload thread tries to abort us */
2598 /* The icall wrapper will execute the abort */
2599 CloseHandle (thread_handle);
2600 unload_data_unref (thread_data);
2604 CloseHandle (thread_handle);
2606 if (thread_data->failure_reason) {
2607 /* Roll back the state change */
2608 domain->state = MONO_APPDOMAIN_CREATED;
2610 g_warning ("%s", thread_data->failure_reason);
2612 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2614 g_free (thread_data->failure_reason);
2615 thread_data->failure_reason = NULL;
2618 unload_data_unref (thread_data);