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
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #undef ASSEMBLY_LOAD_DEBUG
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/domain-internals.h>
39 #include "mono/metadata/metadata-internals.h"
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/exception.h>
42 #include <mono/metadata/threads.h>
43 #include <mono/metadata/threadpool-ms.h>
44 #include <mono/metadata/socket-io.h>
45 #include <mono/metadata/tabledefs.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/mono-gc.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/monitor.h>
50 #include <mono/metadata/mono-debug.h>
51 #include <mono/metadata/mono-debug-debugger.h>
52 #include <mono/metadata/attach.h>
53 #include <mono/metadata/file-io.h>
54 #include <mono/metadata/lock-tracer.h>
55 #include <mono/metadata/console-io.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/tokentype.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/utils/mono-uri.h>
61 #include <mono/utils/mono-logger-internals.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-stdlib.h>
64 #include <mono/utils/mono-io-portability.h>
65 #include <mono/utils/mono-error-internals.h>
66 #include <mono/utils/atomic.h>
67 #include <mono/utils/mono-memory-model.h>
68 #include <mono/utils/mono-threads.h>
74 * This is the version number of the corlib-runtime interface. When
75 * making changes to this interface (by changing the layout
76 * of classes the runtime knows about, changing icall signature or
77 * semantics etc), increment this variable. Also increment the
78 * pair of this variable in mscorlib in:
79 * mcs/class/corlib/System/Environment.cs
81 * Changes which are already detected at runtime, like the addition
82 * of icalls, do not require an increment.
84 #define MONO_CORLIB_VERSION 149
89 int assemblybinding_count;
94 static gunichar2 process_guid [36];
95 static gboolean process_guid_set = FALSE;
97 static gboolean no_exec = FALSE;
100 mono_domain_assembly_preload (MonoAssemblyName *aname,
101 gchar **assemblies_path,
104 static MonoAssembly *
105 mono_domain_assembly_search (MonoAssemblyName *aname,
109 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
112 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
114 static MonoAppDomain *
115 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
118 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
120 static MonoLoadFunc load_function = NULL;
122 /* Lazy class loading functions */
123 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
126 mono_install_runtime_load (MonoLoadFunc func)
128 load_function = func;
132 mono_runtime_load (const char *filename, const char *runtime_version)
134 g_assert (load_function);
135 return load_function (filename, runtime_version);
139 * mono_runtime_set_no_exec:
141 * Instructs the runtime to operate in static mode, i.e. avoid/do not
142 * allow managed code execution. This is useful for running the AOT
143 * compiler on platforms which allow full-aot execution only. This
144 * should be called before mono_runtime_init ().
147 mono_runtime_set_no_exec (gboolean val)
153 * mono_runtime_get_no_exec:
155 * If true, then the runtime will not allow managed code execution.
158 mono_runtime_get_no_exec (void)
164 create_domain_objects (MonoDomain *domain)
167 MonoDomain *old_domain = mono_domain_get ();
169 MonoVTable *string_vt;
170 MonoClassField *string_empty_fld;
172 if (domain != old_domain) {
173 mono_thread_push_appdomain_ref (domain);
174 mono_domain_set_internal_with_options (domain, FALSE);
178 * Initialize String.Empty. This enables the removal of
179 * the static cctor of the String class.
181 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
182 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
183 g_assert (string_empty_fld);
184 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
185 mono_error_assert_ok (&error);
186 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
189 * Create an instance early since we can't do it when there is no memory.
191 arg = mono_string_new (domain, "Out of memory");
192 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
195 * These two are needed because the signal handlers might be executing on
196 * an alternate stack, and Boehm GC can't handle that.
198 arg = mono_string_new (domain, "A null value was found where an object instance was required");
199 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
200 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
201 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
203 /*The ephemeron tombstone i*/
204 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
205 mono_error_assert_ok (&error);
207 if (domain != old_domain) {
208 mono_thread_pop_appdomain_ref ();
209 mono_domain_set_internal_with_options (old_domain, FALSE);
213 * This class is used during exception handling, so initialize it here, to prevent
214 * stack overflows while handling stack overflows.
216 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
221 * @domain: domain returned by mono_init ()
223 * Initialize the core AppDomain: this function will run also some
224 * IL initialization code, so it needs the execution engine to be fully
227 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
228 * we know the entry_assembly.
232 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
235 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
236 mono_error_cleanup (&error);
240 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
242 MonoAppDomainSetup *setup;
246 mono_error_init (error);
248 mono_portability_helpers_init ();
250 mono_gc_base_init ();
251 mono_monitor_init ();
252 mono_marshal_init ();
254 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
255 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
256 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
257 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
258 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
259 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
260 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
262 mono_thread_init (start_cb, attach_cb);
264 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
265 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
266 return_if_nok (error);
268 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
270 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
271 return_if_nok (error);
275 domain->setup = setup;
277 mono_thread_attach (domain);
279 mono_type_initialization_init ();
281 if (!mono_runtime_get_no_exec ())
282 create_domain_objects (domain);
284 /* GC init has to happen after thread init */
287 /* contexts use GC handles, so they must be initialized after the GC */
288 mono_context_init_checked (domain, error);
289 return_if_nok (error);
290 mono_context_set (domain->default_context);
292 #ifndef DISABLE_SOCKETS
293 mono_network_init ();
296 mono_console_init ();
299 mono_locks_tracer_init ();
301 /* mscorlib is loaded before we install the load hook */
302 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
308 mono_get_corlib_version (void)
312 MonoClassField *field;
315 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
316 mono_class_init (klass);
317 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
320 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
322 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
323 mono_error_assert_ok (&error);
324 return *(gint32*)((gchar*)value + sizeof (MonoObject));
328 * mono_check_corlib_version
330 * Checks that the corlib that is loaded matches the version of this runtime.
332 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
333 * allocated string with the error otherwise.
336 mono_check_corlib_version (void)
338 int version = mono_get_corlib_version ();
339 if (version != MONO_CORLIB_VERSION)
340 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
347 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
349 * Initializes the @domain's default System.Runtime.Remoting's Context.
352 mono_context_init (MonoDomain *domain)
355 mono_context_init_checked (domain, &error);
356 mono_error_cleanup (&error);
360 mono_context_init_checked (MonoDomain *domain, MonoError *error)
363 MonoAppContext *context;
365 mono_error_init (error);
367 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
368 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
369 return_if_nok (error);
371 context->domain_id = domain->domain_id;
372 context->context_id = 0;
373 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
374 domain->default_context = context;
378 * mono_runtime_cleanup:
383 * This must not be called while there are still running threads executing
387 mono_runtime_cleanup (MonoDomain *domain)
389 mono_attach_cleanup ();
391 /* This ends up calling any pending pending (for at most 2 seconds) */
394 mono_thread_cleanup ();
396 #ifndef DISABLE_SOCKETS
397 mono_network_cleanup ();
399 mono_marshal_cleanup ();
401 mono_type_initialization_cleanup ();
403 mono_monitor_cleanup ();
406 static MonoDomainFunc quit_function = NULL;
409 mono_install_runtime_cleanup (MonoDomainFunc func)
411 quit_function = func;
417 if (quit_function != NULL)
418 quit_function (mono_get_root_domain (), NULL);
422 * mono_domain_create_appdomain:
423 * @friendly_name: The friendly name of the appdomain to create
424 * @configuration_file: The configuration file to initialize the appdomain with
426 * Returns a MonoDomain initialized with the appdomain
429 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
433 MonoAppDomainSetup *setup;
436 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
437 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
440 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
442 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
446 return mono_domain_from_appdomain (ad);
448 mono_error_cleanup (&error);
453 * mono_domain_set_config:
454 * @domain: MonoDomain initialized with the appdomain we want to change
455 * @base_dir: new base directory for the appdomain
456 * @config_file_name: path to the new configuration for the app domain
458 * Used to set the system configuration for an appdomain
460 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
461 * Error Initializing the configuration system. ---> System.ArgumentException:
462 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
465 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
467 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
468 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
471 static MonoAppDomainSetup*
472 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
474 MonoDomain *caller_domain;
475 MonoClass *ads_class;
476 MonoAppDomainSetup *copy;
478 mono_error_init (error);
480 caller_domain = mono_domain_get ();
481 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
483 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
484 return_val_if_nok (error, NULL);
486 mono_domain_set_internal (domain);
488 #define XCOPY_FIELD(dst,field,src,error) \
490 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
491 return_val_if_nok (error, NULL); \
492 MONO_OBJECT_SETREF ((dst),field,copied_val); \
495 XCOPY_FIELD (copy, application_base, setup->application_base, error);
496 XCOPY_FIELD (copy, application_name, setup->application_name, error);
497 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
498 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
499 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
500 XCOPY_FIELD (copy, license_file, setup->license_file, error);
501 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
502 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
503 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
504 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
505 copy->publisher_policy = setup->publisher_policy;
506 copy->path_changed = setup->path_changed;
507 copy->loader_optimization = setup->loader_optimization;
508 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
509 copy->disallow_code_downloads = setup->disallow_code_downloads;
510 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
511 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
512 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
513 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
514 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
518 mono_domain_set_internal (caller_domain);
523 static MonoAppDomain *
524 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
529 char *shadow_location;
531 mono_error_init (error);
533 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
535 /* FIXME: pin all those objects */
536 data = mono_domain_create();
538 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
539 return_val_if_nok (error, NULL);
542 data->friendly_name = g_strdup (friendly_name);
544 mono_profiler_appdomain_name (data, data->friendly_name);
546 if (!setup->application_base) {
547 /* Inherit from the root domain since MS.NET does this */
548 MonoDomain *root = mono_get_root_domain ();
549 if (root->setup->application_base) {
550 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
551 mono_error_assert_ok (error); /* FIXME don't swallow the error */
552 MONO_OBJECT_SETREF (setup, application_base, s);
556 mono_context_init_checked (data, error);
557 return_val_if_nok (error, NULL);
559 data->setup = copy_app_domain_setup (data, setup, error);
560 if (!mono_error_ok (error)) {
561 g_free (data->friendly_name);
565 mono_domain_set_options_from_config (data);
566 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
568 #ifndef DISABLE_SHADOW_COPY
569 /*FIXME, guard this for when the debugger is not running */
570 shadow_location = get_shadow_assembly_location_base (data, error);
571 if (!mono_error_ok (error)) {
572 g_free (data->friendly_name);
576 g_free (shadow_location);
579 create_domain_objects (data);
585 * mono_domain_has_type_resolve:
586 * @domain: application domains being looked up
588 * Returns: TRUE if the AppDomain.TypeResolve field has been
592 mono_domain_has_type_resolve (MonoDomain *domain)
594 static MonoClassField *field = NULL;
598 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
602 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
606 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
611 * mono_domain_try_type_resolve:
612 * @domain: application domainwhere the name where the type is going to be resolved
613 * @name: the name of the type to resolve or NULL.
614 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
616 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
617 * the assembly that matches name.
619 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
621 * Returns: A MonoReflectionAssembly or NULL if not found
623 MonoReflectionAssembly *
624 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
627 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
628 mono_error_cleanup (&error);
633 MonoReflectionAssembly *
634 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
636 static MonoMethod *method = NULL;
637 MonoReflectionAssembly *ret;
641 mono_error_init (error);
643 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
645 if (method == NULL) {
646 klass = domain->domain->mbr.obj.vtable->klass;
649 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
650 if (method == NULL) {
651 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
657 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
661 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
662 return_val_if_nok (error, NULL);
668 * mono_domain_owns_vtable_slot:
670 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
673 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
677 mono_domain_lock (domain);
678 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
679 mono_domain_unlock (domain);
686 * @force: force setting.
688 * Set the current appdomain to @domain. If @force is set, set it even
689 * if it is being unloaded.
693 * FALSE if the domain is unloaded
696 mono_domain_set (MonoDomain *domain, gboolean force)
698 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
701 mono_domain_set_internal (domain);
707 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
714 MONO_CHECK_ARG_NULL (name, NULL);
720 str = mono_string_to_utf8_checked (name, &error);
721 if (mono_error_set_pending_exception (&error))
724 mono_domain_lock (add);
726 if (!strcmp (str, "APPBASE"))
727 o = (MonoObject *)add->setup->application_base;
728 else if (!strcmp (str, "APP_CONFIG_FILE"))
729 o = (MonoObject *)add->setup->configuration_file;
730 else if (!strcmp (str, "DYNAMIC_BASE"))
731 o = (MonoObject *)add->setup->dynamic_base;
732 else if (!strcmp (str, "APP_NAME"))
733 o = (MonoObject *)add->setup->application_name;
734 else if (!strcmp (str, "CACHE_BASE"))
735 o = (MonoObject *)add->setup->cache_path;
736 else if (!strcmp (str, "PRIVATE_BINPATH"))
737 o = (MonoObject *)add->setup->private_bin_path;
738 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
739 o = (MonoObject *)add->setup->private_bin_path_probe;
740 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
741 o = (MonoObject *)add->setup->shadow_copy_directories;
742 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
743 o = (MonoObject *)add->setup->shadow_copy_files;
745 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
747 mono_domain_unlock (add);
757 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
761 MONO_CHECK_ARG_NULL (name,);
767 mono_domain_lock (add);
769 mono_g_hash_table_insert (add->env, name, data);
771 mono_domain_unlock (add);
775 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
780 return ad->data->setup;
784 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
789 return mono_string_new (ad->data, ad->data->friendly_name);
793 ves_icall_System_AppDomain_getCurDomain ()
795 MonoDomain *add = mono_domain_get ();
801 ves_icall_System_AppDomain_getRootDomain ()
803 MonoDomain *root = mono_get_root_domain ();
809 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
811 MonoDomain *domain = mono_domain_get ();
813 return domain->throw_unobserved_task_exceptions;
817 get_attribute_value (const gchar **attribute_names,
818 const gchar **attribute_values,
819 const char *att_name)
822 for (n = 0; attribute_names [n] != NULL; n++) {
823 if (strcmp (attribute_names [n], att_name) == 0)
824 return g_strdup (attribute_values [n]);
830 start_element (GMarkupParseContext *context,
831 const gchar *element_name,
832 const gchar **attribute_names,
833 const gchar **attribute_values,
837 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
839 if (strcmp (element_name, "runtime") == 0) {
840 runtime_config->runtime_count++;
844 if (strcmp (element_name, "assemblyBinding") == 0) {
845 runtime_config->assemblybinding_count++;
849 if (runtime_config->runtime_count != 1)
852 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
853 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
855 if (value && g_ascii_strcasecmp (value, "true") == 0)
856 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
859 if (runtime_config->assemblybinding_count != 1)
862 if (strcmp (element_name, "probing") != 0)
865 g_free (runtime_config->domain->private_bin_path);
866 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
867 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
868 g_free (runtime_config->domain->private_bin_path);
869 runtime_config->domain->private_bin_path = NULL;
875 end_element (GMarkupParseContext *context,
876 const gchar *element_name,
880 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
881 if (strcmp (element_name, "runtime") == 0)
882 runtime_config->runtime_count--;
883 else if (strcmp (element_name, "assemblyBinding") == 0)
884 runtime_config->assemblybinding_count--;
888 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
890 RuntimeConfig *state = (RuntimeConfig *)user_data;
892 const gchar *filename;
894 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
895 msg = error && error->message ? error->message : "";
896 g_warning ("Error parsing %s: %s", filename, msg);
899 static const GMarkupParser
909 mono_domain_set_options_from_config (MonoDomain *domain)
912 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
914 GMarkupParseContext *context;
915 RuntimeConfig runtime_config;
918 if (!domain || !domain->setup || !domain->setup->configuration_file)
921 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
922 if (!mono_error_ok (&error)) {
923 mono_error_cleanup (&error);
927 config_file_path = mono_portability_find_file (config_file_name, TRUE);
928 if (!config_file_path)
929 config_file_path = config_file_name;
931 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
934 runtime_config.runtime_count = 0;
935 runtime_config.assemblybinding_count = 0;
936 runtime_config.domain = domain;
937 runtime_config.filename = config_file_path;
940 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
941 offset = 3; /* Skip UTF-8 BOM */
943 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
944 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
945 g_markup_parse_context_end_parse (context, NULL);
946 g_markup_parse_context_free (context);
950 if (config_file_name != config_file_path)
951 g_free (config_file_name);
952 g_free (config_file_path);
956 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
959 MonoAppDomain *ad = NULL;
960 #ifdef DISABLE_APPDOMAINS
961 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
965 fname = mono_string_to_utf8_checked (friendly_name, &error);
966 if (mono_error_set_pending_exception (&error))
968 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
972 mono_error_set_pending_exception (&error);
977 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
980 MonoDomain *domain = ad->data;
985 GPtrArray *assemblies;
987 mono_error_init (&error);
990 * Make a copy of the list of assemblies because we can't hold the assemblies
991 * lock while creating objects etc.
993 assemblies = g_ptr_array_new ();
994 /* Need to skip internal assembly builders created by remoting */
995 mono_domain_assemblies_lock (domain);
996 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
997 ass = (MonoAssembly *)tmp->data;
998 if (refonly != ass->ref_only)
1000 if (ass->corlib_internal)
1002 g_ptr_array_add (assemblies, ass);
1004 mono_domain_assemblies_unlock (domain);
1006 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1007 if (!is_ok (&error))
1009 for (i = 0; i < assemblies->len; ++i) {
1010 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1011 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1012 if (!mono_error_ok (&error))
1014 mono_array_setref (res, i, ass_obj);
1018 g_ptr_array_free (assemblies, TRUE);
1019 if (!mono_error_ok (&error))
1020 mono_error_set_pending_exception (&error);
1024 MonoReflectionAssembly *
1025 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1027 MonoReflectionAssembly *ret;
1030 MonoBoolean isrefonly;
1031 gpointer params [3];
1033 mono_error_init (error);
1035 if (mono_runtime_get_no_exec ())
1038 g_assert (domain != NULL && fname != NULL);
1040 klass = domain->domain->mbr.obj.vtable->klass;
1043 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1044 if (method == NULL) {
1045 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1049 isrefonly = refonly ? 1 : 0;
1052 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1053 return_val_if_nok (error, NULL);
1056 params [2] = &isrefonly;
1058 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1059 return_val_if_nok (error, NULL);
1065 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1069 MonoReflectionAssembly *assembly;
1070 MonoDomain *domain = mono_domain_get ();
1074 aname_str = mono_stringify_assembly_name (aname);
1076 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1077 str = mono_string_new (domain, aname_str);
1083 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1084 mono_error_cleanup (&error);
1087 return assembly->assembly;
1093 * LOCKING: assumes assemblies_lock in the domain is already locked.
1096 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1100 gboolean destroy_ht = FALSE;
1102 if (!ass->aname.name)
1106 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1110 /* FIXME: handle lazy loaded assemblies */
1111 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1112 g_hash_table_insert (ht, tmp->data, tmp->data);
1114 if (!g_hash_table_lookup (ht, ass)) {
1115 mono_assembly_addref (ass);
1116 g_hash_table_insert (ht, ass, ass);
1117 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1118 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);
1121 if (ass->image->references) {
1122 for (i = 0; ass->image->references [i] != NULL; i++) {
1123 if (ass->image->references [i] != REFERENCE_MISSING)
1124 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1125 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1130 g_hash_table_destroy (ht);
1134 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1136 static MonoClassField *assembly_load_field;
1137 static MonoMethod *assembly_load_method;
1139 MonoDomain *domain = mono_domain_get ();
1140 MonoReflectionAssembly *ref_assembly;
1142 gpointer load_value;
1145 if (!domain->domain)
1146 /* This can happen during startup */
1148 #ifdef ASSEMBLY_LOAD_DEBUG
1149 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1151 klass = domain->domain->mbr.obj.vtable->klass;
1153 mono_domain_assemblies_lock (domain);
1154 add_assemblies_to_domain (domain, assembly, NULL);
1155 mono_domain_assemblies_unlock (domain);
1157 if (assembly_load_field == NULL) {
1158 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1159 g_assert (assembly_load_field);
1162 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1163 if (load_value == NULL) {
1164 /* No events waiting to be triggered */
1168 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1169 mono_error_assert_ok (&error);
1171 if (assembly_load_method == NULL) {
1172 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1173 g_assert (assembly_load_method);
1176 *params = ref_assembly;
1178 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1179 mono_error_cleanup (&error);
1183 * LOCKING: Acquires the domain assemblies lock.
1186 set_domain_search_path (MonoDomain *domain)
1189 MonoAppDomainSetup *setup;
1191 gchar *search_path = NULL;
1194 gchar **pvt_split = NULL;
1195 GError *gerror = NULL;
1196 gint appbaselen = -1;
1199 * We use the low-level domain assemblies lock, since this is called from
1200 * assembly loads hooks, which means this thread might hold the loader lock.
1202 mono_domain_assemblies_lock (domain);
1204 if (!domain->setup) {
1205 mono_domain_assemblies_unlock (domain);
1209 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1210 mono_domain_assemblies_unlock (domain);
1213 setup = domain->setup;
1214 if (!setup->application_base) {
1215 mono_domain_assemblies_unlock (domain);
1216 return; /* Must set application base to get private path working */
1221 if (setup->private_bin_path) {
1222 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1223 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1224 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1225 mono_error_cleanup (&error);
1226 mono_domain_assemblies_unlock (domain);
1231 if (domain->private_bin_path) {
1232 if (search_path == NULL)
1233 search_path = domain->private_bin_path;
1235 gchar *tmp2 = search_path;
1236 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1243 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1244 * directories relative to ApplicationBase separated by semicolons (see
1245 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1246 * The loop below copes with the fact that some Unix applications may use ':' (or
1247 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1248 * ';' for the subsequent split.
1250 * The issue was reported in bug #81446
1253 #ifndef TARGET_WIN32
1256 slen = strlen (search_path);
1257 for (i = 0; i < slen; i++)
1258 if (search_path [i] == ':')
1259 search_path [i] = ';';
1262 pvt_split = g_strsplit (search_path, ";", 1000);
1263 g_free (search_path);
1264 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1269 g_strfreev (pvt_split);
1271 * Don't do this because the first time is called, the domain
1272 * setup is not finished.
1274 * domain->search_path = g_malloc (sizeof (char *));
1275 * domain->search_path [0] = NULL;
1277 mono_domain_assemblies_unlock (domain);
1281 if (domain->search_path)
1282 g_strfreev (domain->search_path);
1284 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1285 tmp [npaths] = NULL;
1287 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1288 if (!mono_error_ok (&error)) {
1289 mono_error_cleanup (&error);
1290 g_strfreev (pvt_split);
1293 mono_domain_assemblies_unlock (domain);
1297 domain->search_path = tmp;
1299 /* FIXME: is this needed? */
1300 if (strncmp (*tmp, "file://", 7) == 0) {
1306 uri = g_strdup_printf ("file:///%s", uri + 7);
1309 uri = mono_escape_uri_string (tmpuri);
1310 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1316 if (gerror != NULL) {
1317 g_warning ("%s\n", gerror->message);
1318 g_error_free (gerror);
1325 for (i = 1; pvt_split && i < npaths; i++) {
1326 if (g_path_is_absolute (pvt_split [i - 1])) {
1327 tmp [i] = g_strdup (pvt_split [i - 1]);
1329 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1332 if (strchr (tmp [i], '.')) {
1336 reduced = mono_path_canonicalize (tmp [i]);
1337 if (appbaselen == -1)
1338 appbaselen = strlen (tmp [0]);
1340 if (strncmp (tmp [0], reduced, appbaselen)) {
1343 tmp [i] = g_strdup ("");
1353 if (setup->private_bin_path_probe != NULL) {
1355 tmp [0] = g_strdup ("");
1358 domain->setup->path_changed = FALSE;
1360 g_strfreev (pvt_split);
1362 mono_domain_assemblies_unlock (domain);
1365 #ifdef DISABLE_SHADOW_COPY
1367 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1373 mono_make_shadow_copy (const char *filename, MonoError *error)
1375 mono_error_init (error);
1376 return (char *) filename;
1380 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1382 guint16 *orig, *dest;
1383 gboolean copy_result;
1385 strcpy (src + srclen - tail_len, extension);
1387 if (IS_PORTABILITY_CASE) {
1388 gchar *file = mono_portability_find_file (src, TRUE);
1394 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1398 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1400 strcpy (target + targetlen - tail_len, extension);
1401 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1404 copy_result = CopyFile (orig, dest, FALSE);
1406 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1407 * overwritten when updated in their original locations. */
1409 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1418 get_cstring_hash (const char *str)
1424 if (!str || !str [0])
1429 for (i = 0; i < len; i++) {
1430 h = (h << 5) - h + *p;
1438 * Returned memory is malloc'd. Called must free it
1441 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1443 MonoAppDomainSetup *setup;
1444 char *cache_path, *appname;
1448 mono_error_init (error);
1450 setup = domain->setup;
1451 if (setup->cache_path != NULL && setup->application_name != NULL) {
1452 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1453 return_val_if_nok (error, NULL);
1455 #ifndef TARGET_WIN32
1458 for (i = strlen (cache_path) - 1; i >= 0; i--)
1459 if (cache_path [i] == '\\')
1460 cache_path [i] = '/';
1464 appname = mono_string_to_utf8_checked (setup->application_name, error);
1465 if (!mono_error_ok (error)) {
1466 g_free (cache_path);
1470 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1472 g_free (cache_path);
1474 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1475 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1482 get_shadow_assembly_location (const char *filename, MonoError *error)
1484 gint32 hash = 0, hash2 = 0;
1486 char path_hash [30];
1487 char *bname = g_path_get_basename (filename);
1488 char *dirname = g_path_get_dirname (filename);
1489 char *location, *tmploc;
1490 MonoDomain *domain = mono_domain_get ();
1492 mono_error_init (error);
1494 hash = get_cstring_hash (bname);
1495 hash2 = get_cstring_hash (dirname);
1496 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1497 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1498 tmploc = get_shadow_assembly_location_base (domain, error);
1499 if (!mono_error_ok (error)) {
1505 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1513 ensure_directory_exists (const char *filename)
1516 gchar *dir_utf8 = g_path_get_dirname (filename);
1518 gunichar2 *dir_utf16 = NULL;
1521 if (!dir_utf8 || !dir_utf8 [0])
1524 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1532 /* make life easy and only use one directory seperator */
1543 while (*p++ != '\\')
1549 p = wcschr (p, '\\');
1552 retval = _wmkdir (dir_utf16);
1553 if (retval != 0 && errno != EEXIST) {
1566 gchar *dir = g_path_get_dirname (filename);
1570 if (!dir || !dir [0]) {
1575 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1585 p = strchr (p, '/');
1588 retval = mkdir (dir, 0777);
1589 if (retval != 0 && errno != EEXIST) {
1604 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1606 struct stat sbuf_dest;
1608 gchar *real_src = mono_portability_find_file (src, TRUE);
1611 stat_src = (gchar*)src;
1613 stat_src = real_src;
1615 if (stat (stat_src, sbuf_src) == -1) {
1616 time_t tnow = time (NULL);
1621 memset (sbuf_src, 0, sizeof (*sbuf_src));
1622 sbuf_src->st_mtime = tnow;
1623 sbuf_src->st_atime = tnow;
1630 if (stat (dest, &sbuf_dest) == -1)
1633 if (sbuf_src->st_size == sbuf_dest.st_size &&
1634 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1641 shadow_copy_create_ini (const char *shadow, const char *filename)
1651 dir_name = g_path_get_dirname (shadow);
1652 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1654 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1659 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1664 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1665 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1667 if (handle == INVALID_HANDLE_VALUE) {
1671 full_path = mono_path_resolve_symlinks (filename);
1672 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1674 CloseHandle (handle);
1679 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1682 MonoAppDomainSetup *setup;
1685 gchar **directories;
1686 gchar *shadow_status_string;
1688 gboolean shadow_enabled;
1689 gboolean found = FALSE;
1694 setup = domain->setup;
1695 if (setup == NULL || setup->shadow_copy_files == NULL)
1698 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1699 if (!mono_error_ok (&error)) {
1700 mono_error_cleanup (&error);
1703 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1704 g_free (shadow_status_string);
1706 if (!shadow_enabled)
1709 if (setup->shadow_copy_directories == NULL)
1712 /* Is dir_name a shadow_copy destination already? */
1713 base_dir = get_shadow_assembly_location_base (domain, &error);
1714 if (!mono_error_ok (&error)) {
1715 mono_error_cleanup (&error);
1719 if (strstr (dir_name, base_dir)) {
1725 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1726 if (!mono_error_ok (&error)) {
1727 mono_error_cleanup (&error);
1731 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1732 dir_ptr = directories;
1734 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1740 g_strfreev (directories);
1746 This function raises exceptions so it can cause as sorts of nasty stuff if called
1747 while holding a lock.
1748 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1749 or NULL if source file not found.
1750 FIXME bubble up the error instead of raising it here
1753 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1756 gchar *sibling_source, *sibling_target;
1757 gint sibling_source_len, sibling_target_len;
1758 guint16 *orig, *dest;
1761 gboolean copy_result;
1762 struct stat src_sbuf;
1763 struct utimbuf utbuf;
1764 char *dir_name = g_path_get_dirname (filename);
1765 MonoDomain *domain = mono_domain_get ();
1768 mono_error_init (oerror);
1770 set_domain_search_path (domain);
1772 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1774 return (char *) filename;
1777 /* Is dir_name a shadow_copy destination already? */
1778 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1779 if (!mono_error_ok (&error)) {
1780 mono_error_cleanup (&error);
1782 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1786 if (strstr (dir_name, shadow_dir)) {
1787 g_free (shadow_dir);
1789 return (char *) filename;
1791 g_free (shadow_dir);
1794 shadow = get_shadow_assembly_location (filename, &error);
1795 if (!mono_error_ok (&error)) {
1796 mono_error_cleanup (&error);
1797 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1801 if (ensure_directory_exists (shadow) == FALSE) {
1803 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1807 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1808 return (char*) shadow;
1810 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1811 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1814 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1815 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1816 * and not have it runtime error" */
1817 attrs = GetFileAttributes (orig);
1818 if (attrs == INVALID_FILE_ATTRIBUTES) {
1820 return (char *)filename;
1823 copy_result = CopyFile (orig, dest, FALSE);
1825 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1826 * overwritten when updated in their original locations. */
1828 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1833 if (copy_result == FALSE) {
1836 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1837 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1838 return NULL; /* file not found, shadow copy failed */
1840 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1844 /* attempt to copy .mdb, .config if they exist */
1845 sibling_source = g_strconcat (filename, ".config", NULL);
1846 sibling_source_len = strlen (sibling_source);
1847 sibling_target = g_strconcat (shadow, ".config", NULL);
1848 sibling_target_len = strlen (sibling_target);
1850 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1851 if (copy_result == TRUE)
1852 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1854 g_free (sibling_source);
1855 g_free (sibling_target);
1857 if (copy_result == FALSE) {
1859 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1863 /* Create a .ini file containing the original assembly location */
1864 if (!shadow_copy_create_ini (shadow, filename)) {
1866 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1870 utbuf.actime = src_sbuf.st_atime;
1871 utbuf.modtime = src_sbuf.st_mtime;
1872 utime (shadow, &utbuf);
1876 #endif /* DISABLE_SHADOW_COPY */
1879 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1881 if (appdomain == NULL)
1884 return appdomain->data;
1888 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1889 const gchar *path3, const gchar *path4,
1890 gboolean refonly, gboolean is_private)
1893 gboolean found = FALSE;
1896 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1898 if (IS_PORTABILITY_SET) {
1899 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1902 fullpath = new_fullpath;
1906 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1909 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1912 return (*assembly != NULL);
1915 static MonoAssembly *
1916 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1918 MonoAssembly *result = NULL;
1921 const gchar *local_culture;
1923 gboolean is_private = FALSE;
1925 if (!culture || *culture == '\0') {
1928 local_culture = culture;
1931 filename = g_strconcat (name, ".dll", NULL);
1932 len = strlen (filename);
1934 for (path = search_path; *path; path++) {
1935 if (**path == '\0') {
1937 continue; /* Ignore empty ApplicationBase */
1940 /* See test cases in bug #58992 and bug #57710 */
1941 /* 1st try: [culture]/[name].dll (culture may be empty) */
1942 strcpy (filename + len - 4, ".dll");
1943 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1946 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1947 strcpy (filename + len - 4, ".exe");
1948 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1951 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1952 strcpy (filename + len - 4, ".dll");
1953 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1956 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1957 strcpy (filename + len - 4, ".exe");
1958 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1967 * Try loading the assembly from ApplicationBase and PrivateBinPath
1968 * and then from assemblies_path if any.
1969 * LOCKING: This is called from the assembly loading code, which means the caller
1970 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1972 static MonoAssembly *
1973 mono_domain_assembly_preload (MonoAssemblyName *aname,
1974 gchar **assemblies_path,
1977 MonoDomain *domain = mono_domain_get ();
1978 MonoAssembly *result = NULL;
1979 gboolean refonly = GPOINTER_TO_UINT (user_data);
1981 set_domain_search_path (domain);
1983 if (domain->search_path && domain->search_path [0] != NULL) {
1984 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1987 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1988 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1995 * Check whenever a given assembly was already loaded in the current appdomain.
1997 static MonoAssembly *
1998 mono_domain_assembly_search (MonoAssemblyName *aname,
2001 MonoDomain *domain = mono_domain_get ();
2004 gboolean refonly = GPOINTER_TO_UINT (user_data);
2006 mono_domain_assemblies_lock (domain);
2007 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2008 ass = (MonoAssembly *)tmp->data;
2009 /* Dynamic assemblies can't match here in MS.NET */
2010 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2013 mono_domain_assemblies_unlock (domain);
2016 mono_domain_assemblies_unlock (domain);
2021 MonoReflectionAssembly *
2022 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2025 MonoReflectionAssembly *result;
2026 MonoDomain *domain = mono_domain_get ();
2027 char *name, *filename;
2028 MonoImageOpenStatus status = MONO_IMAGE_OK;
2031 if (fname == NULL) {
2032 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2033 mono_set_pending_exception (exc);
2037 name = filename = mono_string_to_utf8_checked (fname, &error);
2038 if (mono_error_set_pending_exception (&error))
2041 ass = mono_assembly_open_full (filename, &status, refOnly);
2046 if (status == MONO_IMAGE_IMAGE_INVALID)
2047 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2049 exc = mono_get_exception_file_not_found2 (NULL, fname);
2051 mono_set_pending_exception (exc);
2057 result = mono_assembly_get_object_checked (domain, ass, &error);
2059 mono_error_set_pending_exception (&error);
2063 MonoReflectionAssembly *
2064 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2065 MonoArray *raw_assembly,
2066 MonoArray *raw_symbol_store, MonoObject *evidence,
2067 MonoBoolean refonly)
2071 MonoReflectionAssembly *refass = NULL;
2072 MonoDomain *domain = ad->data;
2073 MonoImageOpenStatus status;
2074 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2075 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2078 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2082 if (raw_symbol_store != NULL)
2083 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2085 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2089 mono_image_close (image);
2090 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2094 refass = mono_assembly_get_object_checked (domain, ass, &error);
2096 mono_error_set_pending_exception (&error);
2098 MONO_OBJECT_SETREF (refass, evidence, evidence);
2102 MonoReflectionAssembly *
2103 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2106 MonoDomain *domain = ad->data;
2107 MonoImageOpenStatus status = MONO_IMAGE_OK;
2109 MonoAssemblyName aname;
2110 MonoReflectionAssembly *refass = NULL;
2116 name = mono_string_to_utf8_checked (assRef, &error);
2117 if (mono_error_set_pending_exception (&error))
2119 parsed = mono_assembly_name_parse (name, &aname);
2123 /* This is a parse error... */
2125 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2126 if (!mono_error_ok (&error)) {
2127 mono_error_set_pending_exception (&error);
2134 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2135 mono_assembly_name_free (&aname);
2138 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2140 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2141 if (!mono_error_ok (&error)) {
2142 mono_error_set_pending_exception (&error);
2154 refass = mono_assembly_get_object_checked (domain, ass, &error);
2157 mono_error_set_pending_exception (&error);
2159 MONO_OBJECT_SETREF (refass, evidence, evidence);
2164 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2166 MonoException *exc = NULL;
2167 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2169 if (NULL == domain) {
2170 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2171 mono_set_pending_exception (exc);
2175 if (domain == mono_get_root_domain ()) {
2176 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2181 * Unloading seems to cause problems when running NUnit/NAnt, hence
2184 if (g_getenv ("MONO_NO_UNLOAD"))
2186 #ifdef __native_client__
2190 mono_domain_try_unload (domain, (MonoObject**)&exc);
2192 mono_set_pending_exception (exc);
2196 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2198 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2203 return mono_domain_is_unloading (domain);
2207 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2209 mono_unhandled_exception ((MonoObject*) exc);
2213 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2214 MonoReflectionAssembly *refass, MonoArray *args)
2221 image = refass->assembly->image;
2224 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2227 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2230 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2231 mono_error_assert_ok (&error);
2234 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2238 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2240 return ad->data->domain_id;
2244 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2246 MonoDomain *old_domain = mono_domain_get();
2248 if (!mono_domain_set (ad->data, FALSE)) {
2249 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2253 return old_domain->domain;
2257 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2259 MonoDomain *current_domain = mono_domain_get ();
2260 MonoDomain *domain = mono_domain_get_by_id (domainid);
2262 if (!domain || !mono_domain_set (domain, FALSE)) {
2263 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2267 return current_domain->domain;
2271 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2273 mono_thread_push_appdomain_ref (ad->data);
2277 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2279 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2283 * Raise an exception to prevent the managed code from executing a pop
2286 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2290 mono_thread_push_appdomain_ref (domain);
2294 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2296 mono_thread_pop_appdomain_ref ();
2300 ves_icall_System_AppDomain_InternalGetContext ()
2302 return mono_context_get ();
2306 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2308 return mono_domain_get ()->default_context;
2312 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2314 MonoAppContext *old_context = mono_context_get ();
2316 mono_context_set (mc);
2322 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2324 MonoDomain* mono_root_domain = mono_get_root_domain ();
2325 mono_domain_lock (mono_root_domain);
2326 if (process_guid_set) {
2327 mono_domain_unlock (mono_root_domain);
2329 MonoString *res = NULL;
2330 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2331 mono_error_set_pending_exception (&error);
2334 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2335 process_guid_set = TRUE;
2336 mono_domain_unlock (mono_root_domain);
2341 mono_domain_is_unloading (MonoDomain *domain)
2343 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2350 clear_cached_vtable (MonoVTable *vtable)
2352 MonoClass *klass = vtable->klass;
2353 MonoDomain *domain = vtable->domain;
2354 MonoClassRuntimeInfo *runtime_info;
2357 runtime_info = klass->runtime_info;
2358 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2359 runtime_info->domain_vtables [domain->domain_id] = NULL;
2360 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2361 mono_gc_free_fixed (data);
2364 static G_GNUC_UNUSED void
2365 zero_static_data (MonoVTable *vtable)
2367 MonoClass *klass = vtable->klass;
2370 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2371 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2374 typedef struct unload_data {
2377 char *failure_reason;
2382 unload_data_unref (unload_data *data)
2386 mono_atomic_load_acquire (count, gint32, &data->refcount);
2387 g_assert (count >= 1 && count <= 2);
2392 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2396 deregister_reflection_info_roots_from_list (MonoImage *image)
2398 GSList *list = image->reflection_info_unregister_classes;
2401 MonoClass *klass = (MonoClass *)list->data;
2403 mono_class_free_ref_info (klass);
2408 image->reflection_info_unregister_classes = NULL;
2412 deregister_reflection_info_roots (MonoDomain *domain)
2416 mono_domain_assemblies_lock (domain);
2417 for (list = domain->domain_assemblies; list; list = list->next) {
2418 MonoAssembly *assembly = (MonoAssembly *)list->data;
2419 MonoImage *image = assembly->image;
2423 * No need to take the image lock here since dynamic images are appdomain bound and
2424 * at this point the mutator is gone. Taking the image lock here would mean
2425 * promoting it from a simple lock to a complex lock, which we better avoid if
2428 if (image_is_dynamic (image))
2429 deregister_reflection_info_roots_from_list (image);
2431 for (i = 0; i < image->module_count; ++i) {
2432 MonoImage *module = image->modules [i];
2433 if (module && image_is_dynamic (module))
2434 deregister_reflection_info_roots_from_list (module);
2437 mono_domain_assemblies_unlock (domain);
2440 static guint32 WINAPI
2441 unload_thread_main (void *arg)
2444 unload_data *data = (unload_data*)arg;
2445 MonoDomain *domain = data->domain;
2449 /* Have to attach to the runtime so shutdown can wait for this thread */
2450 /* Force it to be attached to avoid racing during shutdown. */
2451 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2453 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2454 if (!is_ok (&error)) {
2455 data->failure_reason = g_strdup (mono_error_get_message (&error));
2456 mono_error_cleanup (&error);
2461 * FIXME: Abort our parent thread last, so we can return a failure
2462 * indication if aborting times out.
2464 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2465 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2469 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2470 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2474 /* Finalize all finalizable objects in the doomed appdomain */
2475 if (!mono_domain_finalize (domain, -1)) {
2476 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2480 /* Clear references to our vtables in class->runtime_info.
2481 * We also hold the loader lock because we're going to change
2482 * class->runtime_info.
2485 mono_loader_lock (); //FIXME why do we need the loader lock here?
2486 mono_domain_lock (domain);
2489 * We need to make sure that we don't have any remsets
2490 * pointing into static data of the to-be-freed domain because
2491 * at the next collections they would be invalid. So what we
2492 * do is we first zero all static data and then do a minor
2493 * collection. Because all references in the static data will
2494 * now be null we won't do any unnecessary copies and after
2495 * the collection there won't be any more remsets.
2497 for (i = 0; i < domain->class_vtable_array->len; ++i)
2498 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2499 mono_gc_collect (0);
2501 for (i = 0; i < domain->class_vtable_array->len; ++i)
2502 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2503 deregister_reflection_info_roots (domain);
2505 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2507 mono_domain_unlock (domain);
2508 mono_loader_unlock ();
2510 mono_threads_clear_cached_culture (domain);
2512 domain->state = MONO_APPDOMAIN_UNLOADED;
2514 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2516 /* remove from the handle table the items related to this domain */
2517 mono_gchandle_free_domain (domain);
2519 mono_domain_free (domain, FALSE);
2521 mono_gc_collect (mono_gc_max_generation ());
2523 mono_atomic_store_release (&data->done, TRUE);
2524 unload_data_unref (data);
2525 mono_thread_detach (thread);
2529 mono_atomic_store_release (&data->done, TRUE);
2530 unload_data_unref (data);
2531 mono_thread_detach (thread);
2536 * mono_domain_unload:
2537 * @domain: The domain to unload
2539 * Unloads an appdomain. Follows the process outlined in the comment
2540 * for mono_domain_try_unload.
2543 mono_domain_unload (MonoDomain *domain)
2545 MonoObject *exc = NULL;
2546 mono_domain_try_unload (domain, &exc);
2550 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2555 result = WaitForSingleObjectEx (handle, timeout, alertable);
2562 * mono_domain_unload:
2563 * @domain: The domain to unload
2564 * @exc: Exception information
2566 * Unloads an appdomain. Follows the process outlined in:
2567 * http://blogs.gotdotnet.com/cbrumme
2569 * If doing things the 'right' way is too hard or complex, we do it the
2570 * 'simple' way, which means do everything needed to avoid crashes and
2571 * memory leaks, but not much else.
2573 * It is required to pass a valid reference to the exc argument, upon return
2574 * from this function *exc will be set to the exception thrown, if any.
2576 * If this method is not called from an icall (embedded scenario for instance),
2577 * it must not be called with any managed frames on the stack, since the unload
2578 * process could end up trying to abort the current thread.
2581 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2584 HANDLE thread_handle;
2585 MonoAppDomainState prev_state;
2587 unload_data *thread_data;
2588 MonoNativeThreadId tid;
2589 MonoDomain *caller_domain = mono_domain_get ();
2591 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2593 /* Atomically change our state to UNLOADING */
2594 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2595 MONO_APPDOMAIN_UNLOADING_START,
2596 MONO_APPDOMAIN_CREATED);
2597 if (prev_state != MONO_APPDOMAIN_CREATED) {
2598 switch (prev_state) {
2599 case MONO_APPDOMAIN_UNLOADING_START:
2600 case MONO_APPDOMAIN_UNLOADING:
2601 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2603 case MONO_APPDOMAIN_UNLOADED:
2604 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2607 g_warning ("Invalid appdomain state %d", prev_state);
2608 g_assert_not_reached ();
2612 mono_domain_set (domain, FALSE);
2613 /* Notify OnDomainUnload listeners */
2614 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2617 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2619 if (!mono_error_ok (&error)) {
2621 mono_error_cleanup (&error);
2623 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2627 /* Roll back the state change */
2628 domain->state = MONO_APPDOMAIN_CREATED;
2629 mono_domain_set (caller_domain, FALSE);
2632 mono_domain_set (caller_domain, FALSE);
2634 thread_data = g_new0 (unload_data, 1);
2635 thread_data->domain = domain;
2636 thread_data->failure_reason = NULL;
2637 thread_data->done = FALSE;
2638 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2640 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2641 domain->state = MONO_APPDOMAIN_UNLOADING;
2643 * First we create a separate thread for unloading, since
2644 * we might have to abort some threads, including the current one.
2646 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2647 if (thread_handle == NULL)
2649 mono_thread_info_resume (tid);
2651 /* Wait for the thread */
2652 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2653 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2654 /* The unload thread tries to abort us */
2655 /* The icall wrapper will execute the abort */
2656 CloseHandle (thread_handle);
2657 unload_data_unref (thread_data);
2661 CloseHandle (thread_handle);
2663 if (thread_data->failure_reason) {
2664 /* Roll back the state change */
2665 domain->state = MONO_APPDOMAIN_CREATED;
2667 g_warning ("%s", thread_data->failure_reason);
2669 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2671 g_free (thread_data->failure_reason);
2672 thread_data->failure_reason = NULL;
2675 unload_data_unref (thread_data);