[netcore] Use requesting assembly's context for InternalLoad calls
[mono-project.git] / mono / metadata / appdomain.c
blob43a394c3276a5138b9f944d54e36a2275365c4f4
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.
15 #undef ASSEMBLY_LOAD_DEBUG
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 char **appctx_keys;
101 static char **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 *hash);
133 static void
134 add_assembly_to_alc (MonoAssemblyLoadContext *alc, MonoAssembly *ass);
136 static MonoAppDomainHandle
137 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
139 static MonoDomain *
140 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
143 static void
144 mono_context_set_default_context (MonoDomain *domain);
146 static char *
147 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
149 static MonoLoadFunc load_function = NULL;
151 /* Lazy class loading functions */
152 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
154 GENERATE_GET_CLASS_WITH_CACHE (appdomain, MONO_APPDOMAIN_CLASS_NAME_SPACE, MONO_APPDOMAIN_CLASS_NAME);
155 GENERATE_GET_CLASS_WITH_CACHE (appdomain_setup, MONO_APPDOMAIN_SETUP_CLASS_NAME_SPACE, MONO_APPDOMAIN_SETUP_CLASS_NAME);
157 static MonoDomain *
158 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
160 static void
161 mono_error_set_appdomain_unloaded (MonoError *error)
163 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
166 void
167 mono_install_runtime_load (MonoLoadFunc func)
169 load_function = func;
172 MonoDomain*
173 mono_runtime_load (const char *filename, const char *runtime_version)
175 g_assert (load_function);
176 return load_function (filename, runtime_version);
180 * mono_runtime_set_no_exec:
182 * Instructs the runtime to operate in static mode, i.e. avoid/do not
183 * allow managed code execution. This is useful for running the AOT
184 * compiler on platforms which allow full-aot execution only. This
185 * should be called before mono_runtime_init ().
187 void
188 mono_runtime_set_no_exec (gboolean val)
190 no_exec = val;
194 * mono_runtime_get_no_exec:
196 * If true, then the runtime will not allow managed code execution.
198 gboolean
199 mono_runtime_get_no_exec (void)
201 return no_exec;
204 static void
205 create_domain_objects (MonoDomain *domain)
207 HANDLE_FUNCTION_ENTER ();
208 ERROR_DECL (error);
210 MonoDomain *old_domain = mono_domain_get ();
211 MonoStringHandle arg;
212 MonoVTable *string_vt;
213 MonoClassField *string_empty_fld;
215 if (domain != old_domain) {
216 mono_thread_push_appdomain_ref (domain);
217 mono_domain_set_internal_with_options (domain, FALSE);
221 * Initialize String.Empty. This enables the removal of
222 * the static cctor of the String class.
224 string_vt = mono_class_vtable_checked (domain, mono_defaults.string_class, error);
225 mono_error_assert_ok (error);
226 string_empty_fld = mono_class_get_field_from_name_full (mono_defaults.string_class, "Empty", NULL);
227 g_assert (string_empty_fld);
228 MonoStringHandle empty_str = mono_string_new_handle (domain, "", error);
229 mono_error_assert_ok (error);
230 empty_str = mono_string_intern_checked (empty_str, error);
231 mono_error_assert_ok (error);
232 mono_field_static_set_value_internal (string_vt, string_empty_fld, MONO_HANDLE_RAW (empty_str));
233 domain->empty_string = MONO_HANDLE_RAW (empty_str);
236 * Create an instance early since we can't do it when there is no memory.
238 arg = mono_string_new_handle (domain, "Out of memory", error);
239 mono_error_assert_ok (error);
240 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));
241 mono_error_assert_ok (error);
244 * These two are needed because the signal handlers might be executing on
245 * an alternate stack, and Boehm GC can't handle that.
247 arg = mono_string_new_handle (domain, "A null value was found where an object instance was required", error);
248 mono_error_assert_ok (error);
249 domain->null_reference_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL_HANDLE_STRING, error));
250 mono_error_assert_ok (error);
251 arg = mono_string_new_handle (domain, "The requested operation caused a stack overflow.", error);
252 mono_error_assert_ok (error);
253 domain->stack_overflow_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL_HANDLE_STRING, error));
254 mono_error_assert_ok (error);
256 /*The ephemeron tombstone i*/
257 domain->ephemeron_tombstone = MONO_HANDLE_RAW (mono_object_new_handle (domain, mono_defaults.object_class, error));
258 mono_error_assert_ok (error);
260 if (domain != old_domain) {
261 mono_thread_pop_appdomain_ref ();
262 mono_domain_set_internal_with_options (old_domain, FALSE);
266 * This class is used during exception handling, so initialize it here, to prevent
267 * stack overflows while handling stack overflows.
269 mono_class_init_internal (mono_class_create_array (mono_defaults.int_class, 1));
270 HANDLE_FUNCTION_RETURN ();
274 * mono_runtime_init:
275 * \param domain domain returned by \c mono_init
277 * Initialize the core AppDomain: this function will run also some
278 * IL initialization code, so it needs the execution engine to be fully
279 * operational.
281 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
282 * we know the \c entry_assembly.
285 void
286 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
288 ERROR_DECL (error);
289 mono_runtime_init_checked (domain, start_cb, attach_cb, error);
290 mono_error_cleanup (error);
293 void
294 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
296 HANDLE_FUNCTION_ENTER ();
298 MonoAppDomainSetupHandle setup;
299 MonoAppDomainHandle ad;
301 error_init (error);
303 mono_portability_helpers_init ();
305 mono_gc_base_init ();
306 mono_monitor_init ();
307 mono_marshal_init ();
308 mono_gc_init_icalls ();
310 mono_install_assembly_preload_hook_v2 (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE), FALSE);
311 mono_install_assembly_search_hook_v2 (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE), FALSE, FALSE);
312 mono_install_assembly_search_hook_v2 (mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE), FALSE, TRUE);
313 mono_install_assembly_load_hook_v2 (mono_domain_fire_assembly_load, NULL);
315 #ifndef ENABLE_NETCORE // refonly hooks
316 mono_install_assembly_preload_hook_v2 (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE), TRUE);
317 mono_install_assembly_search_hook_v2 (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE), TRUE, FALSE);
318 mono_install_assembly_search_hook_v2 (mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE), TRUE, TRUE);
319 mono_install_assembly_asmctx_from_path_hook (mono_domain_asmctx_from_path, NULL);
320 #endif
322 mono_thread_init (start_cb, attach_cb);
324 if (!mono_runtime_get_no_exec ()) {
325 MonoClass *klass = mono_class_get_appdomain_setup_class ();
326 setup = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_pinned_handle (domain, klass, error));
327 goto_if_nok (error, exit);
329 klass = mono_class_get_appdomain_class ();
331 ad = MONO_HANDLE_CAST (MonoAppDomain, mono_object_new_pinned_handle (domain, klass, error));
332 goto_if_nok (error, exit);
334 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, domain);
335 domain->domain = MONO_HANDLE_RAW (ad);
336 domain->setup = MONO_HANDLE_RAW (setup);
339 mono_thread_attach (domain);
341 mono_type_initialization_init ();
343 if (!mono_runtime_get_no_exec ())
344 create_domain_objects (domain);
346 /* GC init has to happen after thread init */
347 mono_gc_init ();
349 /* contexts use GC handles, so they must be initialized after the GC */
350 #ifndef ENABLE_NETCORE
351 mono_context_init_checked (domain, error);
352 goto_if_nok (error, exit);
353 mono_context_set_default_context (domain);
354 #endif
356 #ifdef ENABLE_NETCORE
357 if (!mono_runtime_get_no_exec ())
358 mono_runtime_install_appctx_properties ();
359 #endif
361 #ifndef DISABLE_SOCKETS
362 mono_network_init ();
363 #endif
365 mono_console_init ();
366 mono_attach_init ();
368 mono_locks_tracer_init ();
370 /* mscorlib is loaded before we install the load hook */
371 mono_domain_fire_assembly_load (mono_domain_default_alc (domain), mono_defaults.corlib->assembly, NULL, error);
372 goto_if_nok (error, exit);
374 exit:
375 HANDLE_FUNCTION_RETURN ();
378 static void
379 mono_context_set_default_context (MonoDomain *domain)
381 if (mono_runtime_get_no_exec ())
382 return;
384 HANDLE_FUNCTION_ENTER ();
385 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext, domain->default_context));
386 HANDLE_FUNCTION_RETURN ();
389 static char*
390 mono_get_corlib_version (void)
392 ERROR_DECL (error);
394 MonoClass *klass;
395 MonoClassField *field;
397 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
398 mono_class_init_internal (klass);
399 field = mono_class_get_field_from_name_full (klass, "mono_corlib_version", NULL);
400 if (!field)
401 return NULL;
403 if (! (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_LITERAL)))
404 return NULL;
406 char *value;
407 MonoTypeEnum field_type;
408 const char *data = mono_class_get_field_default_value (field, &field_type);
409 if (field_type != MONO_TYPE_STRING)
410 return NULL;
411 mono_metadata_read_constant_value (data, field_type, &value, error);
412 mono_error_assert_ok (error);
414 char *res = mono_string_from_blob (value, error);
415 mono_error_assert_ok (error);
417 return res;
421 * mono_check_corlib_version:
422 * Checks that the corlib that is loaded matches the version of this runtime.
423 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
424 * allocated string with the error otherwise.
426 const char*
427 mono_check_corlib_version (void)
429 const char* res;
430 MONO_ENTER_GC_UNSAFE;
431 res = mono_check_corlib_version_internal ();
432 MONO_EXIT_GC_UNSAFE;
433 return res;
436 static const char *
437 mono_check_corlib_version_internal (void)
439 #if defined(MONO_CROSS_COMPILE)
440 /* Can't read the corlib version because we only have the target class layouts */
441 return NULL;
442 #endif
444 char *result = NULL;
445 char *version = mono_get_corlib_version ();
446 if (!version) {
447 result = g_strdup_printf ("expected corlib string (%s) but not found or not string", MONO_CORLIB_VERSION);
448 goto exit;
450 if (strcmp (version, MONO_CORLIB_VERSION) != 0) {
451 result = g_strdup_printf ("The runtime did not find the mscorlib.dll it expected. "
452 "Expected interface version %s but found %s. Check that "
453 "your runtime and class libraries are matching.",
454 MONO_CORLIB_VERSION, version);
455 goto exit;
458 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
459 guint32 native_offset;
460 guint32 managed_offset;
461 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
462 managed_offset = mono_field_get_offset (mono_class_get_field_from_name_full (mono_defaults.internal_thread_class, "last", NULL));
463 if (native_offset != managed_offset)
464 result = g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
465 exit:
466 g_free (version);
467 return result;
471 * mono_context_init:
472 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
473 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
475 void
476 mono_context_init (MonoDomain *domain)
478 ERROR_DECL (error);
479 mono_context_init_checked (domain, error);
480 mono_error_cleanup (error);
483 void
484 mono_context_init_checked (MonoDomain *domain, MonoError *error)
486 HANDLE_FUNCTION_ENTER ();
488 MonoClass *klass;
489 MonoAppContextHandle context;
491 error_init (error);
492 if (mono_runtime_get_no_exec ())
493 goto exit;
495 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
496 context = MONO_HANDLE_CAST (MonoAppContext, mono_object_new_pinned_handle (domain, klass, error));
497 goto_if_nok (error, exit);
499 MONO_HANDLE_SETVAL (context, domain_id, gint32, domain->domain_id);
500 MONO_HANDLE_SETVAL (context, context_id, gint32, 0);
501 mono_threads_register_app_context (context, error);
502 mono_error_assert_ok (error);
503 domain->default_context = MONO_HANDLE_RAW (context);
504 exit:
505 HANDLE_FUNCTION_RETURN ();
509 * mono_runtime_cleanup:
510 * \param domain unused.
512 * Internal routine.
514 * This must not be called while there are still running threads executing
515 * managed code.
517 void
518 mono_runtime_cleanup (MonoDomain *domain)
520 mono_attach_cleanup ();
522 /* This ends up calling any pending pending (for at most 2 seconds) */
523 mono_gc_cleanup ();
525 mono_thread_cleanup ();
527 #ifndef DISABLE_SOCKETS
528 mono_network_cleanup ();
529 #endif
530 mono_marshal_cleanup ();
532 mono_type_initialization_cleanup ();
534 mono_monitor_cleanup ();
537 static MonoDomainFunc quit_function = NULL;
540 * mono_install_runtime_cleanup:
542 void
543 mono_install_runtime_cleanup (MonoDomainFunc func)
545 quit_function = func;
549 * mono_runtime_quit:
551 void
552 mono_runtime_quit ()
554 if (quit_function != NULL)
555 quit_function (mono_get_root_domain (), NULL);
559 * mono_domain_create_appdomain:
560 * \param friendly_name The friendly name of the appdomain to create
561 * \param configuration_file The configuration file to initialize the appdomain with
562 * \returns a \c MonoDomain initialized with the appdomain
564 MonoDomain *
565 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
567 HANDLE_FUNCTION_ENTER ();
568 MonoDomain *domain;
569 MONO_ENTER_GC_UNSAFE;
570 ERROR_DECL (error);
571 domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, error);
572 mono_error_cleanup (error);
573 MONO_EXIT_GC_UNSAFE;
574 HANDLE_FUNCTION_RETURN_VAL (domain);
578 * mono_domain_create_appdomain_checked:
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 * \param error Set on error.
583 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
585 MonoDomain *
586 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
588 HANDLE_FUNCTION_ENTER ();
589 error_init (error);
590 MonoDomain *result = NULL;
592 MonoClass *klass = mono_class_get_appdomain_setup_class ();
593 MonoAppDomainSetupHandle setup = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_handle (mono_domain_get (), klass, error));
594 goto_if_nok (error, leave);
595 MonoStringHandle config_file;
596 if (configuration_file != NULL) {
597 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
598 goto_if_nok (error, leave);
599 } else {
600 config_file = MONO_HANDLE_NEW (MonoString, NULL);
602 MONO_HANDLE_SET (setup, configuration_file, config_file);
604 MonoAppDomainHandle ad;
605 ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
606 goto_if_nok (error, leave);
608 result = mono_domain_from_appdomain_handle (ad);
609 leave:
610 HANDLE_FUNCTION_RETURN_VAL (result);
614 * mono_domain_set_config:
615 * \param domain \c MonoDomain initialized with the appdomain we want to change
616 * \param base_dir new base directory for the appdomain
617 * \param config_file_name path to the new configuration for the app domain
619 * Used to set the system configuration for an appdomain
621 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
622 * Error Initializing the configuration system. ---> System.ArgumentException:
623 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
625 void
626 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
628 HANDLE_FUNCTION_ENTER ();
629 MONO_ENTER_GC_UNSAFE;
630 ERROR_DECL (error);
631 mono_domain_set_config_checked (domain, base_dir, config_file_name, error);
632 mono_error_cleanup (error);
633 MONO_EXIT_GC_UNSAFE;
634 HANDLE_FUNCTION_RETURN ();
637 gboolean
638 mono_domain_set_config_checked (MonoDomain *domain, const char *base_dir, const char *config_file_name, MonoError *error)
640 error_init (error);
641 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
642 MonoStringHandle base_dir_str = mono_string_new_handle (domain, base_dir, error);
643 goto_if_nok (error, leave);
644 MONO_HANDLE_SET (setup, application_base, base_dir_str);
645 MonoStringHandle config_file_name_str;
646 config_file_name_str = mono_string_new_handle (domain, config_file_name, error);
647 goto_if_nok (error, leave);
648 MONO_HANDLE_SET (setup, configuration_file, config_file_name_str);
649 leave:
650 return is_ok (error);
653 static MonoAppDomainSetupHandle
654 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
656 HANDLE_FUNCTION_ENTER ();
657 MonoDomain *caller_domain;
658 MonoClass *ads_class;
659 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
661 error_init (error);
663 caller_domain = mono_domain_get ();
664 ads_class = mono_class_get_appdomain_setup_class ();
666 MonoAppDomainSetupHandle copy = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_handle(domain, ads_class, error));
667 goto_if_nok (error, leave);
669 mono_domain_set_internal_with_options (domain, TRUE);
671 #define XCOPY_FIELD(type, dst, field, src, error) \
672 do { \
673 TYPED_HANDLE_NAME (type) src_val = MONO_HANDLE_NEW_GET (type, (src), field); \
674 TYPED_HANDLE_NAME (type) copied_val = MONO_HANDLE_CAST (type, mono_marshal_xdomain_copy_value_handle (MONO_HANDLE_CAST (MonoObject, src_val), error)); \
675 goto_if_nok (error, leave); \
676 MONO_HANDLE_SET ((dst),field,copied_val); \
677 } while (0)
679 #define COPY_VAL(dst,field,type,src) \
680 do { \
681 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
682 } while (0)
684 XCOPY_FIELD (MonoString, copy, application_base, setup, error);
685 XCOPY_FIELD (MonoString, copy, application_name, setup, error);
686 XCOPY_FIELD (MonoString, copy, cache_path, setup, error);
687 XCOPY_FIELD (MonoString, copy, configuration_file, setup, error);
688 XCOPY_FIELD (MonoString, copy, dynamic_base, setup, error);
689 XCOPY_FIELD (MonoString, copy, license_file, setup, error);
690 XCOPY_FIELD (MonoString, copy, private_bin_path, setup, error);
691 XCOPY_FIELD (MonoString, copy, private_bin_path_probe, setup, error);
692 XCOPY_FIELD (MonoString, copy, shadow_copy_directories, setup, error);
693 XCOPY_FIELD (MonoString, copy, shadow_copy_files, setup, error);
694 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
695 COPY_VAL (copy, path_changed, MonoBoolean, setup);
696 COPY_VAL (copy, loader_optimization, int, setup);
697 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
698 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
699 XCOPY_FIELD (MonoArray, copy, domain_initializer_args, setup, error);
700 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
701 XCOPY_FIELD (MonoObject, copy, application_trust, setup, error);
702 XCOPY_FIELD (MonoArray, copy, configuration_bytes, setup, error);
703 XCOPY_FIELD (MonoArray, copy, serialized_non_primitives, setup, error);
705 #undef XCOPY_FIELD
706 #undef COPY_VAL
708 mono_domain_set_internal_with_options (caller_domain, TRUE);
710 MONO_HANDLE_ASSIGN (result, copy);
711 leave:
712 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
715 static MonoAppDomainHandle
716 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
718 HANDLE_FUNCTION_ENTER ();
719 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
720 MonoClass *adclass;
721 MonoDomain *data;
723 error_init (error);
725 adclass = mono_class_get_appdomain_class ();
727 /* FIXME: pin all those objects */
728 data = mono_domain_create();
730 MonoAppDomainHandle ad = MONO_HANDLE_CAST (MonoAppDomain, mono_object_new_handle (data, adclass, error));
731 goto_if_nok (error, leave);
732 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
733 data->domain = MONO_HANDLE_RAW (ad);
734 data->friendly_name = g_strdup (friendly_name);
736 MONO_PROFILER_RAISE (domain_name, (data, data->friendly_name));
738 MonoStringHandle app_base;
739 app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
740 if (MONO_HANDLE_IS_NULL (app_base)) {
741 /* Inherit from the root domain since MS.NET does this */
742 MonoDomain *root = mono_get_root_domain ();
743 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
744 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
745 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
746 /* N.B. new string is in the new domain */
747 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
748 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);
749 mono_gchandle_free_internal (gchandle);
750 if (!is_ok (error)) {
751 g_free (data->friendly_name);
752 goto leave;
754 MONO_HANDLE_SET (setup, application_base, s);
758 mono_context_init_checked (data, error);
759 goto_if_nok (error, leave);
761 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
762 if (!is_ok (error)) {
763 g_free (data->friendly_name);
764 goto leave;
767 mono_domain_set_options_from_config (data);
768 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
770 #ifndef DISABLE_SHADOW_COPY
771 /*FIXME, guard this for when the debugger is not running */
772 char *shadow_location;
773 shadow_location = get_shadow_assembly_location_base (data, error);
774 if (!is_ok (error)) {
775 g_free (data->friendly_name);
776 goto leave;
779 g_free (shadow_location);
780 #endif
782 create_domain_objects (data);
784 MONO_HANDLE_ASSIGN (result, ad);
785 leave:
786 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
790 * mono_domain_has_type_resolve:
791 * \param domain application domain being looked up
793 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
795 gboolean
796 mono_domain_has_type_resolve (MonoDomain *domain)
798 #ifdef ENABLE_NETCORE
799 return FALSE;
800 #else
801 static MonoClassField *field = NULL;
802 MonoObject *o;
804 if (field == NULL) {
805 field = mono_class_get_field_from_name_full (mono_defaults.appdomain_class, "TypeResolve", NULL);
806 g_assert (field);
809 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
810 if (!domain->domain)
811 return FALSE;
813 mono_field_get_value_internal ((MonoObject*)(domain->domain), field, &o);
814 return o != NULL;
815 #endif
819 * mono_domain_try_type_resolve:
820 * \param domain application domain in which to resolve the type
821 * \param name the name of the type to resolve or NULL.
822 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
824 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
825 * the assembly that matches name, or ((TypeBuilder)typebuilder).FullName.
827 * \returns A \c MonoReflectionAssembly or NULL if not found
829 MonoReflectionAssembly *
830 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *typebuilder_raw)
832 HANDLE_FUNCTION_ENTER ();
834 g_assert (domain);
835 g_assert (name || typebuilder_raw);
837 ERROR_DECL (error);
839 MonoReflectionAssemblyHandle ret = NULL_HANDLE_INIT;
841 if (name) {
842 MonoStringHandle name_handle = mono_string_new_handle (mono_domain_get (), name, error);
843 goto_if_nok (error, exit);
844 ret = mono_domain_try_type_resolve_name (domain, name_handle, error);
845 } else {
846 MONO_HANDLE_DCL (MonoObject, typebuilder);
847 ret = mono_domain_try_type_resolve_typebuilder (domain, MONO_HANDLE_CAST (MonoReflectionTypeBuilder, typebuilder), error);
850 exit:
851 mono_error_cleanup (error);
852 HANDLE_FUNCTION_RETURN_OBJ (ret);
856 * mono_class_get_appdomain_do_type_resolve_method:
858 * This routine returns System.AppDomain.DoTypeResolve.
860 static MonoMethod *
861 mono_class_get_appdomain_do_type_resolve_method (MonoError *error)
863 static MonoMethod *method; // cache
865 if (method)
866 return method;
868 // not cached yet, fill cache under caller's lock
870 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoTypeResolve", -1, 0, error);
872 if (method == NULL)
873 g_warning ("%s method AppDomain.DoTypeResolve not found. %s\n", __func__, mono_error_get_message (error));
875 return method;
879 * mono_class_get_appdomain_do_type_builder_resolve_method:
881 * This routine returns System.AppDomain.DoTypeBuilderResolve.
883 static MonoMethod *
884 mono_class_get_appdomain_do_type_builder_resolve_method (MonoError *error)
886 static MonoMethod *method; // cache
888 if (method)
889 return method;
891 // not cached yet, fill cache under caller's lock
893 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoTypeBuilderResolve", -1, 0, error);
895 if (method == NULL)
896 g_warning ("%s method AppDomain.DoTypeBuilderResolve not found. %s\n", __func__, mono_error_get_message (error));
898 return method;
902 * mono_domain_try_type_resolve_name:
903 * \param domain application domain in which to resolve the type
904 * \param name the name of the type to resolve.
906 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
907 * the assembly that matches name.
909 * \returns A \c MonoReflectionAssembly or NULL if not found
911 MonoReflectionAssemblyHandle
912 mono_domain_try_type_resolve_name (MonoDomain *domain, MonoStringHandle name, MonoError *error)
914 HANDLE_FUNCTION_ENTER ();
916 void *params [1] = { 0 };
918 g_assert (domain);
919 g_assert (MONO_HANDLE_BOOL (name));
920 g_assert (error);
922 error_init (error);
924 MonoMethod *method;
925 method = mono_class_get_appdomain_do_type_resolve_method (error);
926 goto_if_nok (error, return_null);
928 MonoAppDomainHandle appdomain;
929 appdomain = MONO_HANDLE_NEW (MonoAppDomain, domain->domain);
931 MonoObjectHandle ret;
932 params [0] = MONO_HANDLE_RAW (name);
933 ret = mono_runtime_invoke_handle (method, MONO_HANDLE_CAST (MonoObject, appdomain), params, error);
934 goto_if_nok (error, return_null);
935 goto exit;
936 return_null:
937 ret = NULL_HANDLE;
938 exit:
939 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
943 * mono_domain_try_type_resolve_typebuilder:
944 * \param domain application domain in which to resolve the type
945 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder; typebuilder.FullName is the name of the type to resolve.
947 * This routine invokes the internal \c System.AppDomain.DoTypeBuilderResolve and returns
948 * the assembly that matches typebuilder.FullName.
950 * \returns A \c MonoReflectionAssembly or NULL_HANDLE if not found
952 MonoReflectionAssemblyHandle
953 mono_domain_try_type_resolve_typebuilder (MonoDomain *domain, MonoReflectionTypeBuilderHandle typebuilder, MonoError *error)
955 HANDLE_FUNCTION_ENTER ();
957 g_assert (domain);
958 g_assert (MONO_HANDLE_BOOL (typebuilder));
959 g_assert (error);
961 error_init (error);
963 MonoMethod * const method = mono_class_get_appdomain_do_type_builder_resolve_method (error);
964 goto_if_nok (error, return_null);
966 MonoAppDomainHandle appdomain;
967 appdomain = MONO_HANDLE_NEW (MonoAppDomain, domain->domain);
968 void *args [1];
969 args [0] = MONO_HANDLE_RAW (typebuilder);
971 MonoObjectHandle ret;
972 ret = mono_runtime_invoke_handle (method, MONO_HANDLE_CAST (MonoObject, appdomain), args, error);
973 goto_if_nok (error, return_null);
974 goto exit;
975 return_null:
976 ret = NULL_HANDLE;
977 exit:
978 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
982 * mono_domain_owns_vtable_slot:
983 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
985 gboolean
986 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
988 gboolean res;
990 mono_domain_lock (domain);
991 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
992 mono_domain_unlock (domain);
993 return res;
996 gboolean
997 mono_domain_set_fast (MonoDomain *domain, gboolean force)
999 MONO_REQ_GC_UNSAFE_MODE;
1000 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
1001 return FALSE;
1003 mono_domain_set_internal_with_options (domain, TRUE);
1004 return TRUE;
1007 #ifndef ENABLE_NETCORE
1008 MonoObjectHandle
1009 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
1011 error_init (error);
1013 if (MONO_HANDLE_IS_NULL (name)) {
1014 mono_error_set_argument_null (error, "name", "");
1015 return NULL_HANDLE;
1018 g_assert (!MONO_HANDLE_IS_NULL (ad));
1019 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
1020 g_assert (add);
1022 char *str = mono_string_handle_to_utf8 (name, error);
1023 return_val_if_nok (error, NULL_HANDLE);
1025 mono_domain_lock (add);
1027 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
1028 MonoStringHandle o;
1029 if (!strcmp (str, "APPBASE"))
1030 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
1031 else if (!strcmp (str, "APP_CONFIG_FILE"))
1032 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
1033 else if (!strcmp (str, "DYNAMIC_BASE"))
1034 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
1035 else if (!strcmp (str, "APP_NAME"))
1036 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
1037 else if (!strcmp (str, "CACHE_BASE"))
1038 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
1039 else if (!strcmp (str, "PRIVATE_BINPATH"))
1040 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
1041 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
1042 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
1043 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
1044 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
1045 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
1046 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
1047 else
1048 o = MONO_HANDLE_NEW (MonoString, (MonoString*)mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
1050 mono_domain_unlock (add);
1051 g_free (str);
1053 return MONO_HANDLE_CAST (MonoObject, o);
1056 void
1057 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
1059 error_init (error);
1061 if (MONO_HANDLE_IS_NULL (name)) {
1062 mono_error_set_argument_null (error, "name", "");
1063 return;
1066 g_assert (!MONO_HANDLE_IS_NULL (ad));
1067 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
1068 g_assert (add);
1070 mono_domain_lock (add);
1072 mono_g_hash_table_insert_internal (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
1074 mono_domain_unlock (add);
1077 MonoAppDomainSetupHandle
1078 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
1080 error_init (error);
1081 g_assert (!MONO_HANDLE_IS_NULL (ad));
1082 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1083 g_assert (domain);
1085 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
1088 MonoStringHandle
1089 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
1091 error_init (error);
1092 g_assert (!MONO_HANDLE_IS_NULL (ad));
1093 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1094 g_assert (domain);
1096 return mono_string_new_handle (domain, domain->friendly_name, error);
1099 MonoAppDomainHandle
1100 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
1102 error_init (error);
1103 MonoDomain *add = mono_domain_get ();
1105 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
1108 MonoAppDomainHandle
1109 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
1111 error_init (error);
1112 MonoDomain *root = mono_get_root_domain ();
1114 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
1117 MonoBoolean
1118 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions (MonoError *error)
1120 MonoDomain *domain = mono_domain_get ();
1122 return domain->throw_unobserved_task_exceptions;
1124 #endif
1126 static char*
1127 get_attribute_value (const gchar **attribute_names,
1128 const gchar **attribute_values,
1129 const char *att_name)
1131 int n;
1132 for (n = 0; attribute_names [n] != NULL; n++) {
1133 if (strcmp (attribute_names [n], att_name) == 0)
1134 return g_strdup (attribute_values [n]);
1136 return NULL;
1139 static void
1140 start_element (GMarkupParseContext *context,
1141 const gchar *element_name,
1142 const gchar **attribute_names,
1143 const gchar **attribute_values,
1144 gpointer user_data,
1145 GError **gerror)
1147 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
1149 if (strcmp (element_name, "runtime") == 0) {
1150 runtime_config->runtime_count++;
1151 return;
1154 if (strcmp (element_name, "assemblyBinding") == 0) {
1155 runtime_config->assemblybinding_count++;
1156 return;
1159 if (runtime_config->runtime_count != 1)
1160 return;
1162 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
1163 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
1165 if (value && g_ascii_strcasecmp (value, "true") == 0)
1166 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
1169 if (runtime_config->assemblybinding_count != 1)
1170 return;
1172 if (strcmp (element_name, "probing") != 0)
1173 return;
1175 g_free (runtime_config->domain->private_bin_path);
1176 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
1177 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
1178 g_free (runtime_config->domain->private_bin_path);
1179 runtime_config->domain->private_bin_path = NULL;
1180 return;
1184 static void
1185 end_element (GMarkupParseContext *context,
1186 const gchar *element_name,
1187 gpointer user_data,
1188 GError **gerror)
1190 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
1191 if (strcmp (element_name, "runtime") == 0)
1192 runtime_config->runtime_count--;
1193 else if (strcmp (element_name, "assemblyBinding") == 0)
1194 runtime_config->assemblybinding_count--;
1197 static void
1198 parse_error (GMarkupParseContext *context, GError *gerror, gpointer user_data)
1200 RuntimeConfig *state = (RuntimeConfig *)user_data;
1201 const gchar *msg;
1202 const gchar *filename;
1204 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
1205 msg = gerror && gerror->message ? gerror->message : "";
1206 g_warning ("Error parsing %s: %s", filename, msg);
1209 static const GMarkupParser
1210 mono_parser = {
1211 start_element,
1212 end_element,
1213 NULL,
1214 NULL,
1215 parse_error
1218 void
1219 mono_domain_set_options_from_config (MonoDomain *domain)
1221 ERROR_DECL (error);
1222 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
1223 gsize len;
1224 GMarkupParseContext *context;
1225 RuntimeConfig runtime_config;
1226 gint offset;
1228 if (!domain || !domain->setup || !domain->setup->configuration_file)
1229 return;
1231 config_file_name = mono_string_to_utf8_checked_internal (domain->setup->configuration_file, error);
1232 if (!is_ok (error)) {
1233 mono_error_cleanup (error);
1234 goto free_and_out;
1237 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1238 if (!config_file_path)
1239 config_file_path = config_file_name;
1241 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1242 goto free_and_out;
1244 runtime_config.runtime_count = 0;
1245 runtime_config.assemblybinding_count = 0;
1246 runtime_config.domain = domain;
1247 runtime_config.filename = config_file_path;
1249 offset = 0;
1250 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1251 offset = 3; /* Skip UTF-8 BOM */
1253 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1254 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1255 g_markup_parse_context_end_parse (context, NULL);
1256 g_markup_parse_context_free (context);
1258 free_and_out:
1259 g_free (text);
1260 if (config_file_name != config_file_path)
1261 g_free (config_file_name);
1262 g_free (config_file_path);
1265 #ifndef ENABLE_NETCORE
1266 MonoAppDomainHandle
1267 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1269 error_init (error);
1270 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1272 #ifdef DISABLE_APPDOMAINS
1273 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1274 #else
1275 char *fname;
1277 fname = mono_string_handle_to_utf8 (friendly_name, error);
1278 return_val_if_nok (error, ad);
1279 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1280 g_free (fname);
1281 #endif
1282 return ad;
1284 #endif
1286 static gboolean
1287 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1289 HANDLE_FUNCTION_ENTER ();
1290 error_init (error);
1291 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1292 goto_if_nok (error, leave);
1293 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1294 leave:
1295 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1298 static MonoArrayHandle
1299 get_assembly_array_from_domain (MonoDomain *domain, MonoBoolean refonly, MonoError *error)
1301 int i;
1302 GPtrArray *assemblies;
1304 assemblies = mono_domain_get_assemblies (domain, refonly);
1306 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1307 goto_if_nok (error, leave);
1308 for (i = 0; i < assemblies->len; ++i) {
1309 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1310 goto leave;
1313 leave:
1314 g_ptr_array_free (assemblies, TRUE);
1315 return res;
1318 #ifdef ENABLE_NETCORE
1319 MonoArrayHandle
1320 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalGetLoadedAssemblies (MonoError *error)
1322 MonoDomain *domain = mono_domain_get ();
1323 return get_assembly_array_from_domain (domain, FALSE, error);
1325 #else
1326 MonoArrayHandle
1327 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1329 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1330 return get_assembly_array_from_domain (domain, refonly, error);
1332 #endif
1334 MonoAssembly*
1335 mono_try_assembly_resolve (MonoAssemblyLoadContext *alc, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1337 HANDLE_FUNCTION_ENTER ();
1338 error_init (error);
1339 MonoAssembly *result = NULL;
1340 MonoStringHandle fname = mono_string_new_handle (mono_alc_domain (alc), fname_raw, error);
1341 goto_if_nok (error, leave);
1342 result = mono_try_assembly_resolve_handle (alc, fname, requesting, refonly, error);
1343 leave:
1344 HANDLE_FUNCTION_RETURN_VAL (result);
1347 MonoAssembly*
1348 mono_try_assembly_resolve_handle (MonoAssemblyLoadContext *alc, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1350 HANDLE_FUNCTION_ENTER ();
1351 MonoAssembly *ret = NULL;
1352 MonoDomain *domain = mono_alc_domain (alc);
1353 static MonoMethod *method;
1355 if (mono_runtime_get_no_exec ())
1356 goto leave;
1358 #ifndef ENABLE_NETCORE
1359 MonoBoolean isrefonly;
1360 gpointer params [3];
1362 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1364 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1, 0, error);
1365 g_assert (method != NULL);
1367 isrefonly = refonly ? 1 : 0;
1368 MonoReflectionAssemblyHandle requesting_handle;
1369 if (requesting) {
1370 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1371 goto_if_nok (error, leave);
1373 params [0] = MONO_HANDLE_RAW (fname);
1374 params [1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1375 params [2] = &isrefonly;
1376 MonoObject *exc;
1377 exc = NULL;
1378 MonoReflectionAssemblyHandle result;
1379 result = MONO_HANDLE_CAST (MonoReflectionAssembly, MONO_HANDLE_NEW (MonoObject, mono_runtime_try_invoke (method, domain->domain, params, &exc, error)));
1380 if (!is_ok (error) || exc != NULL) {
1381 if (is_ok (error))
1382 mono_error_set_exception_instance (error, (MonoException*)exc);
1383 goto leave;
1385 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1387 if (ret && !refonly && mono_asmctx_get_kind (&ret->context) == MONO_ASMCTX_REFONLY) {
1388 /* .NET Framework throws System.IO.FileNotFoundException in this case */
1389 mono_error_set_file_not_found (error, NULL, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only");
1390 ret = NULL;
1391 goto leave;
1393 #else
1394 if (!method) {
1395 ERROR_DECL (local_error);
1396 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
1397 g_assert (alc_class);
1398 MonoMethod *found = mono_class_get_method_from_name_checked (alc_class, "OnAssemblyResolve", -1, 0, local_error);
1399 mono_error_assert_ok (local_error);
1400 method = found;
1402 g_assert (method);
1404 MonoReflectionAssemblyHandle requesting_handle;
1405 if (requesting) {
1406 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1407 goto_if_nok (error, leave);
1410 gpointer params [2];
1411 params [0] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1412 params [1] = MONO_HANDLE_RAW (fname);
1413 MonoReflectionAssemblyHandle result;
1414 result = MONO_HANDLE_CAST (MonoReflectionAssembly, mono_runtime_try_invoke_handle (method, NULL_HANDLE, params, error));
1415 goto_if_nok (error, leave);
1417 if (MONO_HANDLE_BOOL (result))
1418 ret = MONO_HANDLE_GETVAL (result, assembly);
1419 #endif
1421 leave:
1422 HANDLE_FUNCTION_RETURN_VAL (ret);
1425 MonoAssembly *
1426 mono_domain_assembly_postload_search (MonoAssemblyLoadContext *alc, MonoAssembly *requesting,
1427 MonoAssemblyName *aname,
1428 gboolean refonly, gboolean postload,
1429 gpointer user_data,
1430 MonoError *error_out)
1432 ERROR_DECL (error);
1433 MonoAssembly *assembly;
1434 char *aname_str;
1436 aname_str = mono_stringify_assembly_name (aname);
1438 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1440 assembly = mono_try_assembly_resolve (alc, aname_str, requesting, refonly, error);
1441 g_free (aname_str);
1442 mono_error_cleanup (error);
1444 return assembly;
1448 * LOCKING: assumes assemblies_lock in the domain is already locked.
1450 static void
1451 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1453 gint i;
1454 GSList *tmp;
1455 gboolean destroy_ht = FALSE;
1457 g_assert (ass != NULL);
1459 if (!ass->aname.name)
1460 return;
1462 if (!ht) {
1463 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1464 destroy_ht = TRUE;
1465 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1466 g_hash_table_insert (ht, tmp->data, tmp->data);
1470 /* FIXME: handle lazy loaded assemblies */
1472 if (!g_hash_table_lookup (ht, ass)) {
1473 mono_assembly_addref (ass);
1474 g_hash_table_insert (ht, ass, ass);
1475 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1476 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to domain %s, ref_count=%d", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
1479 if (ass->image->references) {
1480 for (i = 0; i < ass->image->nreferences; i++) {
1481 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1482 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1483 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1488 if (destroy_ht)
1489 g_hash_table_destroy (ht);
1492 #ifdef ENABLE_NETCORE
1493 static void
1494 add_assembly_to_alc (MonoAssemblyLoadContext *alc, MonoAssembly *ass)
1496 gint i;
1497 GSList *tmp;
1499 g_assert (ass != NULL);
1501 if (!ass->aname.name)
1502 return;
1504 mono_alc_assemblies_lock (alc);
1506 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
1507 if (tmp->data == ass) {
1508 mono_alc_assemblies_unlock (alc);
1509 return;
1513 mono_assembly_addref (ass);
1514 // Prepending here will break the test suite with frequent InvalidCastExceptions, so we have to append
1515 alc->loaded_assemblies = g_slist_append (alc->loaded_assemblies, ass);
1516 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to ALC (%p), ref_count=%d", ass->aname.name, ass, (gpointer)alc, ass->ref_count);
1518 if (ass->image->references) {
1519 for (i = 0; i < ass->image->nreferences; i++) {
1520 // TODO: remove all this after we're confident this assert isn't hit
1521 g_assertf (!ass->image->references [i], "Did not expect reference %d of %s to be resolved", i, ass->image->name);
1525 mono_alc_assemblies_unlock (alc);
1527 #endif
1529 static void
1530 mono_domain_fire_assembly_load (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer user_data, MonoError *error_out)
1532 HANDLE_FUNCTION_ENTER ();
1533 static MonoClassField *assembly_load_field;
1534 static MonoMethod *assembly_load_method;
1535 ERROR_DECL (error);
1536 MonoDomain *domain = mono_alc_domain (alc);
1537 MonoClass *klass;
1538 MonoObjectHandle appdomain;
1540 if (!MONO_BOOL (domain->domain))
1541 goto leave; // This can happen during startup
1543 if (mono_runtime_get_no_exec ())
1544 goto leave;
1546 #ifdef ASSEMBLY_LOAD_DEBUG
1547 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1548 #endif
1549 appdomain = MONO_HANDLE_NEW (MonoObject, &domain->domain->mbr.obj);
1550 klass = mono_handle_class (appdomain);
1552 mono_domain_assemblies_lock (domain);
1553 add_assemblies_to_domain (domain, assembly, NULL);
1554 mono_domain_assemblies_unlock (domain);
1555 #ifdef ENABLE_NETCORE
1556 add_assembly_to_alc (alc, assembly);
1557 #endif
1559 if (assembly_load_field == NULL) {
1560 assembly_load_field = mono_class_get_field_from_name_full (klass, "AssemblyLoad", NULL);
1561 g_assert (assembly_load_field);
1564 if (!MONO_HANDLE_GET_FIELD_BOOL (appdomain, MonoObject*, assembly_load_field))
1565 goto leave; // No events waiting to be triggered
1567 MonoReflectionAssemblyHandle reflection_assembly;
1568 reflection_assembly = mono_assembly_get_object_handle (domain, assembly, error);
1569 mono_error_assert_ok (error);
1571 if (assembly_load_method == NULL) {
1572 assembly_load_method = mono_class_get_method_from_name_checked (klass, "DoAssemblyLoad", -1, 0, error);
1573 g_assert (assembly_load_method);
1576 void *params [1];
1577 params [0] = MONO_HANDLE_RAW (reflection_assembly);
1578 mono_runtime_invoke_handle_void (assembly_load_method, appdomain, params, error);
1579 leave:
1580 mono_error_cleanup (error);
1581 HANDLE_FUNCTION_RETURN ();
1584 static gboolean
1585 mono_domain_asmctx_from_path (const char *fname, MonoAssembly *requesting_assembly, gpointer user_data, MonoAssemblyContextKind *out_asmctx)
1587 MonoDomain *domain = mono_domain_get ();
1588 char **search_path = NULL;
1590 for (search_path = domain->search_path; search_path && *search_path; search_path++) {
1591 if (mono_path_filename_in_basedir (fname, *search_path)) {
1592 *out_asmctx = MONO_ASMCTX_DEFAULT;
1593 return TRUE;
1596 return FALSE;
1600 * LOCKING: Acquires the domain assemblies lock.
1602 static void
1603 set_domain_search_path (MonoDomain *domain)
1605 HANDLE_FUNCTION_ENTER ();
1606 ERROR_DECL (error);
1607 MonoAppDomainSetupHandle setup;
1608 gchar **tmp;
1609 gchar *search_path = NULL;
1610 gint npaths = 1;
1611 gchar **pvt_split = NULL;
1612 GError *gerror = NULL;
1613 gint appbaselen = -1;
1616 * We use the low-level domain assemblies lock, since this is called from
1617 * assembly loads hooks, which means this thread might hold the loader lock.
1619 mono_domain_assemblies_lock (domain);
1621 if (!MONO_BOOL (domain->setup))
1622 goto exit;
1624 setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
1626 if (domain->search_path && !MONO_HANDLE_GET_BOOL (setup, path_changed))
1627 goto exit;
1629 if (!MONO_HANDLE_GET_BOOL (setup, application_base))
1630 goto exit; // Must set application base to get private path working
1632 if (MONO_HANDLE_GET_BOOL (setup, private_bin_path)) {
1633 search_path = mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString, setup, private_bin_path), error);
1634 if (!is_ok (error)) { /*FIXME maybe we should bubble up the error.*/
1635 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1636 goto exit;
1640 if (domain->private_bin_path) {
1641 if (search_path == NULL)
1642 search_path = domain->private_bin_path;
1643 else {
1644 gchar *tmp2 = search_path;
1645 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1646 g_free (tmp2);
1650 if (search_path) {
1652 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1653 * directories relative to ApplicationBase separated by semicolons (see
1654 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1655 * The loop below copes with the fact that some Unix applications may use ':' (or
1656 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1657 * ';' for the subsequent split.
1659 * The issue was reported in bug #81446
1661 #ifndef TARGET_WIN32
1662 g_strdelimit (search_path, ':', ';');
1663 #endif
1664 pvt_split = g_strsplit (search_path, ";", 1000);
1665 g_free (search_path);
1666 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1669 g_strfreev (domain->search_path);
1670 domain->search_path = NULL;
1672 tmp = g_new (gchar*, npaths + 1);
1673 tmp [npaths] = NULL;
1675 *tmp = mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString, setup, application_base), error);
1676 if (!is_ok (error)) {
1677 g_free (tmp);
1678 goto exit;
1681 domain->search_path = tmp;
1683 /* FIXME: is this needed? */
1684 if (strncmp (*tmp, "file://", 7) == 0) {
1685 gchar *file = *tmp;
1686 gchar *uri = *tmp;
1687 gchar *tmpuri;
1689 if (uri [7] != '/')
1690 uri = g_strdup_printf ("file:///%s", uri + 7);
1692 tmpuri = uri;
1693 uri = mono_escape_uri_string (tmpuri);
1694 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1695 g_free (uri);
1697 if (tmpuri != file)
1698 g_free (tmpuri);
1700 if (gerror != NULL) {
1701 g_warning ("%s\n", gerror->message);
1702 g_error_free (gerror);
1703 *tmp = file;
1704 } else {
1705 g_free (file);
1709 for (gsize i = 1; pvt_split && i < npaths; i++) {
1710 if (g_path_is_absolute (pvt_split [i - 1])) {
1711 tmp [i] = g_strdup (pvt_split [i - 1]);
1712 } else {
1713 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1716 if (strchr (tmp [i], '.')) {
1717 gchar *reduced;
1718 gchar *freeme;
1720 reduced = mono_path_canonicalize (tmp [i]);
1721 if (appbaselen == -1)
1722 appbaselen = strlen (tmp [0]);
1724 if (strncmp (tmp [0], reduced, appbaselen)) {
1725 g_free (reduced);
1726 g_free (tmp [i]);
1727 tmp [i] = g_strdup ("");
1728 continue;
1731 freeme = tmp [i];
1732 tmp [i] = reduced;
1733 g_free (freeme);
1737 if (MONO_HANDLE_GET_BOOL (setup, private_bin_path_probe)) {
1738 g_free (tmp [0]);
1739 tmp [0] = g_strdup ("");
1742 MONO_HANDLE_SETVAL (setup, path_changed, MonoBoolean, FALSE);
1743 exit:
1744 mono_error_cleanup (error);
1745 g_strfreev (pvt_split);
1746 mono_domain_assemblies_unlock (domain);
1747 HANDLE_FUNCTION_RETURN ();
1750 #ifdef DISABLE_SHADOW_COPY
1751 gboolean
1752 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1754 return FALSE;
1757 char *
1758 mono_make_shadow_copy (const char *filename, MonoError *error)
1760 error_init (error);
1761 return (char *) filename;
1763 #else
1765 typedef enum {
1766 SHADOW_COPY_SIBLING_EXT_APPEND,
1767 SHADOW_COPY_SIBLING_EXT_REPLACE,
1768 } ShadowCopySiblingExt;
1770 static
1771 gchar *
1772 make_sibling_path (const gchar *path, gint pathlen, const char *extension, ShadowCopySiblingExt extopt)
1774 gchar *result = NULL;
1775 switch (extopt) {
1776 case SHADOW_COPY_SIBLING_EXT_APPEND: {
1777 result = g_strconcat (path, extension, NULL);
1778 break;
1780 case SHADOW_COPY_SIBLING_EXT_REPLACE: {
1781 /* expect path to be a .dll or .exe (or some case insensitive variant) */
1782 g_assert (pathlen >= 4 && path[pathlen - 4] == '.');
1783 GString *s = g_string_sized_new (pathlen - 4 + strlen (extension));
1784 g_string_append_len (s, path, pathlen - 4);
1785 g_string_append (s, extension);
1786 result = g_string_free (s, FALSE);
1787 break;
1789 default:
1790 g_assert_not_reached ();
1792 return result;
1795 static gboolean
1796 shadow_copy_sibling (const gchar *src_pristine, gint srclen, const char *extension, ShadowCopySiblingExt extopt, const gchar *target_pristine, gint targetlen)
1798 gchar *file = NULL;
1799 gunichar2 *orig = NULL;
1800 gunichar2 *dest = NULL;
1801 gboolean copy_result = TRUE;
1802 gchar *target = NULL;
1804 char *src = make_sibling_path (src_pristine, srclen, extension, extopt);
1806 if (IS_PORTABILITY_CASE) {
1807 file = mono_portability_find_file (src, TRUE);
1808 if (file == NULL)
1809 goto exit;
1810 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR))
1811 goto exit;
1813 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1815 target = make_sibling_path (target_pristine, targetlen, extension, extopt);
1817 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1819 mono_w32file_delete (dest);
1821 gint32 copy_error;
1822 copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1824 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1825 * overwritten when updated in their original locations. */
1826 if (copy_result)
1827 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1829 exit:
1830 g_free (file);
1831 g_free (orig);
1832 g_free (dest);
1833 g_free (src);
1834 g_free (target);
1835 return copy_result;
1838 static gint32
1839 get_cstring_hash (const char *str)
1841 const char *p;
1842 gint32 h = 0;
1844 if (!str || !str [0])
1845 return 0;
1847 gsize const len = strlen (str);
1848 p = str;
1849 for (gsize i = 0; i < len; i++) {
1850 h = (h << 5) - h + *p;
1851 p++;
1854 return h;
1858 * Returned memory is malloc'd. Called must free it
1860 static char *
1861 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1863 MonoAppDomainSetup *setup;
1864 char *cache_path = NULL;
1865 char *appname = NULL;
1866 char *userdir = NULL;
1867 char *location;
1869 error_init (error);
1871 setup = domain->setup;
1872 if (setup->cache_path != NULL && setup->application_name != NULL) {
1873 cache_path = mono_string_to_utf8_checked_internal (setup->cache_path, error);
1874 return_val_if_nok (error, NULL);
1876 #ifndef TARGET_WIN32
1878 gint i;
1879 for (i = strlen (cache_path) - 1; i >= 0; i--)
1880 if (cache_path [i] == '\\')
1881 cache_path [i] = '/';
1883 #endif
1885 appname = mono_string_to_utf8_checked_internal (setup->application_name, error);
1886 if (!is_ok (error)) {
1887 g_free (cache_path);
1888 return NULL;
1891 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1892 } else {
1893 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1894 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1896 g_free (appname);
1897 g_free (cache_path);
1898 g_free (userdir);
1899 return location;
1902 static char *
1903 get_shadow_assembly_location (const char *filename, MonoError *error)
1905 gint32 hash = 0, hash2 = 0;
1906 char name_hash [9];
1907 char path_hash [30];
1908 char *bname = g_path_get_basename (filename);
1909 char *dirname = g_path_get_dirname (filename);
1910 char *location, *tmploc;
1911 MonoDomain *domain = mono_domain_get ();
1913 error_init (error);
1915 hash = get_cstring_hash (bname);
1916 hash2 = get_cstring_hash (dirname);
1917 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1918 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1919 tmploc = get_shadow_assembly_location_base (domain, error);
1920 if (!is_ok (error)) {
1921 g_free (bname);
1922 g_free (dirname);
1923 return NULL;
1926 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1927 g_free (tmploc);
1928 g_free (bname);
1929 g_free (dirname);
1930 return location;
1933 static gboolean
1934 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1936 struct stat sbuf_dest;
1937 gchar *stat_src;
1938 gchar *real_src = mono_portability_find_file (src, TRUE);
1940 if (!real_src)
1941 stat_src = (gchar*)src;
1942 else
1943 stat_src = real_src;
1945 if (stat (stat_src, sbuf_src) == -1) {
1946 time_t tnow = time (NULL);
1948 if (real_src)
1949 g_free (real_src);
1951 memset (sbuf_src, 0, sizeof (*sbuf_src));
1952 sbuf_src->st_mtime = tnow;
1953 sbuf_src->st_atime = tnow;
1954 return TRUE;
1957 if (real_src)
1958 g_free (real_src);
1960 if (stat (dest, &sbuf_dest) == -1)
1961 return TRUE;
1963 if (sbuf_src->st_size == sbuf_dest.st_size &&
1964 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1965 return FALSE;
1967 return TRUE;
1970 static gboolean
1971 shadow_copy_create_ini (const char *shadow, const char *filename)
1973 gunichar2 *u16_ini = NULL;
1974 gboolean result = FALSE;
1975 guint32 n;
1976 HANDLE handle = INVALID_HANDLE_VALUE;
1977 gchar *full_path = NULL;
1979 char *dir_name = g_path_get_dirname (shadow);
1980 char *ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1981 g_free (dir_name);
1982 result = g_file_test (ini_file, G_FILE_TEST_IS_REGULAR);
1983 if (result)
1984 goto exit;
1986 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1987 if (!u16_ini)
1988 goto exit;
1990 handle = mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1991 if (handle == INVALID_HANDLE_VALUE)
1992 goto exit;
1994 full_path = mono_path_resolve_symlinks (filename);
1995 gint32 win32error;
1996 win32error = 0;
1997 result = mono_w32file_write (handle, full_path, strlen (full_path), &n, &win32error);
1998 exit:
1999 if (handle != INVALID_HANDLE_VALUE)
2000 mono_w32file_close (handle);
2001 g_free (u16_ini);
2002 g_free (full_path);
2003 g_free (ini_file);
2004 return result;
2007 gboolean
2008 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
2010 ERROR_DECL (error);
2011 MonoAppDomainSetup *setup;
2012 gchar *all_dirs = NULL;
2013 gchar **dir_ptr;
2014 gchar **directories = NULL;
2015 gchar *shadow_status_string;
2016 gchar *base_dir = NULL;
2017 gboolean shadow_enabled;
2018 gboolean found = FALSE;
2020 if (domain == NULL)
2021 goto exit;
2023 setup = domain->setup;
2024 if (setup == NULL || setup->shadow_copy_files == NULL)
2025 goto exit;
2027 shadow_status_string = mono_string_to_utf8_checked_internal (setup->shadow_copy_files, error);
2028 if (!is_ok (error))
2029 goto exit;
2031 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
2032 g_free (shadow_status_string);
2034 if (!shadow_enabled)
2035 goto exit;
2037 found = (setup->shadow_copy_directories == NULL);
2038 if (found)
2039 goto exit;
2041 /* Is dir_name a shadow_copy destination already? */
2042 base_dir = get_shadow_assembly_location_base (domain, error);
2043 if (!is_ok (error))
2044 goto exit;
2046 found = !!strstr (dir_name, base_dir);
2047 if (found)
2048 goto exit;
2050 all_dirs = mono_string_to_utf8_checked_internal (setup->shadow_copy_directories, error);
2051 if (!is_ok (error))
2052 goto exit;
2054 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
2055 dir_ptr = directories;
2056 while (!found && *dir_ptr) {
2057 found = (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name));
2058 dir_ptr++;
2060 exit:
2061 mono_error_cleanup (error);
2062 g_free (base_dir);
2063 g_strfreev (directories);
2064 g_free (all_dirs);
2065 return found;
2069 This function raises exceptions so it can cause as sorts of nasty stuff if called
2070 while holding a lock.
2071 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
2072 or NULL if source file not found.
2073 FIXME bubble up the error instead of raising it here
2075 char *
2076 mono_make_shadow_copy (const char *filename, MonoError *oerror)
2078 ERROR_DECL (error);
2079 gint filename_len, shadow_len;
2080 gunichar2 *orig, *dest;
2081 guint32 attrs;
2082 char *shadow;
2083 gboolean copy_result;
2084 struct stat src_sbuf;
2085 struct utimbuf utbuf;
2086 char *dir_name = g_path_get_dirname (filename);
2087 MonoDomain *domain = mono_domain_get ();
2088 char *shadow_dir;
2089 gint32 copy_error;
2091 error_init (oerror);
2093 set_domain_search_path (domain);
2095 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
2096 g_free (dir_name);
2097 return (char *) filename;
2100 /* Is dir_name a shadow_copy destination already? */
2101 shadow_dir = get_shadow_assembly_location_base (domain, error);
2102 if (!is_ok (error)) {
2103 mono_error_cleanup (error);
2104 g_free (dir_name);
2105 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
2106 return NULL;
2109 if (strstr (dir_name, shadow_dir)) {
2110 g_free (shadow_dir);
2111 g_free (dir_name);
2112 return (char *) filename;
2114 g_free (shadow_dir);
2115 g_free (dir_name);
2117 shadow = get_shadow_assembly_location (filename, error);
2118 if (!is_ok (error)) {
2119 mono_error_cleanup (error);
2120 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
2121 return NULL;
2124 if (g_ensure_directory_exists (shadow) == FALSE) {
2125 g_free (shadow);
2126 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
2127 return NULL;
2130 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
2131 return (char*) shadow;
2133 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
2134 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
2135 mono_w32file_delete (dest);
2137 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
2138 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
2139 * and not have it runtime error" */
2140 attrs = mono_w32file_get_attributes (orig);
2141 if (attrs == INVALID_FILE_ATTRIBUTES) {
2142 g_free (shadow);
2143 return (char *)filename;
2146 copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
2148 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
2149 * overwritten when updated in their original locations. */
2150 if (copy_result)
2151 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
2153 g_free (dest);
2154 g_free (orig);
2156 if (copy_result == FALSE) {
2157 g_free (shadow);
2159 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
2160 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
2161 return NULL; /* file not found, shadow copy failed */
2163 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
2164 return NULL;
2167 /* attempt to copy .mdb, .pdb and .config if they exist */
2168 filename_len = strlen (filename);
2169 shadow_len = strlen (shadow);
2171 copy_result = shadow_copy_sibling (filename, filename_len, ".mdb", SHADOW_COPY_SIBLING_EXT_APPEND, shadow, shadow_len);
2172 if (copy_result)
2173 copy_result = shadow_copy_sibling (filename, filename_len, ".pdb", SHADOW_COPY_SIBLING_EXT_REPLACE, shadow, shadow_len);
2174 if (copy_result)
2175 copy_result = shadow_copy_sibling (filename, filename_len, ".config", SHADOW_COPY_SIBLING_EXT_APPEND, shadow, shadow_len);
2177 if (!copy_result) {
2178 g_free (shadow);
2179 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
2180 return NULL;
2183 /* Create a .ini file containing the original assembly location */
2184 if (!shadow_copy_create_ini (shadow, filename)) {
2185 g_free (shadow);
2186 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
2187 return NULL;
2190 utbuf.actime = src_sbuf.st_atime;
2191 utbuf.modtime = src_sbuf.st_mtime;
2192 utime (shadow, &utbuf);
2194 return shadow;
2196 #endif /* DISABLE_SHADOW_COPY */
2199 * mono_domain_from_appdomain:
2201 MonoDomain *
2202 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
2204 HANDLE_FUNCTION_ENTER ();
2205 MonoDomain *result;
2206 MONO_ENTER_GC_UNSAFE;
2207 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
2208 result = mono_domain_from_appdomain_handle (appdomain);
2209 MONO_EXIT_GC_UNSAFE;
2210 HANDLE_FUNCTION_RETURN_VAL (result);
2213 MonoDomain *
2214 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
2216 HANDLE_FUNCTION_ENTER ();
2217 MonoDomain *dom = NULL;
2218 if (MONO_HANDLE_IS_NULL (appdomain))
2219 goto leave;
2221 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
2222 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
2223 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
2225 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
2226 } else
2227 dom = MONO_HANDLE_GETVAL (appdomain, data);
2229 leave:
2230 HANDLE_FUNCTION_RETURN_VAL (dom);
2234 static gboolean
2235 try_load_from (MonoAssembly **assembly,
2236 const gchar *path1, const gchar *path2,
2237 const gchar *path3, const gchar *path4,
2238 const MonoAssemblyOpenRequest *req)
2240 gchar *fullpath;
2241 gboolean found = FALSE;
2243 *assembly = NULL;
2244 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
2246 if (IS_PORTABILITY_SET) {
2247 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
2248 if (new_fullpath) {
2249 g_free (fullpath);
2250 fullpath = new_fullpath;
2251 found = TRUE;
2253 } else
2254 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
2256 if (found) {
2257 *assembly = mono_assembly_request_open (fullpath, req, NULL);
2260 g_free (fullpath);
2261 return (*assembly != NULL);
2264 static MonoAssembly *
2265 real_load (gchar **search_path, const gchar *culture, const gchar *name, const MonoAssemblyOpenRequest *req)
2267 MonoAssembly *result = NULL;
2268 gchar **path;
2269 gchar *filename;
2270 const gchar *local_culture;
2271 gint len;
2273 if (!culture || *culture == '\0') {
2274 local_culture = "";
2275 } else {
2276 local_culture = culture;
2279 filename = g_strconcat (name, ".dll", NULL);
2280 len = strlen (filename);
2282 for (path = search_path; *path; path++) {
2283 if (**path == '\0') {
2284 continue; /* Ignore empty ApplicationBase */
2287 /* See test cases in bug #58992 and bug #57710 */
2288 /* 1st try: [culture]/[name].dll (culture may be empty) */
2289 strcpy (filename + len - 4, ".dll");
2290 if (try_load_from (&result, *path, local_culture, "", filename, req))
2291 break;
2293 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2294 strcpy (filename + len - 4, ".exe");
2295 if (try_load_from (&result, *path, local_culture, "", filename, req))
2296 break;
2298 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2299 strcpy (filename + len - 4, ".dll");
2300 if (try_load_from (&result, *path, local_culture, name, filename, req))
2301 break;
2303 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2304 strcpy (filename + len - 4, ".exe");
2305 if (try_load_from (&result, *path, local_culture, name, filename, req))
2306 break;
2309 g_free (filename);
2310 return result;
2314 * Try loading the assembly from ApplicationBase and PrivateBinPath
2315 * and then from assemblies_path if any.
2316 * LOCKING: This is called from the assembly loading code, which means the caller
2317 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2319 static MonoAssembly *
2320 mono_domain_assembly_preload (MonoAssemblyLoadContext *alc,
2321 MonoAssemblyName *aname,
2322 gchar **assemblies_path,
2323 gboolean refonly,
2324 gpointer user_data,
2325 MonoError *error)
2327 MonoDomain *domain = mono_alc_domain (alc);
2328 MonoAssembly *result = NULL;
2329 #ifdef ENABLE_NETCORE
2330 g_assert (alc);
2331 g_assert (domain == mono_domain_get ());
2332 #endif
2334 set_domain_search_path (domain);
2336 MonoAssemblyCandidatePredicate predicate = NULL;
2337 void* predicate_ud = NULL;
2338 #if !defined(DISABLE_DESKTOP_LOADER)
2339 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2340 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2341 predicate_ud = aname;
2343 #endif
2344 MonoAssemblyOpenRequest req;
2345 mono_assembly_request_prepare_open (&req, refonly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_DEFAULT, alc);
2346 req.request.predicate = predicate;
2347 req.request.predicate_ud = predicate_ud;
2349 if (domain->search_path && domain->search_path [0] != NULL) {
2350 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2351 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2352 for (int i = 0; domain->search_path [i]; i++) {
2353 const char *p = domain->search_path[i];
2354 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2356 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2358 result = real_load (domain->search_path, aname->culture, aname->name, &req);
2361 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2362 result = real_load (assemblies_path, aname->culture, aname->name, &req);
2365 return result;
2369 * mono_assembly_load_from_assemblies_path:
2371 * \param assemblies_path directories to search for given assembly name, terminated by NULL
2372 * \param aname assembly name to look for
2373 * \param asmctx assembly load context for this load operation
2375 * Given a NULL-terminated array of paths, look for \c name.ext, \c name, \c
2376 * culture/name.ext, \c culture/name/name.ext where \c ext is \c dll and \c
2377 * exe and try to load it in the given assembly load context.
2379 * \returns A \c MonoAssembly if probing was successful, or NULL otherwise.
2381 MonoAssembly*
2382 mono_assembly_load_from_assemblies_path (gchar **assemblies_path, MonoAssemblyName *aname, MonoAssemblyContextKind asmctx)
2384 MonoAssemblyCandidatePredicate predicate = NULL;
2385 void* predicate_ud = NULL;
2386 #if !defined(DISABLE_DESKTOP_LOADER)
2387 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2388 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2389 predicate_ud = aname;
2391 #endif
2392 MonoAssemblyOpenRequest req;
2393 mono_assembly_request_prepare_open (&req, asmctx, mono_domain_default_alc (mono_domain_get ()));
2394 req.request.predicate = predicate;
2395 req.request.predicate_ud = predicate_ud;
2396 MonoAssembly *result = NULL;
2397 if (assemblies_path && assemblies_path[0] != NULL) {
2398 result = real_load (assemblies_path, aname->culture, aname->name, &req);
2400 return result;
2404 * Check whenever a given assembly was already loaded in the current appdomain.
2406 static MonoAssembly *
2407 mono_domain_assembly_search (MonoAssemblyLoadContext *alc, MonoAssembly *requesting,
2408 MonoAssemblyName *aname,
2409 gboolean refonly,
2410 gboolean postload,
2411 gpointer user_data,
2412 MonoError *error)
2414 g_assert (aname != NULL);
2415 GSList *tmp;
2416 MonoAssembly *ass;
2417 const gboolean strong_name = aname->public_key_token[0] != 0;
2418 /* If it's not a strong name, any version that has the right simple
2419 * name is good enough to satisfy the request. .NET Framework also
2420 * ignores case differences in this case. */
2421 const MonoAssemblyNameEqFlags eq_flags = (MonoAssemblyNameEqFlags)(strong_name ? MONO_ANAME_EQ_IGNORE_CASE :
2422 (MONO_ANAME_EQ_IGNORE_PUBKEY | MONO_ANAME_EQ_IGNORE_VERSION | MONO_ANAME_EQ_IGNORE_CASE));
2424 #ifdef ENABLE_NETCORE
2425 mono_alc_assemblies_lock (alc);
2426 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
2427 ass = (MonoAssembly *)tmp->data;
2428 g_assert (ass != NULL);
2429 // TODO: Can dynamic assemblies match here for netcore? Also, this ignores case while exact_sn_match does not.
2430 if (assembly_is_dynamic (ass) || !mono_assembly_names_equal_flags (aname, &ass->aname, eq_flags))
2431 continue;
2433 mono_alc_assemblies_unlock (alc);
2434 return ass;
2436 mono_alc_assemblies_unlock (alc);
2437 #else
2438 MonoDomain *domain = mono_alc_domain (alc);
2439 mono_domain_assemblies_lock (domain);
2440 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2441 ass = (MonoAssembly *)tmp->data;
2442 g_assert (ass != NULL);
2443 /* Dynamic assemblies can't match here in MS.NET */
2444 gboolean ass_ref_only = mono_asmctx_get_kind (&ass->context) == MONO_ASMCTX_REFONLY;
2445 if (assembly_is_dynamic (ass) || refonly != ass_ref_only || !mono_assembly_names_equal_flags (aname, &ass->aname, eq_flags))
2446 continue;
2448 mono_domain_assemblies_unlock (domain);
2449 return ass;
2451 mono_domain_assemblies_unlock (domain);
2452 #endif
2454 return NULL;
2457 #if ENABLE_NETCORE
2458 MonoReflectionAssemblyHandle
2459 ves_icall_System_Reflection_Assembly_InternalLoad (MonoStringHandle name_handle, MonoStackCrawlMark *stack_mark, gpointer load_Context, MonoError *error)
2461 error_init (error);
2462 MonoAssembly *ass = NULL;
2463 MonoAssemblyName aname;
2464 MonoAssemblyByNameRequest req;
2465 MonoAssemblyContextKind asmctx;
2466 MonoImageOpenStatus status = MONO_IMAGE_OK;
2467 gboolean parsed;
2468 char *name;
2470 MonoAssembly *requesting_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2471 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)load_Context;
2473 if (!alc)
2474 alc = mono_assembly_get_alc (requesting_assembly);
2475 if (!alc)
2476 g_assert_not_reached ();
2478 MonoDomain *domain = mono_alc_domain (alc);
2479 g_assert (alc);
2480 asmctx = MONO_ASMCTX_DEFAULT;
2481 mono_assembly_request_prepare_byname (&req, asmctx, alc);
2482 req.basedir = NULL;
2483 /* Everything currently goes through this function, and the postload hook (aka the AppDomain.AssemblyResolve event)
2484 * is triggered under some scenarios. It's not completely obvious to me in what situations (if any) this should be disabled,
2485 * other than for corlib satellite assemblies (which I've dealt with further down the call stack).
2487 //req.no_postload_search = TRUE;
2488 req.requesting_assembly = requesting_assembly;
2490 name = mono_string_handle_to_utf8 (name_handle, error);
2491 goto_if_nok (error, fail);
2492 parsed = mono_assembly_name_parse (name, &aname);
2493 g_free (name);
2494 if (!parsed)
2495 goto fail;
2497 ass = mono_assembly_request_byname (&aname, &req, &status);
2498 if (!ass)
2499 goto fail;
2501 MonoReflectionAssemblyHandle refass;
2502 refass = mono_assembly_get_object_handle (domain, ass, error);
2503 goto_if_nok (error, fail);
2504 return refass;
2506 fail:
2507 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2509 #endif
2511 #ifndef ENABLE_NETCORE
2512 MonoReflectionAssemblyHandle
2513 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoStackCrawlMark *stack_mark, MonoError *error)
2515 error_init (error);
2516 MonoDomain *domain = mono_domain_get ();
2517 char *name, *filename;
2518 MonoImageOpenStatus status = MONO_IMAGE_OK;
2519 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2521 name = NULL;
2523 if (MONO_HANDLE_IS_NULL (fname)) {
2524 mono_error_set_argument_null (error, "assemblyFile", "");
2525 goto leave;
2528 name = filename = mono_string_handle_to_utf8 (fname, error);
2529 goto_if_nok (error, leave);
2531 MonoAssembly *requesting_assembly;
2532 requesting_assembly = NULL;
2533 if (!refOnly)
2534 requesting_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2536 MonoAssembly *ass;
2537 MonoAssemblyOpenRequest req;
2538 mono_assembly_request_prepare_open (&req, refOnly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_LOADFROM, mono_domain_default_alc (domain));
2539 req.requesting_assembly = requesting_assembly;
2540 ass = mono_assembly_request_open (filename, &req, &status);
2542 if (!ass) {
2543 if (status == MONO_IMAGE_IMAGE_INVALID)
2544 mono_error_set_bad_image_by_name (error, name, "Invalid Image");
2545 else
2546 mono_error_set_file_not_found (error, name, "Invalid Image");
2547 goto leave;
2550 result = mono_assembly_get_object_handle (domain, ass, error);
2552 leave:
2553 g_free (name);
2554 return result;
2556 #endif
2558 static
2559 MonoAssembly *
2560 mono_alc_load_file (MonoAssemblyLoadContext *alc, MonoStringHandle fname, MonoAssembly *executing_assembly, MonoAssemblyContextKind asmctx, MonoError *error)
2562 MonoAssembly *ass = NULL;
2563 HANDLE_FUNCTION_ENTER ();
2564 char *filename = NULL;
2565 if (MONO_HANDLE_IS_NULL (fname)) {
2566 mono_error_set_argument_null (error, "assemblyFile", "");
2567 goto leave;
2570 filename = mono_string_handle_to_utf8 (fname, error);
2571 goto_if_nok (error, leave);
2573 if (!g_path_is_absolute (filename)) {
2574 mono_error_set_argument (error, "assemblyFile", "Absolute path information is required.");
2575 goto leave;
2578 MonoImageOpenStatus status;
2579 MonoAssemblyOpenRequest req;
2580 mono_assembly_request_prepare_open (&req, asmctx, alc);
2581 req.requesting_assembly = executing_assembly;
2582 ass = mono_assembly_request_open (filename, &req, &status);
2583 if (!ass) {
2584 if (status == MONO_IMAGE_IMAGE_INVALID)
2585 mono_error_set_bad_image_by_name (error, filename, "Invalid Image");
2586 else
2587 mono_error_set_file_not_found (error, filename, "Invalid Image");
2590 leave:
2591 g_free (filename);
2592 HANDLE_FUNCTION_RETURN_VAL (ass);
2595 #ifndef ENABLE_NETCORE
2596 MonoReflectionAssemblyHandle
2597 ves_icall_System_Reflection_Assembly_LoadFile_internal (MonoStringHandle fname, MonoStackCrawlMark *stack_mark, MonoError *error)
2599 MonoDomain *domain = mono_domain_get ();
2600 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2601 MonoAssembly *executing_assembly;
2602 executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2603 MonoAssembly *ass = mono_alc_load_file (mono_domain_default_alc (domain), fname, executing_assembly, MONO_ASMCTX_INDIVIDUAL, error);
2604 goto_if_nok (error, leave);
2606 result = mono_assembly_get_object_handle (domain, ass, error);
2607 leave:
2608 return result;
2610 #else
2611 MonoReflectionAssemblyHandle
2612 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalLoadFile (gpointer alc_ptr, MonoStringHandle fname, MonoStackCrawlMark *stack_mark, MonoError *error)
2614 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2615 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)alc_ptr;
2616 MonoDomain *domain = mono_alc_domain (alc);
2618 MonoAssembly *executing_assembly;
2619 executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2620 MonoAssembly *ass = mono_alc_load_file (alc, fname, executing_assembly, mono_alc_is_default (alc) ? MONO_ASMCTX_LOADFROM : MONO_ASMCTX_INDIVIDUAL, error);
2621 goto_if_nok (error, leave);
2623 result = mono_assembly_get_object_handle (domain, ass, error);
2625 leave:
2626 return result;
2628 #endif
2630 static MonoAssembly*
2631 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);
2633 #ifdef ENABLE_NETCORE
2634 MonoReflectionAssemblyHandle
2635 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)
2637 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)native_alc;
2638 MonoDomain *domain = mono_alc_domain (alc);
2639 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2640 MonoAssembly *assm = NULL;
2641 assm = mono_alc_load_raw_bytes (alc, (guint8 *)raw_assembly_ptr, raw_assembly_len, (guint8 *)raw_symbols_ptr, raw_symbols_len, FALSE, error);
2642 goto_if_nok (error, leave);
2644 result = mono_assembly_get_object_handle (domain, assm, error);
2646 leave:
2647 return result;
2649 #else
2650 MonoReflectionAssemblyHandle
2651 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2652 MonoArrayHandle raw_assembly,
2653 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2654 MonoBoolean refonly,
2655 MonoError *error)
2657 MonoAssembly *ass;
2658 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2659 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2660 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2662 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2663 guint8 *assembly_data = (guint8*) g_try_malloc (raw_assembly_len);
2664 if (!assembly_data) {
2665 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2666 return refass;
2668 uint32_t gchandle;
2669 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2670 memcpy (assembly_data, raw_data, raw_assembly_len);
2671 mono_gchandle_free_internal (gchandle); /* unpin */
2672 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2674 MonoAssemblyLoadContext *alc = mono_domain_default_alc (domain);
2676 mono_byte *raw_symbol_data = NULL;
2677 guint32 symbol_len = 0;
2678 uint32_t symbol_gchandle = 0;
2679 if (!MONO_HANDLE_IS_NULL (raw_symbol_store)) {
2680 symbol_len = mono_array_handle_length (raw_symbol_store);
2681 raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2684 ass = mono_alc_load_raw_bytes (alc, assembly_data, raw_assembly_len, raw_symbol_data, symbol_len, refonly, error);
2685 mono_gchandle_free_internal (symbol_gchandle);
2686 goto_if_nok (error, leave);
2688 refass = mono_assembly_get_object_handle (domain, ass, error);
2689 if (!MONO_HANDLE_IS_NULL (refass))
2690 MONO_HANDLE_SET (refass, evidence, evidence);
2692 leave:
2693 return refass;
2695 #endif /* ENABLE_NETCORE */
2697 static MonoAssembly*
2698 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)
2700 MonoAssembly *ass = NULL;
2701 MonoImageOpenStatus status;
2702 MonoImage *image = mono_image_open_from_data_internal (alc, (char*)assembly_data, raw_assembly_len, FALSE, NULL, refonly, FALSE, NULL);
2704 if (!image) {
2705 mono_error_set_bad_image_by_name (error, "In memory assembly", "0x%p", assembly_data);
2706 return ass;
2709 if (raw_symbol_data)
2710 mono_debug_open_image_from_memory (image, raw_symbol_data, raw_symbol_len);
2712 MonoAssembly* redirected_asm = NULL;
2713 MonoImageOpenStatus new_status = MONO_IMAGE_OK;
2714 if ((redirected_asm = mono_assembly_binding_applies_to_image (alc, image, &new_status))) {
2715 mono_image_close (image);
2716 image = redirected_asm->image;
2717 mono_image_addref (image); /* so that mono_image close, below, has something to do */
2718 } else if (new_status != MONO_IMAGE_OK) {
2719 mono_image_close (image);
2720 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);
2721 return ass;
2724 MonoAssemblyLoadRequest req;
2725 mono_assembly_request_prepare_load (&req, refonly? MONO_ASMCTX_REFONLY : MONO_ASMCTX_INDIVIDUAL, alc);
2726 ass = mono_assembly_request_load_from (image, "", &req, &status);
2728 if (!ass) {
2729 mono_image_close (image);
2730 mono_error_set_bad_image_by_name (error, "In Memory assembly", "0x%p", assembly_data);
2731 return ass;
2734 /* Clear the reference added by mono_image_open_from_data_internal above */
2735 mono_image_close (image);
2737 return ass;
2740 #ifndef ENABLE_NETCORE
2741 MonoReflectionAssemblyHandle
2742 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoStackCrawlMark *stack_mark, MonoError *error)
2744 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2745 MonoImageOpenStatus status = MONO_IMAGE_OK;
2746 MonoAssembly *ass;
2747 MonoAssemblyName aname;
2748 gchar *name = NULL;
2749 gboolean parsed;
2751 g_assert (!MONO_HANDLE_IS_NULL (assRef));
2753 name = mono_string_handle_to_utf8 (assRef, error);
2754 goto_if_nok (error, fail);
2755 parsed = mono_assembly_name_parse (name, &aname);
2756 g_free (name);
2758 if (!parsed) {
2759 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2760 /* This is a parse error... */
2761 if (!refOnly) {
2762 MonoAssembly *assm = mono_try_assembly_resolve_handle (mono_domain_default_alc (domain), assRef, NULL, refOnly, error);
2763 goto_if_nok (error, fail);
2764 if (assm) {
2765 refass = mono_assembly_get_object_handle (domain, assm, error);
2766 goto_if_nok (error, fail);
2769 return refass;
2772 MonoAssemblyContextKind asmctx;
2773 asmctx = refOnly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_DEFAULT;
2774 const char *basedir;
2775 basedir = NULL;
2776 if (!refOnly) {
2777 /* Determine if the current assembly is in LoadFrom context.
2778 * If it is, we must include the executing assembly's basedir
2779 * when probing for the given assembly name, and also load the
2780 * requested assembly in LoadFrom context.
2782 MonoAssembly *executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2783 if (executing_assembly && mono_asmctx_get_kind (&executing_assembly->context) == MONO_ASMCTX_LOADFROM) {
2784 asmctx = MONO_ASMCTX_LOADFROM;
2785 basedir = executing_assembly->basedir;
2790 MonoAssemblyByNameRequest req;
2791 mono_assembly_request_prepare_byname (&req, asmctx, mono_domain_default_alc (domain));
2792 req.basedir = basedir;
2793 req.no_postload_search = TRUE;
2794 ass = mono_assembly_request_byname (&aname, &req, &status);
2795 mono_assembly_name_free (&aname);
2797 if (!ass) {
2798 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2799 if (!refOnly) {
2800 ass = mono_try_assembly_resolve_handle (mono_domain_default_alc (domain), assRef, NULL, refOnly, error);
2801 goto_if_nok (error, fail);
2803 if (!ass)
2804 goto fail;
2807 g_assert (ass);
2808 MonoReflectionAssemblyHandle refass;
2809 refass = mono_assembly_get_object_handle (domain, ass, error);
2810 goto_if_nok (error, fail);
2812 MONO_HANDLE_SET (refass, evidence, evidence);
2814 return refass;
2815 fail:
2816 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2819 void
2820 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2822 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2824 if (NULL == domain) {
2825 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2826 return;
2829 if (domain == mono_get_root_domain ()) {
2830 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2831 return;
2835 * Unloading seems to cause problems when running NUnit/NAnt, hence
2836 * this workaround.
2838 if (g_hasenv ("MONO_NO_UNLOAD"))
2839 return;
2841 MonoException *exc = NULL;
2842 mono_domain_try_unload (domain, (MonoObject**)&exc);
2843 if (exc)
2844 mono_error_set_exception_instance (error, exc);
2847 MonoBoolean
2848 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2850 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2852 if (!domain)
2853 return TRUE;
2855 return mono_domain_is_unloading (domain);
2858 void
2859 ves_icall_System_AppDomain_DoUnhandledException (MonoAppDomainHandle ad, MonoExceptionHandle exc, MonoError *error)
2861 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2862 mono_error_assert_ok (error);
2865 gint32
2866 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2867 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2868 MonoError *error)
2870 MonoImage *image;
2871 MonoMethod *method;
2873 g_assert (!MONO_HANDLE_IS_NULL (refass));
2874 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2875 image = assembly->image;
2876 g_assert (image);
2878 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2880 if (!method)
2881 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2883 if (MONO_HANDLE_IS_NULL (args)) {
2884 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2885 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2886 mono_error_assert_ok (error);
2889 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2890 return res;
2893 MonoAppDomainHandle
2894 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2896 error_init (error);
2897 MonoDomain *old_domain = mono_domain_get ();
2899 if (!mono_domain_set_fast (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2900 mono_error_set_appdomain_unloaded (error);
2901 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2904 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2907 MonoAppDomainHandle
2908 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2910 MonoDomain *current_domain = mono_domain_get ();
2911 MonoDomain *domain = mono_domain_get_by_id (domainid);
2913 if (!domain || !mono_domain_set_fast (domain, FALSE)) {
2914 mono_error_set_appdomain_unloaded (error);
2915 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2918 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2921 void
2922 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2924 error_init (error);
2925 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2928 void
2929 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2931 error_init (error);
2932 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2934 if (!domain) {
2936 * Raise an exception to prevent the managed code from executing a pop
2937 * later.
2939 mono_error_set_appdomain_unloaded (error);
2940 return;
2943 mono_thread_push_appdomain_ref (domain);
2946 void
2947 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2949 error_init (error);
2950 mono_thread_pop_appdomain_ref ();
2953 MonoAppContextHandle
2954 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2956 error_init (error);
2957 return mono_context_get_handle ();
2960 MonoAppContextHandle
2961 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2963 error_init (error);
2964 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2967 MonoAppContextHandle
2968 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2970 error_init (error);
2971 MonoAppContextHandle old_context = mono_context_get_handle ();
2973 mono_context_set_handle (mc);
2975 return old_context;
2978 MonoStringHandle
2979 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2981 error_init (error);
2982 MonoDomain* mono_root_domain = mono_get_root_domain ();
2983 mono_domain_lock (mono_root_domain);
2984 if (process_guid_set) {
2985 mono_domain_unlock (mono_root_domain);
2986 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2988 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2989 memcpy (process_guid, mono_string_chars_internal (MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2990 mono_gchandle_free_internal (gchandle);
2991 process_guid_set = TRUE;
2992 mono_domain_unlock (mono_root_domain);
2993 return newguid;
2995 #endif
2998 * mono_domain_is_unloading:
3000 gboolean
3001 mono_domain_is_unloading (MonoDomain *domain)
3003 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
3004 return TRUE;
3005 else
3006 return FALSE;
3009 static void
3010 clear_cached_vtable (MonoVTable *vtable)
3012 MonoClass *klass = vtable->klass;
3013 MonoDomain *domain = vtable->domain;
3014 MonoClassRuntimeInfo *runtime_info;
3015 void *data;
3017 runtime_info = m_class_get_runtime_info (klass);
3018 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
3019 runtime_info->domain_vtables [domain->domain_id] = NULL;
3020 if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable)))
3021 mono_gc_free_fixed (data);
3024 static G_GNUC_UNUSED void
3025 zero_static_data (MonoVTable *vtable)
3027 MonoClass *klass = vtable->klass;
3028 void *data;
3030 if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable)))
3031 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
3034 typedef struct unload_data {
3035 gboolean done;
3036 MonoDomain *domain;
3037 char *failure_reason;
3038 gint32 refcount;
3039 } unload_data;
3041 static void
3042 unload_data_unref (unload_data *data)
3044 if (!data)
3045 return;
3046 gint32 count;
3047 do {
3048 mono_atomic_load_acquire (count, gint32, &data->refcount);
3049 g_assert (count >= 1 && count <= 2);
3050 if (count == 1) {
3051 g_free (data);
3052 return;
3054 } while (mono_atomic_cas_i32 (&data->refcount, count - 1, count) != count);
3057 static void
3058 deregister_reflection_info_roots_from_list (MonoImage *image)
3060 GSList *list = image->reflection_info_unregister_classes;
3062 while (list) {
3063 MonoClass *klass = (MonoClass *)list->data;
3065 mono_class_free_ref_info (klass);
3067 list = list->next;
3070 image->reflection_info_unregister_classes = NULL;
3073 static void
3074 deregister_reflection_info_roots (MonoDomain *domain)
3076 GSList *list;
3078 mono_domain_assemblies_lock (domain);
3079 for (list = domain->domain_assemblies; list; list = list->next) {
3080 MonoAssembly *assembly = (MonoAssembly *)list->data;
3081 MonoImage *image = assembly->image;
3082 int i;
3085 * No need to take the image lock here since dynamic images are appdomain bound and
3086 * at this point the mutator is gone. Taking the image lock here would mean
3087 * promoting it from a simple lock to a complex lock, which we better avoid if
3088 * possible.
3090 if (image_is_dynamic (image))
3091 deregister_reflection_info_roots_from_list (image);
3093 for (i = 0; i < image->module_count; ++i) {
3094 MonoImage *module = image->modules [i];
3095 if (module && image_is_dynamic (module))
3096 deregister_reflection_info_roots_from_list (module);
3099 mono_domain_assemblies_unlock (domain);
3102 static gsize WINAPI
3103 unload_thread_main (void *arg)
3105 unload_data *data = (unload_data*)arg;
3106 MonoDomain *domain = data->domain;
3107 int i;
3108 gsize result = 1; // failure
3110 mono_thread_set_name_constant_ignore_error (mono_thread_internal_current (), "Domain unloader", MonoSetThreadNameFlag_Permanent);
3113 * FIXME: Abort our parent thread last, so we can return a failure
3114 * indication if aborting times out.
3116 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
3117 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
3118 goto failure;
3121 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
3122 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
3123 goto failure;
3126 /* Finalize all finalizable objects in the doomed appdomain */
3127 if (!mono_domain_finalize (domain, -1)) {
3128 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
3129 goto failure;
3132 /* Clear references to our vtables in class->runtime_info.
3133 * We also hold the loader lock because we're going to change
3134 * class->runtime_info.
3137 mono_loader_lock ();
3138 mono_domain_lock (domain);
3140 * We need to make sure that we don't have any remsets
3141 * pointing into static data of the to-be-freed domain because
3142 * at the next collections they would be invalid. So what we
3143 * do is we first zero all static data and then do a minor
3144 * collection. Because all references in the static data will
3145 * now be null we won't do any unnecessary copies and after
3146 * the collection there won't be any more remsets.
3148 for (i = 0; i < domain->class_vtable_array->len; ++i)
3149 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
3150 mono_gc_collect (0);
3151 for (i = 0; i < domain->class_vtable_array->len; ++i)
3152 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
3153 deregister_reflection_info_roots (domain);
3155 mono_assembly_cleanup_domain_bindings (domain->domain_id);
3157 mono_domain_unlock (domain);
3158 mono_loader_unlock ();
3160 domain->state = MONO_APPDOMAIN_UNLOADED;
3162 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
3164 /* remove from the handle table the items related to this domain */
3165 mono_gchandle_free_domain (domain);
3167 mono_domain_free (domain, FALSE);
3169 mono_gc_collect (mono_gc_max_generation ());
3171 result = 0; // success
3172 exit:
3173 mono_atomic_store_release (&data->done, TRUE);
3174 unload_data_unref (data);
3175 return result;
3177 failure:
3178 result = 1;
3179 goto exit;
3183 * mono_domain_unload:
3184 * \param domain The domain to unload
3186 * Unloads an appdomain. Follows the process outlined in the comment
3187 * for \c mono_domain_try_unload.
3189 void
3190 mono_domain_unload (MonoDomain *domain)
3192 MONO_ENTER_GC_UNSAFE;
3193 MonoObject *exc = NULL;
3194 mono_domain_try_unload (domain, &exc);
3195 MONO_EXIT_GC_UNSAFE;
3198 static MonoThreadInfoWaitRet
3199 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
3201 MonoThreadInfoWaitRet result;
3203 MONO_ENTER_GC_SAFE;
3204 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
3205 MONO_EXIT_GC_SAFE;
3207 return result;
3211 * mono_domain_unload:
3212 * \param domain The domain to unload
3213 * \param exc Exception information
3215 * Unloads an appdomain. Follows the process outlined in:
3216 * http://blogs.gotdotnet.com/cbrumme
3218 * If doing things the 'right' way is too hard or complex, we do it the
3219 * 'simple' way, which means do everything needed to avoid crashes and
3220 * memory leaks, but not much else.
3222 * It is required to pass a valid reference to the exc argument, upon return
3223 * from this function *exc will be set to the exception thrown, if any.
3225 * If this method is not called from an icall (embedded scenario for instance),
3226 * it must not be called with any managed frames on the stack, since the unload
3227 * process could end up trying to abort the current thread.
3229 void
3230 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
3232 HANDLE_FUNCTION_ENTER ();
3233 ERROR_DECL (error);
3234 MonoThreadHandle *thread_handle = NULL;
3235 MonoAppDomainState prev_state;
3236 MonoMethod *method;
3237 unload_data *thread_data = NULL;
3238 MonoInternalThreadHandle internal;
3239 MonoDomain *caller_domain = mono_domain_get ();
3241 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
3243 /* Atomically change our state to UNLOADING */
3244 prev_state = (MonoAppDomainState)mono_atomic_cas_i32 ((gint32*)&domain->state,
3245 MONO_APPDOMAIN_UNLOADING_START,
3246 MONO_APPDOMAIN_CREATED);
3247 if (prev_state != MONO_APPDOMAIN_CREATED) {
3248 switch (prev_state) {
3249 case MONO_APPDOMAIN_UNLOADING_START:
3250 case MONO_APPDOMAIN_UNLOADING:
3251 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
3252 goto exit;
3253 case MONO_APPDOMAIN_UNLOADED:
3254 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
3255 goto exit;
3256 default:
3257 g_warning ("Invalid appdomain state %d", prev_state);
3258 g_assert_not_reached ();
3262 mono_domain_set_fast (domain, FALSE);
3263 /* Notify OnDomainUnload listeners */
3264 method = mono_class_get_method_from_name_checked (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1, 0, error);
3265 g_assert (method);
3267 mono_runtime_try_invoke (method, domain->domain, NULL, exc, error);
3269 if (!is_ok (error)) {
3270 if (*exc)
3271 mono_error_cleanup (error);
3272 else
3273 *exc = (MonoObject*)mono_error_convert_to_exception (error);
3276 if (*exc) {
3277 /* Roll back the state change */
3278 domain->state = MONO_APPDOMAIN_CREATED;
3279 mono_domain_set_fast (caller_domain, FALSE);
3280 goto exit;
3282 mono_domain_set_fast (caller_domain, FALSE);
3284 thread_data = g_new0 (unload_data, 1);
3285 thread_data->domain = domain;
3286 thread_data->failure_reason = NULL;
3287 thread_data->done = FALSE;
3288 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
3290 /*The managed callback finished successfully, now we start tearing down the appdomain*/
3291 domain->state = MONO_APPDOMAIN_UNLOADING;
3293 * First we create a separate thread for unloading, since
3294 * we might have to abort some threads, including the current one.
3296 * Have to attach to the runtime so shutdown can wait for this thread.
3298 * Force it to be attached to avoid racing during shutdown.
3300 internal = mono_thread_create_internal_handle (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, error);
3301 mono_error_assert_ok (error);
3303 thread_handle = mono_threads_open_thread_handle (MONO_HANDLE_GETVAL (internal, handle));
3305 /* Wait for the thread */
3306 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
3307 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
3308 /* The unload thread tries to abort us */
3309 /* The icall wrapper will execute the abort */
3310 goto exit;
3314 if (thread_data->failure_reason) {
3315 /* Roll back the state change */
3316 domain->state = MONO_APPDOMAIN_CREATED;
3318 g_warning ("%s", thread_data->failure_reason);
3320 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
3322 g_free (thread_data->failure_reason);
3323 thread_data->failure_reason = NULL;
3326 exit:
3327 mono_threads_close_thread_handle (thread_handle);
3328 unload_data_unref (thread_data);
3329 HANDLE_FUNCTION_RETURN ();
3332 #ifdef ENABLE_NETCORE
3334 /* Remember properties so they can be be installed in AppContext during runtime init */
3335 void
3336 mono_runtime_register_appctx_properties (int nprops, const char **keys, const char **values)
3338 n_appctx_props = nprops;
3339 appctx_keys = g_new0 (char*, nprops);
3340 appctx_values = g_new0 (char*, nprops);
3342 for (int i = 0; i < nprops; ++i) {
3343 appctx_keys [i] = g_strdup (keys [i]);
3344 appctx_values [i] = g_strdup (values [i]);
3348 static GENERATE_GET_CLASS_WITH_CACHE (appctx, "System", "AppContext")
3350 /* Install properties into AppContext */
3351 void
3352 mono_runtime_install_appctx_properties (void)
3354 ERROR_DECL (error);
3355 gpointer args [3];
3357 MonoMethod *setup = mono_class_get_method_from_name_checked (mono_class_get_appctx_class (), "Setup", 3, 0, error);
3358 g_assert (setup);
3360 // FIXME: TRUSTED_PLATFORM_ASSEMBLIES is very large
3362 /* internal static unsafe void Setup(char** pNames, char** pValues, int count) */
3363 args [0] = appctx_keys;
3364 args [1] = appctx_values;
3365 args [2] = &n_appctx_props;
3367 mono_runtime_invoke_checked (setup, NULL, args, error);
3368 mono_error_assert_ok (error);
3370 /* No longer needed */
3371 for (int i = 0; i < n_appctx_props; ++i) {
3372 g_free (appctx_keys [i]);
3373 g_free (appctx_values [i]);
3375 g_free (appctx_keys);
3376 g_free (appctx_values);
3377 appctx_keys = NULL;
3378 appctx_values = NULL;
3381 #endif