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-internal.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/socket-io.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/gc-internal.h>
45 #include <mono/metadata/mono-gc.h>
46 #include <mono/metadata/marshal.h>
47 #include <mono/metadata/monitor.h>
48 #include <mono/metadata/threadpool.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/utils/mono-uri.h>
58 #include <mono/utils/mono-logger-internal.h>
59 #include <mono/utils/mono-path.h>
60 #include <mono/utils/mono-stdlib.h>
61 #include <mono/utils/mono-io-portability.h>
62 #include <mono/utils/mono-error-internals.h>
63 #include <mono/utils/atomic.h>
64 #include <mono/utils/mono-memory-model.h>
65 #include <mono/utils/mono-threads.h>
71 * This is the version number of the corlib-runtime interface. When
72 * making changes to this interface (by changing the layout
73 * of classes the runtime knows about, changing icall signature or
74 * semantics etc), increment this variable. Also increment the
75 * pair of this variable in mscorlib in:
76 * mcs/class/mscorlib/System/Environment.cs
78 * Changes which are already detected at runtime, like the addition
79 * of icalls, do not require an increment.
81 #define MONO_CORLIB_VERSION 111
86 int assemblybinding_count;
91 CRITICAL_SECTION mono_delegate_section;
93 CRITICAL_SECTION mono_strtod_mutex;
95 static gunichar2 process_guid [36];
96 static gboolean process_guid_set = FALSE;
98 static gboolean no_exec = FALSE;
100 static MonoAssembly *
101 mono_domain_assembly_preload (MonoAssemblyName *aname,
102 gchar **assemblies_path,
105 static MonoAssembly *
106 mono_domain_assembly_search (MonoAssemblyName *aname,
109 static MonoAssembly *
110 mono_domain_assembly_postload_search (MonoAssemblyName *aname,
114 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
117 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
119 static MonoAppDomain *
120 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
123 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
125 static MonoLoadFunc load_function = NULL;
128 mono_install_runtime_load (MonoLoadFunc func)
130 load_function = func;
134 mono_runtime_load (const char *filename, const char *runtime_version)
136 g_assert (load_function);
137 return load_function (filename, runtime_version);
141 * mono_runtime_set_no_exec:
143 * Instructs the runtime to operate in static mode, i.e. avoid/do not
144 * allow managed code execution. This is useful for running the AOT
145 * compiler on platforms which allow full-aot execution only. This
146 * should be called before mono_runtime_init ().
149 mono_runtime_set_no_exec (gboolean val)
155 * mono_runtime_get_no_exec:
157 * If true, then the runtime will not allow managed code execution.
160 mono_runtime_get_no_exec (void)
166 create_domain_objects (MonoDomain *domain)
168 MonoDomain *old_domain = mono_domain_get ();
171 if (domain != old_domain) {
172 mono_thread_push_appdomain_ref (domain);
173 mono_domain_set_internal_with_options (domain, FALSE);
177 * Create an instance early since we can't do it when there is no memory.
179 arg = mono_string_new (domain, "Out of memory");
180 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
183 * These two are needed because the signal handlers might be executing on
184 * an alternate stack, and Boehm GC can't handle that.
186 arg = mono_string_new (domain, "A null value was found where an object instance was required");
187 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
188 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
189 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
191 /*The ephemeron tombstone i*/
192 domain->ephemeron_tombstone = mono_object_new (domain, mono_defaults.object_class);
194 if (domain != old_domain) {
195 mono_thread_pop_appdomain_ref ();
196 mono_domain_set_internal_with_options (old_domain, FALSE);
200 * This class is used during exception handling, so initialize it here, to prevent
201 * stack overflows while handling stack overflows.
203 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
208 * @domain: domain returned by mono_init ()
210 * Initialize the core AppDomain: this function will run also some
211 * IL initialization code, so it needs the execution engine to be fully
214 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
215 * we know the entry_assembly.
219 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
220 MonoThreadAttachCB attach_cb)
222 MonoAppDomainSetup *setup;
226 mono_portability_helpers_init ();
228 mono_gc_base_init ();
229 mono_monitor_init ();
230 mono_thread_pool_init ();
231 mono_marshal_init ();
233 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
234 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
235 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
236 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
237 mono_install_assembly_postload_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
238 mono_install_assembly_postload_refonly_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
239 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
240 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
242 mono_thread_init (start_cb, attach_cb);
244 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
245 setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
247 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
248 ad = (MonoAppDomain *) mono_object_new (domain, class);
251 domain->setup = setup;
253 InitializeCriticalSection (&mono_delegate_section);
255 InitializeCriticalSection (&mono_strtod_mutex);
257 mono_thread_attach (domain);
258 mono_context_init (domain);
259 mono_context_set (domain->default_context);
261 mono_type_initialization_init ();
263 if (!mono_runtime_get_no_exec ())
264 create_domain_objects (domain);
266 /* GC init has to happen after thread init */
269 #ifndef DISABLE_SOCKETS
270 mono_network_init ();
273 mono_console_init ();
276 mono_locks_tracer_init ();
278 /* mscorlib is loaded before we install the load hook */
279 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
285 mono_get_corlib_version (void)
288 MonoClassField *field;
291 klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
292 mono_class_init (klass);
293 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
296 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
298 value = mono_field_get_value_object (mono_domain_get (), field, NULL);
299 return *(gint32*)((gchar*)value + sizeof (MonoObject));
303 * mono_check_corlib_version
305 * Checks that the corlib that is loaded matches the version of this runtime.
307 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
308 * allocated string with the error otherwise.
311 mono_check_corlib_version (void)
313 int version = mono_get_corlib_version ();
314 if (version != MONO_CORLIB_VERSION)
315 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
322 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
324 * Initializes the @domain's default System.Runtime.Remoting's Context.
327 mono_context_init (MonoDomain *domain)
330 MonoAppContext *context;
332 class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
333 context = (MonoAppContext *) mono_object_new (domain, class);
334 context->domain_id = domain->domain_id;
335 context->context_id = 0;
336 domain->default_context = context;
340 * mono_runtime_cleanup:
345 * This must not be called while there are still running threads executing
349 mono_runtime_cleanup (MonoDomain *domain)
351 mono_attach_cleanup ();
353 /* This ends up calling any pending pending (for at most 2 seconds) */
356 mono_thread_cleanup ();
358 #ifndef DISABLE_SOCKETS
359 mono_network_cleanup ();
361 mono_marshal_cleanup ();
363 mono_type_initialization_cleanup ();
365 mono_monitor_cleanup ();
368 static MonoDomainFunc quit_function = NULL;
371 mono_install_runtime_cleanup (MonoDomainFunc func)
373 quit_function = func;
379 if (quit_function != NULL)
380 quit_function (mono_get_root_domain (), NULL);
384 * mono_domain_create_appdomain:
385 * @friendly_name: The friendly name of the appdomain to create
386 * @configuration_file: The configuration file to initialize the appdomain with
388 * Returns a MonoDomain initialized with the appdomain
391 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
394 MonoAppDomainSetup *setup;
397 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
398 setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
399 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
401 ad = mono_domain_create_appdomain_internal (friendly_name, setup);
403 return mono_domain_from_appdomain (ad);
406 static MonoAppDomainSetup*
407 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
409 MonoDomain *caller_domain = mono_domain_get ();
410 MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
411 MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
413 mono_domain_set_internal (domain);
415 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
416 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
417 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
418 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
419 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
420 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
421 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
422 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
423 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
424 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
425 copy->publisher_policy = setup->publisher_policy;
426 copy->path_changed = setup->path_changed;
427 copy->loader_optimization = setup->loader_optimization;
428 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
429 copy->disallow_code_downloads = setup->disallow_code_downloads;
430 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
431 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
432 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
433 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
434 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
436 mono_domain_set_internal (caller_domain);
441 static MonoAppDomain *
442 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
448 char *shadow_location;
452 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
454 /* FIXME: pin all those objects */
455 data = mono_domain_create();
457 ad = (MonoAppDomain *) mono_object_new (data, adclass);
460 data->friendly_name = g_strdup (friendly_name);
462 if (!setup->application_base) {
463 /* Inherit from the root domain since MS.NET does this */
464 MonoDomain *root = mono_get_root_domain ();
465 if (root->setup->application_base)
466 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)));
469 mono_context_init (data);
471 data->setup = copy_app_domain_setup (data, setup);
472 mono_set_private_bin_path_from_config (data);
473 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
475 #ifndef DISABLE_SHADOW_COPY
476 /*FIXME, guard this for when the debugger is not running */
477 shadow_location = get_shadow_assembly_location_base (data, &error);
478 if (!mono_error_ok (&error))
479 mono_error_raise_exception (&error);
480 g_free (shadow_location);
483 create_domain_objects (data);
489 * mono_domain_has_type_resolve:
490 * @domain: application domains being looked up
492 * Returns true if the AppDomain.TypeResolve field has been
496 mono_domain_has_type_resolve (MonoDomain *domain)
498 static MonoClassField *field = NULL;
502 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
506 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
510 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
515 * mono_domain_try_type_resolve:
516 * @domain: application domainwhere the name where the type is going to be resolved
517 * @name: the name of the type to resolve or NULL.
518 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
520 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
521 * the assembly that matches name.
523 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
525 * Returns: A MonoReflectionAssembly or NULL if not found
527 MonoReflectionAssembly *
528 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
532 static MonoMethod *method = NULL;
534 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
536 if (method == NULL) {
537 klass = domain->domain->mbr.obj.vtable->klass;
540 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
541 if (method == NULL) {
542 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
548 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
551 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
555 * mono_domain_owns_vtable_slot:
557 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
560 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
564 mono_domain_lock (domain);
565 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
566 mono_domain_unlock (domain);
573 * @force: force setting.
575 * Set the current appdomain to @domain. If @force is set, set it even
576 * if it is being unloaded.
580 * FALSE if the domain is unloaded
583 mono_domain_set (MonoDomain *domain, gboolean force)
585 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
588 mono_domain_set_internal (domain);
594 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
602 g_assert (ad != NULL);
604 g_assert (add != NULL);
607 mono_raise_exception (mono_get_exception_argument_null ("name"));
609 str = mono_string_to_utf8 (name);
611 mono_domain_lock (add);
613 if (!strcmp (str, "APPBASE"))
614 o = (MonoObject *)add->setup->application_base;
615 else if (!strcmp (str, "APP_CONFIG_FILE"))
616 o = (MonoObject *)add->setup->configuration_file;
617 else if (!strcmp (str, "DYNAMIC_BASE"))
618 o = (MonoObject *)add->setup->dynamic_base;
619 else if (!strcmp (str, "APP_NAME"))
620 o = (MonoObject *)add->setup->application_name;
621 else if (!strcmp (str, "CACHE_BASE"))
622 o = (MonoObject *)add->setup->cache_path;
623 else if (!strcmp (str, "PRIVATE_BINPATH"))
624 o = (MonoObject *)add->setup->private_bin_path;
625 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
626 o = (MonoObject *)add->setup->private_bin_path_probe;
627 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
628 o = (MonoObject *)add->setup->shadow_copy_directories;
629 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
630 o = (MonoObject *)add->setup->shadow_copy_files;
632 o = mono_g_hash_table_lookup (add->env, name);
634 mono_domain_unlock (add);
644 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
650 g_assert (ad != NULL);
652 g_assert (add != NULL);
655 mono_raise_exception (mono_get_exception_argument_null ("name"));
657 mono_domain_lock (add);
659 mono_g_hash_table_insert (add->env, name, data);
661 mono_domain_unlock (add);
665 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
669 g_assert (ad != NULL);
670 g_assert (ad->data != NULL);
672 return ad->data->setup;
676 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
680 g_assert (ad != NULL);
681 g_assert (ad->data != NULL);
683 return mono_string_new (ad->data, ad->data->friendly_name);
687 ves_icall_System_AppDomain_getCurDomain ()
689 MonoDomain *add = mono_domain_get ();
697 ves_icall_System_AppDomain_getRootDomain ()
699 MonoDomain *root = mono_get_root_domain ();
707 get_attribute_value (const gchar **attribute_names,
708 const gchar **attribute_values,
709 const char *att_name)
712 for (n = 0; attribute_names [n] != NULL; n++) {
713 if (strcmp (attribute_names [n], att_name) == 0)
714 return g_strdup (attribute_values [n]);
720 start_element (GMarkupParseContext *context,
721 const gchar *element_name,
722 const gchar **attribute_names,
723 const gchar **attribute_values,
727 RuntimeConfig *runtime_config = user_data;
729 if (strcmp (element_name, "runtime") == 0) {
730 runtime_config->runtime_count++;
734 if (strcmp (element_name, "assemblyBinding") == 0) {
735 runtime_config->assemblybinding_count++;
739 if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
742 if (strcmp (element_name, "probing") != 0)
745 g_free (runtime_config->domain->private_bin_path);
746 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
747 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
748 g_free (runtime_config->domain->private_bin_path);
749 runtime_config->domain->private_bin_path = NULL;
755 end_element (GMarkupParseContext *context,
756 const gchar *element_name,
760 RuntimeConfig *runtime_config = user_data;
761 if (strcmp (element_name, "runtime") == 0)
762 runtime_config->runtime_count--;
763 else if (strcmp (element_name, "assemblyBinding") == 0)
764 runtime_config->assemblybinding_count--;
768 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
770 RuntimeConfig *state = user_data;
772 const gchar *filename;
774 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
775 msg = error && error->message ? error->message : "";
776 g_warning ("Error parsing %s: %s", filename, msg);
779 static const GMarkupParser
789 mono_set_private_bin_path_from_config (MonoDomain *domain)
792 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
794 GMarkupParseContext *context;
795 RuntimeConfig runtime_config;
798 if (!domain || !domain->setup || !domain->setup->configuration_file)
801 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
802 if (!mono_error_ok (&error)) {
803 mono_error_cleanup (&error);
807 config_file_path = mono_portability_find_file (config_file_name, TRUE);
808 if (!config_file_path)
809 config_file_path = config_file_name;
811 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
814 runtime_config.runtime_count = 0;
815 runtime_config.assemblybinding_count = 0;
816 runtime_config.domain = domain;
817 runtime_config.filename = config_file_path;
820 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
821 offset = 3; /* Skip UTF-8 BOM */
823 context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
824 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
825 g_markup_parse_context_end_parse (context, NULL);
826 g_markup_parse_context_free (context);
830 if (config_file_name != config_file_path)
831 g_free (config_file_name);
832 g_free (config_file_path);
836 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
838 #ifdef DISABLE_APPDOMAINS
839 mono_raise_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
842 char *fname = mono_string_to_utf8 (friendly_name);
843 MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
852 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
854 MonoDomain *domain = ad->data;
856 static MonoClass *System_Reflection_Assembly;
860 GPtrArray *assemblies;
864 if (!System_Reflection_Assembly)
865 System_Reflection_Assembly = mono_class_from_name (
866 mono_defaults.corlib, "System.Reflection", "Assembly");
869 * Make a copy of the list of assemblies because we can't hold the assemblies
870 * lock while creating objects etc.
872 assemblies = g_ptr_array_new ();
873 /* Need to skip internal assembly builders created by remoting */
874 mono_domain_assemblies_lock (domain);
875 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
877 if (refonly != ass->ref_only)
879 if (ass->corlib_internal)
881 g_ptr_array_add (assemblies, ass);
883 mono_domain_assemblies_unlock (domain);
885 res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
886 for (i = 0; i < assemblies->len; ++i) {
887 ass = g_ptr_array_index (assemblies, i);
888 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
891 g_ptr_array_free (assemblies, TRUE);
896 MonoReflectionAssembly *
897 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, gboolean refonly)
901 MonoBoolean isrefonly;
904 if (mono_runtime_get_no_exec ())
907 g_assert (domain != NULL && fname != NULL);
909 klass = domain->domain->mbr.obj.vtable->klass;
912 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
913 if (method == NULL) {
914 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
918 isrefonly = refonly ? 1 : 0;
920 params [1] = &isrefonly;
921 return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
924 static MonoAssembly *
925 mono_domain_assembly_postload_search (MonoAssemblyName *aname,
928 gboolean refonly = GPOINTER_TO_UINT (user_data);
929 MonoReflectionAssembly *assembly;
930 MonoDomain *domain = mono_domain_get ();
934 aname_str = mono_stringify_assembly_name (aname);
936 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
937 str = mono_string_new (domain, aname_str);
942 assembly = mono_try_assembly_resolve (domain, str, refonly);
946 return assembly->assembly;
952 * LOCKING: assumes assemblies_lock in the domain is already locked.
955 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
959 gboolean destroy_ht = FALSE;
961 if (!ass->aname.name)
965 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
969 /* FIXME: handle lazy loaded assemblies */
970 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
971 g_hash_table_insert (ht, tmp->data, tmp->data);
973 if (!g_hash_table_lookup (ht, ass)) {
974 mono_assembly_addref (ass);
975 g_hash_table_insert (ht, ass, ass);
976 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
977 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);
980 if (ass->image->references) {
981 for (i = 0; ass->image->references [i] != NULL; i++) {
982 if (ass->image->references [i] != REFERENCE_MISSING)
983 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
984 add_assemblies_to_domain (domain, ass->image->references [i], ht);
989 g_hash_table_destroy (ht);
993 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
995 static MonoClassField *assembly_load_field;
996 static MonoMethod *assembly_load_method;
997 MonoDomain *domain = mono_domain_get ();
998 MonoReflectionAssembly *ref_assembly;
1000 gpointer load_value;
1003 if (!domain->domain)
1004 /* This can happen during startup */
1006 #ifdef ASSEMBLY_LOAD_DEBUG
1007 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1009 klass = domain->domain->mbr.obj.vtable->klass;
1011 mono_domain_assemblies_lock (domain);
1012 add_assemblies_to_domain (domain, assembly, NULL);
1013 mono_domain_assemblies_unlock (domain);
1015 if (assembly_load_field == NULL) {
1016 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1017 g_assert (assembly_load_field);
1020 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1021 if (load_value == NULL) {
1022 /* No events waiting to be triggered */
1026 ref_assembly = mono_assembly_get_object (domain, assembly);
1027 g_assert (ref_assembly);
1029 if (assembly_load_method == NULL) {
1030 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1031 g_assert (assembly_load_method);
1034 *params = ref_assembly;
1035 mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1039 * LOCKING: Acquires the domain assemblies lock.
1042 set_domain_search_path (MonoDomain *domain)
1045 MonoAppDomainSetup *setup;
1047 gchar *search_path = NULL;
1050 gchar **pvt_split = NULL;
1051 GError *gerror = NULL;
1052 gint appbaselen = -1;
1055 * We use the low-level domain assemblies lock, since this is called from
1056 * assembly loads hooks, which means this thread might hold the loader lock.
1058 mono_domain_assemblies_lock (domain);
1060 if (!domain->setup) {
1061 mono_domain_assemblies_unlock (domain);
1065 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1066 mono_domain_assemblies_unlock (domain);
1069 setup = domain->setup;
1070 if (!setup->application_base) {
1071 mono_domain_assemblies_unlock (domain);
1072 return; /* Must set application base to get private path working */
1077 if (setup->private_bin_path) {
1078 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1079 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1080 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1081 mono_error_cleanup (&error);
1082 mono_domain_assemblies_unlock (domain);
1087 if (domain->private_bin_path) {
1088 if (search_path == NULL)
1089 search_path = domain->private_bin_path;
1091 gchar *tmp2 = search_path;
1092 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1099 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1100 * directories relative to ApplicationBase separated by semicolons (see
1101 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1102 * The loop below copes with the fact that some Unix applications may use ':' (or
1103 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1104 * ';' for the subsequent split.
1106 * The issue was reported in bug #81446
1109 #ifndef TARGET_WIN32
1112 slen = strlen (search_path);
1113 for (i = 0; i < slen; i++)
1114 if (search_path [i] == ':')
1115 search_path [i] = ';';
1118 pvt_split = g_strsplit (search_path, ";", 1000);
1119 g_free (search_path);
1120 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1125 g_strfreev (pvt_split);
1127 * Don't do this because the first time is called, the domain
1128 * setup is not finished.
1130 * domain->search_path = g_malloc (sizeof (char *));
1131 * domain->search_path [0] = NULL;
1133 mono_domain_assemblies_unlock (domain);
1137 if (domain->search_path)
1138 g_strfreev (domain->search_path);
1140 tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1141 tmp [npaths] = NULL;
1143 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1144 if (!mono_error_ok (&error)) {
1145 mono_error_cleanup (&error);
1146 g_strfreev (pvt_split);
1149 mono_domain_assemblies_unlock (domain);
1153 domain->search_path = tmp;
1155 /* FIXME: is this needed? */
1156 if (strncmp (*tmp, "file://", 7) == 0) {
1162 uri = g_strdup_printf ("file:///%s", uri + 7);
1165 uri = mono_escape_uri_string (tmpuri);
1166 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1172 if (gerror != NULL) {
1173 g_warning ("%s\n", gerror->message);
1174 g_error_free (gerror);
1181 for (i = 1; pvt_split && i < npaths; i++) {
1182 if (g_path_is_absolute (pvt_split [i - 1])) {
1183 tmp [i] = g_strdup (pvt_split [i - 1]);
1185 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1188 if (strchr (tmp [i], '.')) {
1192 reduced = mono_path_canonicalize (tmp [i]);
1193 if (appbaselen == -1)
1194 appbaselen = strlen (tmp [0]);
1196 if (strncmp (tmp [0], reduced, appbaselen)) {
1199 tmp [i] = g_strdup ("");
1209 if (setup->private_bin_path_probe != NULL) {
1211 tmp [0] = g_strdup ("");
1214 domain->setup->path_changed = FALSE;
1216 g_strfreev (pvt_split);
1218 mono_domain_assemblies_unlock (domain);
1221 #ifdef DISABLE_SHADOW_COPY
1223 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1229 mono_make_shadow_copy (const char *filename)
1231 return (char *) filename;
1235 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1237 guint16 *orig, *dest;
1238 gboolean copy_result;
1240 strcpy (src + srclen - tail_len, extension);
1242 if (IS_PORTABILITY_CASE) {
1243 gchar *file = mono_portability_find_file (src, TRUE);
1249 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1253 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1255 strcpy (target + targetlen - tail_len, extension);
1256 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1259 copy_result = CopyFile (orig, dest, FALSE);
1261 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1262 * overwritten when updated in their original locations. */
1264 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1273 get_cstring_hash (const char *str)
1279 if (!str || !str [0])
1284 for (i = 0; i < len; i++) {
1285 h = (h << 5) - h + *p;
1293 * Returned memory is malloc'd. Called must free it
1296 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1298 MonoAppDomainSetup *setup;
1299 char *cache_path, *appname;
1303 mono_error_init (error);
1305 setup = domain->setup;
1306 if (setup->cache_path != NULL && setup->application_name != NULL) {
1307 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1308 if (!mono_error_ok (error))
1310 #ifndef TARGET_WIN32
1313 for (i = strlen (cache_path) - 1; i >= 0; i--)
1314 if (cache_path [i] == '\\')
1315 cache_path [i] = '/';
1319 appname = mono_string_to_utf8_checked (setup->application_name, error);
1320 if (!mono_error_ok (error)) {
1321 g_free (cache_path);
1325 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1327 g_free (cache_path);
1329 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1330 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1337 get_shadow_assembly_location (const char *filename, MonoError *error)
1339 gint32 hash = 0, hash2 = 0;
1341 char path_hash [30];
1342 char *bname = g_path_get_basename (filename);
1343 char *dirname = g_path_get_dirname (filename);
1344 char *location, *tmploc;
1345 MonoDomain *domain = mono_domain_get ();
1347 mono_error_init (error);
1349 hash = get_cstring_hash (bname);
1350 hash2 = get_cstring_hash (dirname);
1351 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1352 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1353 tmploc = get_shadow_assembly_location_base (domain, error);
1354 if (!mono_error_ok (error)) {
1360 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1368 ensure_directory_exists (const char *filename)
1371 gchar *dir_utf8 = g_path_get_dirname (filename);
1373 gunichar2 *dir_utf16 = NULL;
1376 if (!dir_utf8 || !dir_utf8 [0])
1379 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1387 /* make life easy and only use one directory seperator */
1398 while (*p++ != '\\')
1404 p = wcschr (p, '\\');
1407 retval = _wmkdir (dir_utf16);
1408 if (retval != 0 && errno != EEXIST) {
1421 gchar *dir = g_path_get_dirname (filename);
1425 if (!dir || !dir [0]) {
1430 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1440 p = strchr (p, '/');
1443 retval = mkdir (dir, 0777);
1444 if (retval != 0 && errno != EEXIST) {
1459 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1461 struct stat sbuf_dest;
1463 gchar *real_src = mono_portability_find_file (src, TRUE);
1466 stat_src = (gchar*)src;
1468 stat_src = real_src;
1470 if (stat (stat_src, sbuf_src) == -1) {
1471 time_t tnow = time (NULL);
1476 memset (sbuf_src, 0, sizeof (*sbuf_src));
1477 sbuf_src->st_mtime = tnow;
1478 sbuf_src->st_atime = tnow;
1485 if (stat (dest, &sbuf_dest) == -1)
1488 if (sbuf_src->st_size == sbuf_dest.st_size &&
1489 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1496 shadow_copy_create_ini (const char *shadow, const char *filename)
1506 dir_name = g_path_get_dirname (shadow);
1507 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1509 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1514 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1519 handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1520 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1522 if (handle == INVALID_HANDLE_VALUE) {
1526 full_path = mono_path_resolve_symlinks (filename);
1527 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1529 CloseHandle (handle);
1534 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1537 MonoAppDomainSetup *setup;
1540 gchar **directories;
1541 gchar *shadow_status_string;
1543 gboolean shadow_enabled;
1544 gboolean found = FALSE;
1549 setup = domain->setup;
1550 if (setup == NULL || setup->shadow_copy_files == NULL)
1553 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1554 if (!mono_error_ok (&error)) {
1555 mono_error_cleanup (&error);
1558 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1559 g_free (shadow_status_string);
1561 if (!shadow_enabled)
1564 if (setup->shadow_copy_directories == NULL)
1567 /* Is dir_name a shadow_copy destination already? */
1568 base_dir = get_shadow_assembly_location_base (domain, &error);
1569 if (!mono_error_ok (&error)) {
1570 mono_error_cleanup (&error);
1574 if (strstr (dir_name, base_dir)) {
1580 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1581 if (!mono_error_ok (&error)) {
1582 mono_error_cleanup (&error);
1586 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1587 dir_ptr = directories;
1589 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1595 g_strfreev (directories);
1601 This function raises exceptions so it can cause as sorts of nasty stuff if called
1602 while holding a lock.
1603 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1604 or NULL if source file not found.
1605 FIXME bubble up the error instead of raising it here
1608 mono_make_shadow_copy (const char *filename)
1611 gchar *sibling_source, *sibling_target;
1612 gint sibling_source_len, sibling_target_len;
1613 guint16 *orig, *dest;
1616 gboolean copy_result;
1618 struct stat src_sbuf;
1619 struct utimbuf utbuf;
1620 char *dir_name = g_path_get_dirname (filename);
1621 MonoDomain *domain = mono_domain_get ();
1624 set_domain_search_path (domain);
1626 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1628 return (char *) filename;
1631 /* Is dir_name a shadow_copy destination already? */
1632 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1633 if (!mono_error_ok (&error)) {
1634 mono_error_cleanup (&error);
1636 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1637 mono_raise_exception (exc);
1640 if (strstr (dir_name, shadow_dir)) {
1641 g_free (shadow_dir);
1643 return (char *) filename;
1645 g_free (shadow_dir);
1648 shadow = get_shadow_assembly_location (filename, &error);
1649 if (!mono_error_ok (&error)) {
1650 mono_error_cleanup (&error);
1651 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1652 mono_raise_exception (exc);
1655 if (ensure_directory_exists (shadow) == FALSE) {
1657 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1658 mono_raise_exception (exc);
1661 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1662 return (char*) shadow;
1664 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1665 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1668 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1669 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1670 * and not have it runtime error" */
1671 attrs = GetFileAttributes (orig);
1672 if (attrs == INVALID_FILE_ATTRIBUTES) {
1674 return (char *)filename;
1677 copy_result = CopyFile (orig, dest, FALSE);
1679 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1680 * overwritten when updated in their original locations. */
1682 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1687 if (copy_result == FALSE) {
1690 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1691 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1692 return NULL; /* file not found, shadow copy failed */
1694 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1695 mono_raise_exception (exc);
1698 /* attempt to copy .mdb, .config if they exist */
1699 sibling_source = g_strconcat (filename, ".config", NULL);
1700 sibling_source_len = strlen (sibling_source);
1701 sibling_target = g_strconcat (shadow, ".config", NULL);
1702 sibling_target_len = strlen (sibling_target);
1704 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1705 if (copy_result == TRUE)
1706 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1708 g_free (sibling_source);
1709 g_free (sibling_target);
1711 if (copy_result == FALSE) {
1713 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1714 mono_raise_exception (exc);
1717 /* Create a .ini file containing the original assembly location */
1718 if (!shadow_copy_create_ini (shadow, filename)) {
1720 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1721 mono_raise_exception (exc);
1724 utbuf.actime = src_sbuf.st_atime;
1725 utbuf.modtime = src_sbuf.st_mtime;
1726 utime (shadow, &utbuf);
1730 #endif /* DISABLE_SHADOW_COPY */
1733 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1735 if (appdomain == NULL)
1738 return appdomain->data;
1742 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1743 const gchar *path3, const gchar *path4,
1744 gboolean refonly, gboolean is_private)
1747 gboolean found = FALSE;
1750 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1752 if (IS_PORTABILITY_SET) {
1753 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1756 fullpath = new_fullpath;
1760 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1763 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1766 return (*assembly != NULL);
1769 static MonoAssembly *
1770 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1772 MonoAssembly *result = NULL;
1775 const gchar *local_culture;
1777 gboolean is_private = FALSE;
1779 if (!culture || *culture == '\0') {
1782 local_culture = culture;
1785 filename = g_strconcat (name, ".dll", NULL);
1786 len = strlen (filename);
1788 for (path = search_path; *path; path++) {
1789 if (**path == '\0') {
1791 continue; /* Ignore empty ApplicationBase */
1794 /* See test cases in bug #58992 and bug #57710 */
1795 /* 1st try: [culture]/[name].dll (culture may be empty) */
1796 strcpy (filename + len - 4, ".dll");
1797 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1800 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1801 strcpy (filename + len - 4, ".exe");
1802 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1805 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1806 strcpy (filename + len - 4, ".dll");
1807 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1810 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1811 strcpy (filename + len - 4, ".exe");
1812 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1821 * Try loading the assembly from ApplicationBase and PrivateBinPath
1822 * and then from assemblies_path if any.
1823 * LOCKING: This is called from the assembly loading code, which means the caller
1824 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1826 static MonoAssembly *
1827 mono_domain_assembly_preload (MonoAssemblyName *aname,
1828 gchar **assemblies_path,
1831 MonoDomain *domain = mono_domain_get ();
1832 MonoAssembly *result = NULL;
1833 gboolean refonly = GPOINTER_TO_UINT (user_data);
1835 set_domain_search_path (domain);
1837 if (domain->search_path && domain->search_path [0] != NULL) {
1838 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1841 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1842 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1849 * Check whenever a given assembly was already loaded in the current appdomain.
1851 static MonoAssembly *
1852 mono_domain_assembly_search (MonoAssemblyName *aname,
1855 MonoDomain *domain = mono_domain_get ();
1858 gboolean refonly = GPOINTER_TO_UINT (user_data);
1860 mono_domain_assemblies_lock (domain);
1861 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1863 /* Dynamic assemblies can't match here in MS.NET */
1864 if (ass->dynamic || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1867 mono_domain_assemblies_unlock (domain);
1870 mono_domain_assemblies_unlock (domain);
1875 MonoReflectionAssembly *
1876 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1878 MonoDomain *domain = mono_domain_get ();
1879 char *name, *filename;
1880 MonoImageOpenStatus status = MONO_IMAGE_OK;
1883 MONO_ARCH_SAVE_REGS;
1885 if (fname == NULL) {
1886 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1887 mono_raise_exception (exc);
1890 name = filename = mono_string_to_utf8 (fname);
1892 ass = mono_assembly_open_full (filename, &status, refOnly);
1897 if (status == MONO_IMAGE_IMAGE_INVALID)
1898 exc = mono_get_exception_bad_image_format2 (NULL, fname);
1900 exc = mono_get_exception_file_not_found2 (NULL, fname);
1902 mono_raise_exception (exc);
1907 return mono_assembly_get_object (domain, ass);
1910 MonoReflectionAssembly *
1911 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1912 MonoArray *raw_assembly,
1913 MonoArray *raw_symbol_store, MonoObject *evidence,
1914 MonoBoolean refonly)
1917 MonoReflectionAssembly *refass = NULL;
1918 MonoDomain *domain = ad->data;
1919 MonoImageOpenStatus status;
1920 guint32 raw_assembly_len = mono_array_length (raw_assembly);
1921 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1924 mono_raise_exception (mono_get_exception_bad_image_format (""));
1928 if (raw_symbol_store != NULL)
1929 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1931 ass = mono_assembly_load_from_full (image, "", &status, refonly);
1935 mono_image_close (image);
1936 mono_raise_exception (mono_get_exception_bad_image_format (""));
1940 refass = mono_assembly_get_object (domain, ass);
1941 MONO_OBJECT_SETREF (refass, evidence, evidence);
1945 MonoReflectionAssembly *
1946 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1948 MonoDomain *domain = ad->data;
1949 MonoImageOpenStatus status = MONO_IMAGE_OK;
1951 MonoAssemblyName aname;
1952 MonoReflectionAssembly *refass = NULL;
1956 MONO_ARCH_SAVE_REGS;
1958 g_assert (assRef != NULL);
1960 name = mono_string_to_utf8 (assRef);
1961 parsed = mono_assembly_name_parse (name, &aname);
1965 /* This is a parse error... */
1967 refass = mono_try_assembly_resolve (domain, assRef, refOnly);
1971 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1972 mono_assembly_name_free (&aname);
1975 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1977 refass = mono_try_assembly_resolve (domain, assRef, refOnly);
1986 refass = mono_assembly_get_object (domain, ass);
1988 MONO_OBJECT_SETREF (refass, evidence, evidence);
1993 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
1995 MonoDomain * domain = mono_domain_get_by_id (domain_id);
1997 MONO_ARCH_SAVE_REGS;
1999 if (NULL == domain) {
2000 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2001 mono_raise_exception (exc);
2004 if (domain == mono_get_root_domain ()) {
2005 mono_raise_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2010 * Unloading seems to cause problems when running NUnit/NAnt, hence
2013 if (g_getenv ("MONO_NO_UNLOAD"))
2015 #ifdef __native_client__
2019 mono_domain_unload (domain);
2023 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2025 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2030 return mono_domain_is_unloading (domain);
2034 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2035 MonoReflectionAssembly *refass, MonoArray *args)
2040 MONO_ARCH_SAVE_REGS;
2043 image = refass->assembly->image;
2046 method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
2049 g_error ("No entry point method found in %s", image->name);
2052 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2054 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2058 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2060 MONO_ARCH_SAVE_REGS;
2062 return ad->data->domain_id;
2066 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2068 MonoDomain *old_domain = mono_domain_get();
2070 MONO_ARCH_SAVE_REGS;
2072 if (!mono_domain_set (ad->data, FALSE))
2073 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2075 return old_domain->domain;
2079 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2081 MonoDomain *current_domain = mono_domain_get ();
2082 MonoDomain *domain = mono_domain_get_by_id (domainid);
2084 MONO_ARCH_SAVE_REGS;
2086 if (!domain || !mono_domain_set (domain, FALSE))
2087 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2089 return current_domain->domain;
2093 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2095 MONO_ARCH_SAVE_REGS;
2097 mono_thread_push_appdomain_ref (ad->data);
2101 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2103 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2105 MONO_ARCH_SAVE_REGS;
2109 * Raise an exception to prevent the managed code from executing a pop
2112 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2114 mono_thread_push_appdomain_ref (domain);
2118 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2120 MONO_ARCH_SAVE_REGS;
2122 mono_thread_pop_appdomain_ref ();
2126 ves_icall_System_AppDomain_InternalGetContext ()
2128 MONO_ARCH_SAVE_REGS;
2130 return mono_context_get ();
2134 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2136 MONO_ARCH_SAVE_REGS;
2138 return mono_domain_get ()->default_context;
2142 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2144 MonoAppContext *old_context = mono_context_get ();
2146 MONO_ARCH_SAVE_REGS;
2148 mono_context_set (mc);
2154 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2156 MonoDomain* mono_root_domain = mono_get_root_domain ();
2157 mono_domain_lock (mono_root_domain);
2158 if (process_guid_set) {
2159 mono_domain_unlock (mono_root_domain);
2160 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2162 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2163 process_guid_set = TRUE;
2164 mono_domain_unlock (mono_root_domain);
2169 mono_domain_is_unloading (MonoDomain *domain)
2171 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2178 clear_cached_vtable (MonoVTable *vtable)
2180 MonoClass *klass = vtable->klass;
2181 MonoDomain *domain = vtable->domain;
2182 MonoClassRuntimeInfo *runtime_info;
2185 runtime_info = klass->runtime_info;
2186 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2187 runtime_info->domain_vtables [domain->domain_id] = NULL;
2188 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2189 mono_gc_free_fixed (data);
2192 static G_GNUC_UNUSED void
2193 zero_static_data (MonoVTable *vtable)
2195 MonoClass *klass = vtable->klass;
2198 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2199 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2202 typedef struct unload_data {
2205 char *failure_reason;
2210 unload_data_unref (unload_data *data)
2214 mono_atomic_load_acquire (count, gint32, &data->refcount);
2215 g_assert (count >= 1 && count <= 2);
2220 } while (InterlockedCompareExchange (&data->refcount, count, count - 1) != count);
2224 deregister_reflection_info_roots_from_list (MonoImage *image)
2226 GSList *list = image->reflection_info_unregister_classes;
2229 MonoClass *class = list->data;
2231 mono_class_free_ref_info (class);
2236 image->reflection_info_unregister_classes = NULL;
2240 deregister_reflection_info_roots (MonoDomain *domain)
2244 mono_domain_assemblies_lock (domain);
2245 for (list = domain->domain_assemblies; list; list = list->next) {
2246 MonoAssembly *assembly = list->data;
2247 MonoImage *image = assembly->image;
2251 * No need to take the image lock here since dynamic images are appdomain bound and
2252 * at this point the mutator is gone. Taking the image lock here would mean
2253 * promoting it from a simple lock to a complex lock, which we better avoid if
2257 deregister_reflection_info_roots_from_list (image);
2259 for (i = 0; i < image->module_count; ++i) {
2260 MonoImage *module = image->modules [i];
2261 if (module && module->dynamic)
2262 deregister_reflection_info_roots_from_list (module);
2265 mono_domain_assemblies_unlock (domain);
2268 static guint32 WINAPI
2269 unload_thread_main (void *arg)
2271 unload_data *data = (unload_data*)arg;
2272 MonoDomain *domain = data->domain;
2276 /* Have to attach to the runtime so shutdown can wait for this thread */
2277 /* Force it to be attached to avoid racing during shutdown. */
2278 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2281 * FIXME: Abort our parent thread last, so we can return a failure
2282 * indication if aborting times out.
2284 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2285 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2289 if (!mono_thread_pool_remove_domain_jobs (domain, -1)) {
2290 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2294 /* Finalize all finalizable objects in the doomed appdomain */
2295 if (!mono_domain_finalize (domain, -1)) {
2296 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2300 /* Clear references to our vtables in class->runtime_info.
2301 * We also hold the loader lock because we're going to change
2302 * class->runtime_info.
2305 mono_loader_lock ();
2306 mono_domain_lock (domain);
2309 * We need to make sure that we don't have any remsets
2310 * pointing into static data of the to-be-freed domain because
2311 * at the next collections they would be invalid. So what we
2312 * do is we first zero all static data and then do a minor
2313 * collection. Because all references in the static data will
2314 * now be null we won't do any unnecessary copies and after
2315 * the collection there won't be any more remsets.
2317 for (i = 0; i < domain->class_vtable_array->len; ++i)
2318 zero_static_data (g_ptr_array_index (domain->class_vtable_array, i));
2319 mono_gc_collect (0);
2321 for (i = 0; i < domain->class_vtable_array->len; ++i)
2322 clear_cached_vtable (g_ptr_array_index (domain->class_vtable_array, i));
2323 deregister_reflection_info_roots (domain);
2325 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2327 mono_domain_unlock (domain);
2328 mono_loader_unlock ();
2330 mono_threads_clear_cached_culture (domain);
2332 domain->state = MONO_APPDOMAIN_UNLOADED;
2334 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2336 /* remove from the handle table the items related to this domain */
2337 mono_gchandle_free_domain (domain);
2339 mono_domain_free (domain, FALSE);
2341 mono_gc_collect (mono_gc_max_generation ());
2343 mono_atomic_store_release (&data->done, TRUE);
2344 unload_data_unref (data);
2345 mono_thread_detach (thread);
2349 mono_atomic_store_release (&data->done, TRUE);
2350 unload_data_unref (data);
2351 mono_thread_detach (thread);
2356 * mono_domain_unload:
2357 * @domain: The domain to unload
2359 * Unloads an appdomain. Follows the process outlined in the comment
2360 * for mono_domain_try_unload.
2363 mono_domain_unload (MonoDomain *domain)
2365 MonoObject *exc = NULL;
2366 mono_domain_try_unload (domain, &exc);
2368 mono_raise_exception ((MonoException*)exc);
2372 * mono_domain_unload:
2373 * @domain: The domain to unload
2374 * @exc: Exception information
2376 * Unloads an appdomain. Follows the process outlined in:
2377 * http://blogs.gotdotnet.com/cbrumme
2379 * If doing things the 'right' way is too hard or complex, we do it the
2380 * 'simple' way, which means do everything needed to avoid crashes and
2381 * memory leaks, but not much else.
2383 * It is required to pass a valid reference to the exc argument, upon return
2384 * from this function *exc will be set to the exception thrown, if any.
2386 * If this method is not called from an icall (embedded scenario for instance),
2387 * it must not be called with any managed frames on the stack, since the unload
2388 * process could end up trying to abort the current thread.
2391 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2393 HANDLE thread_handle;
2394 MonoAppDomainState prev_state;
2396 unload_data *thread_data;
2397 MonoNativeThreadId tid;
2398 MonoDomain *caller_domain = mono_domain_get ();
2400 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2402 /* Atomically change our state to UNLOADING */
2403 prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2404 MONO_APPDOMAIN_UNLOADING_START,
2405 MONO_APPDOMAIN_CREATED);
2406 if (prev_state != MONO_APPDOMAIN_CREATED) {
2407 switch (prev_state) {
2408 case MONO_APPDOMAIN_UNLOADING_START:
2409 case MONO_APPDOMAIN_UNLOADING:
2410 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2412 case MONO_APPDOMAIN_UNLOADED:
2413 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2416 g_warning ("Invalid appdomain state %d", prev_state);
2417 g_assert_not_reached ();
2421 mono_domain_set (domain, FALSE);
2422 /* Notify OnDomainUnload listeners */
2423 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2426 mono_runtime_invoke (method, domain->domain, NULL, exc);
2428 /* Roll back the state change */
2429 domain->state = MONO_APPDOMAIN_CREATED;
2430 mono_domain_set (caller_domain, FALSE);
2433 mono_domain_set (caller_domain, FALSE);
2435 thread_data = g_new0 (unload_data, 1);
2436 thread_data->domain = domain;
2437 thread_data->failure_reason = NULL;
2438 thread_data->done = FALSE;
2439 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2441 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2442 domain->state = MONO_APPDOMAIN_UNLOADING;
2444 * First we create a separate thread for unloading, since
2445 * we might have to abort some threads, including the current one.
2447 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2448 if (thread_handle == NULL)
2450 mono_thread_info_resume (tid);
2452 /* Wait for the thread */
2453 while (!thread_data->done && WaitForSingleObjectEx (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2454 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2455 /* The unload thread tries to abort us */
2456 /* The icall wrapper will execute the abort */
2457 CloseHandle (thread_handle);
2458 unload_data_unref (thread_data);
2462 CloseHandle (thread_handle);
2464 if (thread_data->failure_reason) {
2465 /* Roll back the state change */
2466 domain->state = MONO_APPDOMAIN_CREATED;
2468 g_warning ("%s", thread_data->failure_reason);
2470 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2472 g_free (thread_data->failure_reason);
2473 thread_data->failure_reason = NULL;
2476 unload_data_unref (thread_data);