Revert "Bump corlib version"
[mono-project.git] / mono / metadata / appdomain.c
blob9e23de19060bbe376ad6d1abdc979c476ddaa32a
1 /*
2 * appdomain.c: AppDomain functions
4 * Authors:
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Patrik Torstensson
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #undef ASSEMBLY_LOAD_DEBUG
15 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #ifdef HAVE_SYS_TIME_H
23 #include <sys/time.h>
24 #endif
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #ifdef HAVE_UTIME_H
29 #include <utime.h>
30 #else
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
33 #endif
34 #endif
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/appdomain-icalls.h>
39 #include <mono/metadata/domain-internals.h>
40 #include "mono/metadata/metadata-internals.h"
41 #include <mono/metadata/assembly.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/exception-internals.h>
44 #include <mono/metadata/threads.h>
45 #include <mono/metadata/threadpool.h>
46 #include <mono/metadata/socket-io.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/mono-gc.h>
50 #include <mono/metadata/marshal.h>
51 #include <mono/metadata/monitor.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/mono-debug-debugger.h>
54 #include <mono/metadata/attach.h>
55 #include <mono/metadata/file-io.h>
56 #include <mono/metadata/lock-tracer.h>
57 #include <mono/metadata/console-io.h>
58 #include <mono/metadata/threads-types.h>
59 #include <mono/metadata/tokentype.h>
60 #include <mono/metadata/profiler-private.h>
61 #include <mono/metadata/reflection-internals.h>
62 #include <mono/metadata/abi-details.h>
63 #include <mono/utils/mono-uri.h>
64 #include <mono/utils/mono-logger-internals.h>
65 #include <mono/utils/mono-path.h>
66 #include <mono/utils/mono-stdlib.h>
67 #include <mono/utils/mono-io-portability.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/atomic.h>
70 #include <mono/utils/mono-memory-model.h>
71 #include <mono/utils/mono-threads.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/io-layer/io-layer.h>
74 #ifdef HOST_WIN32
75 #include <direct.h>
76 #endif
79 * This is the version number of the corlib-runtime interface. When
80 * making changes to this interface (by changing the layout
81 * of classes the runtime knows about, changing icall signature or
82 * semantics etc), increment this variable. Also increment the
83 * pair of this variable in mscorlib in:
84 * mcs/class/corlib/System/Environment.cs
86 * Changes which are already detected at runtime, like the addition
87 * of icalls, do not require an increment.
89 #define MONO_CORLIB_VERSION 164
91 typedef struct
93 int runtime_count;
94 int assemblybinding_count;
95 MonoDomain *domain;
96 gchar *filename;
97 } RuntimeConfig;
99 static gunichar2 process_guid [36];
100 static gboolean process_guid_set = FALSE;
102 static gboolean no_exec = FALSE;
104 static MonoAssembly *
105 mono_domain_assembly_preload (MonoAssemblyName *aname,
106 gchar **assemblies_path,
107 gpointer user_data);
109 static MonoAssembly *
110 mono_domain_assembly_search (MonoAssemblyName *aname,
111 gpointer user_data);
113 static void
114 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
116 static void
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, MonoError *error);
122 static char *
123 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
125 static MonoLoadFunc load_function = NULL;
127 /* Lazy class loading functions */
128 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly);
130 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, System, AppDomain);
132 void
133 mono_install_runtime_load (MonoLoadFunc func)
135 load_function = func;
138 MonoDomain*
139 mono_runtime_load (const char *filename, const char *runtime_version)
141 g_assert (load_function);
142 return load_function (filename, runtime_version);
146 * mono_runtime_set_no_exec:
148 * Instructs the runtime to operate in static mode, i.e. avoid/do not
149 * allow managed code execution. This is useful for running the AOT
150 * compiler on platforms which allow full-aot execution only. This
151 * should be called before mono_runtime_init ().
153 void
154 mono_runtime_set_no_exec (gboolean val)
156 no_exec = val;
160 * mono_runtime_get_no_exec:
162 * If true, then the runtime will not allow managed code execution.
164 gboolean
165 mono_runtime_get_no_exec (void)
167 return no_exec;
170 static void
171 create_domain_objects (MonoDomain *domain)
173 MonoError error;
174 MonoDomain *old_domain = mono_domain_get ();
175 MonoString *arg;
176 MonoVTable *string_vt;
177 MonoClassField *string_empty_fld;
179 if (domain != old_domain) {
180 mono_thread_push_appdomain_ref (domain);
181 mono_domain_set_internal_with_options (domain, FALSE);
185 * Initialize String.Empty. This enables the removal of
186 * the static cctor of the String class.
188 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
189 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
190 g_assert (string_empty_fld);
191 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
192 mono_error_assert_ok (&error);
193 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
194 domain->empty_string = empty_str;
197 * Create an instance early since we can't do it when there is no memory.
199 arg = mono_string_new (domain, "Out of memory");
200 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
201 mono_error_assert_ok (&error);
204 * These two are needed because the signal handlers might be executing on
205 * an alternate stack, and Boehm GC can't handle that.
207 arg = mono_string_new (domain, "A null value was found where an object instance was required");
208 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
209 mono_error_assert_ok (&error);
210 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
211 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
212 mono_error_assert_ok (&error);
214 /*The ephemeron tombstone i*/
215 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
216 mono_error_assert_ok (&error);
218 if (domain != old_domain) {
219 mono_thread_pop_appdomain_ref ();
220 mono_domain_set_internal_with_options (old_domain, FALSE);
224 * This class is used during exception handling, so initialize it here, to prevent
225 * stack overflows while handling stack overflows.
227 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
231 * mono_runtime_init:
232 * @domain: domain returned by mono_init ()
234 * Initialize the core AppDomain: this function will run also some
235 * IL initialization code, so it needs the execution engine to be fully
236 * operational.
238 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
239 * we know the entry_assembly.
242 void
243 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
245 MonoError error;
246 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
247 mono_error_cleanup (&error);
250 void
251 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
253 MonoAppDomainSetup *setup;
254 MonoAppDomain *ad;
255 MonoClass *klass;
257 mono_error_init (error);
259 mono_portability_helpers_init ();
261 mono_gc_base_init ();
262 mono_monitor_init ();
263 mono_marshal_init ();
265 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
266 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
267 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
268 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
269 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
270 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
271 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
273 mono_thread_init (start_cb, attach_cb);
275 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
276 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
277 return_if_nok (error);
279 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
281 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
282 return_if_nok (error);
284 ad->data = domain;
285 domain->domain = ad;
286 domain->setup = setup;
288 mono_thread_attach (domain);
290 mono_type_initialization_init ();
292 if (!mono_runtime_get_no_exec ())
293 create_domain_objects (domain);
295 /* GC init has to happen after thread init */
296 mono_gc_init ();
298 /* contexts use GC handles, so they must be initialized after the GC */
299 mono_context_init_checked (domain, error);
300 return_if_nok (error);
301 mono_context_set (domain->default_context);
303 #ifndef DISABLE_SOCKETS
304 mono_network_init ();
305 #endif
307 mono_console_init ();
308 mono_attach_init ();
310 mono_locks_tracer_init ();
312 /* mscorlib is loaded before we install the load hook */
313 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
315 return;
318 static int
319 mono_get_corlib_version (void)
321 MonoError error;
322 MonoClass *klass;
323 MonoClassField *field;
324 MonoObject *value;
326 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
327 mono_class_init (klass);
328 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
329 if (!field)
330 return -1;
331 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
332 return -1;
333 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
334 mono_error_assert_ok (&error);
335 return *(gint32*)((gchar*)value + sizeof (MonoObject));
339 * mono_check_corlib_version
341 * Checks that the corlib that is loaded matches the version of this runtime.
343 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
344 * allocated string with the error otherwise.
346 const char*
347 mono_check_corlib_version (void)
349 int version = mono_get_corlib_version ();
350 if (version != MONO_CORLIB_VERSION)
351 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
353 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
354 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
355 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
356 if (native_offset != managed_offset)
357 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
359 return NULL;
363 * mono_context_init:
364 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
366 * Initializes the @domain's default System.Runtime.Remoting's Context.
368 void
369 mono_context_init (MonoDomain *domain)
371 MonoError error;
372 mono_context_init_checked (domain, &error);
373 mono_error_cleanup (&error);
376 void
377 mono_context_init_checked (MonoDomain *domain, MonoError *error)
379 MonoClass *klass;
380 MonoAppContext *context;
382 mono_error_init (error);
384 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
385 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
386 return_if_nok (error);
388 context->domain_id = domain->domain_id;
389 context->context_id = 0;
390 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
391 domain->default_context = context;
395 * mono_runtime_cleanup:
396 * @domain: unused.
398 * Internal routine.
400 * This must not be called while there are still running threads executing
401 * managed code.
403 void
404 mono_runtime_cleanup (MonoDomain *domain)
406 mono_attach_cleanup ();
408 /* This ends up calling any pending pending (for at most 2 seconds) */
409 mono_gc_cleanup ();
411 mono_thread_cleanup ();
413 #ifndef DISABLE_SOCKETS
414 mono_network_cleanup ();
415 #endif
416 mono_marshal_cleanup ();
418 mono_type_initialization_cleanup ();
420 mono_monitor_cleanup ();
423 static MonoDomainFunc quit_function = NULL;
425 void
426 mono_install_runtime_cleanup (MonoDomainFunc func)
428 quit_function = func;
431 void
432 mono_runtime_quit ()
434 if (quit_function != NULL)
435 quit_function (mono_get_root_domain (), NULL);
439 * mono_domain_create_appdomain:
440 * @friendly_name: The friendly name of the appdomain to create
441 * @configuration_file: The configuration file to initialize the appdomain with
443 * Returns a MonoDomain initialized with the appdomain
445 MonoDomain *
446 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
448 MonoError error;
449 MonoAppDomain *ad;
450 MonoAppDomainSetup *setup;
451 MonoClass *klass;
453 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
454 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
455 if (!is_ok (&error))
456 goto fail;
457 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
459 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
460 if (!is_ok (&error))
461 goto fail;
463 return mono_domain_from_appdomain (ad);
464 fail:
465 mono_error_cleanup (&error);
466 return NULL;
470 * mono_domain_set_config:
471 * @domain: MonoDomain initialized with the appdomain we want to change
472 * @base_dir: new base directory for the appdomain
473 * @config_file_name: path to the new configuration for the app domain
475 * Used to set the system configuration for an appdomain
477 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
478 * Error Initializing the configuration system. ---> System.ArgumentException:
479 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
481 void
482 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
484 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
485 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
488 static MonoAppDomainSetup*
489 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
491 MonoDomain *caller_domain;
492 MonoClass *ads_class;
493 MonoAppDomainSetup *copy;
495 mono_error_init (error);
497 caller_domain = mono_domain_get ();
498 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
500 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
501 return_val_if_nok (error, NULL);
503 mono_domain_set_internal (domain);
505 #define XCOPY_FIELD(dst,field,src,error) \
506 do { \
507 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
508 return_val_if_nok (error, NULL); \
509 MONO_OBJECT_SETREF ((dst),field,copied_val); \
510 } while (0)
512 XCOPY_FIELD (copy, application_base, setup->application_base, error);
513 XCOPY_FIELD (copy, application_name, setup->application_name, error);
514 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
515 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
516 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
517 XCOPY_FIELD (copy, license_file, setup->license_file, error);
518 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
519 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
520 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
521 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
522 copy->publisher_policy = setup->publisher_policy;
523 copy->path_changed = setup->path_changed;
524 copy->loader_optimization = setup->loader_optimization;
525 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
526 copy->disallow_code_downloads = setup->disallow_code_downloads;
527 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
528 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
529 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
530 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
531 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
533 #undef COPY_FIELD
535 mono_domain_set_internal (caller_domain);
537 return copy;
540 static MonoAppDomain *
541 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
543 MonoClass *adclass;
544 MonoAppDomain *ad;
545 MonoDomain *data;
546 char *shadow_location;
548 mono_error_init (error);
550 adclass = mono_class_get_appdomain_class ();
552 /* FIXME: pin all those objects */
553 data = mono_domain_create();
555 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
556 return_val_if_nok (error, NULL);
557 ad->data = data;
558 data->domain = ad;
559 data->friendly_name = g_strdup (friendly_name);
561 mono_profiler_appdomain_name (data, data->friendly_name);
563 if (!setup->application_base) {
564 /* Inherit from the root domain since MS.NET does this */
565 MonoDomain *root = mono_get_root_domain ();
566 if (root->setup->application_base) {
567 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
568 mono_error_assert_ok (error); /* FIXME don't swallow the error */
569 MONO_OBJECT_SETREF (setup, application_base, s);
573 mono_context_init_checked (data, error);
574 return_val_if_nok (error, NULL);
576 data->setup = copy_app_domain_setup (data, setup, error);
577 if (!mono_error_ok (error)) {
578 g_free (data->friendly_name);
579 return NULL;
582 mono_domain_set_options_from_config (data);
583 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
585 #ifndef DISABLE_SHADOW_COPY
586 /*FIXME, guard this for when the debugger is not running */
587 shadow_location = get_shadow_assembly_location_base (data, error);
588 if (!mono_error_ok (error)) {
589 g_free (data->friendly_name);
590 return NULL;
593 g_free (shadow_location);
594 #endif
596 create_domain_objects (data);
598 return ad;
602 * mono_domain_has_type_resolve:
603 * @domain: application domains being looked up
605 * Returns: TRUE if the AppDomain.TypeResolve field has been
606 * set.
608 gboolean
609 mono_domain_has_type_resolve (MonoDomain *domain)
611 static MonoClassField *field = NULL;
612 MonoObject *o;
614 if (field == NULL) {
615 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
616 g_assert (field);
619 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
620 if (!domain->domain)
621 return FALSE;
623 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
624 return o != NULL;
628 * mono_domain_try_type_resolve:
629 * @domain: application domainwhere the name where the type is going to be resolved
630 * @name: the name of the type to resolve or NULL.
631 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
633 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
634 * the assembly that matches name.
636 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
638 * Returns: A MonoReflectionAssembly or NULL if not found
640 MonoReflectionAssembly *
641 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
643 MonoError error;
644 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
645 mono_error_cleanup (&error);
647 return ret;
650 MonoReflectionAssembly *
651 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
653 static MonoMethod *method = NULL;
654 MonoReflectionAssembly *ret;
655 void *params [1];
657 mono_error_init (error);
659 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
661 if (method == NULL) {
662 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
663 if (method == NULL) {
664 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
665 return NULL;
669 if (name)
670 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
671 else
672 *params = tb;
674 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
675 return_val_if_nok (error, NULL);
677 return ret;
681 * mono_domain_owns_vtable_slot:
683 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
685 gboolean
686 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
688 gboolean res;
690 mono_domain_lock (domain);
691 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
692 mono_domain_unlock (domain);
693 return res;
697 * mono_domain_set:
698 * @domain: domain
699 * @force: force setting.
701 * Set the current appdomain to @domain. If @force is set, set it even
702 * if it is being unloaded.
704 * Returns:
705 * TRUE on success;
706 * FALSE if the domain is unloaded
708 gboolean
709 mono_domain_set (MonoDomain *domain, gboolean force)
711 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
712 return FALSE;
714 mono_domain_set_internal (domain);
716 return TRUE;
719 MonoObject *
720 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
722 MonoError error;
723 MonoDomain *add;
724 MonoObject *o;
725 char *str;
727 MONO_CHECK_ARG_NULL (name, NULL);
729 g_assert (ad);
730 add = ad->data;
731 g_assert (add);
733 str = mono_string_to_utf8_checked (name, &error);
734 if (mono_error_set_pending_exception (&error))
735 return NULL;
737 mono_domain_lock (add);
739 if (!strcmp (str, "APPBASE"))
740 o = (MonoObject *)add->setup->application_base;
741 else if (!strcmp (str, "APP_CONFIG_FILE"))
742 o = (MonoObject *)add->setup->configuration_file;
743 else if (!strcmp (str, "DYNAMIC_BASE"))
744 o = (MonoObject *)add->setup->dynamic_base;
745 else if (!strcmp (str, "APP_NAME"))
746 o = (MonoObject *)add->setup->application_name;
747 else if (!strcmp (str, "CACHE_BASE"))
748 o = (MonoObject *)add->setup->cache_path;
749 else if (!strcmp (str, "PRIVATE_BINPATH"))
750 o = (MonoObject *)add->setup->private_bin_path;
751 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
752 o = (MonoObject *)add->setup->private_bin_path_probe;
753 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
754 o = (MonoObject *)add->setup->shadow_copy_directories;
755 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
756 o = (MonoObject *)add->setup->shadow_copy_files;
757 else
758 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
760 mono_domain_unlock (add);
761 g_free (str);
763 if (!o)
764 return NULL;
766 return o;
769 void
770 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
772 MonoDomain *add;
774 MONO_CHECK_ARG_NULL (name,);
776 g_assert (ad);
777 add = ad->data;
778 g_assert (add);
780 mono_domain_lock (add);
782 mono_g_hash_table_insert (add->env, name, data);
784 mono_domain_unlock (add);
787 MonoAppDomainSetup *
788 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
790 g_assert (ad);
791 g_assert (ad->data);
793 return ad->data->setup;
796 MonoString *
797 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
799 g_assert (ad);
800 g_assert (ad->data);
802 return mono_string_new (ad->data, ad->data->friendly_name);
805 MonoAppDomain *
806 ves_icall_System_AppDomain_getCurDomain ()
808 MonoDomain *add = mono_domain_get ();
810 return add->domain;
813 MonoAppDomain *
814 ves_icall_System_AppDomain_getRootDomain ()
816 MonoDomain *root = mono_get_root_domain ();
818 return root->domain;
821 MonoBoolean
822 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
824 MonoDomain *domain = mono_domain_get ();
826 return domain->throw_unobserved_task_exceptions;
829 static char*
830 get_attribute_value (const gchar **attribute_names,
831 const gchar **attribute_values,
832 const char *att_name)
834 int n;
835 for (n = 0; attribute_names [n] != NULL; n++) {
836 if (strcmp (attribute_names [n], att_name) == 0)
837 return g_strdup (attribute_values [n]);
839 return NULL;
842 static void
843 start_element (GMarkupParseContext *context,
844 const gchar *element_name,
845 const gchar **attribute_names,
846 const gchar **attribute_values,
847 gpointer user_data,
848 GError **error)
850 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
852 if (strcmp (element_name, "runtime") == 0) {
853 runtime_config->runtime_count++;
854 return;
857 if (strcmp (element_name, "assemblyBinding") == 0) {
858 runtime_config->assemblybinding_count++;
859 return;
862 if (runtime_config->runtime_count != 1)
863 return;
865 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
866 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
868 if (value && g_ascii_strcasecmp (value, "true") == 0)
869 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
872 if (runtime_config->assemblybinding_count != 1)
873 return;
875 if (strcmp (element_name, "probing") != 0)
876 return;
878 g_free (runtime_config->domain->private_bin_path);
879 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
880 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
881 g_free (runtime_config->domain->private_bin_path);
882 runtime_config->domain->private_bin_path = NULL;
883 return;
887 static void
888 end_element (GMarkupParseContext *context,
889 const gchar *element_name,
890 gpointer user_data,
891 GError **error)
893 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
894 if (strcmp (element_name, "runtime") == 0)
895 runtime_config->runtime_count--;
896 else if (strcmp (element_name, "assemblyBinding") == 0)
897 runtime_config->assemblybinding_count--;
900 static void
901 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
903 RuntimeConfig *state = (RuntimeConfig *)user_data;
904 const gchar *msg;
905 const gchar *filename;
907 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
908 msg = error && error->message ? error->message : "";
909 g_warning ("Error parsing %s: %s", filename, msg);
912 static const GMarkupParser
913 mono_parser = {
914 start_element,
915 end_element,
916 NULL,
917 NULL,
918 parse_error
921 void
922 mono_domain_set_options_from_config (MonoDomain *domain)
924 MonoError error;
925 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
926 gsize len;
927 GMarkupParseContext *context;
928 RuntimeConfig runtime_config;
929 gint offset;
931 if (!domain || !domain->setup || !domain->setup->configuration_file)
932 return;
934 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
935 if (!mono_error_ok (&error)) {
936 mono_error_cleanup (&error);
937 goto free_and_out;
940 config_file_path = mono_portability_find_file (config_file_name, TRUE);
941 if (!config_file_path)
942 config_file_path = config_file_name;
944 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
945 goto free_and_out;
947 runtime_config.runtime_count = 0;
948 runtime_config.assemblybinding_count = 0;
949 runtime_config.domain = domain;
950 runtime_config.filename = config_file_path;
952 offset = 0;
953 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
954 offset = 3; /* Skip UTF-8 BOM */
956 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
957 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
958 g_markup_parse_context_end_parse (context, NULL);
959 g_markup_parse_context_free (context);
961 free_and_out:
962 g_free (text);
963 if (config_file_name != config_file_path)
964 g_free (config_file_name);
965 g_free (config_file_path);
968 MonoAppDomain *
969 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
971 MonoError error;
972 MonoAppDomain *ad = NULL;
974 #ifdef DISABLE_APPDOMAINS
975 mono_error_init (&error);
976 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
977 #else
978 char *fname;
980 fname = mono_string_to_utf8_checked (friendly_name, &error);
981 if (mono_error_set_pending_exception (&error))
982 return NULL;
983 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
985 g_free (fname);
986 #endif
987 mono_error_set_pending_exception (&error);
988 return ad;
991 static gboolean
992 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
994 HANDLE_FUNCTION_ENTER ();
995 mono_error_init (error);
996 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
997 if (!is_ok (error))
998 goto leave;
999 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1000 leave:
1001 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1004 MonoArrayHandle
1005 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1007 mono_error_init (error);
1008 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1009 MonoAssembly* ass;
1010 GSList *tmp;
1011 int i;
1012 GPtrArray *assemblies;
1015 * Make a copy of the list of assemblies because we can't hold the assemblies
1016 * lock while creating objects etc.
1018 assemblies = g_ptr_array_new ();
1019 /* Need to skip internal assembly builders created by remoting */
1020 mono_domain_assemblies_lock (domain);
1021 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1022 ass = (MonoAssembly *)tmp->data;
1023 if (refonly != ass->ref_only)
1024 continue;
1025 if (ass->corlib_internal)
1026 continue;
1027 g_ptr_array_add (assemblies, ass);
1029 mono_domain_assemblies_unlock (domain);
1031 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1032 if (!is_ok (error))
1033 goto leave;
1034 for (i = 0; i < assemblies->len; ++i) {
1035 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1036 goto leave;
1039 leave:
1040 g_ptr_array_free (assemblies, TRUE);
1041 return res;
1044 MonoAssembly*
1045 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1047 HANDLE_FUNCTION_ENTER ();
1048 mono_error_init (error);
1049 MonoAssembly *result = NULL;
1050 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1051 if (!is_ok (error))
1052 goto leave;
1053 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1054 leave:
1055 HANDLE_FUNCTION_RETURN_VAL (result);
1058 MonoAssembly*
1059 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1061 MonoAssembly *ret = NULL;
1062 MonoMethod *method;
1063 MonoBoolean isrefonly;
1064 gpointer params [3];
1066 mono_error_init (error);
1068 if (mono_runtime_get_no_exec ())
1069 return ret;
1071 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1073 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1074 g_assert (method != NULL);
1076 isrefonly = refonly ? 1 : 0;
1077 MonoReflectionAssemblyHandle requesting_handle;
1078 if (requesting) {
1079 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1080 return_val_if_nok (error, ret);
1082 params [0] = MONO_HANDLE_RAW (fname);
1083 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1084 params [2] = &isrefonly;
1085 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1086 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1087 return ret;
1090 MonoAssembly *
1091 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1092 gboolean refonly)
1094 MonoError error;
1095 MonoAssembly *assembly;
1096 MonoDomain *domain = mono_domain_get ();
1097 char *aname_str;
1099 aname_str = mono_stringify_assembly_name (aname);
1101 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1103 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1104 g_free (aname_str);
1105 mono_error_cleanup (&error);
1107 return assembly;
1111 * LOCKING: assumes assemblies_lock in the domain is already locked.
1113 static void
1114 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1116 gint i;
1117 GSList *tmp;
1118 gboolean destroy_ht = FALSE;
1120 if (!ass->aname.name)
1121 return;
1123 if (!ht) {
1124 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1125 destroy_ht = TRUE;
1128 /* FIXME: handle lazy loaded assemblies */
1129 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1130 g_hash_table_insert (ht, tmp->data, tmp->data);
1132 if (!g_hash_table_lookup (ht, ass)) {
1133 mono_assembly_addref (ass);
1134 g_hash_table_insert (ht, ass, ass);
1135 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1136 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);
1139 if (ass->image->references) {
1140 for (i = 0; ass->image->references [i] != NULL; i++) {
1141 if (ass->image->references [i] != REFERENCE_MISSING)
1142 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1143 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1147 if (destroy_ht)
1148 g_hash_table_destroy (ht);
1151 static void
1152 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1154 static MonoClassField *assembly_load_field;
1155 static MonoMethod *assembly_load_method;
1156 MonoError error;
1157 MonoDomain *domain = mono_domain_get ();
1158 MonoClass *klass;
1159 gpointer load_value;
1160 void *params [1];
1162 if (!domain->domain)
1163 /* This can happen during startup */
1164 return;
1165 #ifdef ASSEMBLY_LOAD_DEBUG
1166 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1167 #endif
1168 klass = domain->domain->mbr.obj.vtable->klass;
1170 mono_domain_assemblies_lock (domain);
1171 add_assemblies_to_domain (domain, assembly, NULL);
1172 mono_domain_assemblies_unlock (domain);
1174 if (assembly_load_field == NULL) {
1175 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1176 g_assert (assembly_load_field);
1179 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1180 if (load_value == NULL) {
1181 /* No events waiting to be triggered */
1182 return;
1185 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1186 mono_error_assert_ok (&error);
1188 if (assembly_load_method == NULL) {
1189 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1190 g_assert (assembly_load_method);
1193 *params = MONO_HANDLE_RAW(ref_assembly);
1195 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1196 mono_error_cleanup (&error);
1200 * LOCKING: Acquires the domain assemblies lock.
1202 static void
1203 set_domain_search_path (MonoDomain *domain)
1205 MonoError error;
1206 MonoAppDomainSetup *setup;
1207 gchar **tmp;
1208 gchar *search_path = NULL;
1209 gint i;
1210 gint npaths = 0;
1211 gchar **pvt_split = NULL;
1212 GError *gerror = NULL;
1213 gint appbaselen = -1;
1216 * We use the low-level domain assemblies lock, since this is called from
1217 * assembly loads hooks, which means this thread might hold the loader lock.
1219 mono_domain_assemblies_lock (domain);
1221 if (!domain->setup) {
1222 mono_domain_assemblies_unlock (domain);
1223 return;
1226 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1227 mono_domain_assemblies_unlock (domain);
1228 return;
1230 setup = domain->setup;
1231 if (!setup->application_base) {
1232 mono_domain_assemblies_unlock (domain);
1233 return; /* Must set application base to get private path working */
1236 npaths++;
1238 if (setup->private_bin_path) {
1239 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1240 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1241 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1242 mono_error_cleanup (&error);
1243 mono_domain_assemblies_unlock (domain);
1244 return;
1248 if (domain->private_bin_path) {
1249 if (search_path == NULL)
1250 search_path = domain->private_bin_path;
1251 else {
1252 gchar *tmp2 = search_path;
1253 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1254 g_free (tmp2);
1258 if (search_path) {
1260 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1261 * directories relative to ApplicationBase separated by semicolons (see
1262 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1263 * The loop below copes with the fact that some Unix applications may use ':' (or
1264 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1265 * ';' for the subsequent split.
1267 * The issue was reported in bug #81446
1270 #ifndef TARGET_WIN32
1271 gint slen;
1273 slen = strlen (search_path);
1274 for (i = 0; i < slen; i++)
1275 if (search_path [i] == ':')
1276 search_path [i] = ';';
1277 #endif
1279 pvt_split = g_strsplit (search_path, ";", 1000);
1280 g_free (search_path);
1281 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1284 if (!npaths) {
1285 if (pvt_split)
1286 g_strfreev (pvt_split);
1288 * Don't do this because the first time is called, the domain
1289 * setup is not finished.
1291 * domain->search_path = g_malloc (sizeof (char *));
1292 * domain->search_path [0] = NULL;
1294 mono_domain_assemblies_unlock (domain);
1295 return;
1298 if (domain->search_path)
1299 g_strfreev (domain->search_path);
1301 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1302 tmp [npaths] = NULL;
1304 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1305 if (!mono_error_ok (&error)) {
1306 mono_error_cleanup (&error);
1307 g_strfreev (pvt_split);
1308 g_free (tmp);
1310 mono_domain_assemblies_unlock (domain);
1311 return;
1314 domain->search_path = tmp;
1316 /* FIXME: is this needed? */
1317 if (strncmp (*tmp, "file://", 7) == 0) {
1318 gchar *file = *tmp;
1319 gchar *uri = *tmp;
1320 gchar *tmpuri;
1322 if (uri [7] != '/')
1323 uri = g_strdup_printf ("file:///%s", uri + 7);
1325 tmpuri = uri;
1326 uri = mono_escape_uri_string (tmpuri);
1327 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1328 g_free (uri);
1330 if (tmpuri != file)
1331 g_free (tmpuri);
1333 if (gerror != NULL) {
1334 g_warning ("%s\n", gerror->message);
1335 g_error_free (gerror);
1336 *tmp = file;
1337 } else {
1338 g_free (file);
1342 for (i = 1; pvt_split && i < npaths; i++) {
1343 if (g_path_is_absolute (pvt_split [i - 1])) {
1344 tmp [i] = g_strdup (pvt_split [i - 1]);
1345 } else {
1346 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1349 if (strchr (tmp [i], '.')) {
1350 gchar *reduced;
1351 gchar *freeme;
1353 reduced = mono_path_canonicalize (tmp [i]);
1354 if (appbaselen == -1)
1355 appbaselen = strlen (tmp [0]);
1357 if (strncmp (tmp [0], reduced, appbaselen)) {
1358 g_free (reduced);
1359 g_free (tmp [i]);
1360 tmp [i] = g_strdup ("");
1361 continue;
1364 freeme = tmp [i];
1365 tmp [i] = reduced;
1366 g_free (freeme);
1370 if (setup->private_bin_path_probe != NULL) {
1371 g_free (tmp [0]);
1372 tmp [0] = g_strdup ("");
1375 domain->setup->path_changed = FALSE;
1377 g_strfreev (pvt_split);
1379 mono_domain_assemblies_unlock (domain);
1382 #ifdef DISABLE_SHADOW_COPY
1383 gboolean
1384 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1386 return FALSE;
1389 char *
1390 mono_make_shadow_copy (const char *filename, MonoError *error)
1392 mono_error_init (error);
1393 return (char *) filename;
1395 #else
1396 static gboolean
1397 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1399 guint16 *orig, *dest;
1400 gboolean copy_result;
1402 strcpy (src + srclen - tail_len, extension);
1404 if (IS_PORTABILITY_CASE) {
1405 gchar *file = mono_portability_find_file (src, TRUE);
1407 if (file == NULL)
1408 return TRUE;
1410 g_free (file);
1411 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1412 return TRUE;
1415 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1417 strcpy (target + targetlen - tail_len, extension);
1418 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1420 DeleteFile (dest);
1422 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1423 copy_result = CopyFile (orig, dest, FALSE);
1424 #else
1425 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1426 #endif
1428 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1429 * overwritten when updated in their original locations. */
1430 if (copy_result)
1431 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1433 g_free (orig);
1434 g_free (dest);
1436 return copy_result;
1439 static gint32
1440 get_cstring_hash (const char *str)
1442 int len, i;
1443 const char *p;
1444 gint32 h = 0;
1446 if (!str || !str [0])
1447 return 0;
1449 len = strlen (str);
1450 p = str;
1451 for (i = 0; i < len; i++) {
1452 h = (h << 5) - h + *p;
1453 p++;
1456 return h;
1460 * Returned memory is malloc'd. Called must free it
1462 static char *
1463 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1465 MonoAppDomainSetup *setup;
1466 char *cache_path, *appname;
1467 char *userdir;
1468 char *location;
1470 mono_error_init (error);
1472 setup = domain->setup;
1473 if (setup->cache_path != NULL && setup->application_name != NULL) {
1474 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1475 return_val_if_nok (error, NULL);
1477 #ifndef TARGET_WIN32
1479 gint i;
1480 for (i = strlen (cache_path) - 1; i >= 0; i--)
1481 if (cache_path [i] == '\\')
1482 cache_path [i] = '/';
1484 #endif
1486 appname = mono_string_to_utf8_checked (setup->application_name, error);
1487 if (!mono_error_ok (error)) {
1488 g_free (cache_path);
1489 return NULL;
1492 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1493 g_free (appname);
1494 g_free (cache_path);
1495 } else {
1496 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1497 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1498 g_free (userdir);
1500 return location;
1503 static char *
1504 get_shadow_assembly_location (const char *filename, MonoError *error)
1506 gint32 hash = 0, hash2 = 0;
1507 char name_hash [9];
1508 char path_hash [30];
1509 char *bname = g_path_get_basename (filename);
1510 char *dirname = g_path_get_dirname (filename);
1511 char *location, *tmploc;
1512 MonoDomain *domain = mono_domain_get ();
1514 mono_error_init (error);
1516 hash = get_cstring_hash (bname);
1517 hash2 = get_cstring_hash (dirname);
1518 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1519 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1520 tmploc = get_shadow_assembly_location_base (domain, error);
1521 if (!mono_error_ok (error)) {
1522 g_free (bname);
1523 g_free (dirname);
1524 return NULL;
1527 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1528 g_free (tmploc);
1529 g_free (bname);
1530 g_free (dirname);
1531 return location;
1534 static gboolean
1535 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1537 struct stat sbuf_dest;
1538 gchar *stat_src;
1539 gchar *real_src = mono_portability_find_file (src, TRUE);
1541 if (!real_src)
1542 stat_src = (gchar*)src;
1543 else
1544 stat_src = real_src;
1546 if (stat (stat_src, sbuf_src) == -1) {
1547 time_t tnow = time (NULL);
1549 if (real_src)
1550 g_free (real_src);
1552 memset (sbuf_src, 0, sizeof (*sbuf_src));
1553 sbuf_src->st_mtime = tnow;
1554 sbuf_src->st_atime = tnow;
1555 return TRUE;
1558 if (real_src)
1559 g_free (real_src);
1561 if (stat (dest, &sbuf_dest) == -1)
1562 return TRUE;
1564 if (sbuf_src->st_size == sbuf_dest.st_size &&
1565 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1566 return FALSE;
1568 return TRUE;
1571 static gboolean
1572 shadow_copy_create_ini (const char *shadow, const char *filename)
1574 char *dir_name;
1575 char *ini_file;
1576 guint16 *u16_ini;
1577 gboolean result;
1578 guint32 n;
1579 HANDLE *handle;
1580 gchar *full_path;
1582 dir_name = g_path_get_dirname (shadow);
1583 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1584 g_free (dir_name);
1585 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1586 g_free (ini_file);
1587 return TRUE;
1590 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1591 g_free (ini_file);
1592 if (!u16_ini) {
1593 return FALSE;
1595 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1596 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1597 g_free (u16_ini);
1598 if (handle == INVALID_HANDLE_VALUE) {
1599 return FALSE;
1602 full_path = mono_path_resolve_symlinks (filename);
1603 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1604 g_free (full_path);
1605 CloseHandle (handle);
1606 return result;
1609 gboolean
1610 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1612 MonoError error;
1613 MonoAppDomainSetup *setup;
1614 gchar *all_dirs;
1615 gchar **dir_ptr;
1616 gchar **directories;
1617 gchar *shadow_status_string;
1618 gchar *base_dir;
1619 gboolean shadow_enabled;
1620 gboolean found = FALSE;
1622 if (domain == NULL)
1623 return FALSE;
1625 setup = domain->setup;
1626 if (setup == NULL || setup->shadow_copy_files == NULL)
1627 return FALSE;
1629 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1630 if (!mono_error_ok (&error)) {
1631 mono_error_cleanup (&error);
1632 return FALSE;
1634 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1635 g_free (shadow_status_string);
1637 if (!shadow_enabled)
1638 return FALSE;
1640 if (setup->shadow_copy_directories == NULL)
1641 return TRUE;
1643 /* Is dir_name a shadow_copy destination already? */
1644 base_dir = get_shadow_assembly_location_base (domain, &error);
1645 if (!mono_error_ok (&error)) {
1646 mono_error_cleanup (&error);
1647 return FALSE;
1650 if (strstr (dir_name, base_dir)) {
1651 g_free (base_dir);
1652 return TRUE;
1654 g_free (base_dir);
1656 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1657 if (!mono_error_ok (&error)) {
1658 mono_error_cleanup (&error);
1659 return FALSE;
1662 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1663 dir_ptr = directories;
1664 while (*dir_ptr) {
1665 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1666 found = TRUE;
1667 break;
1669 dir_ptr++;
1671 g_strfreev (directories);
1672 g_free (all_dirs);
1673 return found;
1677 This function raises exceptions so it can cause as sorts of nasty stuff if called
1678 while holding a lock.
1679 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1680 or NULL if source file not found.
1681 FIXME bubble up the error instead of raising it here
1683 char *
1684 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1686 MonoError error;
1687 gchar *sibling_source, *sibling_target;
1688 gint sibling_source_len, sibling_target_len;
1689 guint16 *orig, *dest;
1690 guint32 attrs;
1691 char *shadow;
1692 gboolean copy_result;
1693 struct stat src_sbuf;
1694 struct utimbuf utbuf;
1695 char *dir_name = g_path_get_dirname (filename);
1696 MonoDomain *domain = mono_domain_get ();
1697 char *shadow_dir;
1699 mono_error_init (oerror);
1701 set_domain_search_path (domain);
1703 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1704 g_free (dir_name);
1705 return (char *) filename;
1708 /* Is dir_name a shadow_copy destination already? */
1709 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1710 if (!mono_error_ok (&error)) {
1711 mono_error_cleanup (&error);
1712 g_free (dir_name);
1713 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1714 return NULL;
1717 if (strstr (dir_name, shadow_dir)) {
1718 g_free (shadow_dir);
1719 g_free (dir_name);
1720 return (char *) filename;
1722 g_free (shadow_dir);
1723 g_free (dir_name);
1725 shadow = get_shadow_assembly_location (filename, &error);
1726 if (!mono_error_ok (&error)) {
1727 mono_error_cleanup (&error);
1728 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1729 return NULL;
1732 if (g_ensure_directory_exists (shadow) == FALSE) {
1733 g_free (shadow);
1734 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1735 return NULL;
1738 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1739 return (char*) shadow;
1741 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1742 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1743 DeleteFile (dest);
1745 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1746 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1747 * and not have it runtime error" */
1748 attrs = GetFileAttributes (orig);
1749 if (attrs == INVALID_FILE_ATTRIBUTES) {
1750 g_free (shadow);
1751 return (char *)filename;
1754 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1755 copy_result = CopyFile (orig, dest, FALSE);
1756 #else
1757 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1758 #endif
1760 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1761 * overwritten when updated in their original locations. */
1762 if (copy_result)
1763 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1765 g_free (dest);
1766 g_free (orig);
1768 if (copy_result == FALSE) {
1769 g_free (shadow);
1771 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1772 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1773 return NULL; /* file not found, shadow copy failed */
1775 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1776 return NULL;
1779 /* attempt to copy .mdb, .config if they exist */
1780 sibling_source = g_strconcat (filename, ".config", NULL);
1781 sibling_source_len = strlen (sibling_source);
1782 sibling_target = g_strconcat (shadow, ".config", NULL);
1783 sibling_target_len = strlen (sibling_target);
1785 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1786 if (copy_result)
1787 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1789 g_free (sibling_source);
1790 g_free (sibling_target);
1792 if (!copy_result) {
1793 g_free (shadow);
1794 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1795 return NULL;
1798 /* Create a .ini file containing the original assembly location */
1799 if (!shadow_copy_create_ini (shadow, filename)) {
1800 g_free (shadow);
1801 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1802 return NULL;
1805 utbuf.actime = src_sbuf.st_atime;
1806 utbuf.modtime = src_sbuf.st_mtime;
1807 utime (shadow, &utbuf);
1809 return shadow;
1811 #endif /* DISABLE_SHADOW_COPY */
1813 MonoDomain *
1814 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1816 if (appdomain == NULL)
1817 return NULL;
1819 return appdomain->data;
1822 static gboolean
1823 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1824 const gchar *path3, const gchar *path4,
1825 gboolean refonly, gboolean is_private)
1827 gchar *fullpath;
1828 gboolean found = FALSE;
1830 *assembly = NULL;
1831 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1833 if (IS_PORTABILITY_SET) {
1834 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1835 if (new_fullpath) {
1836 g_free (fullpath);
1837 fullpath = new_fullpath;
1838 found = TRUE;
1840 } else
1841 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1843 if (found)
1844 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1846 g_free (fullpath);
1847 return (*assembly != NULL);
1850 static MonoAssembly *
1851 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1853 MonoAssembly *result = NULL;
1854 gchar **path;
1855 gchar *filename;
1856 const gchar *local_culture;
1857 gint len;
1858 gboolean is_private = FALSE;
1860 if (!culture || *culture == '\0') {
1861 local_culture = "";
1862 } else {
1863 local_culture = culture;
1866 filename = g_strconcat (name, ".dll", NULL);
1867 len = strlen (filename);
1869 for (path = search_path; *path; path++) {
1870 if (**path == '\0') {
1871 is_private = TRUE;
1872 continue; /* Ignore empty ApplicationBase */
1875 /* See test cases in bug #58992 and bug #57710 */
1876 /* 1st try: [culture]/[name].dll (culture may be empty) */
1877 strcpy (filename + len - 4, ".dll");
1878 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1879 break;
1881 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1882 strcpy (filename + len - 4, ".exe");
1883 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1884 break;
1886 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1887 strcpy (filename + len - 4, ".dll");
1888 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1889 break;
1891 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1892 strcpy (filename + len - 4, ".exe");
1893 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1894 break;
1897 g_free (filename);
1898 return result;
1902 * Try loading the assembly from ApplicationBase and PrivateBinPath
1903 * and then from assemblies_path if any.
1904 * LOCKING: This is called from the assembly loading code, which means the caller
1905 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1907 static MonoAssembly *
1908 mono_domain_assembly_preload (MonoAssemblyName *aname,
1909 gchar **assemblies_path,
1910 gpointer user_data)
1912 MonoDomain *domain = mono_domain_get ();
1913 MonoAssembly *result = NULL;
1914 gboolean refonly = GPOINTER_TO_UINT (user_data);
1916 set_domain_search_path (domain);
1918 if (domain->search_path && domain->search_path [0] != NULL) {
1919 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1922 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1923 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1926 return result;
1930 * Check whenever a given assembly was already loaded in the current appdomain.
1932 static MonoAssembly *
1933 mono_domain_assembly_search (MonoAssemblyName *aname,
1934 gpointer user_data)
1936 MonoDomain *domain = mono_domain_get ();
1937 GSList *tmp;
1938 MonoAssembly *ass;
1939 gboolean refonly = GPOINTER_TO_UINT (user_data);
1941 mono_domain_assemblies_lock (domain);
1942 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1943 ass = (MonoAssembly *)tmp->data;
1944 /* Dynamic assemblies can't match here in MS.NET */
1945 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1946 continue;
1948 mono_domain_assemblies_unlock (domain);
1949 return ass;
1951 mono_domain_assemblies_unlock (domain);
1953 return NULL;
1956 MonoReflectionAssemblyHandle
1957 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
1959 mono_error_init (error);
1960 MonoDomain *domain = mono_domain_get ();
1961 char *name, *filename;
1962 MonoImageOpenStatus status = MONO_IMAGE_OK;
1963 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
1965 name = NULL;
1966 result = NULL;
1968 if (fname == NULL) {
1969 mono_error_set_argument_null (error, "assemblyFile", "");
1970 goto leave;
1973 name = filename = mono_string_handle_to_utf8 (fname, error);
1974 if (!is_ok (error))
1975 goto leave;
1977 MonoAssembly *ass = mono_assembly_open_full (filename, &status, refOnly);
1979 if (!ass) {
1980 if (status == MONO_IMAGE_IMAGE_INVALID)
1981 mono_error_set_bad_image_name (error, g_strdup (name), "");
1982 else
1983 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
1984 goto leave;
1987 result = mono_assembly_get_object_handle (domain, ass, error);
1989 leave:
1990 g_free (name);
1991 return result;
1994 MonoReflectionAssemblyHandle
1995 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
1996 MonoArrayHandle raw_assembly,
1997 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
1998 MonoBoolean refonly,
1999 MonoError *error)
2001 mono_error_init (error);
2002 MonoAssembly *ass;
2003 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2004 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2005 MonoImageOpenStatus status;
2006 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2008 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2009 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2010 if (!assembly_data) {
2011 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2012 return refass;
2014 uint32_t gchandle;
2015 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2016 memcpy (assembly_data, raw_data, raw_assembly_len);
2017 mono_gchandle_free (gchandle); /* unpin */
2018 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2020 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2022 if (!image) {
2023 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2024 return refass;
2027 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2028 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2029 uint32_t symbol_gchandle;
2030 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2031 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2032 mono_gchandle_free (symbol_gchandle);
2035 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2038 if (!ass) {
2039 mono_image_close (image);
2040 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2041 return refass;
2044 refass = mono_assembly_get_object_handle (domain, ass, error);
2045 if (!MONO_HANDLE_IS_NULL(refass))
2046 MONO_HANDLE_SET (refass, evidence, evidence);
2047 return refass;
2050 MonoReflectionAssemblyHandle
2051 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2053 mono_error_init (error);
2054 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2055 MonoImageOpenStatus status = MONO_IMAGE_OK;
2056 MonoAssembly *ass;
2057 MonoAssemblyName aname;
2058 gchar *name = NULL;
2059 gboolean parsed;
2061 g_assert (assRef);
2063 name = mono_string_handle_to_utf8 (assRef, error);
2064 if (!is_ok (error))
2065 goto fail;
2066 parsed = mono_assembly_name_parse (name, &aname);
2067 g_free (name);
2069 if (!parsed) {
2070 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2071 /* This is a parse error... */
2072 if (!refOnly) {
2073 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2074 if (!is_ok (error))
2075 goto fail;
2076 if (assm) {
2077 refass = mono_assembly_get_object_handle (domain, assm, error);
2078 if (!is_ok (error))
2079 goto fail;
2082 return refass;
2085 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2086 mono_assembly_name_free (&aname);
2088 if (!ass) {
2089 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2090 if (!refOnly) {
2091 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2092 if (!is_ok (error))
2093 goto fail;
2095 if (!ass)
2096 goto fail;
2099 g_assert (ass);
2100 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2101 if (!is_ok (error))
2102 goto fail;
2104 MONO_HANDLE_SET (refass, evidence, evidence);
2106 return refass;
2107 fail:
2108 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2111 void
2112 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2114 MonoException *exc = NULL;
2115 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2117 if (NULL == domain) {
2118 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2119 mono_set_pending_exception (exc);
2120 return;
2123 if (domain == mono_get_root_domain ()) {
2124 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2125 return;
2129 * Unloading seems to cause problems when running NUnit/NAnt, hence
2130 * this workaround.
2132 if (g_getenv ("MONO_NO_UNLOAD"))
2133 return;
2134 #ifdef __native_client__
2135 return;
2136 #endif
2138 mono_domain_try_unload (domain, (MonoObject**)&exc);
2139 if (exc)
2140 mono_set_pending_exception (exc);
2143 gboolean
2144 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2146 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2148 if (!domain)
2149 return TRUE;
2151 return mono_domain_is_unloading (domain);
2154 void
2155 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2157 mono_unhandled_exception ((MonoObject*) exc);
2160 gint32
2161 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2162 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2163 MonoError *error)
2165 mono_error_init (error);
2166 MonoImage *image;
2167 MonoMethod *method;
2169 g_assert (!MONO_HANDLE_IS_NULL (refass));
2170 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2171 image = assembly->image;
2172 g_assert (image);
2174 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2176 if (!method)
2177 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2179 if (MONO_HANDLE_IS_NULL (args)) {
2180 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2181 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2182 mono_error_assert_ok (error);
2185 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2186 return res;
2189 gint32
2190 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2192 return ad->data->domain_id;
2195 MonoAppDomain *
2196 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2198 MonoDomain *old_domain = mono_domain_get();
2200 if (!mono_domain_set (ad->data, FALSE)) {
2201 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2202 return NULL;
2205 return old_domain->domain;
2208 MonoAppDomain *
2209 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2211 MonoDomain *current_domain = mono_domain_get ();
2212 MonoDomain *domain = mono_domain_get_by_id (domainid);
2214 if (!domain || !mono_domain_set (domain, FALSE)) {
2215 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2216 return NULL;
2219 return current_domain->domain;
2222 void
2223 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2225 mono_thread_push_appdomain_ref (ad->data);
2228 void
2229 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2231 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2233 if (!domain) {
2235 * Raise an exception to prevent the managed code from executing a pop
2236 * later.
2238 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2239 return;
2242 mono_thread_push_appdomain_ref (domain);
2245 void
2246 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2248 mono_thread_pop_appdomain_ref ();
2251 MonoAppContext *
2252 ves_icall_System_AppDomain_InternalGetContext ()
2254 return mono_context_get ();
2257 MonoAppContext *
2258 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2260 return mono_domain_get ()->default_context;
2263 MonoAppContext *
2264 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2266 MonoAppContext *old_context = mono_context_get ();
2268 mono_context_set (mc);
2270 return old_context;
2273 MonoString *
2274 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2276 MonoDomain* mono_root_domain = mono_get_root_domain ();
2277 mono_domain_lock (mono_root_domain);
2278 if (process_guid_set) {
2279 mono_domain_unlock (mono_root_domain);
2280 MonoError error;
2281 MonoString *res = NULL;
2282 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2283 mono_error_set_pending_exception (&error);
2284 return res;
2286 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2287 process_guid_set = TRUE;
2288 mono_domain_unlock (mono_root_domain);
2289 return newguid;
2292 gboolean
2293 mono_domain_is_unloading (MonoDomain *domain)
2295 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2296 return TRUE;
2297 else
2298 return FALSE;
2301 static void
2302 clear_cached_vtable (MonoVTable *vtable)
2304 MonoClass *klass = vtable->klass;
2305 MonoDomain *domain = vtable->domain;
2306 MonoClassRuntimeInfo *runtime_info;
2307 void *data;
2309 runtime_info = klass->runtime_info;
2310 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2311 runtime_info->domain_vtables [domain->domain_id] = NULL;
2312 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2313 mono_gc_free_fixed (data);
2316 static G_GNUC_UNUSED void
2317 zero_static_data (MonoVTable *vtable)
2319 MonoClass *klass = vtable->klass;
2320 void *data;
2322 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2323 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2326 typedef struct unload_data {
2327 gboolean done;
2328 MonoDomain *domain;
2329 char *failure_reason;
2330 gint32 refcount;
2331 } unload_data;
2333 static void
2334 unload_data_unref (unload_data *data)
2336 gint32 count;
2337 do {
2338 mono_atomic_load_acquire (count, gint32, &data->refcount);
2339 g_assert (count >= 1 && count <= 2);
2340 if (count == 1) {
2341 g_free (data);
2342 return;
2344 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2347 static void
2348 deregister_reflection_info_roots_from_list (MonoImage *image)
2350 GSList *list = image->reflection_info_unregister_classes;
2352 while (list) {
2353 MonoClass *klass = (MonoClass *)list->data;
2355 mono_class_free_ref_info (klass);
2357 list = list->next;
2360 image->reflection_info_unregister_classes = NULL;
2363 static void
2364 deregister_reflection_info_roots (MonoDomain *domain)
2366 GSList *list;
2368 mono_domain_assemblies_lock (domain);
2369 for (list = domain->domain_assemblies; list; list = list->next) {
2370 MonoAssembly *assembly = (MonoAssembly *)list->data;
2371 MonoImage *image = assembly->image;
2372 int i;
2375 * No need to take the image lock here since dynamic images are appdomain bound and
2376 * at this point the mutator is gone. Taking the image lock here would mean
2377 * promoting it from a simple lock to a complex lock, which we better avoid if
2378 * possible.
2380 if (image_is_dynamic (image))
2381 deregister_reflection_info_roots_from_list (image);
2383 for (i = 0; i < image->module_count; ++i) {
2384 MonoImage *module = image->modules [i];
2385 if (module && image_is_dynamic (module))
2386 deregister_reflection_info_roots_from_list (module);
2389 mono_domain_assemblies_unlock (domain);
2392 static gsize WINAPI
2393 unload_thread_main (void *arg)
2395 MonoError error;
2396 unload_data *data = (unload_data*)arg;
2397 MonoDomain *domain = data->domain;
2398 MonoThread *thread;
2399 int i;
2401 /* Have to attach to the runtime so shutdown can wait for this thread */
2402 /* Force it to be attached to avoid racing during shutdown. */
2403 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2405 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2406 if (!is_ok (&error)) {
2407 data->failure_reason = g_strdup (mono_error_get_message (&error));
2408 mono_error_cleanup (&error);
2409 goto failure;
2413 * FIXME: Abort our parent thread last, so we can return a failure
2414 * indication if aborting times out.
2416 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2417 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2418 goto failure;
2421 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2422 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2423 goto failure;
2426 /* Finalize all finalizable objects in the doomed appdomain */
2427 if (!mono_domain_finalize (domain, -1)) {
2428 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2429 goto failure;
2432 /* Clear references to our vtables in class->runtime_info.
2433 * We also hold the loader lock because we're going to change
2434 * class->runtime_info.
2437 mono_loader_lock (); //FIXME why do we need the loader lock here?
2438 mono_domain_lock (domain);
2439 #ifdef HAVE_SGEN_GC
2441 * We need to make sure that we don't have any remsets
2442 * pointing into static data of the to-be-freed domain because
2443 * at the next collections they would be invalid. So what we
2444 * do is we first zero all static data and then do a minor
2445 * collection. Because all references in the static data will
2446 * now be null we won't do any unnecessary copies and after
2447 * the collection there won't be any more remsets.
2449 for (i = 0; i < domain->class_vtable_array->len; ++i)
2450 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2451 mono_gc_collect (0);
2452 #endif
2453 for (i = 0; i < domain->class_vtable_array->len; ++i)
2454 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2455 deregister_reflection_info_roots (domain);
2457 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2459 mono_domain_unlock (domain);
2460 mono_loader_unlock ();
2462 mono_threads_clear_cached_culture (domain);
2464 domain->state = MONO_APPDOMAIN_UNLOADED;
2466 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2468 /* remove from the handle table the items related to this domain */
2469 mono_gchandle_free_domain (domain);
2471 mono_domain_free (domain, FALSE);
2473 mono_gc_collect (mono_gc_max_generation ());
2475 mono_atomic_store_release (&data->done, TRUE);
2476 unload_data_unref (data);
2477 mono_thread_detach (thread);
2478 return 0;
2480 failure:
2481 mono_atomic_store_release (&data->done, TRUE);
2482 unload_data_unref (data);
2483 mono_thread_detach (thread);
2484 return 1;
2488 * mono_domain_unload:
2489 * @domain: The domain to unload
2491 * Unloads an appdomain. Follows the process outlined in the comment
2492 * for mono_domain_try_unload.
2494 void
2495 mono_domain_unload (MonoDomain *domain)
2497 MonoObject *exc = NULL;
2498 mono_domain_try_unload (domain, &exc);
2501 static MonoThreadInfoWaitRet
2502 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2504 MonoThreadInfoWaitRet result;
2506 MONO_ENTER_GC_SAFE;
2507 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2508 MONO_EXIT_GC_SAFE;
2510 return result;
2514 * mono_domain_unload:
2515 * @domain: The domain to unload
2516 * @exc: Exception information
2518 * Unloads an appdomain. Follows the process outlined in:
2519 * http://blogs.gotdotnet.com/cbrumme
2521 * If doing things the 'right' way is too hard or complex, we do it the
2522 * 'simple' way, which means do everything needed to avoid crashes and
2523 * memory leaks, but not much else.
2525 * It is required to pass a valid reference to the exc argument, upon return
2526 * from this function *exc will be set to the exception thrown, if any.
2528 * If this method is not called from an icall (embedded scenario for instance),
2529 * it must not be called with any managed frames on the stack, since the unload
2530 * process could end up trying to abort the current thread.
2532 void
2533 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2535 MonoError error;
2536 MonoThreadHandle *thread_handle;
2537 MonoAppDomainState prev_state;
2538 MonoMethod *method;
2539 unload_data *thread_data;
2540 MonoNativeThreadId tid;
2541 MonoDomain *caller_domain = mono_domain_get ();
2543 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2545 /* Atomically change our state to UNLOADING */
2546 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2547 MONO_APPDOMAIN_UNLOADING_START,
2548 MONO_APPDOMAIN_CREATED);
2549 if (prev_state != MONO_APPDOMAIN_CREATED) {
2550 switch (prev_state) {
2551 case MONO_APPDOMAIN_UNLOADING_START:
2552 case MONO_APPDOMAIN_UNLOADING:
2553 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2554 return;
2555 case MONO_APPDOMAIN_UNLOADED:
2556 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2557 return;
2558 default:
2559 g_warning ("Invalid appdomain state %d", prev_state);
2560 g_assert_not_reached ();
2564 mono_domain_set (domain, FALSE);
2565 /* Notify OnDomainUnload listeners */
2566 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2567 g_assert (method);
2569 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2571 if (!mono_error_ok (&error)) {
2572 if (*exc)
2573 mono_error_cleanup (&error);
2574 else
2575 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2578 if (*exc) {
2579 /* Roll back the state change */
2580 domain->state = MONO_APPDOMAIN_CREATED;
2581 mono_domain_set (caller_domain, FALSE);
2582 return;
2584 mono_domain_set (caller_domain, FALSE);
2586 thread_data = g_new0 (unload_data, 1);
2587 thread_data->domain = domain;
2588 thread_data->failure_reason = NULL;
2589 thread_data->done = FALSE;
2590 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2592 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2593 domain->state = MONO_APPDOMAIN_UNLOADING;
2595 * First we create a separate thread for unloading, since
2596 * we might have to abort some threads, including the current one.
2598 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, NULL, &tid);
2599 if (thread_handle == NULL)
2600 return;
2602 /* Wait for the thread */
2603 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2604 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2605 /* The unload thread tries to abort us */
2606 /* The icall wrapper will execute the abort */
2607 mono_threads_close_thread_handle (thread_handle);
2608 unload_data_unref (thread_data);
2609 return;
2613 mono_threads_close_thread_handle (thread_handle);
2615 if (thread_data->failure_reason) {
2616 /* Roll back the state change */
2617 domain->state = MONO_APPDOMAIN_CREATED;
2619 g_warning ("%s", thread_data->failure_reason);
2621 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2623 g_free (thread_data->failure_reason);
2624 thread_data->failure_reason = NULL;
2627 unload_data_unref (thread_data);