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 147
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)
713 MONO_CHECK_ARG_NULL (name, NULL);
719 str = mono_string_to_utf8 (name);
721 mono_domain_lock (add);
723 if (!strcmp (str, "APPBASE"))
724 o = (MonoObject *)add->setup->application_base;
725 else if (!strcmp (str, "APP_CONFIG_FILE"))
726 o = (MonoObject *)add->setup->configuration_file;
727 else if (!strcmp (str, "DYNAMIC_BASE"))
728 o = (MonoObject *)add->setup->dynamic_base;
729 else if (!strcmp (str, "APP_NAME"))
730 o = (MonoObject *)add->setup->application_name;
731 else if (!strcmp (str, "CACHE_BASE"))
732 o = (MonoObject *)add->setup->cache_path;
733 else if (!strcmp (str, "PRIVATE_BINPATH"))
734 o = (MonoObject *)add->setup->private_bin_path;
735 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
736 o = (MonoObject *)add->setup->private_bin_path_probe;
737 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
738 o = (MonoObject *)add->setup->shadow_copy_directories;
739 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
740 o = (MonoObject *)add->setup->shadow_copy_files;
742 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
744 mono_domain_unlock (add);
754 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
758 MONO_CHECK_ARG_NULL (name,);
764 mono_domain_lock (add);
766 mono_g_hash_table_insert (add->env, name, data);
768 mono_domain_unlock (add);
772 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
777 return ad->data->setup;
781 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
786 return mono_string_new (ad->data, ad->data->friendly_name);
790 ves_icall_System_AppDomain_getCurDomain ()
792 MonoDomain *add = mono_domain_get ();
798 ves_icall_System_AppDomain_getRootDomain ()
800 MonoDomain *root = mono_get_root_domain ();
806 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
808 MonoDomain *domain = mono_domain_get ();
810 return domain->throw_unobserved_task_exceptions;
814 get_attribute_value (const gchar **attribute_names,
815 const gchar **attribute_values,
816 const char *att_name)
819 for (n = 0; attribute_names [n] != NULL; n++) {
820 if (strcmp (attribute_names [n], att_name) == 0)
821 return g_strdup (attribute_values [n]);
827 start_element (GMarkupParseContext *context,
828 const gchar *element_name,
829 const gchar **attribute_names,
830 const gchar **attribute_values,
834 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
836 if (strcmp (element_name, "runtime") == 0) {
837 runtime_config->runtime_count++;
841 if (strcmp (element_name, "assemblyBinding") == 0) {
842 runtime_config->assemblybinding_count++;
846 if (runtime_config->runtime_count != 1)
849 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
850 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
852 if (value && g_ascii_strcasecmp (value, "true") == 0)
853 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
856 if (runtime_config->assemblybinding_count != 1)
859 if (strcmp (element_name, "probing") != 0)
862 g_free (runtime_config->domain->private_bin_path);
863 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
864 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
865 g_free (runtime_config->domain->private_bin_path);
866 runtime_config->domain->private_bin_path = NULL;
872 end_element (GMarkupParseContext *context,
873 const gchar *element_name,
877 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
878 if (strcmp (element_name, "runtime") == 0)
879 runtime_config->runtime_count--;
880 else if (strcmp (element_name, "assemblyBinding") == 0)
881 runtime_config->assemblybinding_count--;
885 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
887 RuntimeConfig *state = (RuntimeConfig *)user_data;
889 const gchar *filename;
891 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
892 msg = error && error->message ? error->message : "";
893 g_warning ("Error parsing %s: %s", filename, msg);
896 static const GMarkupParser
906 mono_domain_set_options_from_config (MonoDomain *domain)
909 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
911 GMarkupParseContext *context;
912 RuntimeConfig runtime_config;
915 if (!domain || !domain->setup || !domain->setup->configuration_file)
918 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
919 if (!mono_error_ok (&error)) {
920 mono_error_cleanup (&error);
924 config_file_path = mono_portability_find_file (config_file_name, TRUE);
925 if (!config_file_path)
926 config_file_path = config_file_name;
928 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
931 runtime_config.runtime_count = 0;
932 runtime_config.assemblybinding_count = 0;
933 runtime_config.domain = domain;
934 runtime_config.filename = config_file_path;
937 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
938 offset = 3; /* Skip UTF-8 BOM */
940 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
941 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
942 g_markup_parse_context_end_parse (context, NULL);
943 g_markup_parse_context_free (context);
947 if (config_file_name != config_file_path)
948 g_free (config_file_name);
949 g_free (config_file_path);
953 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
956 MonoAppDomain *ad = NULL;
957 #ifdef DISABLE_APPDOMAINS
958 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
962 fname = mono_string_to_utf8 (friendly_name);
963 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
967 mono_error_set_pending_exception (&error);
972 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
975 MonoDomain *domain = ad->data;
980 GPtrArray *assemblies;
982 mono_error_init (&error);
985 * Make a copy of the list of assemblies because we can't hold the assemblies
986 * lock while creating objects etc.
988 assemblies = g_ptr_array_new ();
989 /* Need to skip internal assembly builders created by remoting */
990 mono_domain_assemblies_lock (domain);
991 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
992 ass = (MonoAssembly *)tmp->data;
993 if (refonly != ass->ref_only)
995 if (ass->corlib_internal)
997 g_ptr_array_add (assemblies, ass);
999 mono_domain_assemblies_unlock (domain);
1001 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1002 if (!is_ok (&error))
1004 for (i = 0; i < assemblies->len; ++i) {
1005 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1006 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1007 if (!mono_error_ok (&error))
1009 mono_array_setref (res, i, ass_obj);
1013 g_ptr_array_free (assemblies, TRUE);
1014 if (!mono_error_ok (&error))
1015 mono_error_set_pending_exception (&error);
1019 MonoReflectionAssembly *
1020 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1022 MonoReflectionAssembly *ret;
1025 MonoBoolean isrefonly;
1026 gpointer params [3];
1028 mono_error_init (error);
1030 if (mono_runtime_get_no_exec ())
1033 g_assert (domain != NULL && fname != NULL);
1035 klass = domain->domain->mbr.obj.vtable->klass;
1038 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1039 if (method == NULL) {
1040 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1044 isrefonly = refonly ? 1 : 0;
1047 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1048 return_val_if_nok (error, NULL);
1051 params [2] = &isrefonly;
1053 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1054 return_val_if_nok (error, NULL);
1060 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1064 MonoReflectionAssembly *assembly;
1065 MonoDomain *domain = mono_domain_get ();
1069 aname_str = mono_stringify_assembly_name (aname);
1071 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1072 str = mono_string_new (domain, aname_str);
1078 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1079 mono_error_cleanup (&error);
1082 return assembly->assembly;
1088 * LOCKING: assumes assemblies_lock in the domain is already locked.
1091 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1095 gboolean destroy_ht = FALSE;
1097 if (!ass->aname.name)
1101 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1105 /* FIXME: handle lazy loaded assemblies */
1106 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1107 g_hash_table_insert (ht, tmp->data, tmp->data);
1109 if (!g_hash_table_lookup (ht, ass)) {
1110 mono_assembly_addref (ass);
1111 g_hash_table_insert (ht, ass, ass);
1112 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1113 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);
1116 if (ass->image->references) {
1117 for (i = 0; ass->image->references [i] != NULL; i++) {
1118 if (ass->image->references [i] != REFERENCE_MISSING)
1119 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1120 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1125 g_hash_table_destroy (ht);
1129 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1131 static MonoClassField *assembly_load_field;
1132 static MonoMethod *assembly_load_method;
1134 MonoDomain *domain = mono_domain_get ();
1135 MonoReflectionAssembly *ref_assembly;
1137 gpointer load_value;
1140 if (!domain->domain)
1141 /* This can happen during startup */
1143 #ifdef ASSEMBLY_LOAD_DEBUG
1144 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1146 klass = domain->domain->mbr.obj.vtable->klass;
1148 mono_domain_assemblies_lock (domain);
1149 add_assemblies_to_domain (domain, assembly, NULL);
1150 mono_domain_assemblies_unlock (domain);
1152 if (assembly_load_field == NULL) {
1153 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1154 g_assert (assembly_load_field);
1157 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1158 if (load_value == NULL) {
1159 /* No events waiting to be triggered */
1163 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1164 mono_error_assert_ok (&error);
1166 if (assembly_load_method == NULL) {
1167 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1168 g_assert (assembly_load_method);
1171 *params = ref_assembly;
1173 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1174 mono_error_cleanup (&error);
1178 * LOCKING: Acquires the domain assemblies lock.
1181 set_domain_search_path (MonoDomain *domain)
1184 MonoAppDomainSetup *setup;
1186 gchar *search_path = NULL;
1189 gchar **pvt_split = NULL;
1190 GError *gerror = NULL;
1191 gint appbaselen = -1;
1194 * We use the low-level domain assemblies lock, since this is called from
1195 * assembly loads hooks, which means this thread might hold the loader lock.
1197 mono_domain_assemblies_lock (domain);
1199 if (!domain->setup) {
1200 mono_domain_assemblies_unlock (domain);
1204 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1205 mono_domain_assemblies_unlock (domain);
1208 setup = domain->setup;
1209 if (!setup->application_base) {
1210 mono_domain_assemblies_unlock (domain);
1211 return; /* Must set application base to get private path working */
1216 if (setup->private_bin_path) {
1217 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1218 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1219 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1220 mono_error_cleanup (&error);
1221 mono_domain_assemblies_unlock (domain);
1226 if (domain->private_bin_path) {
1227 if (search_path == NULL)
1228 search_path = domain->private_bin_path;
1230 gchar *tmp2 = search_path;
1231 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1238 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1239 * directories relative to ApplicationBase separated by semicolons (see
1240 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1241 * The loop below copes with the fact that some Unix applications may use ':' (or
1242 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1243 * ';' for the subsequent split.
1245 * The issue was reported in bug #81446
1248 #ifndef TARGET_WIN32
1251 slen = strlen (search_path);
1252 for (i = 0; i < slen; i++)
1253 if (search_path [i] == ':')
1254 search_path [i] = ';';
1257 pvt_split = g_strsplit (search_path, ";", 1000);
1258 g_free (search_path);
1259 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1264 g_strfreev (pvt_split);
1266 * Don't do this because the first time is called, the domain
1267 * setup is not finished.
1269 * domain->search_path = g_malloc (sizeof (char *));
1270 * domain->search_path [0] = NULL;
1272 mono_domain_assemblies_unlock (domain);
1276 if (domain->search_path)
1277 g_strfreev (domain->search_path);
1279 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1280 tmp [npaths] = NULL;
1282 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1283 if (!mono_error_ok (&error)) {
1284 mono_error_cleanup (&error);
1285 g_strfreev (pvt_split);
1288 mono_domain_assemblies_unlock (domain);
1292 domain->search_path = tmp;
1294 /* FIXME: is this needed? */
1295 if (strncmp (*tmp, "file://", 7) == 0) {
1301 uri = g_strdup_printf ("file:///%s", uri + 7);
1304 uri = mono_escape_uri_string (tmpuri);
1305 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1311 if (gerror != NULL) {
1312 g_warning ("%s\n", gerror->message);
1313 g_error_free (gerror);
1320 for (i = 1; pvt_split && i < npaths; i++) {
1321 if (g_path_is_absolute (pvt_split [i - 1])) {
1322 tmp [i] = g_strdup (pvt_split [i - 1]);
1324 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1327 if (strchr (tmp [i], '.')) {
1331 reduced = mono_path_canonicalize (tmp [i]);
1332 if (appbaselen == -1)
1333 appbaselen = strlen (tmp [0]);
1335 if (strncmp (tmp [0], reduced, appbaselen)) {
1338 tmp [i] = g_strdup ("");
1348 if (setup->private_bin_path_probe != NULL) {
1350 tmp [0] = g_strdup ("");
1353 domain->setup->path_changed = FALSE;
1355 g_strfreev (pvt_split);
1357 mono_domain_assemblies_unlock (domain);
1360 #ifdef DISABLE_SHADOW_COPY
1362 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1368 mono_make_shadow_copy (const char *filename, MonoError *error)
1370 mono_error_init (error);
1371 return (char *) filename;
1375 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1377 guint16 *orig, *dest;
1378 gboolean copy_result;
1380 strcpy (src + srclen - tail_len, extension);
1382 if (IS_PORTABILITY_CASE) {
1383 gchar *file = mono_portability_find_file (src, TRUE);
1389 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1393 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1395 strcpy (target + targetlen - tail_len, extension);
1396 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1399 copy_result = CopyFile (orig, dest, FALSE);
1401 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1402 * overwritten when updated in their original locations. */
1404 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1413 get_cstring_hash (const char *str)
1419 if (!str || !str [0])
1424 for (i = 0; i < len; i++) {
1425 h = (h << 5) - h + *p;
1433 * Returned memory is malloc'd. Called must free it
1436 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1438 MonoAppDomainSetup *setup;
1439 char *cache_path, *appname;
1443 mono_error_init (error);
1445 setup = domain->setup;
1446 if (setup->cache_path != NULL && setup->application_name != NULL) {
1447 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1448 return_val_if_nok (error, NULL);
1450 #ifndef TARGET_WIN32
1453 for (i = strlen (cache_path) - 1; i >= 0; i--)
1454 if (cache_path [i] == '\\')
1455 cache_path [i] = '/';
1459 appname = mono_string_to_utf8_checked (setup->application_name, error);
1460 if (!mono_error_ok (error)) {
1461 g_free (cache_path);
1465 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1467 g_free (cache_path);
1469 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1470 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1477 get_shadow_assembly_location (const char *filename, MonoError *error)
1479 gint32 hash = 0, hash2 = 0;
1481 char path_hash [30];
1482 char *bname = g_path_get_basename (filename);
1483 char *dirname = g_path_get_dirname (filename);
1484 char *location, *tmploc;
1485 MonoDomain *domain = mono_domain_get ();
1487 mono_error_init (error);
1489 hash = get_cstring_hash (bname);
1490 hash2 = get_cstring_hash (dirname);
1491 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1492 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1493 tmploc = get_shadow_assembly_location_base (domain, error);
1494 if (!mono_error_ok (error)) {
1500 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1508 ensure_directory_exists (const char *filename)
1511 gchar *dir_utf8 = g_path_get_dirname (filename);
1513 gunichar2 *dir_utf16 = NULL;
1516 if (!dir_utf8 || !dir_utf8 [0])
1519 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1527 /* make life easy and only use one directory seperator */
1538 while (*p++ != '\\')
1544 p = wcschr (p, '\\');
1547 retval = _wmkdir (dir_utf16);
1548 if (retval != 0 && errno != EEXIST) {
1561 gchar *dir = g_path_get_dirname (filename);
1565 if (!dir || !dir [0]) {
1570 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1580 p = strchr (p, '/');
1583 retval = mkdir (dir, 0777);
1584 if (retval != 0 && errno != EEXIST) {
1599 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1601 struct stat sbuf_dest;
1603 gchar *real_src = mono_portability_find_file (src, TRUE);
1606 stat_src = (gchar*)src;
1608 stat_src = real_src;
1610 if (stat (stat_src, sbuf_src) == -1) {
1611 time_t tnow = time (NULL);
1616 memset (sbuf_src, 0, sizeof (*sbuf_src));
1617 sbuf_src->st_mtime = tnow;
1618 sbuf_src->st_atime = tnow;
1625 if (stat (dest, &sbuf_dest) == -1)
1628 if (sbuf_src->st_size == sbuf_dest.st_size &&
1629 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1636 shadow_copy_create_ini (const char *shadow, const char *filename)
1646 dir_name = g_path_get_dirname (shadow);
1647 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1649 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1654 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1659 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1660 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1662 if (handle == INVALID_HANDLE_VALUE) {
1666 full_path = mono_path_resolve_symlinks (filename);
1667 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1669 CloseHandle (handle);
1674 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1677 MonoAppDomainSetup *setup;
1680 gchar **directories;
1681 gchar *shadow_status_string;
1683 gboolean shadow_enabled;
1684 gboolean found = FALSE;
1689 setup = domain->setup;
1690 if (setup == NULL || setup->shadow_copy_files == NULL)
1693 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1694 if (!mono_error_ok (&error)) {
1695 mono_error_cleanup (&error);
1698 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1699 g_free (shadow_status_string);
1701 if (!shadow_enabled)
1704 if (setup->shadow_copy_directories == NULL)
1707 /* Is dir_name a shadow_copy destination already? */
1708 base_dir = get_shadow_assembly_location_base (domain, &error);
1709 if (!mono_error_ok (&error)) {
1710 mono_error_cleanup (&error);
1714 if (strstr (dir_name, base_dir)) {
1720 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1721 if (!mono_error_ok (&error)) {
1722 mono_error_cleanup (&error);
1726 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1727 dir_ptr = directories;
1729 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1735 g_strfreev (directories);
1741 This function raises exceptions so it can cause as sorts of nasty stuff if called
1742 while holding a lock.
1743 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1744 or NULL if source file not found.
1745 FIXME bubble up the error instead of raising it here
1748 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1751 gchar *sibling_source, *sibling_target;
1752 gint sibling_source_len, sibling_target_len;
1753 guint16 *orig, *dest;
1756 gboolean copy_result;
1757 struct stat src_sbuf;
1758 struct utimbuf utbuf;
1759 char *dir_name = g_path_get_dirname (filename);
1760 MonoDomain *domain = mono_domain_get ();
1763 mono_error_init (oerror);
1765 set_domain_search_path (domain);
1767 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1769 return (char *) filename;
1772 /* Is dir_name a shadow_copy destination already? */
1773 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1774 if (!mono_error_ok (&error)) {
1775 mono_error_cleanup (&error);
1777 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1781 if (strstr (dir_name, shadow_dir)) {
1782 g_free (shadow_dir);
1784 return (char *) filename;
1786 g_free (shadow_dir);
1789 shadow = get_shadow_assembly_location (filename, &error);
1790 if (!mono_error_ok (&error)) {
1791 mono_error_cleanup (&error);
1792 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1796 if (ensure_directory_exists (shadow) == FALSE) {
1798 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1802 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1803 return (char*) shadow;
1805 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1806 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1809 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1810 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1811 * and not have it runtime error" */
1812 attrs = GetFileAttributes (orig);
1813 if (attrs == INVALID_FILE_ATTRIBUTES) {
1815 return (char *)filename;
1818 copy_result = CopyFile (orig, dest, FALSE);
1820 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1821 * overwritten when updated in their original locations. */
1823 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1828 if (copy_result == FALSE) {
1831 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1832 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1833 return NULL; /* file not found, shadow copy failed */
1835 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1839 /* attempt to copy .mdb, .config if they exist */
1840 sibling_source = g_strconcat (filename, ".config", NULL);
1841 sibling_source_len = strlen (sibling_source);
1842 sibling_target = g_strconcat (shadow, ".config", NULL);
1843 sibling_target_len = strlen (sibling_target);
1845 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1846 if (copy_result == TRUE)
1847 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1849 g_free (sibling_source);
1850 g_free (sibling_target);
1852 if (copy_result == FALSE) {
1854 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1858 /* Create a .ini file containing the original assembly location */
1859 if (!shadow_copy_create_ini (shadow, filename)) {
1861 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1865 utbuf.actime = src_sbuf.st_atime;
1866 utbuf.modtime = src_sbuf.st_mtime;
1867 utime (shadow, &utbuf);
1871 #endif /* DISABLE_SHADOW_COPY */
1874 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1876 if (appdomain == NULL)
1879 return appdomain->data;
1883 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1884 const gchar *path3, const gchar *path4,
1885 gboolean refonly, gboolean is_private)
1888 gboolean found = FALSE;
1891 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1893 if (IS_PORTABILITY_SET) {
1894 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1897 fullpath = new_fullpath;
1901 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1904 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1907 return (*assembly != NULL);
1910 static MonoAssembly *
1911 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1913 MonoAssembly *result = NULL;
1916 const gchar *local_culture;
1918 gboolean is_private = FALSE;
1920 if (!culture || *culture == '\0') {
1923 local_culture = culture;
1926 filename = g_strconcat (name, ".dll", NULL);
1927 len = strlen (filename);
1929 for (path = search_path; *path; path++) {
1930 if (**path == '\0') {
1932 continue; /* Ignore empty ApplicationBase */
1935 /* See test cases in bug #58992 and bug #57710 */
1936 /* 1st try: [culture]/[name].dll (culture may be empty) */
1937 strcpy (filename + len - 4, ".dll");
1938 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1941 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1942 strcpy (filename + len - 4, ".exe");
1943 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1946 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1947 strcpy (filename + len - 4, ".dll");
1948 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1951 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1952 strcpy (filename + len - 4, ".exe");
1953 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1962 * Try loading the assembly from ApplicationBase and PrivateBinPath
1963 * and then from assemblies_path if any.
1964 * LOCKING: This is called from the assembly loading code, which means the caller
1965 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1967 static MonoAssembly *
1968 mono_domain_assembly_preload (MonoAssemblyName *aname,
1969 gchar **assemblies_path,
1972 MonoDomain *domain = mono_domain_get ();
1973 MonoAssembly *result = NULL;
1974 gboolean refonly = GPOINTER_TO_UINT (user_data);
1976 set_domain_search_path (domain);
1978 if (domain->search_path && domain->search_path [0] != NULL) {
1979 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1982 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1983 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1990 * Check whenever a given assembly was already loaded in the current appdomain.
1992 static MonoAssembly *
1993 mono_domain_assembly_search (MonoAssemblyName *aname,
1996 MonoDomain *domain = mono_domain_get ();
1999 gboolean refonly = GPOINTER_TO_UINT (user_data);
2001 mono_domain_assemblies_lock (domain);
2002 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2003 ass = (MonoAssembly *)tmp->data;
2004 /* Dynamic assemblies can't match here in MS.NET */
2005 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2008 mono_domain_assemblies_unlock (domain);
2011 mono_domain_assemblies_unlock (domain);
2016 MonoReflectionAssembly *
2017 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2020 MonoReflectionAssembly *result;
2021 MonoDomain *domain = mono_domain_get ();
2022 char *name, *filename;
2023 MonoImageOpenStatus status = MONO_IMAGE_OK;
2026 if (fname == NULL) {
2027 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2028 mono_set_pending_exception (exc);
2032 name = filename = mono_string_to_utf8 (fname);
2034 ass = mono_assembly_open_full (filename, &status, refOnly);
2039 if (status == MONO_IMAGE_IMAGE_INVALID)
2040 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2042 exc = mono_get_exception_file_not_found2 (NULL, fname);
2044 mono_set_pending_exception (exc);
2050 result = mono_assembly_get_object_checked (domain, ass, &error);
2052 mono_error_set_pending_exception (&error);
2056 MonoReflectionAssembly *
2057 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2058 MonoArray *raw_assembly,
2059 MonoArray *raw_symbol_store, MonoObject *evidence,
2060 MonoBoolean refonly)
2064 MonoReflectionAssembly *refass = NULL;
2065 MonoDomain *domain = ad->data;
2066 MonoImageOpenStatus status;
2067 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2068 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2071 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2075 if (raw_symbol_store != NULL)
2076 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2078 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2082 mono_image_close (image);
2083 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2087 refass = mono_assembly_get_object_checked (domain, ass, &error);
2089 mono_error_set_pending_exception (&error);
2091 MONO_OBJECT_SETREF (refass, evidence, evidence);
2095 MonoReflectionAssembly *
2096 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2099 MonoDomain *domain = ad->data;
2100 MonoImageOpenStatus status = MONO_IMAGE_OK;
2102 MonoAssemblyName aname;
2103 MonoReflectionAssembly *refass = NULL;
2109 name = mono_string_to_utf8 (assRef);
2110 parsed = mono_assembly_name_parse (name, &aname);
2114 /* This is a parse error... */
2116 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2117 if (!mono_error_ok (&error)) {
2118 mono_error_set_pending_exception (&error);
2125 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2126 mono_assembly_name_free (&aname);
2129 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2131 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2132 if (!mono_error_ok (&error)) {
2133 mono_error_set_pending_exception (&error);
2145 refass = mono_assembly_get_object_checked (domain, ass, &error);
2148 mono_error_set_pending_exception (&error);
2150 MONO_OBJECT_SETREF (refass, evidence, evidence);
2155 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2157 MonoException *exc = NULL;
2158 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2160 if (NULL == domain) {
2161 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2162 mono_set_pending_exception (exc);
2166 if (domain == mono_get_root_domain ()) {
2167 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2172 * Unloading seems to cause problems when running NUnit/NAnt, hence
2175 if (g_getenv ("MONO_NO_UNLOAD"))
2177 #ifdef __native_client__
2181 mono_domain_try_unload (domain, (MonoObject**)&exc);
2183 mono_set_pending_exception (exc);
2187 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2189 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2194 return mono_domain_is_unloading (domain);
2198 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2200 mono_unhandled_exception ((MonoObject*) exc);
2204 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2205 MonoReflectionAssembly *refass, MonoArray *args)
2212 image = refass->assembly->image;
2215 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2218 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2221 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2222 mono_error_assert_ok (&error);
2225 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2229 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2231 return ad->data->domain_id;
2235 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2237 MonoDomain *old_domain = mono_domain_get();
2239 if (!mono_domain_set (ad->data, FALSE)) {
2240 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2244 return old_domain->domain;
2248 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2250 MonoDomain *current_domain = mono_domain_get ();
2251 MonoDomain *domain = mono_domain_get_by_id (domainid);
2253 if (!domain || !mono_domain_set (domain, FALSE)) {
2254 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2258 return current_domain->domain;
2262 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2264 mono_thread_push_appdomain_ref (ad->data);
2268 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2270 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2274 * Raise an exception to prevent the managed code from executing a pop
2277 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2281 mono_thread_push_appdomain_ref (domain);
2285 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2287 mono_thread_pop_appdomain_ref ();
2291 ves_icall_System_AppDomain_InternalGetContext ()
2293 return mono_context_get ();
2297 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2299 return mono_domain_get ()->default_context;
2303 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2305 MonoAppContext *old_context = mono_context_get ();
2307 mono_context_set (mc);
2313 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2315 MonoDomain* mono_root_domain = mono_get_root_domain ();
2316 mono_domain_lock (mono_root_domain);
2317 if (process_guid_set) {
2318 mono_domain_unlock (mono_root_domain);
2320 MonoString *res = NULL;
2321 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2322 mono_error_set_pending_exception (&error);
2325 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2326 process_guid_set = TRUE;
2327 mono_domain_unlock (mono_root_domain);
2332 mono_domain_is_unloading (MonoDomain *domain)
2334 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2341 clear_cached_vtable (MonoVTable *vtable)
2343 MonoClass *klass = vtable->klass;
2344 MonoDomain *domain = vtable->domain;
2345 MonoClassRuntimeInfo *runtime_info;
2348 runtime_info = klass->runtime_info;
2349 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2350 runtime_info->domain_vtables [domain->domain_id] = NULL;
2351 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2352 mono_gc_free_fixed (data);
2355 static G_GNUC_UNUSED void
2356 zero_static_data (MonoVTable *vtable)
2358 MonoClass *klass = vtable->klass;
2361 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2362 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2365 typedef struct unload_data {
2368 char *failure_reason;
2373 unload_data_unref (unload_data *data)
2377 mono_atomic_load_acquire (count, gint32, &data->refcount);
2378 g_assert (count >= 1 && count <= 2);
2383 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2387 deregister_reflection_info_roots_from_list (MonoImage *image)
2389 GSList *list = image->reflection_info_unregister_classes;
2392 MonoClass *klass = (MonoClass *)list->data;
2394 mono_class_free_ref_info (klass);
2399 image->reflection_info_unregister_classes = NULL;
2403 deregister_reflection_info_roots (MonoDomain *domain)
2407 mono_domain_assemblies_lock (domain);
2408 for (list = domain->domain_assemblies; list; list = list->next) {
2409 MonoAssembly *assembly = (MonoAssembly *)list->data;
2410 MonoImage *image = assembly->image;
2414 * No need to take the image lock here since dynamic images are appdomain bound and
2415 * at this point the mutator is gone. Taking the image lock here would mean
2416 * promoting it from a simple lock to a complex lock, which we better avoid if
2419 if (image_is_dynamic (image))
2420 deregister_reflection_info_roots_from_list (image);
2422 for (i = 0; i < image->module_count; ++i) {
2423 MonoImage *module = image->modules [i];
2424 if (module && image_is_dynamic (module))
2425 deregister_reflection_info_roots_from_list (module);
2428 mono_domain_assemblies_unlock (domain);
2431 static guint32 WINAPI
2432 unload_thread_main (void *arg)
2435 unload_data *data = (unload_data*)arg;
2436 MonoDomain *domain = data->domain;
2440 /* Have to attach to the runtime so shutdown can wait for this thread */
2441 /* Force it to be attached to avoid racing during shutdown. */
2442 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2443 if (!is_ok (&error)) {
2444 data->failure_reason = g_strdup (mono_error_get_message (&error));
2445 mono_error_cleanup (&error);
2448 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2449 if (!is_ok (&error)) {
2450 data->failure_reason = g_strdup (mono_error_get_message (&error));
2451 mono_error_cleanup (&error);
2456 * FIXME: Abort our parent thread last, so we can return a failure
2457 * indication if aborting times out.
2459 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2460 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2464 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2465 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2469 /* Finalize all finalizable objects in the doomed appdomain */
2470 if (!mono_domain_finalize (domain, -1)) {
2471 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2475 /* Clear references to our vtables in class->runtime_info.
2476 * We also hold the loader lock because we're going to change
2477 * class->runtime_info.
2480 mono_loader_lock (); //FIXME why do we need the loader lock here?
2481 mono_domain_lock (domain);
2484 * We need to make sure that we don't have any remsets
2485 * pointing into static data of the to-be-freed domain because
2486 * at the next collections they would be invalid. So what we
2487 * do is we first zero all static data and then do a minor
2488 * collection. Because all references in the static data will
2489 * now be null we won't do any unnecessary copies and after
2490 * the collection there won't be any more remsets.
2492 for (i = 0; i < domain->class_vtable_array->len; ++i)
2493 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2494 mono_gc_collect (0);
2496 for (i = 0; i < domain->class_vtable_array->len; ++i)
2497 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2498 deregister_reflection_info_roots (domain);
2500 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2502 mono_domain_unlock (domain);
2503 mono_loader_unlock ();
2505 mono_threads_clear_cached_culture (domain);
2507 domain->state = MONO_APPDOMAIN_UNLOADED;
2509 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2511 /* remove from the handle table the items related to this domain */
2512 mono_gchandle_free_domain (domain);
2514 mono_domain_free (domain, FALSE);
2516 mono_gc_collect (mono_gc_max_generation ());
2518 mono_atomic_store_release (&data->done, TRUE);
2519 unload_data_unref (data);
2520 mono_thread_detach (thread);
2524 mono_atomic_store_release (&data->done, TRUE);
2525 unload_data_unref (data);
2526 mono_thread_detach (thread);
2531 * mono_domain_unload:
2532 * @domain: The domain to unload
2534 * Unloads an appdomain. Follows the process outlined in the comment
2535 * for mono_domain_try_unload.
2538 mono_domain_unload (MonoDomain *domain)
2540 MonoObject *exc = NULL;
2541 mono_domain_try_unload (domain, &exc);
2545 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2550 result = WaitForSingleObjectEx (handle, timeout, alertable);
2557 * mono_domain_unload:
2558 * @domain: The domain to unload
2559 * @exc: Exception information
2561 * Unloads an appdomain. Follows the process outlined in:
2562 * http://blogs.gotdotnet.com/cbrumme
2564 * If doing things the 'right' way is too hard or complex, we do it the
2565 * 'simple' way, which means do everything needed to avoid crashes and
2566 * memory leaks, but not much else.
2568 * It is required to pass a valid reference to the exc argument, upon return
2569 * from this function *exc will be set to the exception thrown, if any.
2571 * If this method is not called from an icall (embedded scenario for instance),
2572 * it must not be called with any managed frames on the stack, since the unload
2573 * process could end up trying to abort the current thread.
2576 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2579 HANDLE thread_handle;
2580 MonoAppDomainState prev_state;
2582 unload_data *thread_data;
2583 MonoNativeThreadId tid;
2584 MonoDomain *caller_domain = mono_domain_get ();
2586 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2588 /* Atomically change our state to UNLOADING */
2589 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2590 MONO_APPDOMAIN_UNLOADING_START,
2591 MONO_APPDOMAIN_CREATED);
2592 if (prev_state != MONO_APPDOMAIN_CREATED) {
2593 switch (prev_state) {
2594 case MONO_APPDOMAIN_UNLOADING_START:
2595 case MONO_APPDOMAIN_UNLOADING:
2596 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2598 case MONO_APPDOMAIN_UNLOADED:
2599 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2602 g_warning ("Invalid appdomain state %d", prev_state);
2603 g_assert_not_reached ();
2607 mono_domain_set (domain, FALSE);
2608 /* Notify OnDomainUnload listeners */
2609 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2612 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2614 if (!mono_error_ok (&error)) {
2616 mono_error_cleanup (&error);
2618 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2622 /* Roll back the state change */
2623 domain->state = MONO_APPDOMAIN_CREATED;
2624 mono_domain_set (caller_domain, FALSE);
2627 mono_domain_set (caller_domain, FALSE);
2629 thread_data = g_new0 (unload_data, 1);
2630 thread_data->domain = domain;
2631 thread_data->failure_reason = NULL;
2632 thread_data->done = FALSE;
2633 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2635 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2636 domain->state = MONO_APPDOMAIN_UNLOADING;
2638 * First we create a separate thread for unloading, since
2639 * we might have to abort some threads, including the current one.
2641 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2642 if (thread_handle == NULL)
2644 mono_thread_info_resume (tid);
2646 /* Wait for the thread */
2647 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2648 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2649 /* The unload thread tries to abort us */
2650 /* The icall wrapper will execute the abort */
2651 CloseHandle (thread_handle);
2652 unload_data_unref (thread_data);
2656 CloseHandle (thread_handle);
2658 if (thread_data->failure_reason) {
2659 /* Roll back the state change */
2660 domain->state = MONO_APPDOMAIN_CREATED;
2662 g_warning ("%s", thread_data->failure_reason);
2664 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2666 g_free (thread_data->failure_reason);
2667 thread_data->failure_reason = NULL;
2670 unload_data_unref (thread_data);