[Loader] Change mono_trace level from info to debug (#19110)
[mono-project.git] / mono / metadata / appdomain.c
blob55ff92e847db93ffdd85ba5939edff624ae76782
1 /**
2 * \file
3 * AppDomain functions
5 * Authors:
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Patrik Torstensson
8 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2012 Xamarin Inc
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
16 #include <config.h>
17 #include <glib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <time.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_UTIME_H
30 #include <utime.h>
31 #else
32 #ifdef HAVE_SYS_UTIME_H
33 #include <sys/utime.h>
34 #endif
35 #endif
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/object.h>
39 #include <mono/metadata/appdomain-icalls.h>
40 #include <mono/metadata/class-init.h>
41 #include <mono/metadata/domain-internals.h>
42 #include "mono/metadata/metadata-internals.h"
43 #include <mono/metadata/assembly-internals.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/exception-internals.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/mono-gc.h>
50 #include <mono/metadata/mono-hash-internals.h>
51 #include <mono/metadata/marshal.h>
52 #include <mono/metadata/marshal-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/metadata/mono-debug.h>
55 #include <mono/metadata/attach.h>
56 #include <mono/metadata/w32file.h>
57 #include <mono/metadata/lock-tracer.h>
58 #include <mono/metadata/console-io.h>
59 #include <mono/metadata/threads-types.h>
60 #include <mono/metadata/tokentype.h>
61 #include <mono/metadata/profiler-private.h>
62 #include <mono/metadata/reflection-internals.h>
63 #include <mono/metadata/abi-details.h>
64 #include <mono/metadata/w32socket.h>
65 #include <mono/utils/mono-uri.h>
66 #include <mono/utils/mono-logger-internals.h>
67 #include <mono/utils/mono-path.h>
68 #include <mono/utils/mono-stdlib.h>
69 #include <mono/utils/mono-io-portability.h>
70 #include <mono/utils/mono-error-internals.h>
71 #include <mono/utils/atomic.h>
72 #include <mono/utils/mono-memory-model.h>
73 #include <mono/utils/mono-threads.h>
74 #include <mono/metadata/w32handle.h>
75 #include <mono/metadata/w32error.h>
76 #include <mono/utils/w32api.h>
77 #ifdef HOST_WIN32
78 #include <direct.h>
79 #endif
80 #include "object-internals.h"
81 #include "icall-decl.h"
83 typedef struct
85 int runtime_count;
86 int assemblybinding_count;
87 MonoDomain *domain;
88 gchar *filename;
89 } RuntimeConfig;
91 #ifndef ENABLE_NETCORE
92 static gunichar2 process_guid [36];
93 static gboolean process_guid_set = FALSE;
94 #endif
96 static gboolean no_exec = FALSE;
98 #ifdef ENABLE_NETCORE
99 static int n_appctx_props;
100 static gunichar2 **appctx_keys;
101 static gunichar2 **appctx_values;
102 #endif
104 static const char *
105 mono_check_corlib_version_internal (void);
107 static MonoAssembly *
108 mono_domain_assembly_preload (MonoAssemblyLoadContext *alc,
109 MonoAssemblyName *aname,
110 gchar **assemblies_path,
111 gboolean refonly,
112 gpointer user_data,
113 MonoError *error);
115 static MonoAssembly *
116 mono_domain_assembly_search (MonoAssemblyLoadContext *alc, MonoAssembly *requesting,
117 MonoAssemblyName *aname,
118 gboolean refonly,
119 gboolean postload,
120 gpointer user_data,
121 MonoError *error);
124 static void
125 mono_domain_fire_assembly_load (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer user_data, MonoError *error_out);
127 static gboolean
128 mono_domain_asmctx_from_path (const char *fname, MonoAssembly *requesting_assembly, gpointer user_data, MonoAssemblyContextKind *out_asmctx);
130 static void
131 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht);
133 #if ENABLE_NETCORE
135 static void
136 add_assembly_to_alc (MonoAssemblyLoadContext *alc, MonoAssembly *ass);
138 #endif
140 static MonoAppDomainHandle
141 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
143 static MonoDomain *
144 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
147 static void
148 mono_context_set_default_context (MonoDomain *domain);
150 static char *
151 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
153 static MonoLoadFunc load_function = NULL;
155 /* Lazy class loading functions */
156 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
157 #ifdef ENABLE_NETCORE
158 static GENERATE_GET_CLASS_WITH_CACHE (app_context, "System", "AppContext");
159 #endif
161 GENERATE_GET_CLASS_WITH_CACHE (appdomain, MONO_APPDOMAIN_CLASS_NAME_SPACE, MONO_APPDOMAIN_CLASS_NAME);
162 GENERATE_GET_CLASS_WITH_CACHE (appdomain_setup, MONO_APPDOMAIN_SETUP_CLASS_NAME_SPACE, MONO_APPDOMAIN_SETUP_CLASS_NAME);
164 static MonoDomain *
165 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
167 static void
168 mono_error_set_appdomain_unloaded (MonoError *error)
170 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
173 void
174 mono_install_runtime_load (MonoLoadFunc func)
176 load_function = func;
179 MonoDomain*
180 mono_runtime_load (const char *filename, const char *runtime_version)
182 g_assert (load_function);
183 return load_function (filename, runtime_version);
187 * mono_runtime_set_no_exec:
189 * Instructs the runtime to operate in static mode, i.e. avoid/do not
190 * allow managed code execution. This is useful for running the AOT
191 * compiler on platforms which allow full-aot execution only. This
192 * should be called before mono_runtime_init ().
194 void
195 mono_runtime_set_no_exec (gboolean val)
197 no_exec = val;
201 * mono_runtime_get_no_exec:
203 * If true, then the runtime will not allow managed code execution.
205 gboolean
206 mono_runtime_get_no_exec (void)
208 return no_exec;
211 static void
212 create_domain_objects (MonoDomain *domain)
214 HANDLE_FUNCTION_ENTER ();
215 ERROR_DECL (error);
217 MonoDomain *old_domain = mono_domain_get ();
218 MonoStringHandle arg;
219 MonoVTable *string_vt;
220 MonoClassField *string_empty_fld;
222 if (domain != old_domain) {
223 mono_thread_push_appdomain_ref (domain);
224 mono_domain_set_internal_with_options (domain, FALSE);
228 * Initialize String.Empty. This enables the removal of
229 * the static cctor of the String class.
231 string_vt = mono_class_vtable_checked (domain, mono_defaults.string_class, error);
232 mono_error_assert_ok (error);
233 string_empty_fld = mono_class_get_field_from_name_full (mono_defaults.string_class, "Empty", NULL);
234 g_assert (string_empty_fld);
235 MonoStringHandle empty_str = mono_string_new_handle (domain, "", error);
236 mono_error_assert_ok (error);
237 empty_str = mono_string_intern_checked (empty_str, error);
238 mono_error_assert_ok (error);
239 mono_field_static_set_value_internal (string_vt, string_empty_fld, MONO_HANDLE_RAW (empty_str));
240 domain->empty_string = MONO_HANDLE_RAW (empty_str);
243 * Create an instance early since we can't do it when there is no memory.
245 arg = mono_string_new_handle (domain, "Out of memory", error);
246 mono_error_assert_ok (error);
247 domain->out_of_memory_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL_HANDLE_STRING, error));
248 mono_error_assert_ok (error);
251 * These two are needed because the signal handlers might be executing on
252 * an alternate stack, and Boehm GC can't handle that.
254 arg = mono_string_new_handle (domain, "A null value was found where an object instance was required", error);
255 mono_error_assert_ok (error);
256 domain->null_reference_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL_HANDLE_STRING, error));
257 mono_error_assert_ok (error);
258 arg = mono_string_new_handle (domain, "The requested operation caused a stack overflow.", error);
259 mono_error_assert_ok (error);
260 domain->stack_overflow_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL_HANDLE_STRING, error));
261 mono_error_assert_ok (error);
263 /*The ephemeron tombstone i*/
264 domain->ephemeron_tombstone = MONO_HANDLE_RAW (mono_object_new_handle (domain, mono_defaults.object_class, error));
265 mono_error_assert_ok (error);
267 if (domain != old_domain) {
268 mono_thread_pop_appdomain_ref ();
269 mono_domain_set_internal_with_options (old_domain, FALSE);
273 * This class is used during exception handling, so initialize it here, to prevent
274 * stack overflows while handling stack overflows.
276 mono_class_init_internal (mono_class_create_array (mono_defaults.int_class, 1));
277 HANDLE_FUNCTION_RETURN ();
281 * mono_runtime_init:
282 * \param domain domain returned by \c mono_init
284 * Initialize the core AppDomain: this function will run also some
285 * IL initialization code, so it needs the execution engine to be fully
286 * operational.
288 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
289 * we know the \c entry_assembly.
292 void
293 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
295 ERROR_DECL (error);
296 mono_runtime_init_checked (domain, start_cb, attach_cb, error);
297 mono_error_cleanup (error);
300 void
301 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
303 HANDLE_FUNCTION_ENTER ();
305 MonoAppDomainSetupHandle setup;
306 MonoAppDomainHandle ad;
308 error_init (error);
310 mono_portability_helpers_init ();
312 mono_gc_base_init ();
313 mono_monitor_init ();
314 mono_marshal_init ();
315 mono_gc_init_icalls ();
317 mono_install_assembly_preload_hook_v2 (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE), FALSE);
318 mono_install_assembly_search_hook_v2 (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE), FALSE, FALSE);
319 mono_install_assembly_search_hook_v2 (mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE), FALSE, TRUE);
320 mono_install_assembly_load_hook_v2 (mono_domain_fire_assembly_load, NULL);
322 #ifndef ENABLE_NETCORE // refonly hooks
323 mono_install_assembly_preload_hook_v2 (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE), TRUE);
324 mono_install_assembly_search_hook_v2 (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE), TRUE, FALSE);
325 mono_install_assembly_search_hook_v2 (mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE), TRUE, TRUE);
326 mono_install_assembly_asmctx_from_path_hook (mono_domain_asmctx_from_path, NULL);
327 #endif
329 mono_thread_init (start_cb, attach_cb);
331 if (!mono_runtime_get_no_exec ()) {
332 MonoClass *klass = mono_class_get_appdomain_setup_class ();
333 setup = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_pinned_handle (domain, klass, error));
334 goto_if_nok (error, exit);
336 klass = mono_class_get_appdomain_class ();
338 ad = MONO_HANDLE_CAST (MonoAppDomain, mono_object_new_pinned_handle (domain, klass, error));
339 goto_if_nok (error, exit);
341 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, domain);
342 domain->domain = MONO_HANDLE_RAW (ad);
343 domain->setup = MONO_HANDLE_RAW (setup);
346 mono_thread_attach (domain);
348 mono_type_initialization_init ();
350 if (!mono_runtime_get_no_exec ())
351 create_domain_objects (domain);
353 /* GC init has to happen after thread init */
354 mono_gc_init ();
356 /* contexts use GC handles, so they must be initialized after the GC */
357 #ifndef ENABLE_NETCORE
358 mono_context_init_checked (domain, error);
359 goto_if_nok (error, exit);
360 mono_context_set_default_context (domain);
361 #endif
363 #ifdef ENABLE_NETCORE
364 if (!mono_runtime_get_no_exec ())
365 mono_runtime_install_appctx_properties ();
366 #endif
368 mono_network_init ();
369 mono_console_init ();
370 mono_attach_init ();
372 mono_locks_tracer_init ();
374 /* mscorlib is loaded before we install the load hook */
375 mono_domain_fire_assembly_load (mono_domain_default_alc (domain), mono_defaults.corlib->assembly, NULL, error);
376 goto_if_nok (error, exit);
378 exit:
379 HANDLE_FUNCTION_RETURN ();
382 static void
383 mono_context_set_default_context (MonoDomain *domain)
385 if (mono_runtime_get_no_exec ())
386 return;
388 HANDLE_FUNCTION_ENTER ();
389 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext, domain->default_context));
390 HANDLE_FUNCTION_RETURN ();
393 static char*
394 mono_get_corlib_version (void)
396 ERROR_DECL (error);
398 MonoClass *klass;
399 MonoClassField *field;
401 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
402 mono_class_init_internal (klass);
403 field = mono_class_get_field_from_name_full (klass, "mono_corlib_version", NULL);
404 if (!field)
405 return NULL;
407 if (! (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_LITERAL)))
408 return NULL;
410 char *value;
411 MonoTypeEnum field_type;
412 const char *data = mono_class_get_field_default_value (field, &field_type);
413 if (field_type != MONO_TYPE_STRING)
414 return NULL;
415 mono_metadata_read_constant_value (data, field_type, &value, error);
416 mono_error_assert_ok (error);
418 char *res = mono_string_from_blob (value, error);
419 mono_error_assert_ok (error);
421 return res;
425 * mono_check_corlib_version:
426 * Checks that the corlib that is loaded matches the version of this runtime.
427 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
428 * allocated string with the error otherwise.
430 const char*
431 mono_check_corlib_version (void)
433 const char* res;
434 MONO_ENTER_GC_UNSAFE;
435 res = mono_check_corlib_version_internal ();
436 MONO_EXIT_GC_UNSAFE;
437 return res;
440 static const char *
441 mono_check_corlib_version_internal (void)
443 #if defined(MONO_CROSS_COMPILE)
444 /* Can't read the corlib version because we only have the target class layouts */
445 return NULL;
446 #else
447 char *result = NULL;
448 char *version = mono_get_corlib_version ();
449 if (!version) {
450 result = g_strdup_printf ("expected corlib string (%s) but not found or not string", MONO_CORLIB_VERSION);
451 goto exit;
453 if (strcmp (version, MONO_CORLIB_VERSION) != 0) {
454 result = g_strdup_printf ("The runtime did not find the mscorlib.dll it expected. "
455 "Expected interface version %s but found %s. Check that "
456 "your runtime and class libraries are matching.",
457 MONO_CORLIB_VERSION, version);
458 goto exit;
461 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
462 guint32 native_offset;
463 guint32 managed_offset;
464 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
465 managed_offset = mono_field_get_offset (mono_class_get_field_from_name_full (mono_defaults.internal_thread_class, "last", NULL));
466 if (native_offset != managed_offset)
467 result = g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
468 exit:
469 g_free (version);
470 return result;
471 #endif
475 * mono_context_init:
476 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
477 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
479 void
480 mono_context_init (MonoDomain *domain)
482 ERROR_DECL (error);
483 mono_context_init_checked (domain, error);
484 mono_error_cleanup (error);
487 void
488 mono_context_init_checked (MonoDomain *domain, MonoError *error)
490 HANDLE_FUNCTION_ENTER ();
492 MonoClass *klass;
493 MonoAppContextHandle context;
495 error_init (error);
496 if (mono_runtime_get_no_exec ())
497 goto exit;
499 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
500 context = MONO_HANDLE_CAST (MonoAppContext, mono_object_new_pinned_handle (domain, klass, error));
501 goto_if_nok (error, exit);
503 MONO_HANDLE_SETVAL (context, domain_id, gint32, domain->domain_id);
504 MONO_HANDLE_SETVAL (context, context_id, gint32, 0);
505 mono_threads_register_app_context (context, error);
506 mono_error_assert_ok (error);
507 domain->default_context = MONO_HANDLE_RAW (context);
508 exit:
509 HANDLE_FUNCTION_RETURN ();
513 * mono_runtime_cleanup:
514 * \param domain unused.
516 * Internal routine.
518 * This must not be called while there are still running threads executing
519 * managed code.
521 void
522 mono_runtime_cleanup (MonoDomain *domain)
524 mono_attach_cleanup ();
526 /* This ends up calling any pending pending (for at most 2 seconds) */
527 mono_gc_cleanup ();
529 mono_thread_cleanup ();
530 mono_network_cleanup ();
531 mono_marshal_cleanup ();
533 mono_type_initialization_cleanup ();
535 mono_monitor_cleanup ();
538 static MonoDomainFunc quit_function = NULL;
541 * mono_install_runtime_cleanup:
543 void
544 mono_install_runtime_cleanup (MonoDomainFunc func)
546 quit_function = func;
550 * mono_runtime_quit:
552 void
553 mono_runtime_quit (void)
555 MONO_STACKDATA (dummy);
556 (void) mono_threads_enter_gc_unsafe_region_unbalanced_internal (&dummy);
557 // after quit_function (in particular, mini_cleanup) everything is
558 // cleaned up so MONO_EXIT_GC_UNSAFE can't work and doesn't make sense.
560 mono_runtime_quit_internal ();
564 * mono_runtime_quit_internal:
566 void
567 mono_runtime_quit_internal (void)
569 MONO_REQ_GC_UNSAFE_MODE;
570 // but note that when we return, we're not in GC Unsafe mode anymore.
571 // After clean up threads don't _have_ a thread state anymore.
573 if (quit_function != NULL)
574 quit_function (mono_get_root_domain (), NULL);
578 * mono_domain_create_appdomain:
579 * \param friendly_name The friendly name of the appdomain to create
580 * \param configuration_file The configuration file to initialize the appdomain with
581 * \returns a \c MonoDomain initialized with the appdomain
583 MonoDomain *
584 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
586 HANDLE_FUNCTION_ENTER ();
587 MonoDomain *domain;
588 MONO_ENTER_GC_UNSAFE;
589 ERROR_DECL (error);
590 domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, error);
591 mono_error_cleanup (error);
592 MONO_EXIT_GC_UNSAFE;
593 HANDLE_FUNCTION_RETURN_VAL (domain);
597 * mono_domain_create_appdomain_checked:
598 * \param friendly_name The friendly name of the appdomain to create
599 * \param configuration_file The configuration file to initialize the appdomain with
600 * \param error Set on error.
602 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
604 MonoDomain *
605 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
607 HANDLE_FUNCTION_ENTER ();
608 error_init (error);
609 MonoDomain *result = NULL;
611 MonoClass *klass = mono_class_get_appdomain_setup_class ();
612 MonoAppDomainSetupHandle setup = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_handle (mono_domain_get (), klass, error));
613 goto_if_nok (error, leave);
614 MonoStringHandle config_file;
615 if (configuration_file != NULL) {
616 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
617 goto_if_nok (error, leave);
618 } else {
619 config_file = MONO_HANDLE_NEW (MonoString, NULL);
621 MONO_HANDLE_SET (setup, configuration_file, config_file);
623 MonoAppDomainHandle ad;
624 ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
625 goto_if_nok (error, leave);
627 result = mono_domain_from_appdomain_handle (ad);
628 leave:
629 HANDLE_FUNCTION_RETURN_VAL (result);
633 * mono_domain_set_config:
634 * \param domain \c MonoDomain initialized with the appdomain we want to change
635 * \param base_dir new base directory for the appdomain
636 * \param config_file_name path to the new configuration for the app domain
638 * Used to set the system configuration for an appdomain
640 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
641 * Error Initializing the configuration system. ---> System.ArgumentException:
642 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
644 void
645 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
647 HANDLE_FUNCTION_ENTER ();
648 MONO_ENTER_GC_UNSAFE;
649 ERROR_DECL (error);
650 mono_domain_set_config_checked (domain, base_dir, config_file_name, error);
651 mono_error_cleanup (error);
652 MONO_EXIT_GC_UNSAFE;
653 HANDLE_FUNCTION_RETURN ();
656 gboolean
657 mono_domain_set_config_checked (MonoDomain *domain, const char *base_dir, const char *config_file_name, MonoError *error)
659 error_init (error);
660 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
661 MonoStringHandle base_dir_str = mono_string_new_handle (domain, base_dir, error);
662 goto_if_nok (error, leave);
663 MONO_HANDLE_SET (setup, application_base, base_dir_str);
664 MonoStringHandle config_file_name_str;
665 config_file_name_str = mono_string_new_handle (domain, config_file_name, error);
666 goto_if_nok (error, leave);
667 MONO_HANDLE_SET (setup, configuration_file, config_file_name_str);
668 leave:
669 return is_ok (error);
672 static MonoAppDomainSetupHandle
673 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
675 HANDLE_FUNCTION_ENTER ();
676 MonoDomain *caller_domain;
677 MonoClass *ads_class;
678 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
680 error_init (error);
682 caller_domain = mono_domain_get ();
683 ads_class = mono_class_get_appdomain_setup_class ();
685 MonoAppDomainSetupHandle copy = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_handle(domain, ads_class, error));
686 goto_if_nok (error, leave);
688 mono_domain_set_internal_with_options (domain, TRUE);
690 #define XCOPY_FIELD(type, dst, field, src, error) \
691 do { \
692 TYPED_HANDLE_NAME (type) src_val = MONO_HANDLE_NEW_GET (type, (src), field); \
693 TYPED_HANDLE_NAME (type) copied_val = MONO_HANDLE_CAST (type, mono_marshal_xdomain_copy_value_handle (MONO_HANDLE_CAST (MonoObject, src_val), error)); \
694 goto_if_nok (error, leave); \
695 MONO_HANDLE_SET ((dst),field,copied_val); \
696 } while (0)
698 #define COPY_VAL(dst,field,type,src) \
699 do { \
700 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
701 } while (0)
703 XCOPY_FIELD (MonoString, copy, application_base, setup, error);
704 XCOPY_FIELD (MonoString, copy, application_name, setup, error);
705 XCOPY_FIELD (MonoString, copy, cache_path, setup, error);
706 XCOPY_FIELD (MonoString, copy, configuration_file, setup, error);
707 XCOPY_FIELD (MonoString, copy, dynamic_base, setup, error);
708 XCOPY_FIELD (MonoString, copy, license_file, setup, error);
709 XCOPY_FIELD (MonoString, copy, private_bin_path, setup, error);
710 XCOPY_FIELD (MonoString, copy, private_bin_path_probe, setup, error);
711 XCOPY_FIELD (MonoString, copy, shadow_copy_directories, setup, error);
712 XCOPY_FIELD (MonoString, copy, shadow_copy_files, setup, error);
713 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
714 COPY_VAL (copy, path_changed, MonoBoolean, setup);
715 COPY_VAL (copy, loader_optimization, int, setup);
716 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
717 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
718 XCOPY_FIELD (MonoArray, copy, domain_initializer_args, setup, error);
719 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
720 XCOPY_FIELD (MonoObject, copy, application_trust, setup, error);
721 XCOPY_FIELD (MonoArray, copy, configuration_bytes, setup, error);
722 XCOPY_FIELD (MonoArray, copy, serialized_non_primitives, setup, error);
724 #undef XCOPY_FIELD
725 #undef COPY_VAL
727 mono_domain_set_internal_with_options (caller_domain, TRUE);
729 MONO_HANDLE_ASSIGN (result, copy);
730 leave:
731 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
734 static MonoAppDomainHandle
735 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
737 HANDLE_FUNCTION_ENTER ();
738 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
739 MonoClass *adclass;
740 MonoDomain *data;
742 error_init (error);
744 adclass = mono_class_get_appdomain_class ();
746 /* FIXME: pin all those objects */
747 data = mono_domain_create();
749 MonoAppDomainHandle ad = MONO_HANDLE_CAST (MonoAppDomain, mono_object_new_handle (data, adclass, error));
750 goto_if_nok (error, leave);
751 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
752 data->domain = MONO_HANDLE_RAW (ad);
753 data->friendly_name = g_strdup (friendly_name);
755 MONO_PROFILER_RAISE (domain_name, (data, data->friendly_name));
757 MonoStringHandle app_base;
758 app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
759 if (MONO_HANDLE_IS_NULL (app_base)) {
760 /* Inherit from the root domain since MS.NET does this */
761 MonoDomain *root = mono_get_root_domain ();
762 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
763 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
764 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
765 /* N.B. new string is in the new domain */
766 MonoGCHandle gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
767 MonoStringHandle s = mono_string_new_utf16_handle (data, mono_string_chars_internal (MONO_HANDLE_RAW (root_app_base)), mono_string_handle_length (root_app_base), error);
768 mono_gchandle_free_internal (gchandle);
769 if (!is_ok (error)) {
770 g_free (data->friendly_name);
771 goto leave;
773 MONO_HANDLE_SET (setup, application_base, s);
777 mono_context_init_checked (data, error);
778 goto_if_nok (error, leave);
780 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
781 if (!is_ok (error)) {
782 g_free (data->friendly_name);
783 goto leave;
786 mono_domain_set_options_from_config (data);
787 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
789 #ifndef DISABLE_SHADOW_COPY
790 /*FIXME, guard this for when the debugger is not running */
791 char *shadow_location;
792 shadow_location = get_shadow_assembly_location_base (data, error);
793 if (!is_ok (error)) {
794 g_free (data->friendly_name);
795 goto leave;
798 g_free (shadow_location);
799 #endif
801 create_domain_objects (data);
803 MONO_HANDLE_ASSIGN (result, ad);
804 leave:
805 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
809 * mono_domain_has_type_resolve:
810 * \param domain application domain being looked up
812 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
814 gboolean
815 mono_domain_has_type_resolve (MonoDomain *domain)
817 // Check whether managed code is running, and if the managed AppDomain object doesn't exist neither does the event handler
818 if (!domain->domain)
819 return FALSE;
821 #ifdef ENABLE_NETCORE
822 return TRUE;
823 #else
824 MonoObject *o;
826 MONO_STATIC_POINTER_INIT (MonoClassField, field)
828 field = mono_class_get_field_from_name_full (mono_defaults.appdomain_class, "TypeResolve", NULL);
829 g_assert (field);
831 MONO_STATIC_POINTER_INIT_END (MonoClassField, field)
833 mono_field_get_value_internal ((MonoObject*)(domain->domain), field, &o);
834 return o != NULL;
835 #endif
839 * mono_domain_try_type_resolve:
840 * \param domain application domain in which to resolve the type
841 * \param name the name of the type to resolve or NULL.
842 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
844 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
845 * the assembly that matches name, or ((TypeBuilder)typebuilder).FullName.
847 * \returns A \c MonoReflectionAssembly or NULL if not found
849 MonoReflectionAssembly *
850 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *typebuilder_raw)
852 HANDLE_FUNCTION_ENTER ();
854 g_assert (domain);
855 g_assert (name || typebuilder_raw);
857 ERROR_DECL (error);
859 MonoReflectionAssemblyHandle ret = NULL_HANDLE_INIT;
861 // This will not work correctly on netcore
862 if (name) {
863 MonoStringHandle name_handle = mono_string_new_handle (mono_domain_get (), name, error);
864 goto_if_nok (error, exit);
865 ret = mono_domain_try_type_resolve_name (domain, NULL, name_handle, error);
866 } else {
867 #ifndef ENABLE_NETCORE
868 MONO_HANDLE_DCL (MonoObject, typebuilder);
869 ret = mono_domain_try_type_resolve_typebuilder (domain, MONO_HANDLE_CAST (MonoReflectionTypeBuilder, typebuilder), error);
870 #else
871 // TODO: make this work on netcore when working on SRE.TypeBuilder
872 g_assert_not_reached ();
873 #endif
876 exit:
877 mono_error_cleanup (error);
878 HANDLE_FUNCTION_RETURN_OBJ (ret);
881 #ifdef ENABLE_NETCORE
882 MonoReflectionAssemblyHandle
883 mono_domain_try_type_resolve_name (MonoDomain *domain, MonoAssembly *assembly, MonoStringHandle name, MonoError *error)
885 MonoObjectHandle ret;
886 MonoReflectionAssemblyHandle assembly_handle;
888 HANDLE_FUNCTION_ENTER ();
890 MONO_STATIC_POINTER_INIT (MonoMethod, method)
892 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
893 g_assert (alc_class);
894 method = mono_class_get_method_from_name_checked (alc_class, "OnTypeResolve", -1, 0, error);
896 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
898 goto_if_nok (error, return_null);
900 g_assert (domain);
901 g_assert (MONO_HANDLE_BOOL (name));
903 if (mono_runtime_get_no_exec ())
904 goto return_null;
906 if (assembly) {
907 assembly_handle = mono_assembly_get_object_handle (domain, assembly, error);
908 goto_if_nok (error, return_null);
911 gpointer args [2];
912 args [0] = assembly ? MONO_HANDLE_RAW (assembly_handle) : NULL;
913 args [1] = MONO_HANDLE_RAW (name);
914 ret = mono_runtime_try_invoke_handle (method, NULL_HANDLE, args, error);
915 goto_if_nok (error, return_null);
916 goto exit;
918 return_null:
919 ret = NULL_HANDLE;
921 exit:
922 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
924 #else
926 * mono_class_get_appdomain_do_type_resolve_method:
928 * This routine returns System.AppDomain.DoTypeResolve.
930 static MonoMethod *
931 mono_class_get_appdomain_do_type_resolve_method (MonoError *error)
933 MONO_STATIC_POINTER_INIT (MonoMethod, method)
935 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoTypeResolve", -1, 0, error);
937 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
939 if (method == NULL)
940 g_warning ("%s method AppDomain.DoTypeResolve not found. %s\n", __func__, mono_error_get_message (error));
942 return method;
946 * mono_class_get_appdomain_do_type_builder_resolve_method:
948 * This routine returns System.AppDomain.DoTypeBuilderResolve.
950 static MonoMethod *
951 mono_class_get_appdomain_do_type_builder_resolve_method (MonoError *error)
953 MONO_STATIC_POINTER_INIT (MonoMethod, method)
955 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoTypeBuilderResolve", -1, 0, error);
957 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
959 if (method == NULL)
960 g_warning ("%s method AppDomain.DoTypeBuilderResolve not found. %s\n", __func__, mono_error_get_message (error));
962 return method;
966 * mono_domain_try_type_resolve_name:
967 * \param domain application domain in which to resolve the type
968 * \param name the name of the type to resolve.
970 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
971 * the assembly that matches name.
973 * \returns A \c MonoReflectionAssembly or NULL if not found
975 MonoReflectionAssemblyHandle
976 mono_domain_try_type_resolve_name (MonoDomain *domain, MonoAssembly *assembly, MonoStringHandle name, MonoError *error)
978 HANDLE_FUNCTION_ENTER ();
980 void *params [1] = { 0 };
982 g_assert (domain);
983 g_assert (MONO_HANDLE_BOOL (name));
984 g_assert (error);
986 error_init (error);
988 MonoMethod *method;
989 method = mono_class_get_appdomain_do_type_resolve_method (error);
990 goto_if_nok (error, return_null);
992 MonoAppDomainHandle appdomain;
993 appdomain = MONO_HANDLE_NEW (MonoAppDomain, domain->domain);
995 MonoObjectHandle ret;
996 params [0] = MONO_HANDLE_RAW (name);
997 ret = mono_runtime_invoke_handle (method, MONO_HANDLE_CAST (MonoObject, appdomain), params, error);
998 goto_if_nok (error, return_null);
999 goto exit;
1000 return_null:
1001 ret = NULL_HANDLE;
1002 exit:
1003 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
1007 * mono_domain_try_type_resolve_typebuilder:
1008 * \param domain application domain in which to resolve the type
1009 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder; typebuilder.FullName is the name of the type to resolve.
1011 * This routine invokes the internal \c System.AppDomain.DoTypeBuilderResolve and returns
1012 * the assembly that matches typebuilder.FullName.
1014 * \returns A \c MonoReflectionAssembly or NULL_HANDLE if not found
1016 MonoReflectionAssemblyHandle
1017 mono_domain_try_type_resolve_typebuilder (MonoDomain *domain, MonoReflectionTypeBuilderHandle typebuilder, MonoError *error)
1019 HANDLE_FUNCTION_ENTER ();
1021 g_assert (domain);
1022 g_assert (MONO_HANDLE_BOOL (typebuilder));
1023 g_assert (error);
1025 error_init (error);
1027 MonoMethod * const method = mono_class_get_appdomain_do_type_builder_resolve_method (error);
1028 goto_if_nok (error, return_null);
1030 MonoAppDomainHandle appdomain;
1031 appdomain = MONO_HANDLE_NEW (MonoAppDomain, domain->domain);
1032 void *args [1];
1033 args [0] = MONO_HANDLE_RAW (typebuilder);
1035 MonoObjectHandle ret;
1036 ret = mono_runtime_invoke_handle (method, MONO_HANDLE_CAST (MonoObject, appdomain), args, error);
1037 goto_if_nok (error, return_null);
1038 goto exit;
1039 return_null:
1040 ret = NULL_HANDLE;
1041 exit:
1042 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
1044 #endif
1047 * mono_domain_owns_vtable_slot:
1048 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
1050 gboolean
1051 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
1053 gboolean res;
1055 mono_domain_lock (domain);
1056 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
1057 mono_domain_unlock (domain);
1058 return res;
1061 gboolean
1062 mono_domain_set_fast (MonoDomain *domain, gboolean force)
1064 MONO_REQ_GC_UNSAFE_MODE;
1065 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
1066 return FALSE;
1068 mono_domain_set_internal_with_options (domain, TRUE);
1069 return TRUE;
1072 #ifndef ENABLE_NETCORE
1073 MonoObjectHandle
1074 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
1076 error_init (error);
1078 if (MONO_HANDLE_IS_NULL (name)) {
1079 mono_error_set_argument_null (error, "name", "");
1080 return NULL_HANDLE;
1083 g_assert (!MONO_HANDLE_IS_NULL (ad));
1084 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
1085 g_assert (add);
1087 char *str = mono_string_handle_to_utf8 (name, error);
1088 return_val_if_nok (error, NULL_HANDLE);
1090 mono_domain_lock (add);
1092 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
1093 MonoStringHandle o;
1094 if (!strcmp (str, "APPBASE"))
1095 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
1096 else if (!strcmp (str, "APP_CONFIG_FILE"))
1097 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
1098 else if (!strcmp (str, "DYNAMIC_BASE"))
1099 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
1100 else if (!strcmp (str, "APP_NAME"))
1101 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
1102 else if (!strcmp (str, "CACHE_BASE"))
1103 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
1104 else if (!strcmp (str, "PRIVATE_BINPATH"))
1105 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
1106 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
1107 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
1108 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
1109 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
1110 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
1111 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
1112 else
1113 o = MONO_HANDLE_NEW (MonoString, (MonoString*)mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
1115 mono_domain_unlock (add);
1116 g_free (str);
1118 return MONO_HANDLE_CAST (MonoObject, o);
1121 void
1122 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
1124 error_init (error);
1126 if (MONO_HANDLE_IS_NULL (name)) {
1127 mono_error_set_argument_null (error, "name", "");
1128 return;
1131 g_assert (!MONO_HANDLE_IS_NULL (ad));
1132 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
1133 g_assert (add);
1135 mono_domain_lock (add);
1137 mono_g_hash_table_insert_internal (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
1139 mono_domain_unlock (add);
1142 MonoAppDomainSetupHandle
1143 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
1145 error_init (error);
1146 g_assert (!MONO_HANDLE_IS_NULL (ad));
1147 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1148 g_assert (domain);
1150 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
1153 MonoStringHandle
1154 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
1156 error_init (error);
1157 g_assert (!MONO_HANDLE_IS_NULL (ad));
1158 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1159 g_assert (domain);
1161 return mono_string_new_handle (domain, domain->friendly_name, error);
1164 MonoAppDomainHandle
1165 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
1167 error_init (error);
1168 MonoDomain *add = mono_domain_get ();
1170 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
1173 MonoAppDomainHandle
1174 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
1176 error_init (error);
1177 MonoDomain *root = mono_get_root_domain ();
1179 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
1182 MonoBoolean
1183 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions (MonoError *error)
1185 MonoDomain *domain = mono_domain_get ();
1187 return domain->throw_unobserved_task_exceptions;
1189 #endif
1191 static char*
1192 get_attribute_value (const gchar **attribute_names,
1193 const gchar **attribute_values,
1194 const char *att_name)
1196 int n;
1197 for (n = 0; attribute_names [n] != NULL; n++) {
1198 if (strcmp (attribute_names [n], att_name) == 0)
1199 return g_strdup (attribute_values [n]);
1201 return NULL;
1204 static void
1205 start_element (GMarkupParseContext *context,
1206 const gchar *element_name,
1207 const gchar **attribute_names,
1208 const gchar **attribute_values,
1209 gpointer user_data,
1210 GError **gerror)
1212 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
1214 if (strcmp (element_name, "runtime") == 0) {
1215 runtime_config->runtime_count++;
1216 return;
1219 if (strcmp (element_name, "assemblyBinding") == 0) {
1220 runtime_config->assemblybinding_count++;
1221 return;
1224 if (runtime_config->runtime_count != 1)
1225 return;
1227 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
1228 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
1230 if (value && g_ascii_strcasecmp (value, "true") == 0)
1231 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
1234 if (runtime_config->assemblybinding_count != 1)
1235 return;
1237 if (strcmp (element_name, "probing") != 0)
1238 return;
1240 g_free (runtime_config->domain->private_bin_path);
1241 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
1242 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
1243 g_free (runtime_config->domain->private_bin_path);
1244 runtime_config->domain->private_bin_path = NULL;
1245 return;
1249 static void
1250 end_element (GMarkupParseContext *context,
1251 const gchar *element_name,
1252 gpointer user_data,
1253 GError **gerror)
1255 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
1256 if (strcmp (element_name, "runtime") == 0)
1257 runtime_config->runtime_count--;
1258 else if (strcmp (element_name, "assemblyBinding") == 0)
1259 runtime_config->assemblybinding_count--;
1262 static void
1263 parse_error (GMarkupParseContext *context, GError *gerror, gpointer user_data)
1265 RuntimeConfig *state = (RuntimeConfig *)user_data;
1266 const gchar *msg;
1267 const gchar *filename;
1269 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
1270 msg = gerror && gerror->message ? gerror->message : "";
1271 g_warning ("Error parsing %s: %s", filename, msg);
1274 static const GMarkupParser
1275 mono_parser = {
1276 start_element,
1277 end_element,
1278 NULL,
1279 NULL,
1280 parse_error
1283 void
1284 mono_domain_set_options_from_config (MonoDomain *domain)
1286 ERROR_DECL (error);
1287 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
1288 gsize len;
1289 GMarkupParseContext *context;
1290 RuntimeConfig runtime_config;
1291 gint offset;
1293 if (!domain || !domain->setup || !domain->setup->configuration_file)
1294 return;
1296 config_file_name = mono_string_to_utf8_checked_internal (domain->setup->configuration_file, error);
1297 if (!is_ok (error)) {
1298 mono_error_cleanup (error);
1299 goto free_and_out;
1302 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1303 if (!config_file_path)
1304 config_file_path = config_file_name;
1306 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1307 goto free_and_out;
1309 runtime_config.runtime_count = 0;
1310 runtime_config.assemblybinding_count = 0;
1311 runtime_config.domain = domain;
1312 runtime_config.filename = config_file_path;
1314 offset = 0;
1315 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1316 offset = 3; /* Skip UTF-8 BOM */
1318 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1319 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1320 g_markup_parse_context_end_parse (context, NULL);
1321 g_markup_parse_context_free (context);
1323 free_and_out:
1324 g_free (text);
1325 if (config_file_name != config_file_path)
1326 g_free (config_file_name);
1327 g_free (config_file_path);
1330 #ifndef ENABLE_NETCORE
1331 MonoAppDomainHandle
1332 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1334 error_init (error);
1335 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1337 #ifdef DISABLE_APPDOMAINS
1338 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1339 #else
1340 char *fname;
1342 fname = mono_string_handle_to_utf8 (friendly_name, error);
1343 return_val_if_nok (error, ad);
1344 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1345 g_free (fname);
1346 #endif
1347 return ad;
1349 #endif
1351 static gboolean
1352 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1354 HANDLE_FUNCTION_ENTER ();
1355 error_init (error);
1356 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1357 goto_if_nok (error, leave);
1358 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1359 leave:
1360 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1363 static MonoArrayHandle
1364 get_assembly_array_from_domain (MonoDomain *domain, MonoBoolean refonly, MonoError *error)
1366 int i;
1367 GPtrArray *assemblies;
1369 assemblies = mono_domain_get_assemblies (domain, refonly);
1371 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1372 goto_if_nok (error, leave);
1373 for (i = 0; i < assemblies->len; ++i) {
1374 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1375 goto leave;
1378 leave:
1379 g_ptr_array_free (assemblies, TRUE);
1380 return res;
1383 #ifdef ENABLE_NETCORE
1384 MonoArrayHandle
1385 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalGetLoadedAssemblies (MonoError *error)
1387 MonoDomain *domain = mono_domain_get ();
1388 return get_assembly_array_from_domain (domain, FALSE, error);
1390 #else
1391 MonoArrayHandle
1392 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1394 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1395 return get_assembly_array_from_domain (domain, refonly, error);
1397 #endif
1399 MonoAssembly*
1400 mono_try_assembly_resolve (MonoAssemblyLoadContext *alc, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1402 HANDLE_FUNCTION_ENTER ();
1403 error_init (error);
1404 MonoAssembly *result = NULL;
1405 MonoStringHandle fname = mono_string_new_handle (mono_alc_domain (alc), fname_raw, error);
1406 goto_if_nok (error, leave);
1407 result = mono_try_assembly_resolve_handle (alc, fname, requesting, refonly, error);
1408 leave:
1409 HANDLE_FUNCTION_RETURN_VAL (result);
1412 MonoAssembly*
1413 mono_try_assembly_resolve_handle (MonoAssemblyLoadContext *alc, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1415 HANDLE_FUNCTION_ENTER ();
1416 MonoAssembly *ret = NULL;
1417 MonoDomain *domain = mono_alc_domain (alc);
1418 char *filename = NULL;
1420 if (mono_runtime_get_no_exec ())
1421 goto leave;
1423 #ifndef ENABLE_NETCORE
1425 static MonoMethod *method;
1426 MonoBoolean isrefonly;
1427 gpointer params [3];
1429 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1431 // FIXME cache?
1433 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1, 0, error);
1434 g_assert (method != NULL);
1436 isrefonly = refonly ? 1 : 0;
1437 MonoReflectionAssemblyHandle requesting_handle;
1438 if (requesting) {
1439 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1440 goto_if_nok (error, leave);
1442 params [0] = MONO_HANDLE_RAW (fname);
1443 params [1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1444 params [2] = &isrefonly;
1445 MonoObject *exc;
1446 exc = NULL;
1447 MonoReflectionAssemblyHandle result;
1448 result = MONO_HANDLE_CAST (MonoReflectionAssembly, MONO_HANDLE_NEW (MonoObject, mono_runtime_try_invoke (method, domain->domain, params, &exc, error)));
1449 if (!is_ok (error) || exc != NULL) {
1450 if (is_ok (error))
1451 mono_error_set_exception_instance (error, (MonoException*)exc);
1452 goto leave;
1454 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1456 if (ret && !refonly && mono_asmctx_get_kind (&ret->context) == MONO_ASMCTX_REFONLY) {
1457 /* .NET Framework throws System.IO.FileNotFoundException in this case */
1458 filename = mono_string_handle_to_utf8 (fname, error);
1459 mono_error_set_file_not_found (error, filename, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only: %s", filename);
1460 ret = NULL;
1461 goto leave;
1463 #else
1464 MONO_STATIC_POINTER_INIT (MonoMethod, method)
1466 ERROR_DECL (local_error);
1467 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
1468 g_assert (alc_class);
1469 method = mono_class_get_method_from_name_checked (alc_class, "OnAssemblyResolve", -1, 0, local_error);
1470 mono_error_assert_ok (local_error);
1472 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
1474 g_assert (method);
1476 MonoReflectionAssemblyHandle requesting_handle;
1477 if (requesting) {
1478 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1479 goto_if_nok (error, leave);
1482 gpointer params [2];
1483 params [0] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1484 params [1] = MONO_HANDLE_RAW (fname);
1485 MonoReflectionAssemblyHandle result;
1486 result = MONO_HANDLE_CAST (MonoReflectionAssembly, mono_runtime_try_invoke_handle (method, NULL_HANDLE, params, error));
1487 goto_if_nok (error, leave);
1489 if (MONO_HANDLE_BOOL (result))
1490 ret = MONO_HANDLE_GETVAL (result, assembly);
1491 #endif
1493 leave:
1494 g_free (filename);
1495 HANDLE_FUNCTION_RETURN_VAL (ret);
1498 MonoAssembly *
1499 mono_domain_assembly_postload_search (MonoAssemblyLoadContext *alc, MonoAssembly *requesting,
1500 MonoAssemblyName *aname,
1501 gboolean refonly, gboolean postload,
1502 gpointer user_data,
1503 MonoError *error_out)
1505 ERROR_DECL (error);
1506 MonoAssembly *assembly;
1507 char *aname_str;
1509 aname_str = mono_stringify_assembly_name (aname);
1511 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1513 assembly = mono_try_assembly_resolve (alc, aname_str, requesting, refonly, error);
1514 g_free (aname_str);
1515 mono_error_cleanup (error);
1517 return assembly;
1521 * LOCKING: assumes assemblies_lock in the domain is already locked.
1523 static void
1524 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1526 GSList *tmp;
1527 gboolean destroy_ht = FALSE;
1529 g_assert (ass != NULL);
1531 if (!ass->aname.name)
1532 return;
1534 if (!ht) {
1535 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1536 destroy_ht = TRUE;
1537 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1538 g_hash_table_add (ht, tmp->data);
1542 if (!g_hash_table_lookup (ht, ass)) {
1543 mono_assembly_addref (ass);
1544 g_hash_table_add (ht, ass);
1545 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1546 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to domain %s, ref_count=%d", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
1549 #ifndef ENABLE_NETCORE
1550 if (ass->image->references) {
1551 for (int i = 0; i < ass->image->nreferences; i++) {
1552 MonoAssembly *ref = ass->image->references [i];
1553 if (ref && ref != REFERENCE_MISSING) {
1554 if (!g_hash_table_lookup (ht, ref))
1555 add_assemblies_to_domain (domain, ref, ht);
1559 #endif
1561 if (destroy_ht)
1562 g_hash_table_destroy (ht);
1566 * LOCKING: assumes the ALC's assemblies lock is taken
1568 #ifdef ENABLE_NETCORE
1569 static void
1570 add_assembly_to_alc (MonoAssemblyLoadContext *alc, MonoAssembly *ass)
1572 GSList *tmp;
1574 g_assert (ass != NULL);
1576 if (!ass->aname.name)
1577 return;
1579 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
1580 if (tmp->data == ass) {
1581 return;
1585 mono_assembly_addref (ass);
1586 // Prepending here will break the test suite with frequent InvalidCastExceptions, so we have to append
1587 alc->loaded_assemblies = g_slist_append (alc->loaded_assemblies, ass);
1588 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to ALC (%p), ref_count=%d", ass->aname.name, ass, (gpointer)alc, ass->ref_count);
1591 #endif
1593 static void
1594 mono_domain_fire_assembly_load_event (MonoDomain *domain, MonoAssembly *assembly, MonoError *error)
1596 HANDLE_FUNCTION_ENTER ();
1598 g_assert (domain);
1599 g_assert (assembly);
1601 #ifdef ENABLE_NETCORE
1602 MONO_STATIC_POINTER_INIT (MonoMethod, method)
1604 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
1605 g_assert (alc_class);
1606 method = mono_class_get_method_from_name_checked (alc_class, "OnAssemblyLoad", -1, 0, error);
1608 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
1609 goto_if_nok (error, exit);
1611 MonoReflectionAssemblyHandle assembly_handle = mono_assembly_get_object_handle (domain, assembly, error);
1612 goto_if_nok (error, exit);
1614 gpointer args [1];
1615 args [0] = MONO_HANDLE_RAW (assembly_handle);
1616 mono_runtime_try_invoke_handle (method, NULL_HANDLE, args, error);
1617 #else
1618 MonoObjectHandle appdomain = MONO_HANDLE_NEW (MonoObject, &domain->domain->mbr.obj);
1619 MonoClass *klass = mono_handle_class (appdomain);
1621 MONO_STATIC_POINTER_INIT (MonoClassField, assembly_load_field)
1623 assembly_load_field = mono_class_get_field_from_name_full (klass, "AssemblyLoad", NULL);
1624 g_assert (assembly_load_field);
1626 MONO_STATIC_POINTER_INIT_END (MonoClassField, assembly_load_field)
1628 if (!MONO_HANDLE_GET_FIELD_BOOL (appdomain, MonoObject*, assembly_load_field))
1629 goto exit; // No events waiting to be triggered
1631 MonoReflectionAssemblyHandle reflection_assembly;
1632 reflection_assembly = mono_assembly_get_object_handle (domain, assembly, error);
1633 goto_if_nok (error, exit);
1635 MONO_STATIC_POINTER_INIT (MonoMethod, assembly_load_method)
1637 assembly_load_method = mono_class_get_method_from_name_checked (klass, "DoAssemblyLoad", -1, 0, error);
1638 g_assert (assembly_load_method);
1640 MONO_STATIC_POINTER_INIT_END (MonoMethod, assembly_load_method)
1642 void *params [1];
1643 params [0] = MONO_HANDLE_RAW (reflection_assembly);
1644 mono_runtime_invoke_handle_void (assembly_load_method, appdomain, params, error);
1645 #endif
1647 exit:
1648 HANDLE_FUNCTION_RETURN ();
1651 static void
1652 mono_domain_fire_assembly_load (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer user_data, MonoError *error_out)
1654 ERROR_DECL (error);
1655 MonoDomain *domain = mono_alc_domain (alc);
1657 g_assert (assembly);
1658 g_assert (domain);
1660 if (!MONO_BOOL (domain->domain))
1661 goto leave; // This can happen during startup
1663 if (mono_runtime_get_no_exec ())
1664 goto leave;
1666 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Loading assembly %s (%p) into domain %s (%p) and ALC %p", assembly->aname.name, assembly, domain->friendly_name, domain, alc);
1668 mono_domain_assemblies_lock (domain);
1669 #ifdef ENABLE_NETCORE
1670 mono_alc_assemblies_lock (alc);
1671 #endif
1672 add_assemblies_to_domain (domain, assembly, NULL);
1673 #ifdef ENABLE_NETCORE
1674 add_assembly_to_alc (alc, assembly);
1675 mono_alc_assemblies_unlock (alc);
1676 #endif
1677 mono_domain_assemblies_unlock (domain);
1679 mono_domain_fire_assembly_load_event (domain, assembly, error_out);
1681 leave:
1682 mono_error_cleanup (error);
1685 static gboolean
1686 mono_domain_asmctx_from_path (const char *fname, MonoAssembly *requesting_assembly, gpointer user_data, MonoAssemblyContextKind *out_asmctx)
1688 MonoDomain *domain = mono_domain_get ();
1689 char **search_path = NULL;
1691 for (search_path = domain->search_path; search_path && *search_path; search_path++) {
1692 if (mono_path_filename_in_basedir (fname, *search_path)) {
1693 *out_asmctx = MONO_ASMCTX_DEFAULT;
1694 return TRUE;
1697 return FALSE;
1701 * LOCKING: Acquires the domain assemblies lock.
1703 static void
1704 set_domain_search_path (MonoDomain *domain)
1706 HANDLE_FUNCTION_ENTER ();
1707 ERROR_DECL (error);
1708 MonoAppDomainSetupHandle setup;
1709 gchar **tmp;
1710 gchar *search_path = NULL;
1711 gint npaths = 1;
1712 gchar **pvt_split = NULL;
1713 GError *gerror = NULL;
1714 gint appbaselen = -1;
1717 * We use the low-level domain assemblies lock, since this is called from
1718 * assembly loads hooks, which means this thread might hold the loader lock.
1720 mono_domain_assemblies_lock (domain);
1722 if (!MONO_BOOL (domain->setup))
1723 goto exit;
1725 setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
1727 if (domain->search_path && !MONO_HANDLE_GET_BOOL (setup, path_changed))
1728 goto exit;
1730 if (!MONO_HANDLE_GET_BOOL (setup, application_base))
1731 goto exit; // Must set application base to get private path working
1733 if (MONO_HANDLE_GET_BOOL (setup, private_bin_path)) {
1734 search_path = mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString, setup, private_bin_path), error);
1735 if (!is_ok (error)) { /*FIXME maybe we should bubble up the error.*/
1736 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1737 goto exit;
1741 if (domain->private_bin_path) {
1742 if (search_path == NULL)
1743 search_path = domain->private_bin_path;
1744 else {
1745 gchar *tmp2 = search_path;
1746 search_path = g_strjoin (";", search_path, domain->private_bin_path, (const char*)NULL);
1747 g_free (tmp2);
1751 if (search_path) {
1753 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1754 * directories relative to ApplicationBase separated by semicolons (see
1755 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1756 * The loop below copes with the fact that some Unix applications may use ':' (or
1757 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1758 * ';' for the subsequent split.
1760 * The issue was reported in bug #81446
1762 #ifndef TARGET_WIN32
1763 g_strdelimit (search_path, ':', ';');
1764 #endif
1765 pvt_split = g_strsplit (search_path, ";", 1000);
1766 g_free (search_path);
1767 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1770 g_strfreev (domain->search_path);
1771 domain->search_path = NULL;
1773 tmp = g_new (gchar*, npaths + 1);
1774 tmp [npaths] = NULL;
1776 *tmp = mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString, setup, application_base), error);
1777 if (!is_ok (error)) {
1778 g_free (tmp);
1779 goto exit;
1782 domain->search_path = tmp;
1784 /* FIXME: is this needed? */
1785 if (strncmp (*tmp, "file://", 7) == 0) {
1786 gchar *file = *tmp;
1787 gchar *uri = *tmp;
1788 gchar *tmpuri;
1790 if (uri [7] != '/')
1791 uri = g_strdup_printf ("file:///%s", uri + 7);
1793 tmpuri = uri;
1794 uri = mono_escape_uri_string (tmpuri);
1795 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1796 g_free (uri);
1798 if (tmpuri != file)
1799 g_free (tmpuri);
1801 if (gerror != NULL) {
1802 g_warning ("%s\n", gerror->message);
1803 g_error_free (gerror);
1804 *tmp = file;
1805 } else {
1806 g_free (file);
1810 for (gsize i = 1; pvt_split && i < npaths; i++) {
1811 if (g_path_is_absolute (pvt_split [i - 1])) {
1812 tmp [i] = g_strdup (pvt_split [i - 1]);
1813 } else {
1814 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], (const char*)NULL);
1817 if (strchr (tmp [i], '.')) {
1818 gchar *reduced;
1819 gchar *freeme;
1821 reduced = mono_path_canonicalize (tmp [i]);
1822 if (appbaselen == -1)
1823 appbaselen = strlen (tmp [0]);
1825 if (strncmp (tmp [0], reduced, appbaselen)) {
1826 g_free (reduced);
1827 g_free (tmp [i]);
1828 tmp [i] = g_strdup ("");
1829 continue;
1832 freeme = tmp [i];
1833 tmp [i] = reduced;
1834 g_free (freeme);
1838 if (MONO_HANDLE_GET_BOOL (setup, private_bin_path_probe)) {
1839 g_free (tmp [0]);
1840 tmp [0] = g_strdup ("");
1843 MONO_HANDLE_SETVAL (setup, path_changed, MonoBoolean, FALSE);
1844 exit:
1845 mono_error_cleanup (error);
1846 g_strfreev (pvt_split);
1847 mono_domain_assemblies_unlock (domain);
1848 HANDLE_FUNCTION_RETURN ();
1851 #ifdef DISABLE_SHADOW_COPY
1852 gboolean
1853 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1855 return FALSE;
1858 char *
1859 mono_make_shadow_copy (const char *filename, MonoError *error)
1861 error_init (error);
1862 return (char *) filename;
1864 #else
1866 typedef enum {
1867 SHADOW_COPY_SIBLING_EXT_APPEND,
1868 SHADOW_COPY_SIBLING_EXT_REPLACE,
1869 } ShadowCopySiblingExt;
1871 static
1872 gchar *
1873 make_sibling_path (const gchar *path, gint pathlen, const char *extension, ShadowCopySiblingExt extopt)
1875 gchar *result = NULL;
1876 switch (extopt) {
1877 case SHADOW_COPY_SIBLING_EXT_APPEND: {
1878 result = g_strconcat (path, extension, (const char*)NULL);
1879 break;
1881 case SHADOW_COPY_SIBLING_EXT_REPLACE: {
1882 /* expect path to be a .dll or .exe (or some case insensitive variant) */
1883 g_assert (pathlen >= 4 && path[pathlen - 4] == '.');
1884 GString *s = g_string_sized_new (pathlen - 4 + strlen (extension));
1885 g_string_append_len (s, path, pathlen - 4);
1886 g_string_append (s, extension);
1887 result = g_string_free (s, FALSE);
1888 break;
1890 default:
1891 g_assert_not_reached ();
1893 return result;
1896 static gboolean
1897 shadow_copy_sibling (const gchar *src_pristine, gint srclen, const char *extension, ShadowCopySiblingExt extopt, const gchar *target_pristine, gint targetlen)
1899 gchar *file = NULL;
1900 gunichar2 *orig = NULL;
1901 gunichar2 *dest = NULL;
1902 gboolean copy_result = TRUE;
1903 gchar *target = NULL;
1905 char *src = make_sibling_path (src_pristine, srclen, extension, extopt);
1907 if (IS_PORTABILITY_CASE) {
1908 file = mono_portability_find_file (src, TRUE);
1909 if (file == NULL)
1910 goto exit;
1911 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR))
1912 goto exit;
1914 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1916 target = make_sibling_path (target_pristine, targetlen, extension, extopt);
1918 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1920 mono_w32file_delete (dest);
1922 gint32 copy_error;
1923 copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1925 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1926 * overwritten when updated in their original locations. */
1927 if (copy_result)
1928 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1930 exit:
1931 g_free (file);
1932 g_free (orig);
1933 g_free (dest);
1934 g_free (src);
1935 g_free (target);
1936 return copy_result;
1939 static gint32
1940 get_cstring_hash (const char *str)
1942 const char *p;
1943 gint32 h = 0;
1945 if (!str || !str [0])
1946 return 0;
1948 gsize const len = strlen (str);
1949 p = str;
1950 for (gsize i = 0; i < len; i++) {
1951 h = (h << 5) - h + *p;
1952 p++;
1955 return h;
1959 * Returned memory is malloc'd. Called must free it
1961 static char *
1962 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1964 MonoAppDomainSetup *setup;
1965 char *cache_path = NULL;
1966 char *appname = NULL;
1967 char *userdir = NULL;
1968 char *location;
1970 error_init (error);
1972 setup = domain->setup;
1973 if (setup->cache_path != NULL && setup->application_name != NULL) {
1974 cache_path = mono_string_to_utf8_checked_internal (setup->cache_path, error);
1975 return_val_if_nok (error, NULL);
1977 #ifndef TARGET_WIN32
1979 gint i;
1980 for (i = strlen (cache_path) - 1; i >= 0; i--)
1981 if (cache_path [i] == '\\')
1982 cache_path [i] = '/';
1984 #endif
1986 appname = mono_string_to_utf8_checked_internal (setup->application_name, error);
1987 if (!is_ok (error)) {
1988 g_free (cache_path);
1989 return NULL;
1992 location = g_build_filename (cache_path, appname, "assembly", "shadow", (const char*)NULL);
1993 } else {
1994 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1995 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", (const char*)NULL);
1997 g_free (appname);
1998 g_free (cache_path);
1999 g_free (userdir);
2000 return location;
2003 static char *
2004 get_shadow_assembly_location (const char *filename, MonoError *error)
2006 gint32 hash = 0, hash2 = 0;
2007 char name_hash [9];
2008 char path_hash [30];
2009 char *bname = g_path_get_basename (filename);
2010 char *dirname = g_path_get_dirname (filename);
2011 char *location, *tmploc;
2012 MonoDomain *domain = mono_domain_get ();
2014 error_init (error);
2016 hash = get_cstring_hash (bname);
2017 hash2 = get_cstring_hash (dirname);
2018 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
2019 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
2020 tmploc = get_shadow_assembly_location_base (domain, error);
2021 if (!is_ok (error)) {
2022 g_free (bname);
2023 g_free (dirname);
2024 return NULL;
2027 location = g_build_filename (tmploc, name_hash, path_hash, bname, (const char*)NULL);
2028 g_free (tmploc);
2029 g_free (bname);
2030 g_free (dirname);
2031 return location;
2034 static gboolean
2035 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
2037 struct stat sbuf_dest;
2038 gchar *stat_src;
2039 gchar *real_src = mono_portability_find_file (src, TRUE);
2041 if (!real_src)
2042 stat_src = (gchar*)src;
2043 else
2044 stat_src = real_src;
2046 if (stat (stat_src, sbuf_src) == -1) {
2047 time_t tnow = time (NULL);
2049 if (real_src)
2050 g_free (real_src);
2052 memset (sbuf_src, 0, sizeof (*sbuf_src));
2053 sbuf_src->st_mtime = tnow;
2054 sbuf_src->st_atime = tnow;
2055 return TRUE;
2058 if (real_src)
2059 g_free (real_src);
2061 if (stat (dest, &sbuf_dest) == -1)
2062 return TRUE;
2064 if (sbuf_src->st_size == sbuf_dest.st_size &&
2065 sbuf_src->st_mtime == sbuf_dest.st_mtime)
2066 return FALSE;
2068 return TRUE;
2071 static gboolean
2072 shadow_copy_create_ini (const char *shadow, const char *filename)
2074 gunichar2 *u16_ini = NULL;
2075 gboolean result = FALSE;
2076 guint32 n;
2077 HANDLE handle = INVALID_HANDLE_VALUE;
2078 gchar *full_path = NULL;
2080 char *dir_name = g_path_get_dirname (shadow);
2081 char *ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", (const char*)NULL);
2082 g_free (dir_name);
2083 result = g_file_test (ini_file, G_FILE_TEST_IS_REGULAR);
2084 if (result)
2085 goto exit;
2087 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
2088 if (!u16_ini)
2089 goto exit;
2091 handle = mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
2092 if (handle == INVALID_HANDLE_VALUE)
2093 goto exit;
2095 full_path = mono_path_resolve_symlinks (filename);
2096 gint32 win32error;
2097 win32error = 0;
2098 result = mono_w32file_write (handle, full_path, strlen (full_path), &n, &win32error);
2099 exit:
2100 if (handle != INVALID_HANDLE_VALUE)
2101 mono_w32file_close (handle);
2102 g_free (u16_ini);
2103 g_free (full_path);
2104 g_free (ini_file);
2105 return result;
2108 gboolean
2109 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
2111 ERROR_DECL (error);
2112 MonoAppDomainSetup *setup;
2113 gchar *all_dirs = NULL;
2114 gchar **dir_ptr;
2115 gchar **directories = NULL;
2116 gchar *shadow_status_string;
2117 gchar *base_dir = NULL;
2118 gboolean shadow_enabled;
2119 gboolean found = FALSE;
2121 if (domain == NULL)
2122 goto exit;
2124 setup = domain->setup;
2125 if (setup == NULL || setup->shadow_copy_files == NULL)
2126 goto exit;
2128 shadow_status_string = mono_string_to_utf8_checked_internal (setup->shadow_copy_files, error);
2129 if (!is_ok (error))
2130 goto exit;
2132 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
2133 g_free (shadow_status_string);
2135 if (!shadow_enabled)
2136 goto exit;
2138 found = (setup->shadow_copy_directories == NULL);
2139 if (found)
2140 goto exit;
2142 /* Is dir_name a shadow_copy destination already? */
2143 base_dir = get_shadow_assembly_location_base (domain, error);
2144 if (!is_ok (error))
2145 goto exit;
2147 found = !!strstr (dir_name, base_dir);
2148 if (found)
2149 goto exit;
2151 all_dirs = mono_string_to_utf8_checked_internal (setup->shadow_copy_directories, error);
2152 if (!is_ok (error))
2153 goto exit;
2155 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
2156 dir_ptr = directories;
2157 while (!found && *dir_ptr) {
2158 found = (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name));
2159 dir_ptr++;
2161 exit:
2162 mono_error_cleanup (error);
2163 g_free (base_dir);
2164 g_strfreev (directories);
2165 g_free (all_dirs);
2166 return found;
2170 This function raises exceptions so it can cause as sorts of nasty stuff if called
2171 while holding a lock.
2172 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
2173 or NULL if source file not found.
2174 FIXME bubble up the error instead of raising it here
2176 char *
2177 mono_make_shadow_copy (const char *filename, MonoError *oerror)
2179 ERROR_DECL (error);
2180 gint filename_len, shadow_len;
2181 gunichar2 *orig, *dest;
2182 guint32 attrs;
2183 char *shadow;
2184 gboolean copy_result;
2185 struct stat src_sbuf;
2186 struct utimbuf utbuf;
2187 char *dir_name = g_path_get_dirname (filename);
2188 MonoDomain *domain = mono_domain_get ();
2189 char *shadow_dir;
2190 gint32 copy_error;
2192 #ifndef ENABLE_NETCORE
2193 set_domain_search_path (domain);
2194 #endif
2196 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
2197 g_free (dir_name);
2198 return (char *) filename;
2201 /* Is dir_name a shadow_copy destination already? */
2202 shadow_dir = get_shadow_assembly_location_base (domain, error);
2203 if (!is_ok (error)) {
2204 mono_error_cleanup (error);
2205 g_free (dir_name);
2206 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
2207 return NULL;
2210 if (strstr (dir_name, shadow_dir)) {
2211 g_free (shadow_dir);
2212 g_free (dir_name);
2213 return (char *) filename;
2215 g_free (shadow_dir);
2216 g_free (dir_name);
2218 shadow = get_shadow_assembly_location (filename, error);
2219 if (!is_ok (error)) {
2220 mono_error_cleanup (error);
2221 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
2222 return NULL;
2225 if (g_ensure_directory_exists (shadow) == FALSE) {
2226 g_free (shadow);
2227 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
2228 return NULL;
2231 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
2232 return (char*) shadow;
2234 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
2235 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
2236 mono_w32file_delete (dest);
2238 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
2239 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
2240 * and not have it runtime error" */
2241 attrs = mono_w32file_get_attributes (orig);
2242 if (attrs == INVALID_FILE_ATTRIBUTES) {
2243 g_free (shadow);
2244 return (char *)filename;
2247 copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
2249 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
2250 * overwritten when updated in their original locations. */
2251 if (copy_result)
2252 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
2254 g_free (dest);
2255 g_free (orig);
2257 if (copy_result == FALSE) {
2258 g_free (shadow);
2260 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
2261 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
2262 return NULL; /* file not found, shadow copy failed */
2264 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
2265 return NULL;
2268 /* attempt to copy .mdb, .pdb and .config if they exist */
2269 filename_len = strlen (filename);
2270 shadow_len = strlen (shadow);
2272 copy_result = shadow_copy_sibling (filename, filename_len, ".mdb", SHADOW_COPY_SIBLING_EXT_APPEND, shadow, shadow_len);
2273 if (copy_result)
2274 copy_result = shadow_copy_sibling (filename, filename_len, ".pdb", SHADOW_COPY_SIBLING_EXT_REPLACE, shadow, shadow_len);
2275 if (copy_result)
2276 copy_result = shadow_copy_sibling (filename, filename_len, ".config", SHADOW_COPY_SIBLING_EXT_APPEND, shadow, shadow_len);
2278 if (!copy_result) {
2279 g_free (shadow);
2280 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
2281 return NULL;
2284 /* Create a .ini file containing the original assembly location */
2285 if (!shadow_copy_create_ini (shadow, filename)) {
2286 g_free (shadow);
2287 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
2288 return NULL;
2291 utbuf.actime = src_sbuf.st_atime;
2292 utbuf.modtime = src_sbuf.st_mtime;
2293 utime (shadow, &utbuf);
2295 return shadow;
2297 #endif /* DISABLE_SHADOW_COPY */
2300 * mono_domain_from_appdomain:
2302 MonoDomain *
2303 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
2305 HANDLE_FUNCTION_ENTER ();
2306 MonoDomain *result;
2307 MONO_ENTER_GC_UNSAFE;
2308 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
2309 result = mono_domain_from_appdomain_handle (appdomain);
2310 MONO_EXIT_GC_UNSAFE;
2311 HANDLE_FUNCTION_RETURN_VAL (result);
2314 MonoDomain *
2315 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
2317 HANDLE_FUNCTION_ENTER ();
2318 MonoDomain *dom = NULL;
2319 if (MONO_HANDLE_IS_NULL (appdomain))
2320 goto leave;
2322 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
2323 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
2324 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
2326 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
2327 } else
2328 dom = MONO_HANDLE_GETVAL (appdomain, data);
2330 leave:
2331 HANDLE_FUNCTION_RETURN_VAL (dom);
2335 static gboolean
2336 try_load_from (MonoAssembly **assembly,
2337 const gchar *path1, const gchar *path2,
2338 const gchar *path3, const gchar *path4,
2339 const MonoAssemblyOpenRequest *req)
2341 gchar *fullpath;
2342 gboolean found = FALSE;
2344 *assembly = NULL;
2345 fullpath = g_build_filename (path1, path2, path3, path4, (const char*)NULL);
2347 if (IS_PORTABILITY_SET) {
2348 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
2349 if (new_fullpath) {
2350 g_free (fullpath);
2351 fullpath = new_fullpath;
2352 found = TRUE;
2354 } else
2355 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
2357 if (found) {
2358 *assembly = mono_assembly_request_open (fullpath, req, NULL);
2361 g_free (fullpath);
2362 return (*assembly != NULL);
2365 static MonoAssembly *
2366 real_load (gchar **search_path, const gchar *culture, const gchar *name, const MonoAssemblyOpenRequest *req)
2368 MonoAssembly *result = NULL;
2369 gchar **path;
2370 gchar *filename;
2371 const gchar *local_culture;
2372 gint len;
2374 if (!culture || *culture == '\0') {
2375 local_culture = "";
2376 } else {
2377 local_culture = culture;
2380 filename = g_strconcat (name, ".dll", (const char*)NULL);
2381 len = strlen (filename);
2383 for (path = search_path; *path; path++) {
2384 if (**path == '\0') {
2385 continue; /* Ignore empty ApplicationBase */
2388 /* See test cases in bug #58992 and bug #57710 */
2389 /* 1st try: [culture]/[name].dll (culture may be empty) */
2390 strcpy (filename + len - 4, ".dll");
2391 if (try_load_from (&result, *path, local_culture, "", filename, req))
2392 break;
2394 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2395 strcpy (filename + len - 4, ".exe");
2396 if (try_load_from (&result, *path, local_culture, "", filename, req))
2397 break;
2399 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2400 strcpy (filename + len - 4, ".dll");
2401 if (try_load_from (&result, *path, local_culture, name, filename, req))
2402 break;
2404 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2405 strcpy (filename + len - 4, ".exe");
2406 if (try_load_from (&result, *path, local_culture, name, filename, req))
2407 break;
2410 g_free (filename);
2411 return result;
2414 #ifdef ENABLE_NETCORE
2415 static char *
2416 get_app_context_base_directory (MonoError *error)
2418 MONO_STATIC_POINTER_INIT (MonoMethod, get_basedir)
2420 ERROR_DECL (local_error);
2421 MonoClass *app_context = mono_class_get_app_context_class ();
2422 g_assert (app_context);
2423 get_basedir = mono_class_get_method_from_name_checked (app_context, "get_BaseDirectory", -1, 0, local_error);
2424 mono_error_assert_ok (local_error);
2426 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_basedir)
2428 HANDLE_FUNCTION_ENTER ();
2430 MonoStringHandle result = MONO_HANDLE_CAST (MonoString, mono_runtime_try_invoke_handle (get_basedir, NULL_HANDLE, NULL, error));
2431 char *base_dir = mono_string_handle_to_utf8 (result, error);
2433 HANDLE_FUNCTION_RETURN_VAL (base_dir);
2435 #endif
2438 * Try loading the assembly from ApplicationBase and PrivateBinPath
2439 * and then from assemblies_path if any.
2440 * LOCKING: This is called from the assembly loading code, which means the caller
2441 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2443 static MonoAssembly *
2444 mono_domain_assembly_preload (MonoAssemblyLoadContext *alc,
2445 MonoAssemblyName *aname,
2446 gchar **assemblies_path,
2447 gboolean refonly,
2448 gpointer user_data,
2449 MonoError *error)
2451 MonoDomain *domain = mono_alc_domain (alc);
2452 MonoAssembly *result = NULL;
2453 #ifdef ENABLE_NETCORE
2454 g_assert (alc);
2455 g_assert (domain == mono_domain_get ());
2456 #endif
2458 #ifndef ENABLE_NETCORE
2459 set_domain_search_path (domain);
2460 #endif
2462 MonoAssemblyCandidatePredicate predicate = NULL;
2463 void* predicate_ud = NULL;
2464 if (mono_loader_get_strict_assembly_name_check ()) {
2465 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2466 predicate_ud = aname;
2468 MonoAssemblyOpenRequest req;
2469 mono_assembly_request_prepare_open (&req, refonly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_DEFAULT, alc);
2470 req.request.predicate = predicate;
2471 req.request.predicate_ud = predicate_ud;
2473 #ifdef ENABLE_NETCORE
2474 if (!mono_runtime_get_no_exec ()) {
2475 char *search_path [2];
2476 search_path [1] = NULL;
2478 char *base_dir = get_app_context_base_directory (error);
2479 search_path [0] = base_dir;
2480 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s (%p) ApplicationBase is %s", domain->friendly_name, domain, base_dir);
2482 result = real_load (search_path, aname->culture, aname->name, &req);
2484 g_free (base_dir);
2486 #else
2487 if (domain->search_path && domain->search_path [0] != NULL) {
2488 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2489 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2490 for (int i = 0; domain->search_path [i]; i++) {
2491 const char *p = domain->search_path[i];
2492 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2494 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2496 result = real_load (domain->search_path, aname->culture, aname->name, &req);
2498 #endif
2500 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2501 result = real_load (assemblies_path, aname->culture, aname->name, &req);
2504 return result;
2508 * Check whenever a given assembly was already loaded in the current appdomain.
2510 static MonoAssembly *
2511 mono_domain_assembly_search (MonoAssemblyLoadContext *alc, MonoAssembly *requesting,
2512 MonoAssemblyName *aname,
2513 gboolean refonly,
2514 gboolean postload,
2515 gpointer user_data,
2516 MonoError *error)
2518 g_assert (aname != NULL);
2519 GSList *tmp;
2520 MonoAssembly *ass;
2522 #ifdef ENABLE_NETCORE
2523 const MonoAssemblyNameEqFlags eq_flags = MONO_ANAME_EQ_IGNORE_PUBKEY | MONO_ANAME_EQ_IGNORE_VERSION | MONO_ANAME_EQ_IGNORE_CASE;
2525 mono_alc_assemblies_lock (alc);
2526 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
2527 ass = (MonoAssembly *)tmp->data;
2528 g_assert (ass != NULL);
2529 // FIXME: Can dynamic assemblies match here for netcore?
2530 if (assembly_is_dynamic (ass) || !mono_assembly_names_equal_flags (aname, &ass->aname, eq_flags))
2531 continue;
2533 mono_alc_assemblies_unlock (alc);
2534 return ass;
2536 mono_alc_assemblies_unlock (alc);
2537 #else
2538 MonoDomain *domain = mono_alc_domain (alc);
2540 const gboolean strong_name = aname->public_key_token[0] != 0;
2541 /* If it's not a strong name, any version that has the right simple
2542 * name is good enough to satisfy the request. .NET Framework also
2543 * ignores case differences in this case. */
2544 const MonoAssemblyNameEqFlags eq_flags = (MonoAssemblyNameEqFlags)(strong_name ? MONO_ANAME_EQ_IGNORE_CASE :
2545 (MONO_ANAME_EQ_IGNORE_PUBKEY | MONO_ANAME_EQ_IGNORE_VERSION | MONO_ANAME_EQ_IGNORE_CASE));
2547 mono_domain_assemblies_lock (domain);
2548 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2549 ass = (MonoAssembly *)tmp->data;
2550 g_assert (ass != NULL);
2551 /* Dynamic assemblies can't match here in MS.NET */
2552 gboolean ass_ref_only = mono_asmctx_get_kind (&ass->context) == MONO_ASMCTX_REFONLY;
2553 if (assembly_is_dynamic (ass) || refonly != ass_ref_only || !mono_assembly_names_equal_flags (aname, &ass->aname, eq_flags))
2554 continue;
2556 mono_domain_assemblies_unlock (domain);
2557 return ass;
2559 mono_domain_assemblies_unlock (domain);
2560 #endif
2562 return NULL;
2565 #if ENABLE_NETCORE
2566 MonoReflectionAssemblyHandle
2567 ves_icall_System_Reflection_Assembly_InternalLoad (MonoStringHandle name_handle, MonoStackCrawlMark *stack_mark, gpointer load_Context, MonoError *error)
2569 error_init (error);
2570 MonoAssembly *ass = NULL;
2571 MonoAssemblyName aname;
2572 MonoAssemblyByNameRequest req;
2573 MonoAssemblyContextKind asmctx;
2574 MonoImageOpenStatus status = MONO_IMAGE_OK;
2575 gboolean parsed;
2576 char *name;
2578 MonoAssembly *requesting_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2579 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)load_Context;
2581 if (!alc)
2582 alc = mono_assembly_get_alc (requesting_assembly);
2583 if (!alc)
2584 g_assert_not_reached ();
2586 MonoDomain *domain = mono_alc_domain (alc);
2587 g_assert (alc);
2588 asmctx = MONO_ASMCTX_DEFAULT;
2589 mono_assembly_request_prepare_byname (&req, asmctx, alc);
2590 req.basedir = NULL;
2591 /* Everything currently goes through this function, and the postload hook (aka the AppDomain.AssemblyResolve event)
2592 * is triggered under some scenarios. It's not completely obvious to me in what situations (if any) this should be disabled,
2593 * other than for corlib satellite assemblies (which I've dealt with further down the call stack).
2595 //req.no_postload_search = TRUE;
2596 req.requesting_assembly = requesting_assembly;
2598 name = mono_string_handle_to_utf8 (name_handle, error);
2599 goto_if_nok (error, fail);
2600 parsed = mono_assembly_name_parse (name, &aname);
2601 g_free (name);
2602 if (!parsed)
2603 goto fail;
2605 MonoAssemblyCandidatePredicate predicate = NULL;
2606 void* predicate_ud = NULL;
2607 if (mono_loader_get_strict_assembly_name_check ()) {
2608 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2609 predicate_ud = &aname;
2611 req.request.predicate = predicate;
2612 req.request.predicate_ud = predicate_ud;
2614 ass = mono_assembly_request_byname (&aname, &req, &status);
2615 if (!ass)
2616 goto fail;
2618 MonoReflectionAssemblyHandle refass;
2619 refass = mono_assembly_get_object_handle (domain, ass, error);
2620 goto_if_nok (error, fail);
2621 return refass;
2623 fail:
2624 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2626 #endif
2628 #ifndef ENABLE_NETCORE
2629 MonoReflectionAssemblyHandle
2630 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoStackCrawlMark *stack_mark, MonoError *error)
2632 error_init (error);
2633 MonoDomain *domain = mono_domain_get ();
2634 char *name, *filename;
2635 MonoImageOpenStatus status = MONO_IMAGE_OK;
2636 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2638 name = NULL;
2640 if (MONO_HANDLE_IS_NULL (fname)) {
2641 mono_error_set_argument_null (error, "assemblyFile", "");
2642 goto leave;
2645 name = filename = mono_string_handle_to_utf8 (fname, error);
2646 goto_if_nok (error, leave);
2648 MonoAssembly *requesting_assembly;
2649 requesting_assembly = NULL;
2650 if (!refOnly)
2651 requesting_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2653 MonoAssembly *ass;
2654 MonoAssemblyOpenRequest req;
2655 mono_assembly_request_prepare_open (&req, refOnly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_LOADFROM, mono_domain_default_alc (domain));
2656 req.requesting_assembly = requesting_assembly;
2657 ass = mono_assembly_request_open (filename, &req, &status);
2659 if (!ass) {
2660 if (status == MONO_IMAGE_IMAGE_INVALID)
2661 mono_error_set_bad_image_by_name (error, name, "Invalid Image: %s", name);
2662 else
2663 mono_error_set_simple_file_not_found (error, name, refOnly);
2664 goto leave;
2667 result = mono_assembly_get_object_handle (domain, ass, error);
2669 leave:
2670 g_free (name);
2671 return result;
2673 #endif
2675 static
2676 MonoAssembly *
2677 mono_alc_load_file (MonoAssemblyLoadContext *alc, MonoStringHandle fname, MonoAssembly *executing_assembly, MonoAssemblyContextKind asmctx, MonoError *error)
2679 MonoAssembly *ass = NULL;
2680 HANDLE_FUNCTION_ENTER ();
2681 char *filename = NULL;
2682 if (MONO_HANDLE_IS_NULL (fname)) {
2683 mono_error_set_argument_null (error, "assemblyFile", "");
2684 goto leave;
2687 filename = mono_string_handle_to_utf8 (fname, error);
2688 goto_if_nok (error, leave);
2690 if (!g_path_is_absolute (filename)) {
2691 mono_error_set_argument (error, "assemblyFile", "Absolute path information is required.");
2692 goto leave;
2695 MonoImageOpenStatus status;
2696 MonoAssemblyOpenRequest req;
2697 mono_assembly_request_prepare_open (&req, asmctx, alc);
2698 req.requesting_assembly = executing_assembly;
2699 ass = mono_assembly_request_open (filename, &req, &status);
2700 if (!ass) {
2701 if (status == MONO_IMAGE_IMAGE_INVALID)
2702 mono_error_set_bad_image_by_name (error, filename, "Invalid Image: %s", filename);
2703 else
2704 mono_error_set_simple_file_not_found (error, filename, asmctx == MONO_ASMCTX_REFONLY);
2707 leave:
2708 g_free (filename);
2709 HANDLE_FUNCTION_RETURN_VAL (ass);
2712 #ifndef ENABLE_NETCORE
2713 MonoReflectionAssemblyHandle
2714 ves_icall_System_Reflection_Assembly_LoadFile_internal (MonoStringHandle fname, MonoStackCrawlMark *stack_mark, MonoError *error)
2716 MonoDomain *domain = mono_domain_get ();
2717 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2718 MonoAssembly *executing_assembly;
2719 executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2720 MonoAssembly *ass = mono_alc_load_file (mono_domain_default_alc (domain), fname, executing_assembly, MONO_ASMCTX_INDIVIDUAL, error);
2721 goto_if_nok (error, leave);
2723 result = mono_assembly_get_object_handle (domain, ass, error);
2724 leave:
2725 return result;
2727 #else
2728 MonoReflectionAssemblyHandle
2729 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalLoadFile (gpointer alc_ptr, MonoStringHandle fname, MonoStackCrawlMark *stack_mark, MonoError *error)
2731 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2732 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)alc_ptr;
2733 MonoDomain *domain = mono_alc_domain (alc);
2735 MonoAssembly *executing_assembly;
2736 executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2737 MonoAssembly *ass = mono_alc_load_file (alc, fname, executing_assembly, mono_alc_is_default (alc) ? MONO_ASMCTX_LOADFROM : MONO_ASMCTX_INDIVIDUAL, error);
2738 goto_if_nok (error, leave);
2740 result = mono_assembly_get_object_handle (domain, ass, error);
2742 leave:
2743 return result;
2745 #endif
2747 static MonoAssembly*
2748 mono_alc_load_raw_bytes (MonoAssemblyLoadContext *alc, guint8 *raw_assembly, guint32 raw_assembly_len, guint8 *raw_symbol_data, guint32 raw_symbol_len, gboolean refonly, MonoError *error);
2750 #ifdef ENABLE_NETCORE
2751 MonoReflectionAssemblyHandle
2752 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalLoadFromStream (gpointer native_alc, gpointer raw_assembly_ptr, gint32 raw_assembly_len, gpointer raw_symbols_ptr, gint32 raw_symbols_len, MonoError *error)
2754 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)native_alc;
2755 MonoDomain *domain = mono_alc_domain (alc);
2756 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2757 MonoAssembly *assm = NULL;
2758 assm = mono_alc_load_raw_bytes (alc, (guint8 *)raw_assembly_ptr, raw_assembly_len, (guint8 *)raw_symbols_ptr, raw_symbols_len, FALSE, error);
2759 goto_if_nok (error, leave);
2761 result = mono_assembly_get_object_handle (domain, assm, error);
2763 leave:
2764 return result;
2766 #else
2767 MonoReflectionAssemblyHandle
2768 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2769 MonoArrayHandle raw_assembly,
2770 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2771 MonoBoolean refonly,
2772 MonoError *error)
2774 MonoAssembly *ass;
2775 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2776 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2777 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2779 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2780 guint8 *assembly_data = (guint8*) g_try_malloc (raw_assembly_len);
2781 if (!assembly_data) {
2782 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2783 return refass;
2785 MonoGCHandle gchandle;
2786 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2787 memcpy (assembly_data, raw_data, raw_assembly_len);
2788 mono_gchandle_free_internal (gchandle); /* unpin */
2789 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2791 MonoAssemblyLoadContext *alc = mono_domain_default_alc (domain);
2793 mono_byte *raw_symbol_data = NULL;
2794 guint32 symbol_len = 0;
2795 MonoGCHandle symbol_gchandle = 0;
2796 if (!MONO_HANDLE_IS_NULL (raw_symbol_store)) {
2797 symbol_len = mono_array_handle_length (raw_symbol_store);
2798 raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2801 ass = mono_alc_load_raw_bytes (alc, assembly_data, raw_assembly_len, raw_symbol_data, symbol_len, refonly, error);
2802 mono_gchandle_free_internal (symbol_gchandle);
2803 goto_if_nok (error, leave);
2805 refass = mono_assembly_get_object_handle (domain, ass, error);
2806 if (!MONO_HANDLE_IS_NULL (refass))
2807 MONO_HANDLE_SET (refass, evidence, evidence);
2809 leave:
2810 return refass;
2812 #endif /* ENABLE_NETCORE */
2814 static MonoAssembly*
2815 mono_alc_load_raw_bytes (MonoAssemblyLoadContext *alc, guint8 *assembly_data, guint32 raw_assembly_len, guint8 *raw_symbol_data, guint32 raw_symbol_len, gboolean refonly, MonoError *error)
2817 MonoAssembly *ass = NULL;
2818 MonoImageOpenStatus status;
2819 MonoImage *image = mono_image_open_from_data_internal (alc, (char*)assembly_data, raw_assembly_len, FALSE, NULL, refonly, FALSE, NULL);
2821 if (!image) {
2822 mono_error_set_bad_image_by_name (error, "In memory assembly", "0x%p", assembly_data);
2823 return ass;
2826 if (raw_symbol_data)
2827 mono_debug_open_image_from_memory (image, raw_symbol_data, raw_symbol_len);
2829 MonoAssembly* redirected_asm = NULL;
2830 MonoImageOpenStatus new_status = MONO_IMAGE_OK;
2831 // http://blogs.microsoft.co.il/sasha/2010/06/09/assemblyreflectiononlyload-ignores-assembly-binding-redirects/
2832 if (!refonly && (redirected_asm = mono_assembly_binding_applies_to_image (alc, image, &new_status))) {
2833 mono_image_close (image);
2834 image = redirected_asm->image;
2835 mono_image_addref (image); /* so that mono_image close, below, has something to do */
2836 } else if (new_status != MONO_IMAGE_OK) {
2837 mono_image_close (image);
2838 mono_error_set_bad_image_by_name (error, "In Memory assembly", "0x%p was assembly binding redirected to another assembly that failed to load", assembly_data);
2839 return ass;
2842 MonoAssemblyLoadRequest req;
2843 mono_assembly_request_prepare_load (&req, refonly? MONO_ASMCTX_REFONLY : MONO_ASMCTX_INDIVIDUAL, alc);
2844 ass = mono_assembly_request_load_from (image, "", &req, &status);
2846 if (!ass) {
2847 mono_image_close (image);
2848 mono_error_set_bad_image_by_name (error, "In Memory assembly", "0x%p", assembly_data);
2849 return ass;
2852 /* Clear the reference added by mono_image_open_from_data_internal above */
2853 mono_image_close (image);
2855 return ass;
2858 #ifndef ENABLE_NETCORE
2859 MonoReflectionAssemblyHandle
2860 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoStackCrawlMark *stack_mark, MonoError *error)
2862 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2863 MonoImageOpenStatus status = MONO_IMAGE_OK;
2864 MonoAssembly *ass;
2865 MonoAssemblyName aname;
2866 gchar *name = NULL;
2867 gboolean parsed;
2869 g_assert (!MONO_HANDLE_IS_NULL (assRef));
2871 name = mono_string_handle_to_utf8 (assRef, error);
2872 goto_if_nok (error, fail);
2873 parsed = mono_assembly_name_parse (name, &aname);
2874 g_free (name);
2876 if (!parsed) {
2877 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2878 /* This is a parse error... */
2879 if (!refOnly) {
2880 MonoAssembly *assm = mono_try_assembly_resolve_handle (mono_domain_default_alc (domain), assRef, NULL, refOnly, error);
2881 goto_if_nok (error, fail);
2882 if (assm) {
2883 refass = mono_assembly_get_object_handle (domain, assm, error);
2884 goto_if_nok (error, fail);
2887 return refass;
2890 MonoAssemblyContextKind asmctx;
2891 asmctx = refOnly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_DEFAULT;
2892 const char *basedir;
2893 basedir = NULL;
2894 if (!refOnly) {
2895 /* Determine if the current assembly is in LoadFrom context.
2896 * If it is, we must include the executing assembly's basedir
2897 * when probing for the given assembly name, and also load the
2898 * requested assembly in LoadFrom context.
2900 MonoAssembly *executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2901 if (executing_assembly && mono_asmctx_get_kind (&executing_assembly->context) == MONO_ASMCTX_LOADFROM) {
2902 asmctx = MONO_ASMCTX_LOADFROM;
2903 basedir = executing_assembly->basedir;
2908 MonoAssemblyByNameRequest req;
2909 mono_assembly_request_prepare_byname (&req, asmctx, mono_domain_default_alc (domain));
2910 req.basedir = basedir;
2911 req.no_postload_search = TRUE;
2912 ass = mono_assembly_request_byname (&aname, &req, &status);
2913 mono_assembly_name_free_internal (&aname);
2915 if (!ass) {
2916 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2917 if (!refOnly) {
2918 ass = mono_try_assembly_resolve_handle (mono_domain_default_alc (domain), assRef, NULL, refOnly, error);
2919 goto_if_nok (error, fail);
2921 if (!ass)
2922 goto fail;
2925 g_assert (ass);
2926 MonoReflectionAssemblyHandle refass;
2927 refass = mono_assembly_get_object_handle (domain, ass, error);
2928 goto_if_nok (error, fail);
2930 MONO_HANDLE_SET (refass, evidence, evidence);
2932 return refass;
2933 fail:
2934 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2937 void
2938 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2940 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2942 if (NULL == domain) {
2943 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2944 return;
2947 if (domain == mono_get_root_domain ()) {
2948 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2949 return;
2953 * Unloading seems to cause problems when running NUnit/NAnt, hence
2954 * this workaround.
2956 if (g_hasenv ("MONO_NO_UNLOAD"))
2957 return;
2959 MonoException *exc = NULL;
2960 mono_domain_try_unload (domain, (MonoObject**)&exc);
2961 if (exc)
2962 mono_error_set_exception_instance (error, exc);
2965 MonoBoolean
2966 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2968 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2970 if (!domain)
2971 return TRUE;
2973 return mono_domain_is_unloading (domain);
2976 void
2977 ves_icall_System_AppDomain_DoUnhandledException (MonoAppDomainHandle ad, MonoExceptionHandle exc, MonoError *error)
2979 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2980 mono_error_assert_ok (error);
2983 gint32
2984 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2985 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2986 MonoError *error)
2988 MonoImage *image;
2989 MonoMethod *method;
2991 g_assert (!MONO_HANDLE_IS_NULL (refass));
2992 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2993 image = assembly->image;
2994 g_assert (image);
2996 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2998 if (!method)
2999 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
3001 if (MONO_HANDLE_IS_NULL (args)) {
3002 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
3003 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
3004 mono_error_assert_ok (error);
3007 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
3008 return res;
3011 MonoAppDomainHandle
3012 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
3014 error_init (error);
3015 MonoDomain *old_domain = mono_domain_get ();
3017 if (!mono_domain_set_fast (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
3018 mono_error_set_appdomain_unloaded (error);
3019 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
3022 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
3025 MonoAppDomainHandle
3026 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
3028 MonoDomain *current_domain = mono_domain_get ();
3029 MonoDomain *domain = mono_domain_get_by_id (domainid);
3031 if (!domain || !mono_domain_set_fast (domain, FALSE)) {
3032 mono_error_set_appdomain_unloaded (error);
3033 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
3036 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
3039 void
3040 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
3042 error_init (error);
3043 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
3046 void
3047 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
3049 error_init (error);
3050 MonoDomain *domain = mono_domain_get_by_id (domain_id);
3052 if (!domain) {
3054 * Raise an exception to prevent the managed code from executing a pop
3055 * later.
3057 mono_error_set_appdomain_unloaded (error);
3058 return;
3061 mono_thread_push_appdomain_ref (domain);
3064 void
3065 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
3067 error_init (error);
3068 mono_thread_pop_appdomain_ref ();
3071 MonoAppContextHandle
3072 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
3074 error_init (error);
3075 return mono_context_get_handle ();
3078 MonoAppContextHandle
3079 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
3081 error_init (error);
3082 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
3085 MonoAppContextHandle
3086 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
3088 error_init (error);
3089 MonoAppContextHandle old_context = mono_context_get_handle ();
3091 mono_context_set_handle (mc);
3093 return old_context;
3096 MonoStringHandle
3097 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
3099 error_init (error);
3100 MonoDomain* mono_root_domain = mono_get_root_domain ();
3101 mono_domain_lock (mono_root_domain);
3102 if (process_guid_set) {
3103 mono_domain_unlock (mono_root_domain);
3104 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
3106 MonoGCHandle gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
3107 memcpy (process_guid, mono_string_chars_internal (MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
3108 mono_gchandle_free_internal (gchandle);
3109 process_guid_set = TRUE;
3110 mono_domain_unlock (mono_root_domain);
3111 return newguid;
3113 #endif
3116 * mono_domain_is_unloading:
3118 gboolean
3119 mono_domain_is_unloading (MonoDomain *domain)
3121 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
3122 return TRUE;
3123 else
3124 return FALSE;
3127 #ifndef ENABLE_NETCORE
3129 static void
3130 clear_cached_vtable (MonoVTable *vtable)
3132 MonoClass *klass = vtable->klass;
3133 MonoDomain *domain = vtable->domain;
3134 MonoClassRuntimeInfo *runtime_info;
3135 void *data;
3137 runtime_info = m_class_get_runtime_info (klass);
3138 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
3139 runtime_info->domain_vtables [domain->domain_id] = NULL;
3140 if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable)))
3141 mono_gc_free_fixed (data);
3144 static G_GNUC_UNUSED void
3145 zero_static_data (MonoVTable *vtable)
3147 MonoClass *klass = vtable->klass;
3148 void *data;
3150 if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable)))
3151 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
3154 typedef struct unload_data {
3155 gboolean done;
3156 MonoDomain *domain;
3157 char *failure_reason;
3158 gint32 refcount;
3159 } unload_data;
3161 static void
3162 unload_data_unref (unload_data *data)
3164 if (!data)
3165 return;
3166 gint32 count;
3167 do {
3168 mono_atomic_load_acquire (count, gint32, &data->refcount);
3169 g_assert (count >= 1 && count <= 2);
3170 if (count == 1) {
3171 g_free (data);
3172 return;
3174 } while (mono_atomic_cas_i32 (&data->refcount, count - 1, count) != count);
3177 static void
3178 deregister_reflection_info_roots_from_list (MonoImage *image)
3180 GSList *list = image->reflection_info_unregister_classes;
3182 while (list) {
3183 MonoClass *klass = (MonoClass *)list->data;
3185 mono_class_free_ref_info (klass);
3187 list = list->next;
3190 image->reflection_info_unregister_classes = NULL;
3193 static void
3194 deregister_reflection_info_roots (MonoDomain *domain)
3196 GSList *list;
3198 mono_domain_assemblies_lock (domain);
3199 for (list = domain->domain_assemblies; list; list = list->next) {
3200 MonoAssembly *assembly = (MonoAssembly *)list->data;
3201 MonoImage *image = assembly->image;
3202 int i;
3205 * No need to take the image lock here since dynamic images are appdomain bound and
3206 * at this point the mutator is gone. Taking the image lock here would mean
3207 * promoting it from a simple lock to a complex lock, which we better avoid if
3208 * possible.
3210 if (image_is_dynamic (image))
3211 deregister_reflection_info_roots_from_list (image);
3213 for (i = 0; i < image->module_count; ++i) {
3214 MonoImage *module = image->modules [i];
3215 if (module && image_is_dynamic (module))
3216 deregister_reflection_info_roots_from_list (module);
3219 mono_domain_assemblies_unlock (domain);
3222 static gsize WINAPI
3223 unload_thread_main (void *arg)
3225 unload_data *data = (unload_data*)arg;
3226 MonoDomain *domain = data->domain;
3227 int i;
3228 gsize result = 1; // failure
3230 mono_thread_set_name_constant_ignore_error (mono_thread_internal_current (), "Domain unloader", MonoSetThreadNameFlag_Permanent);
3233 * FIXME: Abort our parent thread last, so we can return a failure
3234 * indication if aborting times out.
3236 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
3237 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
3238 goto failure;
3241 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
3242 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
3243 goto failure;
3246 /* Finalize all finalizable objects in the doomed appdomain */
3247 if (!mono_domain_finalize (domain, -1)) {
3248 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
3249 goto failure;
3252 /* Clear references to our vtables in class->runtime_info.
3253 * We also hold the loader lock because we're going to change
3254 * class->runtime_info.
3257 mono_loader_lock ();
3258 mono_domain_lock (domain);
3260 * We need to make sure that we don't have any remsets
3261 * pointing into static data of the to-be-freed domain because
3262 * at the next collections they would be invalid. So what we
3263 * do is we first zero all static data and then do a minor
3264 * collection. Because all references in the static data will
3265 * now be null we won't do any unnecessary copies and after
3266 * the collection there won't be any more remsets.
3268 for (i = 0; i < domain->class_vtable_array->len; ++i)
3269 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
3270 #if !HAVE_BOEHM_GC
3271 mono_gc_collect (0);
3272 #endif
3273 for (i = 0; i < domain->class_vtable_array->len; ++i)
3274 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
3275 deregister_reflection_info_roots (domain);
3277 mono_assembly_cleanup_domain_bindings (domain->domain_id);
3279 mono_domain_unlock (domain);
3280 mono_loader_unlock ();
3282 domain->state = MONO_APPDOMAIN_UNLOADED;
3284 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
3286 /* remove from the handle table the items related to this domain */
3287 mono_gchandle_free_domain (domain);
3289 mono_domain_free (domain, FALSE);
3291 result = 0; // success
3292 exit:
3293 mono_atomic_store_release (&data->done, TRUE);
3294 unload_data_unref (data);
3295 return result;
3297 failure:
3298 result = 1;
3299 goto exit;
3303 * mono_domain_unload:
3304 * \param domain The domain to unload
3306 * Unloads an appdomain. Follows the process outlined in the comment
3307 * for \c mono_domain_try_unload.
3309 void
3310 mono_domain_unload (MonoDomain *domain)
3312 MONO_ENTER_GC_UNSAFE;
3313 MonoObject *exc = NULL;
3314 mono_domain_try_unload (domain, &exc);
3315 MONO_EXIT_GC_UNSAFE;
3318 static MonoThreadInfoWaitRet
3319 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
3321 MonoThreadInfoWaitRet result;
3323 MONO_ENTER_GC_SAFE;
3324 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
3325 MONO_EXIT_GC_SAFE;
3327 return result;
3331 * mono_domain_unload:
3332 * \param domain The domain to unload
3333 * \param exc Exception information
3335 * Unloads an appdomain. Follows the process outlined in:
3336 * http://blogs.gotdotnet.com/cbrumme
3338 * If doing things the 'right' way is too hard or complex, we do it the
3339 * 'simple' way, which means do everything needed to avoid crashes and
3340 * memory leaks, but not much else.
3342 * It is required to pass a valid reference to the exc argument, upon return
3343 * from this function *exc will be set to the exception thrown, if any.
3345 * If this method is not called from an icall (embedded scenario for instance),
3346 * it must not be called with any managed frames on the stack, since the unload
3347 * process could end up trying to abort the current thread.
3349 void
3350 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
3352 HANDLE_FUNCTION_ENTER ();
3353 ERROR_DECL (error);
3354 MonoThreadHandle *thread_handle = NULL;
3355 MonoAppDomainState prev_state;
3356 MonoMethod *method;
3357 unload_data *thread_data = NULL;
3358 MonoInternalThreadHandle internal;
3359 MonoDomain *caller_domain = mono_domain_get ();
3361 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
3363 /* Atomically change our state to UNLOADING */
3364 prev_state = (MonoAppDomainState)mono_atomic_cas_i32 ((gint32*)&domain->state,
3365 MONO_APPDOMAIN_UNLOADING_START,
3366 MONO_APPDOMAIN_CREATED);
3367 if (prev_state != MONO_APPDOMAIN_CREATED) {
3368 switch (prev_state) {
3369 case MONO_APPDOMAIN_UNLOADING_START:
3370 case MONO_APPDOMAIN_UNLOADING:
3371 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
3372 goto exit;
3373 case MONO_APPDOMAIN_UNLOADED:
3374 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
3375 goto exit;
3376 default:
3377 g_warning ("Invalid appdomain state %d", prev_state);
3378 g_assert_not_reached ();
3382 mono_domain_set_fast (domain, FALSE);
3383 /* Notify OnDomainUnload listeners */
3384 method = mono_class_get_method_from_name_checked (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1, 0, error);
3385 g_assert (method);
3387 mono_runtime_try_invoke (method, domain->domain, NULL, exc, error);
3389 if (!is_ok (error)) {
3390 if (*exc)
3391 mono_error_cleanup (error);
3392 else
3393 *exc = (MonoObject*)mono_error_convert_to_exception (error);
3396 if (*exc) {
3397 /* Roll back the state change */
3398 domain->state = MONO_APPDOMAIN_CREATED;
3399 mono_domain_set_fast (caller_domain, FALSE);
3400 goto exit;
3402 mono_domain_set_fast (caller_domain, FALSE);
3404 thread_data = g_new0 (unload_data, 1);
3405 thread_data->domain = domain;
3406 thread_data->failure_reason = NULL;
3407 thread_data->done = FALSE;
3408 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
3410 /*The managed callback finished successfully, now we start tearing down the appdomain*/
3411 domain->state = MONO_APPDOMAIN_UNLOADING;
3413 * First we create a separate thread for unloading, since
3414 * we might have to abort some threads, including the current one.
3416 * Have to attach to the runtime so shutdown can wait for this thread.
3418 * Force it to be attached to avoid racing during shutdown.
3420 internal = mono_thread_create_internal_handle (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, error);
3421 mono_error_assert_ok (error);
3423 thread_handle = mono_threads_open_thread_handle (MONO_HANDLE_GETVAL (internal, handle));
3425 /* Wait for the thread */
3426 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
3427 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
3428 /* The unload thread tries to abort us */
3429 /* The icall wrapper will execute the abort */
3430 goto exit;
3434 if (thread_data->failure_reason) {
3435 /* Roll back the state change */
3436 domain->state = MONO_APPDOMAIN_CREATED;
3438 g_warning ("%s", thread_data->failure_reason);
3440 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
3442 g_free (thread_data->failure_reason);
3443 thread_data->failure_reason = NULL;
3446 exit:
3447 mono_threads_close_thread_handle (thread_handle);
3448 unload_data_unref (thread_data);
3449 HANDLE_FUNCTION_RETURN ();
3452 #endif /* ENABLE_NETCORE */
3454 #ifdef ENABLE_NETCORE
3456 /* Remember properties so they can be be installed in AppContext during runtime init */
3457 void
3458 mono_runtime_register_appctx_properties (int nprops, const char **keys, const char **values)
3460 n_appctx_props = nprops;
3461 appctx_keys = g_new0 (gunichar2*, nprops);
3462 appctx_values = g_new0 (gunichar2*, nprops);
3464 for (int i = 0; i < nprops; ++i) {
3465 appctx_keys [i] = g_utf8_to_utf16 (keys [i], strlen (keys [i]), NULL, NULL, NULL);
3466 appctx_values [i] = g_utf8_to_utf16 (values [i], strlen (values [i]), NULL, NULL, NULL);
3470 static GENERATE_GET_CLASS_WITH_CACHE (appctx, "System", "AppContext")
3472 /* Install properties into AppContext */
3473 void
3474 mono_runtime_install_appctx_properties (void)
3476 ERROR_DECL (error);
3477 gpointer args [3];
3479 MonoMethod *setup = mono_class_get_method_from_name_checked (mono_class_get_appctx_class (), "Setup", 3, 0, error);
3480 g_assert (setup);
3482 // FIXME: TRUSTED_PLATFORM_ASSEMBLIES is very large
3484 /* internal static unsafe void Setup(char** pNames, char** pValues, int count) */
3485 args [0] = appctx_keys;
3486 args [1] = appctx_values;
3487 args [2] = &n_appctx_props;
3489 mono_runtime_invoke_checked (setup, NULL, args, error);
3490 mono_error_assert_ok (error);
3492 /* No longer needed */
3493 for (int i = 0; i < n_appctx_props; ++i) {
3494 g_free (appctx_keys [i]);
3495 g_free (appctx_values [i]);
3497 g_free (appctx_keys);
3498 g_free (appctx_values);
3499 appctx_keys = NULL;
3500 appctx_values = NULL;
3503 #endif