2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
13 #undef ASSEMBLY_LOAD_DEBUG
19 #include <sys/types.h>
21 #ifdef HAVE_SYS_TIME_H
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
35 #include <mono/metadata/gc-internals.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/threadpool-ms.h>
43 #include <mono/metadata/socket-io.h>
44 #include <mono/metadata/tabledefs.h>
45 #include <mono/metadata/gc-internals.h>
46 #include <mono/metadata/mono-gc.h>
47 #include <mono/metadata/marshal.h>
48 #include <mono/metadata/monitor.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/utils/mono-uri.h>
59 #include <mono/utils/mono-logger-internals.h>
60 #include <mono/utils/mono-path.h>
61 #include <mono/utils/mono-stdlib.h>
62 #include <mono/utils/mono-io-portability.h>
63 #include <mono/utils/mono-error-internals.h>
64 #include <mono/utils/atomic.h>
65 #include <mono/utils/mono-memory-model.h>
66 #include <mono/utils/mono-threads.h>
72 * This is the version number of the corlib-runtime interface. When
73 * making changes to this interface (by changing the layout
74 * of classes the runtime knows about, changing icall signature or
75 * semantics etc), increment this variable. Also increment the
76 * pair of this variable in mscorlib in:
77 * mcs/class/corlib/System/Environment.cs
79 * Changes which are already detected at runtime, like the addition
80 * of icalls, do not require an increment.
82 #define MONO_CORLIB_VERSION 140
87 int assemblybinding_count;
92 static gunichar2 process_guid [36];
93 static gboolean process_guid_set = FALSE;
95 static gboolean no_exec = FALSE;
98 mono_domain_assembly_preload (MonoAssemblyName *aname,
99 gchar **assemblies_path,
102 static MonoAssembly *
103 mono_domain_assembly_search (MonoAssemblyName *aname,
107 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
110 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
112 static MonoAppDomain *
113 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
116 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
118 static MonoLoadFunc load_function = NULL;
121 mono_install_runtime_load (MonoLoadFunc func)
123 load_function = func;
127 mono_runtime_load (const char *filename, const char *runtime_version)
129 g_assert (load_function);
130 return load_function (filename, runtime_version);
134 * mono_runtime_set_no_exec:
136 * Instructs the runtime to operate in static mode, i.e. avoid/do not
137 * allow managed code execution. This is useful for running the AOT
138 * compiler on platforms which allow full-aot execution only. This
139 * should be called before mono_runtime_init ().
142 mono_runtime_set_no_exec (gboolean val)
148 * mono_runtime_get_no_exec:
150 * If true, then the runtime will not allow managed code execution.
153 mono_runtime_get_no_exec (void)
159 create_domain_objects (MonoDomain *domain)
162 MonoDomain *old_domain = mono_domain_get ();
164 MonoVTable *string_vt;
165 MonoClassField *string_empty_fld;
167 if (domain != old_domain) {
168 mono_thread_push_appdomain_ref (domain);
169 mono_domain_set_internal_with_options (domain, FALSE);
173 * Initialize String.Empty. This enables the removal of
174 * the static cctor of the String class.
176 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
177 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
178 g_assert (string_empty_fld);
179 mono_field_static_set_value (string_vt, string_empty_fld, mono_string_intern (mono_string_new (domain, "")));
182 * Create an instance early since we can't do it when there is no memory.
184 arg = mono_string_new (domain, "Out of memory");
185 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
188 * These two are needed because the signal handlers might be executing on
189 * an alternate stack, and Boehm GC can't handle that.
191 arg = mono_string_new (domain, "A null value was found where an object instance was required");
192 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
193 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
194 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
196 /*The ephemeron tombstone i*/
197 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
198 mono_error_assert_ok (&error);
200 if (domain != old_domain) {
201 mono_thread_pop_appdomain_ref ();
202 mono_domain_set_internal_with_options (old_domain, FALSE);
206 * This class is used during exception handling, so initialize it here, to prevent
207 * stack overflows while handling stack overflows.
209 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
214 * @domain: domain returned by mono_init ()
216 * Initialize the core AppDomain: this function will run also some
217 * IL initialization code, so it needs the execution engine to be fully
220 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
221 * we know the entry_assembly.
225 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
226 MonoThreadAttachCB attach_cb)
229 MonoAppDomainSetup *setup;
233 mono_portability_helpers_init ();
235 mono_gc_base_init ();
236 mono_monitor_init ();
237 mono_marshal_init ();
239 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
240 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
241 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
242 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
243 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
244 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
245 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
246 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
248 mono_thread_init (start_cb, attach_cb);
250 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
251 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, &error);
252 mono_error_raise_exception (&error); /* FIXME don't raise here */
254 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
255 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, &error);
256 mono_error_raise_exception (&error); /* FIXME don't raise here */
259 domain->setup = setup;
261 mono_thread_attach (domain);
263 mono_type_initialization_init ();
265 if (!mono_runtime_get_no_exec ())
266 create_domain_objects (domain);
268 /* GC init has to happen after thread init */
271 /* contexts use GC handles, so they must be initialized after the GC */
272 mono_context_init (domain);
273 mono_context_set (domain->default_context);
275 #ifndef DISABLE_SOCKETS
276 mono_network_init ();
279 mono_console_init ();
282 mono_locks_tracer_init ();
284 /* mscorlib is loaded before we install the load hook */
285 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
291 mono_get_corlib_version (void)
294 MonoClassField *field;
297 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
298 mono_class_init (klass);
299 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
302 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
304 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
305 return *(gint32*)((gchar*)value + sizeof (MonoObject));
309 * mono_check_corlib_version
311 * Checks that the corlib that is loaded matches the version of this runtime.
313 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
314 * allocated string with the error otherwise.
317 mono_check_corlib_version (void)
319 int version = mono_get_corlib_version ();
320 if (version != MONO_CORLIB_VERSION)
321 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
328 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
330 * Initializes the @domain's default System.Runtime.Remoting's Context.
333 mono_context_init (MonoDomain *domain)
337 MonoAppContext *context;
339 klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
340 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, &error);
341 mono_error_raise_exception (&error); /* FIXME don't raise here */
342 context->domain_id = domain->domain_id;
343 context->context_id = 0;
344 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
345 domain->default_context = context;
349 * mono_runtime_cleanup:
354 * This must not be called while there are still running threads executing
358 mono_runtime_cleanup (MonoDomain *domain)
360 mono_attach_cleanup ();
362 /* This ends up calling any pending pending (for at most 2 seconds) */
365 mono_thread_cleanup ();
367 #ifndef DISABLE_SOCKETS
368 mono_network_cleanup ();
370 mono_marshal_cleanup ();
372 mono_type_initialization_cleanup ();
374 mono_monitor_cleanup ();
377 static MonoDomainFunc quit_function = NULL;
380 mono_install_runtime_cleanup (MonoDomainFunc func)
382 quit_function = func;
388 if (quit_function != NULL)
389 quit_function (mono_get_root_domain (), NULL);
393 * mono_domain_create_appdomain:
394 * @friendly_name: The friendly name of the appdomain to create
395 * @configuration_file: The configuration file to initialize the appdomain with
397 * Returns a MonoDomain initialized with the appdomain
400 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
404 MonoAppDomainSetup *setup;
407 klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
408 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
409 mono_error_raise_exception (&error); /* FIXME don't raise here */
410 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
412 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
413 mono_error_raise_exception (&error); /* FIXME don't raise here */
415 return mono_domain_from_appdomain (ad);
419 * mono_domain_set_config:
420 * @domain: MonoDomain initialized with the appdomain we want to change
421 * @base_dir: new base directory for the appdomain
422 * @config_file_name: path to the new configuration for the app domain
424 * Used to set the system configuration for an appdomain
426 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
427 * Error Initializing the configuration system. ---> System.ArgumentException:
428 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
431 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
433 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
434 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
437 static MonoAppDomainSetup*
438 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
441 MonoDomain *caller_domain = mono_domain_get ();
442 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
443 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, &error);
444 mono_error_raise_exception (&error); /* FIXME don't raise here */
446 mono_domain_set_internal (domain);
448 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
449 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
450 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
451 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
452 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
453 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
454 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
455 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
456 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
457 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
458 copy->publisher_policy = setup->publisher_policy;
459 copy->path_changed = setup->path_changed;
460 copy->loader_optimization = setup->loader_optimization;
461 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
462 copy->disallow_code_downloads = setup->disallow_code_downloads;
463 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
464 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
465 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
466 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
467 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
469 mono_domain_set_internal (caller_domain);
474 static MonoAppDomain *
475 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
480 char *shadow_location;
482 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
484 /* FIXME: pin all those objects */
485 data = mono_domain_create();
487 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
488 if (!mono_error_ok (error)) return NULL;
491 data->friendly_name = g_strdup (friendly_name);
493 mono_profiler_appdomain_name (data, data->friendly_name);
495 if (!setup->application_base) {
496 /* Inherit from the root domain since MS.NET does this */
497 MonoDomain *root = mono_get_root_domain ();
498 if (root->setup->application_base)
499 MONO_OBJECT_SETREF (setup, application_base, mono_string_new_utf16 (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base)));
502 mono_context_init (data);
504 data->setup = copy_app_domain_setup (data, setup);
505 mono_domain_set_options_from_config (data);
506 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
508 #ifndef DISABLE_SHADOW_COPY
509 /*FIXME, guard this for when the debugger is not running */
510 shadow_location = get_shadow_assembly_location_base (data, error);
511 if (!mono_error_ok (error))
514 g_free (shadow_location);
517 create_domain_objects (data);
523 * mono_domain_has_type_resolve:
524 * @domain: application domains being looked up
526 * Returns true if the AppDomain.TypeResolve field has been
530 mono_domain_has_type_resolve (MonoDomain *domain)
532 static MonoClassField *field = NULL;
536 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
540 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
544 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
549 * mono_domain_try_type_resolve:
550 * @domain: application domainwhere the name where the type is going to be resolved
551 * @name: the name of the type to resolve or NULL.
552 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
554 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
555 * the assembly that matches name.
557 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
559 * Returns: A MonoReflectionAssembly or NULL if not found
561 MonoReflectionAssembly *
562 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
566 static MonoMethod *method = NULL;
568 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
570 if (method == NULL) {
571 klass = domain->domain->mbr.obj.vtable->klass;
574 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
575 if (method == NULL) {
576 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
582 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
585 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
589 * mono_domain_owns_vtable_slot:
591 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
594 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
598 mono_domain_lock (domain);
599 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
600 mono_domain_unlock (domain);
607 * @force: force setting.
609 * Set the current appdomain to @domain. If @force is set, set it even
610 * if it is being unloaded.
614 * FALSE if the domain is unloaded
617 mono_domain_set (MonoDomain *domain, gboolean force)
619 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
622 mono_domain_set_internal (domain);
628 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
634 MONO_CHECK_ARG_NULL (name, NULL);
640 str = mono_string_to_utf8 (name);
642 mono_domain_lock (add);
644 if (!strcmp (str, "APPBASE"))
645 o = (MonoObject *)add->setup->application_base;
646 else if (!strcmp (str, "APP_CONFIG_FILE"))
647 o = (MonoObject *)add->setup->configuration_file;
648 else if (!strcmp (str, "DYNAMIC_BASE"))
649 o = (MonoObject *)add->setup->dynamic_base;
650 else if (!strcmp (str, "APP_NAME"))
651 o = (MonoObject *)add->setup->application_name;
652 else if (!strcmp (str, "CACHE_BASE"))
653 o = (MonoObject *)add->setup->cache_path;
654 else if (!strcmp (str, "PRIVATE_BINPATH"))
655 o = (MonoObject *)add->setup->private_bin_path;
656 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
657 o = (MonoObject *)add->setup->private_bin_path_probe;
658 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
659 o = (MonoObject *)add->setup->shadow_copy_directories;
660 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
661 o = (MonoObject *)add->setup->shadow_copy_files;
663 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
665 mono_domain_unlock (add);
675 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
679 MONO_CHECK_ARG_NULL (name,);
685 mono_domain_lock (add);
687 mono_g_hash_table_insert (add->env, name, data);
689 mono_domain_unlock (add);
693 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
698 return ad->data->setup;
702 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
707 return mono_string_new (ad->data, ad->data->friendly_name);
711 ves_icall_System_AppDomain_getCurDomain ()
713 MonoDomain *add = mono_domain_get ();
719 ves_icall_System_AppDomain_getRootDomain ()
721 MonoDomain *root = mono_get_root_domain ();
727 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
729 MonoDomain *domain = mono_domain_get ();
731 return domain->throw_unobserved_task_exceptions;
735 get_attribute_value (const gchar **attribute_names,
736 const gchar **attribute_values,
737 const char *att_name)
740 for (n = 0; attribute_names [n] != NULL; n++) {
741 if (strcmp (attribute_names [n], att_name) == 0)
742 return g_strdup (attribute_values [n]);
748 start_element (GMarkupParseContext *context,
749 const gchar *element_name,
750 const gchar **attribute_names,
751 const gchar **attribute_values,
755 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
757 if (strcmp (element_name, "runtime") == 0) {
758 runtime_config->runtime_count++;
762 if (strcmp (element_name, "assemblyBinding") == 0) {
763 runtime_config->assemblybinding_count++;
767 if (runtime_config->runtime_count != 1)
770 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
771 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
773 if (value && g_ascii_strcasecmp (value, "true") == 0)
774 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
777 if (runtime_config->assemblybinding_count != 1)
780 if (strcmp (element_name, "probing") != 0)
783 g_free (runtime_config->domain->private_bin_path);
784 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
785 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
786 g_free (runtime_config->domain->private_bin_path);
787 runtime_config->domain->private_bin_path = NULL;
793 end_element (GMarkupParseContext *context,
794 const gchar *element_name,
798 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
799 if (strcmp (element_name, "runtime") == 0)
800 runtime_config->runtime_count--;
801 else if (strcmp (element_name, "assemblyBinding") == 0)
802 runtime_config->assemblybinding_count--;
806 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
808 RuntimeConfig *state = (RuntimeConfig *)user_data;
810 const gchar *filename;
812 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
813 msg = error && error->message ? error->message : "";
814 g_warning ("Error parsing %s: %s", filename, msg);
817 static const GMarkupParser
827 mono_domain_set_options_from_config (MonoDomain *domain)
830 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
832 GMarkupParseContext *context;
833 RuntimeConfig runtime_config;
836 if (!domain || !domain->setup || !domain->setup->configuration_file)
839 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
840 if (!mono_error_ok (&error)) {
841 mono_error_cleanup (&error);
845 config_file_path = mono_portability_find_file (config_file_name, TRUE);
846 if (!config_file_path)
847 config_file_path = config_file_name;
849 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
852 runtime_config.runtime_count = 0;
853 runtime_config.assemblybinding_count = 0;
854 runtime_config.domain = domain;
855 runtime_config.filename = config_file_path;
858 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
859 offset = 3; /* Skip UTF-8 BOM */
861 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
862 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
863 g_markup_parse_context_end_parse (context, NULL);
864 g_markup_parse_context_free (context);
868 if (config_file_name != config_file_path)
869 g_free (config_file_name);
870 g_free (config_file_path);
874 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
876 #ifdef DISABLE_APPDOMAINS
877 mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
884 fname = mono_string_to_utf8 (friendly_name);
885 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
889 mono_error_raise_exception (&error);
896 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
898 MonoDomain *domain = ad->data;
900 static MonoClass *System_Reflection_Assembly;
904 GPtrArray *assemblies;
906 if (!System_Reflection_Assembly)
907 System_Reflection_Assembly = mono_class_from_name (
908 mono_defaults.corlib, "System.Reflection", "Assembly");
911 * Make a copy of the list of assemblies because we can't hold the assemblies
912 * lock while creating objects etc.
914 assemblies = g_ptr_array_new ();
915 /* Need to skip internal assembly builders created by remoting */
916 mono_domain_assemblies_lock (domain);
917 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
918 ass = (MonoAssembly *)tmp->data;
919 if (refonly != ass->ref_only)
921 if (ass->corlib_internal)
923 g_ptr_array_add (assemblies, ass);
925 mono_domain_assemblies_unlock (domain);
927 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
928 for (i = 0; i < assemblies->len; ++i) {
929 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
930 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
933 g_ptr_array_free (assemblies, TRUE);
938 MonoReflectionAssembly *
939 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
943 MonoBoolean isrefonly;
946 if (mono_runtime_get_no_exec ())
949 g_assert (domain != NULL && fname != NULL);
951 klass = domain->domain->mbr.obj.vtable->klass;
954 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
955 if (method == NULL) {
956 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
960 isrefonly = refonly ? 1 : 0;
962 params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
963 params [2] = &isrefonly;
964 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
968 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
971 MonoReflectionAssembly *assembly;
972 MonoDomain *domain = mono_domain_get ();
976 aname_str = mono_stringify_assembly_name (aname);
978 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
979 str = mono_string_new (domain, aname_str);
984 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
988 return assembly->assembly;
994 * LOCKING: assumes assemblies_lock in the domain is already locked.
997 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1001 gboolean destroy_ht = FALSE;
1003 if (!ass->aname.name)
1007 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1011 /* FIXME: handle lazy loaded assemblies */
1012 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1013 g_hash_table_insert (ht, tmp->data, tmp->data);
1015 if (!g_hash_table_lookup (ht, ass)) {
1016 mono_assembly_addref (ass);
1017 g_hash_table_insert (ht, ass, ass);
1018 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1019 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);
1022 if (ass->image->references) {
1023 for (i = 0; ass->image->references [i] != NULL; i++) {
1024 if (ass->image->references [i] != REFERENCE_MISSING)
1025 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1026 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1031 g_hash_table_destroy (ht);
1035 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1037 static MonoClassField *assembly_load_field;
1038 static MonoMethod *assembly_load_method;
1039 MonoDomain *domain = mono_domain_get ();
1040 MonoReflectionAssembly *ref_assembly;
1042 gpointer load_value;
1045 if (!domain->domain)
1046 /* This can happen during startup */
1048 #ifdef ASSEMBLY_LOAD_DEBUG
1049 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1051 klass = domain->domain->mbr.obj.vtable->klass;
1053 mono_domain_assemblies_lock (domain);
1054 add_assemblies_to_domain (domain, assembly, NULL);
1055 mono_domain_assemblies_unlock (domain);
1057 if (assembly_load_field == NULL) {
1058 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1059 g_assert (assembly_load_field);
1062 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1063 if (load_value == NULL) {
1064 /* No events waiting to be triggered */
1068 ref_assembly = mono_assembly_get_object (domain, assembly);
1069 g_assert (ref_assembly);
1071 if (assembly_load_method == NULL) {
1072 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1073 g_assert (assembly_load_method);
1076 *params = ref_assembly;
1077 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1081 * LOCKING: Acquires the domain assemblies lock.
1084 set_domain_search_path (MonoDomain *domain)
1087 MonoAppDomainSetup *setup;
1089 gchar *search_path = NULL;
1092 gchar **pvt_split = NULL;
1093 GError *gerror = NULL;
1094 gint appbaselen = -1;
1097 * We use the low-level domain assemblies lock, since this is called from
1098 * assembly loads hooks, which means this thread might hold the loader lock.
1100 mono_domain_assemblies_lock (domain);
1102 if (!domain->setup) {
1103 mono_domain_assemblies_unlock (domain);
1107 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1108 mono_domain_assemblies_unlock (domain);
1111 setup = domain->setup;
1112 if (!setup->application_base) {
1113 mono_domain_assemblies_unlock (domain);
1114 return; /* Must set application base to get private path working */
1119 if (setup->private_bin_path) {
1120 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1121 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1122 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1123 mono_error_cleanup (&error);
1124 mono_domain_assemblies_unlock (domain);
1129 if (domain->private_bin_path) {
1130 if (search_path == NULL)
1131 search_path = domain->private_bin_path;
1133 gchar *tmp2 = search_path;
1134 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1141 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1142 * directories relative to ApplicationBase separated by semicolons (see
1143 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1144 * The loop below copes with the fact that some Unix applications may use ':' (or
1145 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1146 * ';' for the subsequent split.
1148 * The issue was reported in bug #81446
1151 #ifndef TARGET_WIN32
1154 slen = strlen (search_path);
1155 for (i = 0; i < slen; i++)
1156 if (search_path [i] == ':')
1157 search_path [i] = ';';
1160 pvt_split = g_strsplit (search_path, ";", 1000);
1161 g_free (search_path);
1162 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1167 g_strfreev (pvt_split);
1169 * Don't do this because the first time is called, the domain
1170 * setup is not finished.
1172 * domain->search_path = g_malloc (sizeof (char *));
1173 * domain->search_path [0] = NULL;
1175 mono_domain_assemblies_unlock (domain);
1179 if (domain->search_path)
1180 g_strfreev (domain->search_path);
1182 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1183 tmp [npaths] = NULL;
1185 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1186 if (!mono_error_ok (&error)) {
1187 mono_error_cleanup (&error);
1188 g_strfreev (pvt_split);
1191 mono_domain_assemblies_unlock (domain);
1195 domain->search_path = tmp;
1197 /* FIXME: is this needed? */
1198 if (strncmp (*tmp, "file://", 7) == 0) {
1204 uri = g_strdup_printf ("file:///%s", uri + 7);
1207 uri = mono_escape_uri_string (tmpuri);
1208 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1214 if (gerror != NULL) {
1215 g_warning ("%s\n", gerror->message);
1216 g_error_free (gerror);
1223 for (i = 1; pvt_split && i < npaths; i++) {
1224 if (g_path_is_absolute (pvt_split [i - 1])) {
1225 tmp [i] = g_strdup (pvt_split [i - 1]);
1227 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1230 if (strchr (tmp [i], '.')) {
1234 reduced = mono_path_canonicalize (tmp [i]);
1235 if (appbaselen == -1)
1236 appbaselen = strlen (tmp [0]);
1238 if (strncmp (tmp [0], reduced, appbaselen)) {
1241 tmp [i] = g_strdup ("");
1251 if (setup->private_bin_path_probe != NULL) {
1253 tmp [0] = g_strdup ("");
1256 domain->setup->path_changed = FALSE;
1258 g_strfreev (pvt_split);
1260 mono_domain_assemblies_unlock (domain);
1263 #ifdef DISABLE_SHADOW_COPY
1265 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1271 mono_make_shadow_copy (const char *filename, MonoError *error)
1273 mono_error_init (error);
1274 return (char *) filename;
1278 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1280 guint16 *orig, *dest;
1281 gboolean copy_result;
1283 strcpy (src + srclen - tail_len, extension);
1285 if (IS_PORTABILITY_CASE) {
1286 gchar *file = mono_portability_find_file (src, TRUE);
1292 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1296 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1298 strcpy (target + targetlen - tail_len, extension);
1299 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1302 copy_result = CopyFile (orig, dest, FALSE);
1304 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1305 * overwritten when updated in their original locations. */
1307 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1316 get_cstring_hash (const char *str)
1322 if (!str || !str [0])
1327 for (i = 0; i < len; i++) {
1328 h = (h << 5) - h + *p;
1336 * Returned memory is malloc'd. Called must free it
1339 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1341 MonoAppDomainSetup *setup;
1342 char *cache_path, *appname;
1346 mono_error_init (error);
1348 setup = domain->setup;
1349 if (setup->cache_path != NULL && setup->application_name != NULL) {
1350 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1351 return_val_if_nok (error, NULL);
1353 #ifndef TARGET_WIN32
1356 for (i = strlen (cache_path) - 1; i >= 0; i--)
1357 if (cache_path [i] == '\\')
1358 cache_path [i] = '/';
1362 appname = mono_string_to_utf8_checked (setup->application_name, error);
1363 if (!mono_error_ok (error)) {
1364 g_free (cache_path);
1368 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1370 g_free (cache_path);
1372 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1373 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1380 get_shadow_assembly_location (const char *filename, MonoError *error)
1382 gint32 hash = 0, hash2 = 0;
1384 char path_hash [30];
1385 char *bname = g_path_get_basename (filename);
1386 char *dirname = g_path_get_dirname (filename);
1387 char *location, *tmploc;
1388 MonoDomain *domain = mono_domain_get ();
1390 mono_error_init (error);
1392 hash = get_cstring_hash (bname);
1393 hash2 = get_cstring_hash (dirname);
1394 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1395 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1396 tmploc = get_shadow_assembly_location_base (domain, error);
1397 if (!mono_error_ok (error)) {
1403 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1411 ensure_directory_exists (const char *filename)
1414 gchar *dir_utf8 = g_path_get_dirname (filename);
1416 gunichar2 *dir_utf16 = NULL;
1419 if (!dir_utf8 || !dir_utf8 [0])
1422 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1430 /* make life easy and only use one directory seperator */
1441 while (*p++ != '\\')
1447 p = wcschr (p, '\\');
1450 retval = _wmkdir (dir_utf16);
1451 if (retval != 0 && errno != EEXIST) {
1464 gchar *dir = g_path_get_dirname (filename);
1468 if (!dir || !dir [0]) {
1473 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1483 p = strchr (p, '/');
1486 retval = mkdir (dir, 0777);
1487 if (retval != 0 && errno != EEXIST) {
1502 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1504 struct stat sbuf_dest;
1506 gchar *real_src = mono_portability_find_file (src, TRUE);
1509 stat_src = (gchar*)src;
1511 stat_src = real_src;
1513 if (stat (stat_src, sbuf_src) == -1) {
1514 time_t tnow = time (NULL);
1519 memset (sbuf_src, 0, sizeof (*sbuf_src));
1520 sbuf_src->st_mtime = tnow;
1521 sbuf_src->st_atime = tnow;
1528 if (stat (dest, &sbuf_dest) == -1)
1531 if (sbuf_src->st_size == sbuf_dest.st_size &&
1532 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1539 shadow_copy_create_ini (const char *shadow, const char *filename)
1549 dir_name = g_path_get_dirname (shadow);
1550 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1552 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1557 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1562 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1563 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1565 if (handle == INVALID_HANDLE_VALUE) {
1569 full_path = mono_path_resolve_symlinks (filename);
1570 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1572 CloseHandle (handle);
1577 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1580 MonoAppDomainSetup *setup;
1583 gchar **directories;
1584 gchar *shadow_status_string;
1586 gboolean shadow_enabled;
1587 gboolean found = FALSE;
1592 setup = domain->setup;
1593 if (setup == NULL || setup->shadow_copy_files == NULL)
1596 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1597 if (!mono_error_ok (&error)) {
1598 mono_error_cleanup (&error);
1601 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1602 g_free (shadow_status_string);
1604 if (!shadow_enabled)
1607 if (setup->shadow_copy_directories == NULL)
1610 /* Is dir_name a shadow_copy destination already? */
1611 base_dir = get_shadow_assembly_location_base (domain, &error);
1612 if (!mono_error_ok (&error)) {
1613 mono_error_cleanup (&error);
1617 if (strstr (dir_name, base_dir)) {
1623 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1624 if (!mono_error_ok (&error)) {
1625 mono_error_cleanup (&error);
1629 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1630 dir_ptr = directories;
1632 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1638 g_strfreev (directories);
1644 This function raises exceptions so it can cause as sorts of nasty stuff if called
1645 while holding a lock.
1646 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1647 or NULL if source file not found.
1648 FIXME bubble up the error instead of raising it here
1651 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1654 gchar *sibling_source, *sibling_target;
1655 gint sibling_source_len, sibling_target_len;
1656 guint16 *orig, *dest;
1659 gboolean copy_result;
1660 struct stat src_sbuf;
1661 struct utimbuf utbuf;
1662 char *dir_name = g_path_get_dirname (filename);
1663 MonoDomain *domain = mono_domain_get ();
1666 mono_error_init (oerror);
1668 set_domain_search_path (domain);
1670 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1672 return (char *) filename;
1675 /* Is dir_name a shadow_copy destination already? */
1676 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1677 if (!mono_error_ok (&error)) {
1678 mono_error_cleanup (&error);
1680 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1684 if (strstr (dir_name, shadow_dir)) {
1685 g_free (shadow_dir);
1687 return (char *) filename;
1689 g_free (shadow_dir);
1692 shadow = get_shadow_assembly_location (filename, &error);
1693 if (!mono_error_ok (&error)) {
1694 mono_error_cleanup (&error);
1695 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1699 if (ensure_directory_exists (shadow) == FALSE) {
1701 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1705 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1706 return (char*) shadow;
1708 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1709 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1712 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1713 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1714 * and not have it runtime error" */
1715 attrs = GetFileAttributes (orig);
1716 if (attrs == INVALID_FILE_ATTRIBUTES) {
1718 return (char *)filename;
1721 copy_result = CopyFile (orig, dest, FALSE);
1723 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1724 * overwritten when updated in their original locations. */
1726 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1731 if (copy_result == FALSE) {
1734 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1735 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1736 return NULL; /* file not found, shadow copy failed */
1738 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1742 /* attempt to copy .mdb, .config if they exist */
1743 sibling_source = g_strconcat (filename, ".config", NULL);
1744 sibling_source_len = strlen (sibling_source);
1745 sibling_target = g_strconcat (shadow, ".config", NULL);
1746 sibling_target_len = strlen (sibling_target);
1748 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1749 if (copy_result == TRUE)
1750 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1752 g_free (sibling_source);
1753 g_free (sibling_target);
1755 if (copy_result == FALSE) {
1757 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1761 /* Create a .ini file containing the original assembly location */
1762 if (!shadow_copy_create_ini (shadow, filename)) {
1764 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1768 utbuf.actime = src_sbuf.st_atime;
1769 utbuf.modtime = src_sbuf.st_mtime;
1770 utime (shadow, &utbuf);
1774 #endif /* DISABLE_SHADOW_COPY */
1777 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1779 if (appdomain == NULL)
1782 return appdomain->data;
1786 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1787 const gchar *path3, const gchar *path4,
1788 gboolean refonly, gboolean is_private)
1791 gboolean found = FALSE;
1794 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1796 if (IS_PORTABILITY_SET) {
1797 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1800 fullpath = new_fullpath;
1804 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1807 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1810 return (*assembly != NULL);
1813 static MonoAssembly *
1814 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1816 MonoAssembly *result = NULL;
1819 const gchar *local_culture;
1821 gboolean is_private = FALSE;
1823 if (!culture || *culture == '\0') {
1826 local_culture = culture;
1829 filename = g_strconcat (name, ".dll", NULL);
1830 len = strlen (filename);
1832 for (path = search_path; *path; path++) {
1833 if (**path == '\0') {
1835 continue; /* Ignore empty ApplicationBase */
1838 /* See test cases in bug #58992 and bug #57710 */
1839 /* 1st try: [culture]/[name].dll (culture may be empty) */
1840 strcpy (filename + len - 4, ".dll");
1841 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1844 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1845 strcpy (filename + len - 4, ".exe");
1846 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1849 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1850 strcpy (filename + len - 4, ".dll");
1851 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1854 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1855 strcpy (filename + len - 4, ".exe");
1856 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1865 * Try loading the assembly from ApplicationBase and PrivateBinPath
1866 * and then from assemblies_path if any.
1867 * LOCKING: This is called from the assembly loading code, which means the caller
1868 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1870 static MonoAssembly *
1871 mono_domain_assembly_preload (MonoAssemblyName *aname,
1872 gchar **assemblies_path,
1875 MonoDomain *domain = mono_domain_get ();
1876 MonoAssembly *result = NULL;
1877 gboolean refonly = GPOINTER_TO_UINT (user_data);
1879 set_domain_search_path (domain);
1881 if (domain->search_path && domain->search_path [0] != NULL) {
1882 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1885 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1886 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1893 * Check whenever a given assembly was already loaded in the current appdomain.
1895 static MonoAssembly *
1896 mono_domain_assembly_search (MonoAssemblyName *aname,
1899 MonoDomain *domain = mono_domain_get ();
1902 gboolean refonly = GPOINTER_TO_UINT (user_data);
1904 mono_domain_assemblies_lock (domain);
1905 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1906 ass = (MonoAssembly *)tmp->data;
1907 /* Dynamic assemblies can't match here in MS.NET */
1908 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1911 mono_domain_assemblies_unlock (domain);
1914 mono_domain_assemblies_unlock (domain);
1919 MonoReflectionAssembly *
1920 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1922 MonoDomain *domain = mono_domain_get ();
1923 char *name, *filename;
1924 MonoImageOpenStatus status = MONO_IMAGE_OK;
1927 if (fname == NULL) {
1928 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1929 mono_set_pending_exception (exc);
1933 name = filename = mono_string_to_utf8 (fname);
1935 ass = mono_assembly_open_full (filename, &status, refOnly);
1940 if (status == MONO_IMAGE_IMAGE_INVALID)
1941 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1943 exc = mono_get_exception_file_not_found2 (NULL, fname);
1945 mono_set_pending_exception (exc);
1951 return mono_assembly_get_object (domain, ass);
1954 MonoReflectionAssembly *
1955 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1956 MonoArray *raw_assembly,
1957 MonoArray *raw_symbol_store, MonoObject *evidence,
1958 MonoBoolean refonly)
1961 MonoReflectionAssembly *refass = NULL;
1962 MonoDomain *domain = ad->data;
1963 MonoImageOpenStatus status;
1964 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1965 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1968 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1972 if (raw_symbol_store != NULL)
1973 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1975 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1979 mono_image_close (image);
1980 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1984 refass = mono_assembly_get_object (domain, ass);
1985 MONO_OBJECT_SETREF (refass, evidence, evidence);
1989 MonoReflectionAssembly *
1990 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1992 MonoDomain *domain = ad->data;
1993 MonoImageOpenStatus status = MONO_IMAGE_OK;
1995 MonoAssemblyName aname;
1996 MonoReflectionAssembly *refass = NULL;
2002 name = mono_string_to_utf8 (assRef);
2003 parsed = mono_assembly_name_parse (name, &aname);
2007 /* This is a parse error... */
2009 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2013 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2014 mono_assembly_name_free (&aname);
2017 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2019 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2028 refass = mono_assembly_get_object (domain, ass);
2030 MONO_OBJECT_SETREF (refass, evidence, evidence);
2035 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2037 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2039 if (NULL == domain) {
2040 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2041 mono_set_pending_exception (exc);
2045 if (domain == mono_get_root_domain ()) {
2046 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2051 * Unloading seems to cause problems when running NUnit/NAnt, hence
2054 if (g_getenv ("MONO_NO_UNLOAD"))
2056 #ifdef __native_client__
2060 mono_domain_unload (domain);
2064 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2066 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2071 return mono_domain_is_unloading (domain);
2075 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2077 mono_unhandled_exception ((MonoObject*) exc);
2081 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2082 MonoReflectionAssembly *refass, MonoArray *args)
2089 image = refass->assembly->image;
2092 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2095 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2098 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2100 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2104 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2106 return ad->data->domain_id;
2110 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2112 MonoDomain *old_domain = mono_domain_get();
2114 if (!mono_domain_set (ad->data, FALSE)) {
2115 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2119 return old_domain->domain;
2123 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2125 MonoDomain *current_domain = mono_domain_get ();
2126 MonoDomain *domain = mono_domain_get_by_id (domainid);
2128 if (!domain || !mono_domain_set (domain, FALSE)) {
2129 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2133 return current_domain->domain;
2137 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2139 mono_thread_push_appdomain_ref (ad->data);
2143 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2145 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2149 * Raise an exception to prevent the managed code from executing a pop
2152 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2156 mono_thread_push_appdomain_ref (domain);
2160 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2162 mono_thread_pop_appdomain_ref ();
2166 ves_icall_System_AppDomain_InternalGetContext ()
2168 return mono_context_get ();
2172 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2174 return mono_domain_get ()->default_context;
2178 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2180 MonoAppContext *old_context = mono_context_get ();
2182 mono_context_set (mc);
2188 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2190 MonoDomain* mono_root_domain = mono_get_root_domain ();
2191 mono_domain_lock (mono_root_domain);
2192 if (process_guid_set) {
2193 mono_domain_unlock (mono_root_domain);
2194 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2196 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2197 process_guid_set = TRUE;
2198 mono_domain_unlock (mono_root_domain);
2203 mono_domain_is_unloading (MonoDomain *domain)
2205 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2212 clear_cached_vtable (MonoVTable *vtable)
2214 MonoClass *klass = vtable->klass;
2215 MonoDomain *domain = vtable->domain;
2216 MonoClassRuntimeInfo *runtime_info;
2219 runtime_info = klass->runtime_info;
2220 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2221 runtime_info->domain_vtables [domain->domain_id] = NULL;
2222 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2223 mono_gc_free_fixed (data);
2226 static G_GNUC_UNUSED void
2227 zero_static_data (MonoVTable *vtable)
2229 MonoClass *klass = vtable->klass;
2232 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2233 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2236 typedef struct unload_data {
2239 char *failure_reason;
2244 unload_data_unref (unload_data *data)
2248 mono_atomic_load_acquire (count, gint32, &data->refcount);
2249 g_assert (count >= 1 && count <= 2);
2254 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2258 deregister_reflection_info_roots_from_list (MonoImage *image)
2260 GSList *list = image->reflection_info_unregister_classes;
2263 MonoClass *klass = (MonoClass *)list->data;
2265 mono_class_free_ref_info (klass);
2270 image->reflection_info_unregister_classes = NULL;
2274 deregister_reflection_info_roots (MonoDomain *domain)
2278 mono_domain_assemblies_lock (domain);
2279 for (list = domain->domain_assemblies; list; list = list->next) {
2280 MonoAssembly *assembly = (MonoAssembly *)list->data;
2281 MonoImage *image = assembly->image;
2285 * No need to take the image lock here since dynamic images are appdomain bound and
2286 * at this point the mutator is gone. Taking the image lock here would mean
2287 * promoting it from a simple lock to a complex lock, which we better avoid if
2290 if (image_is_dynamic (image))
2291 deregister_reflection_info_roots_from_list (image);
2293 for (i = 0; i < image->module_count; ++i) {
2294 MonoImage *module = image->modules [i];
2295 if (module && image_is_dynamic (module))
2296 deregister_reflection_info_roots_from_list (module);
2299 mono_domain_assemblies_unlock (domain);
2302 static guint32 WINAPI
2303 unload_thread_main (void *arg)
2306 unload_data *data = (unload_data*)arg;
2307 MonoDomain *domain = data->domain;
2311 /* Have to attach to the runtime so shutdown can wait for this thread */
2312 /* Force it to be attached to avoid racing during shutdown. */
2313 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2314 mono_error_raise_exception (&error); /* FIXME don't raise here */
2317 * FIXME: Abort our parent thread last, so we can return a failure
2318 * indication if aborting times out.
2320 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2321 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2325 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2326 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2330 /* Finalize all finalizable objects in the doomed appdomain */
2331 if (!mono_domain_finalize (domain, -1)) {
2332 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2336 /* Clear references to our vtables in class->runtime_info.
2337 * We also hold the loader lock because we're going to change
2338 * class->runtime_info.
2341 mono_loader_lock (); //FIXME why do we need the loader lock here?
2342 mono_domain_lock (domain);
2345 * We need to make sure that we don't have any remsets
2346 * pointing into static data of the to-be-freed domain because
2347 * at the next collections they would be invalid. So what we
2348 * do is we first zero all static data and then do a minor
2349 * collection. Because all references in the static data will
2350 * now be null we won't do any unnecessary copies and after
2351 * the collection there won't be any more remsets.
2353 for (i = 0; i < domain->class_vtable_array->len; ++i)
2354 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2355 mono_gc_collect (0);
2357 for (i = 0; i < domain->class_vtable_array->len; ++i)
2358 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2359 deregister_reflection_info_roots (domain);
2361 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2363 mono_domain_unlock (domain);
2364 mono_loader_unlock ();
2366 mono_threads_clear_cached_culture (domain);
2368 domain->state = MONO_APPDOMAIN_UNLOADED;
2370 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2372 /* remove from the handle table the items related to this domain */
2373 mono_gchandle_free_domain (domain);
2375 mono_domain_free (domain, FALSE);
2377 mono_gc_collect (mono_gc_max_generation ());
2379 mono_atomic_store_release (&data->done, TRUE);
2380 unload_data_unref (data);
2381 mono_thread_detach (thread);
2385 mono_atomic_store_release (&data->done, TRUE);
2386 unload_data_unref (data);
2387 mono_thread_detach (thread);
2392 * mono_domain_unload:
2393 * @domain: The domain to unload
2395 * Unloads an appdomain. Follows the process outlined in the comment
2396 * for mono_domain_try_unload.
2399 mono_domain_unload (MonoDomain *domain)
2401 MonoObject *exc = NULL;
2402 mono_domain_try_unload (domain, &exc);
2404 mono_raise_exception ((MonoException*)exc);
2408 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2412 MONO_PREPARE_BLOCKING;
2413 result = WaitForSingleObjectEx (handle, timeout, alertable);
2414 MONO_FINISH_BLOCKING;
2420 * mono_domain_unload:
2421 * @domain: The domain to unload
2422 * @exc: Exception information
2424 * Unloads an appdomain. Follows the process outlined in:
2425 * http://blogs.gotdotnet.com/cbrumme
2427 * If doing things the 'right' way is too hard or complex, we do it the
2428 * 'simple' way, which means do everything needed to avoid crashes and
2429 * memory leaks, but not much else.
2431 * It is required to pass a valid reference to the exc argument, upon return
2432 * from this function *exc will be set to the exception thrown, if any.
2434 * If this method is not called from an icall (embedded scenario for instance),
2435 * it must not be called with any managed frames on the stack, since the unload
2436 * process could end up trying to abort the current thread.
2439 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2441 HANDLE thread_handle;
2442 MonoAppDomainState prev_state;
2444 unload_data *thread_data;
2445 MonoNativeThreadId tid;
2446 MonoDomain *caller_domain = mono_domain_get ();
2449 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2451 /* Atomically change our state to UNLOADING */
2452 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2453 MONO_APPDOMAIN_UNLOADING_START,
2454 MONO_APPDOMAIN_CREATED);
2455 if (prev_state != MONO_APPDOMAIN_CREATED) {
2456 switch (prev_state) {
2457 case MONO_APPDOMAIN_UNLOADING_START:
2458 case MONO_APPDOMAIN_UNLOADING:
2459 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2461 case MONO_APPDOMAIN_UNLOADED:
2462 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2465 g_warning ("Invalid appdomain state %d", prev_state);
2466 g_assert_not_reached ();
2470 mono_domain_set (domain, FALSE);
2471 /* Notify OnDomainUnload listeners */
2472 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2475 mono_runtime_invoke (method, domain->domain, NULL, exc);
2477 /* Roll back the state change */
2478 domain->state = MONO_APPDOMAIN_CREATED;
2479 mono_domain_set (caller_domain, FALSE);
2482 mono_domain_set (caller_domain, FALSE);
2484 thread_data = g_new0 (unload_data, 1);
2485 thread_data->domain = domain;
2486 thread_data->failure_reason = NULL;
2487 thread_data->done = FALSE;
2488 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2490 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2491 domain->state = MONO_APPDOMAIN_UNLOADING;
2493 * First we create a separate thread for unloading, since
2494 * we might have to abort some threads, including the current one.
2496 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2497 if (thread_handle == NULL)
2499 name = g_strdup_printf ("Unload thread for domain %x", domain);
2500 mono_thread_info_set_name (tid, name);
2501 mono_thread_info_resume (tid);
2504 /* Wait for the thread */
2505 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2506 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2507 /* The unload thread tries to abort us */
2508 /* The icall wrapper will execute the abort */
2509 CloseHandle (thread_handle);
2510 unload_data_unref (thread_data);
2514 CloseHandle (thread_handle);
2516 if (thread_data->failure_reason) {
2517 /* Roll back the state change */
2518 domain->state = MONO_APPDOMAIN_CREATED;
2520 g_warning ("%s", thread_data->failure_reason);
2522 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2524 g_free (thread_data->failure_reason);
2525 thread_data->failure_reason = NULL;
2528 unload_data_unref (thread_data);