[loader] ReflectionOnlyLoad(byte[]) should not apply binding redirects (#18457)
[mono-project.git] / mono / metadata / appdomain.c
blob6d7805ad159a4a984d359e89ed1d4d8798c726af
1 /**
2 * \file
3 * AppDomain functions
5 * Authors:
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Patrik Torstensson
8 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2012 Xamarin Inc
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
16 #include <config.h>
17 #include <glib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <time.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_UTIME_H
30 #include <utime.h>
31 #else
32 #ifdef HAVE_SYS_UTIME_H
33 #include <sys/utime.h>
34 #endif
35 #endif
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/object.h>
39 #include <mono/metadata/appdomain-icalls.h>
40 #include <mono/metadata/class-init.h>
41 #include <mono/metadata/domain-internals.h>
42 #include "mono/metadata/metadata-internals.h"
43 #include <mono/metadata/assembly-internals.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/exception-internals.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/mono-gc.h>
50 #include <mono/metadata/mono-hash-internals.h>
51 #include <mono/metadata/marshal.h>
52 #include <mono/metadata/marshal-internals.h>
53 #include <mono/metadata/monitor.h>
54 #include <mono/metadata/mono-debug.h>
55 #include <mono/metadata/attach.h>
56 #include <mono/metadata/w32file.h>
57 #include <mono/metadata/lock-tracer.h>
58 #include <mono/metadata/console-io.h>
59 #include <mono/metadata/threads-types.h>
60 #include <mono/metadata/tokentype.h>
61 #include <mono/metadata/profiler-private.h>
62 #include <mono/metadata/reflection-internals.h>
63 #include <mono/metadata/abi-details.h>
64 #include <mono/metadata/w32socket.h>
65 #include <mono/utils/mono-uri.h>
66 #include <mono/utils/mono-logger-internals.h>
67 #include <mono/utils/mono-path.h>
68 #include <mono/utils/mono-stdlib.h>
69 #include <mono/utils/mono-io-portability.h>
70 #include <mono/utils/mono-error-internals.h>
71 #include <mono/utils/atomic.h>
72 #include <mono/utils/mono-memory-model.h>
73 #include <mono/utils/mono-threads.h>
74 #include <mono/metadata/w32handle.h>
75 #include <mono/metadata/w32error.h>
76 #include <mono/utils/w32api.h>
77 #ifdef HOST_WIN32
78 #include <direct.h>
79 #endif
80 #include "object-internals.h"
81 #include "icall-decl.h"
83 typedef struct
85 int runtime_count;
86 int assemblybinding_count;
87 MonoDomain *domain;
88 gchar *filename;
89 } RuntimeConfig;
91 #ifndef ENABLE_NETCORE
92 static gunichar2 process_guid [36];
93 static gboolean process_guid_set = FALSE;
94 #endif
96 static gboolean no_exec = FALSE;
98 #ifdef ENABLE_NETCORE
99 static int n_appctx_props;
100 static gunichar2 **appctx_keys;
101 static gunichar2 **appctx_values;
102 #endif
104 static const char *
105 mono_check_corlib_version_internal (void);
107 static MonoAssembly *
108 mono_domain_assembly_preload (MonoAssemblyLoadContext *alc,
109 MonoAssemblyName *aname,
110 gchar **assemblies_path,
111 gboolean refonly,
112 gpointer user_data,
113 MonoError *error);
115 static MonoAssembly *
116 mono_domain_assembly_search (MonoAssemblyLoadContext *alc, MonoAssembly *requesting,
117 MonoAssemblyName *aname,
118 gboolean refonly,
119 gboolean postload,
120 gpointer user_data,
121 MonoError *error);
124 static void
125 mono_domain_fire_assembly_load (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer user_data, MonoError *error_out);
127 static gboolean
128 mono_domain_asmctx_from_path (const char *fname, MonoAssembly *requesting_assembly, gpointer user_data, MonoAssemblyContextKind *out_asmctx);
130 static void
131 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
133 #if ENABLE_NETCORE
135 static void
136 add_assembly_to_alc (MonoAssemblyLoadContext *alc, MonoAssembly *ass);
138 #endif
140 static MonoAppDomainHandle
141 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
143 static MonoDomain *
144 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
147 static void
148 mono_context_set_default_context (MonoDomain *domain);
150 static char *
151 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
153 static MonoLoadFunc load_function = NULL;
155 /* Lazy class loading functions */
156 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
157 static GENERATE_GET_CLASS_WITH_CACHE (app_context, "System", "AppContext");
159 GENERATE_GET_CLASS_WITH_CACHE (appdomain, MONO_APPDOMAIN_CLASS_NAME_SPACE, MONO_APPDOMAIN_CLASS_NAME);
160 GENERATE_GET_CLASS_WITH_CACHE (appdomain_setup, MONO_APPDOMAIN_SETUP_CLASS_NAME_SPACE, MONO_APPDOMAIN_SETUP_CLASS_NAME);
162 static MonoDomain *
163 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
165 static void
166 mono_error_set_appdomain_unloaded (MonoError *error)
168 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
171 void
172 mono_install_runtime_load (MonoLoadFunc func)
174 load_function = func;
177 MonoDomain*
178 mono_runtime_load (const char *filename, const char *runtime_version)
180 g_assert (load_function);
181 return load_function (filename, runtime_version);
185 * mono_runtime_set_no_exec:
187 * Instructs the runtime to operate in static mode, i.e. avoid/do not
188 * allow managed code execution. This is useful for running the AOT
189 * compiler on platforms which allow full-aot execution only. This
190 * should be called before mono_runtime_init ().
192 void
193 mono_runtime_set_no_exec (gboolean val)
195 no_exec = val;
199 * mono_runtime_get_no_exec:
201 * If true, then the runtime will not allow managed code execution.
203 gboolean
204 mono_runtime_get_no_exec (void)
206 return no_exec;
209 static void
210 create_domain_objects (MonoDomain *domain)
212 HANDLE_FUNCTION_ENTER ();
213 ERROR_DECL (error);
215 MonoDomain *old_domain = mono_domain_get ();
216 MonoStringHandle arg;
217 MonoVTable *string_vt;
218 MonoClassField *string_empty_fld;
220 if (domain != old_domain) {
221 mono_thread_push_appdomain_ref (domain);
222 mono_domain_set_internal_with_options (domain, FALSE);
226 * Initialize String.Empty. This enables the removal of
227 * the static cctor of the String class.
229 string_vt = mono_class_vtable_checked (domain, mono_defaults.string_class, error);
230 mono_error_assert_ok (error);
231 string_empty_fld = mono_class_get_field_from_name_full (mono_defaults.string_class, "Empty", NULL);
232 g_assert (string_empty_fld);
233 MonoStringHandle empty_str = mono_string_new_handle (domain, "", error);
234 mono_error_assert_ok (error);
235 empty_str = mono_string_intern_checked (empty_str, error);
236 mono_error_assert_ok (error);
237 mono_field_static_set_value_internal (string_vt, string_empty_fld, MONO_HANDLE_RAW (empty_str));
238 domain->empty_string = MONO_HANDLE_RAW (empty_str);
241 * Create an instance early since we can't do it when there is no memory.
243 arg = mono_string_new_handle (domain, "Out of memory", error);
244 mono_error_assert_ok (error);
245 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));
246 mono_error_assert_ok (error);
249 * These two are needed because the signal handlers might be executing on
250 * an alternate stack, and Boehm GC can't handle that.
252 arg = mono_string_new_handle (domain, "A null value was found where an object instance was required", error);
253 mono_error_assert_ok (error);
254 domain->null_reference_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL_HANDLE_STRING, error));
255 mono_error_assert_ok (error);
256 arg = mono_string_new_handle (domain, "The requested operation caused a stack overflow.", error);
257 mono_error_assert_ok (error);
258 domain->stack_overflow_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL_HANDLE_STRING, error));
259 mono_error_assert_ok (error);
261 /*The ephemeron tombstone i*/
262 domain->ephemeron_tombstone = MONO_HANDLE_RAW (mono_object_new_handle (domain, mono_defaults.object_class, error));
263 mono_error_assert_ok (error);
265 if (domain != old_domain) {
266 mono_thread_pop_appdomain_ref ();
267 mono_domain_set_internal_with_options (old_domain, FALSE);
271 * This class is used during exception handling, so initialize it here, to prevent
272 * stack overflows while handling stack overflows.
274 mono_class_init_internal (mono_class_create_array (mono_defaults.int_class, 1));
275 HANDLE_FUNCTION_RETURN ();
279 * mono_runtime_init:
280 * \param domain domain returned by \c mono_init
282 * Initialize the core AppDomain: this function will run also some
283 * IL initialization code, so it needs the execution engine to be fully
284 * operational.
286 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
287 * we know the \c entry_assembly.
290 void
291 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
293 ERROR_DECL (error);
294 mono_runtime_init_checked (domain, start_cb, attach_cb, error);
295 mono_error_cleanup (error);
298 void
299 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
301 HANDLE_FUNCTION_ENTER ();
303 MonoAppDomainSetupHandle setup;
304 MonoAppDomainHandle ad;
306 error_init (error);
308 mono_portability_helpers_init ();
310 mono_gc_base_init ();
311 mono_monitor_init ();
312 mono_marshal_init ();
313 mono_gc_init_icalls ();
315 mono_install_assembly_preload_hook_v2 (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE), FALSE);
316 mono_install_assembly_search_hook_v2 (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE), FALSE, FALSE);
317 mono_install_assembly_search_hook_v2 (mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE), FALSE, TRUE);
318 mono_install_assembly_load_hook_v2 (mono_domain_fire_assembly_load, NULL);
320 #ifndef ENABLE_NETCORE // refonly hooks
321 mono_install_assembly_preload_hook_v2 (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE), TRUE);
322 mono_install_assembly_search_hook_v2 (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE), TRUE, FALSE);
323 mono_install_assembly_search_hook_v2 (mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE), TRUE, TRUE);
324 mono_install_assembly_asmctx_from_path_hook (mono_domain_asmctx_from_path, NULL);
325 #endif
327 mono_thread_init (start_cb, attach_cb);
329 if (!mono_runtime_get_no_exec ()) {
330 MonoClass *klass = mono_class_get_appdomain_setup_class ();
331 setup = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_pinned_handle (domain, klass, error));
332 goto_if_nok (error, exit);
334 klass = mono_class_get_appdomain_class ();
336 ad = MONO_HANDLE_CAST (MonoAppDomain, mono_object_new_pinned_handle (domain, klass, error));
337 goto_if_nok (error, exit);
339 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, domain);
340 domain->domain = MONO_HANDLE_RAW (ad);
341 domain->setup = MONO_HANDLE_RAW (setup);
344 mono_thread_attach (domain);
346 mono_type_initialization_init ();
348 if (!mono_runtime_get_no_exec ())
349 create_domain_objects (domain);
351 /* GC init has to happen after thread init */
352 mono_gc_init ();
354 /* contexts use GC handles, so they must be initialized after the GC */
355 #ifndef ENABLE_NETCORE
356 mono_context_init_checked (domain, error);
357 goto_if_nok (error, exit);
358 mono_context_set_default_context (domain);
359 #endif
361 #ifdef ENABLE_NETCORE
362 if (!mono_runtime_get_no_exec ())
363 mono_runtime_install_appctx_properties ();
364 #endif
366 mono_network_init ();
367 mono_console_init ();
368 mono_attach_init ();
370 mono_locks_tracer_init ();
372 /* mscorlib is loaded before we install the load hook */
373 mono_domain_fire_assembly_load (mono_domain_default_alc (domain), mono_defaults.corlib->assembly, NULL, error);
374 goto_if_nok (error, exit);
376 exit:
377 HANDLE_FUNCTION_RETURN ();
380 static void
381 mono_context_set_default_context (MonoDomain *domain)
383 if (mono_runtime_get_no_exec ())
384 return;
386 HANDLE_FUNCTION_ENTER ();
387 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext, domain->default_context));
388 HANDLE_FUNCTION_RETURN ();
391 static char*
392 mono_get_corlib_version (void)
394 ERROR_DECL (error);
396 MonoClass *klass;
397 MonoClassField *field;
399 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
400 mono_class_init_internal (klass);
401 field = mono_class_get_field_from_name_full (klass, "mono_corlib_version", NULL);
402 if (!field)
403 return NULL;
405 if (! (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_LITERAL)))
406 return NULL;
408 char *value;
409 MonoTypeEnum field_type;
410 const char *data = mono_class_get_field_default_value (field, &field_type);
411 if (field_type != MONO_TYPE_STRING)
412 return NULL;
413 mono_metadata_read_constant_value (data, field_type, &value, error);
414 mono_error_assert_ok (error);
416 char *res = mono_string_from_blob (value, error);
417 mono_error_assert_ok (error);
419 return res;
423 * mono_check_corlib_version:
424 * Checks that the corlib that is loaded matches the version of this runtime.
425 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
426 * allocated string with the error otherwise.
428 const char*
429 mono_check_corlib_version (void)
431 const char* res;
432 MONO_ENTER_GC_UNSAFE;
433 res = mono_check_corlib_version_internal ();
434 MONO_EXIT_GC_UNSAFE;
435 return res;
438 static const char *
439 mono_check_corlib_version_internal (void)
441 #if defined(MONO_CROSS_COMPILE)
442 /* Can't read the corlib version because we only have the target class layouts */
443 return NULL;
444 #else
445 char *result = NULL;
446 char *version = mono_get_corlib_version ();
447 if (!version) {
448 result = g_strdup_printf ("expected corlib string (%s) but not found or not string", MONO_CORLIB_VERSION);
449 goto exit;
451 if (strcmp (version, MONO_CORLIB_VERSION) != 0) {
452 result = g_strdup_printf ("The runtime did not find the mscorlib.dll it expected. "
453 "Expected interface version %s but found %s. Check that "
454 "your runtime and class libraries are matching.",
455 MONO_CORLIB_VERSION, version);
456 goto exit;
459 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
460 guint32 native_offset;
461 guint32 managed_offset;
462 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
463 managed_offset = mono_field_get_offset (mono_class_get_field_from_name_full (mono_defaults.internal_thread_class, "last", NULL));
464 if (native_offset != managed_offset)
465 result = g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
466 exit:
467 g_free (version);
468 return result;
469 #endif
473 * mono_context_init:
474 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
475 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
477 void
478 mono_context_init (MonoDomain *domain)
480 ERROR_DECL (error);
481 mono_context_init_checked (domain, error);
482 mono_error_cleanup (error);
485 void
486 mono_context_init_checked (MonoDomain *domain, MonoError *error)
488 HANDLE_FUNCTION_ENTER ();
490 MonoClass *klass;
491 MonoAppContextHandle context;
493 error_init (error);
494 if (mono_runtime_get_no_exec ())
495 goto exit;
497 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
498 context = MONO_HANDLE_CAST (MonoAppContext, mono_object_new_pinned_handle (domain, klass, error));
499 goto_if_nok (error, exit);
501 MONO_HANDLE_SETVAL (context, domain_id, gint32, domain->domain_id);
502 MONO_HANDLE_SETVAL (context, context_id, gint32, 0);
503 mono_threads_register_app_context (context, error);
504 mono_error_assert_ok (error);
505 domain->default_context = MONO_HANDLE_RAW (context);
506 exit:
507 HANDLE_FUNCTION_RETURN ();
511 * mono_runtime_cleanup:
512 * \param domain unused.
514 * Internal routine.
516 * This must not be called while there are still running threads executing
517 * managed code.
519 void
520 mono_runtime_cleanup (MonoDomain *domain)
522 mono_attach_cleanup ();
524 /* This ends up calling any pending pending (for at most 2 seconds) */
525 mono_gc_cleanup ();
527 mono_thread_cleanup ();
528 mono_network_cleanup ();
529 mono_marshal_cleanup ();
531 mono_type_initialization_cleanup ();
533 mono_monitor_cleanup ();
536 static MonoDomainFunc quit_function = NULL;
539 * mono_install_runtime_cleanup:
541 void
542 mono_install_runtime_cleanup (MonoDomainFunc func)
544 quit_function = func;
548 * mono_runtime_quit:
550 void
551 mono_runtime_quit (void)
553 MONO_STACKDATA (dummy);
554 (void) mono_threads_enter_gc_unsafe_region_unbalanced_internal (&dummy);
555 // after quit_function (in particular, mini_cleanup) everything is
556 // cleaned up so MONO_EXIT_GC_UNSAFE can't work and doesn't make sense.
558 mono_runtime_quit_internal ();
562 * mono_runtime_quit_internal:
564 void
565 mono_runtime_quit_internal (void)
567 MONO_REQ_GC_UNSAFE_MODE;
568 // but note that when we return, we're not in GC Unsafe mode anymore.
569 // After clean up threads don't _have_ a thread state anymore.
571 if (quit_function != NULL)
572 quit_function (mono_get_root_domain (), NULL);
576 * mono_domain_create_appdomain:
577 * \param friendly_name The friendly name of the appdomain to create
578 * \param configuration_file The configuration file to initialize the appdomain with
579 * \returns a \c MonoDomain initialized with the appdomain
581 MonoDomain *
582 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
584 HANDLE_FUNCTION_ENTER ();
585 MonoDomain *domain;
586 MONO_ENTER_GC_UNSAFE;
587 ERROR_DECL (error);
588 domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, error);
589 mono_error_cleanup (error);
590 MONO_EXIT_GC_UNSAFE;
591 HANDLE_FUNCTION_RETURN_VAL (domain);
595 * mono_domain_create_appdomain_checked:
596 * \param friendly_name The friendly name of the appdomain to create
597 * \param configuration_file The configuration file to initialize the appdomain with
598 * \param error Set on error.
600 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
602 MonoDomain *
603 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
605 HANDLE_FUNCTION_ENTER ();
606 error_init (error);
607 MonoDomain *result = NULL;
609 MonoClass *klass = mono_class_get_appdomain_setup_class ();
610 MonoAppDomainSetupHandle setup = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_handle (mono_domain_get (), klass, error));
611 goto_if_nok (error, leave);
612 MonoStringHandle config_file;
613 if (configuration_file != NULL) {
614 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
615 goto_if_nok (error, leave);
616 } else {
617 config_file = MONO_HANDLE_NEW (MonoString, NULL);
619 MONO_HANDLE_SET (setup, configuration_file, config_file);
621 MonoAppDomainHandle ad;
622 ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
623 goto_if_nok (error, leave);
625 result = mono_domain_from_appdomain_handle (ad);
626 leave:
627 HANDLE_FUNCTION_RETURN_VAL (result);
631 * mono_domain_set_config:
632 * \param domain \c MonoDomain initialized with the appdomain we want to change
633 * \param base_dir new base directory for the appdomain
634 * \param config_file_name path to the new configuration for the app domain
636 * Used to set the system configuration for an appdomain
638 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
639 * Error Initializing the configuration system. ---> System.ArgumentException:
640 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
642 void
643 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
645 HANDLE_FUNCTION_ENTER ();
646 MONO_ENTER_GC_UNSAFE;
647 ERROR_DECL (error);
648 mono_domain_set_config_checked (domain, base_dir, config_file_name, error);
649 mono_error_cleanup (error);
650 MONO_EXIT_GC_UNSAFE;
651 HANDLE_FUNCTION_RETURN ();
654 gboolean
655 mono_domain_set_config_checked (MonoDomain *domain, const char *base_dir, const char *config_file_name, MonoError *error)
657 error_init (error);
658 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
659 MonoStringHandle base_dir_str = mono_string_new_handle (domain, base_dir, error);
660 goto_if_nok (error, leave);
661 MONO_HANDLE_SET (setup, application_base, base_dir_str);
662 MonoStringHandle config_file_name_str;
663 config_file_name_str = mono_string_new_handle (domain, config_file_name, error);
664 goto_if_nok (error, leave);
665 MONO_HANDLE_SET (setup, configuration_file, config_file_name_str);
666 leave:
667 return is_ok (error);
670 static MonoAppDomainSetupHandle
671 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
673 HANDLE_FUNCTION_ENTER ();
674 MonoDomain *caller_domain;
675 MonoClass *ads_class;
676 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
678 error_init (error);
680 caller_domain = mono_domain_get ();
681 ads_class = mono_class_get_appdomain_setup_class ();
683 MonoAppDomainSetupHandle copy = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_handle(domain, ads_class, error));
684 goto_if_nok (error, leave);
686 mono_domain_set_internal_with_options (domain, TRUE);
688 #define XCOPY_FIELD(type, dst, field, src, error) \
689 do { \
690 TYPED_HANDLE_NAME (type) src_val = MONO_HANDLE_NEW_GET (type, (src), field); \
691 TYPED_HANDLE_NAME (type) copied_val = MONO_HANDLE_CAST (type, mono_marshal_xdomain_copy_value_handle (MONO_HANDLE_CAST (MonoObject, src_val), error)); \
692 goto_if_nok (error, leave); \
693 MONO_HANDLE_SET ((dst),field,copied_val); \
694 } while (0)
696 #define COPY_VAL(dst,field,type,src) \
697 do { \
698 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
699 } while (0)
701 XCOPY_FIELD (MonoString, copy, application_base, setup, error);
702 XCOPY_FIELD (MonoString, copy, application_name, setup, error);
703 XCOPY_FIELD (MonoString, copy, cache_path, setup, error);
704 XCOPY_FIELD (MonoString, copy, configuration_file, setup, error);
705 XCOPY_FIELD (MonoString, copy, dynamic_base, setup, error);
706 XCOPY_FIELD (MonoString, copy, license_file, setup, error);
707 XCOPY_FIELD (MonoString, copy, private_bin_path, setup, error);
708 XCOPY_FIELD (MonoString, copy, private_bin_path_probe, setup, error);
709 XCOPY_FIELD (MonoString, copy, shadow_copy_directories, setup, error);
710 XCOPY_FIELD (MonoString, copy, shadow_copy_files, setup, error);
711 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
712 COPY_VAL (copy, path_changed, MonoBoolean, setup);
713 COPY_VAL (copy, loader_optimization, int, setup);
714 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
715 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
716 XCOPY_FIELD (MonoArray, copy, domain_initializer_args, setup, error);
717 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
718 XCOPY_FIELD (MonoObject, copy, application_trust, setup, error);
719 XCOPY_FIELD (MonoArray, copy, configuration_bytes, setup, error);
720 XCOPY_FIELD (MonoArray, copy, serialized_non_primitives, setup, error);
722 #undef XCOPY_FIELD
723 #undef COPY_VAL
725 mono_domain_set_internal_with_options (caller_domain, TRUE);
727 MONO_HANDLE_ASSIGN (result, copy);
728 leave:
729 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
732 static MonoAppDomainHandle
733 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
735 HANDLE_FUNCTION_ENTER ();
736 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
737 MonoClass *adclass;
738 MonoDomain *data;
740 error_init (error);
742 adclass = mono_class_get_appdomain_class ();
744 /* FIXME: pin all those objects */
745 data = mono_domain_create();
747 MonoAppDomainHandle ad = MONO_HANDLE_CAST (MonoAppDomain, mono_object_new_handle (data, adclass, error));
748 goto_if_nok (error, leave);
749 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
750 data->domain = MONO_HANDLE_RAW (ad);
751 data->friendly_name = g_strdup (friendly_name);
753 MONO_PROFILER_RAISE (domain_name, (data, data->friendly_name));
755 MonoStringHandle app_base;
756 app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
757 if (MONO_HANDLE_IS_NULL (app_base)) {
758 /* Inherit from the root domain since MS.NET does this */
759 MonoDomain *root = mono_get_root_domain ();
760 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
761 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
762 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
763 /* N.B. new string is in the new domain */
764 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
765 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);
766 mono_gchandle_free_internal (gchandle);
767 if (!is_ok (error)) {
768 g_free (data->friendly_name);
769 goto leave;
771 MONO_HANDLE_SET (setup, application_base, s);
775 mono_context_init_checked (data, error);
776 goto_if_nok (error, leave);
778 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
779 if (!is_ok (error)) {
780 g_free (data->friendly_name);
781 goto leave;
784 mono_domain_set_options_from_config (data);
785 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
787 #ifndef DISABLE_SHADOW_COPY
788 /*FIXME, guard this for when the debugger is not running */
789 char *shadow_location;
790 shadow_location = get_shadow_assembly_location_base (data, error);
791 if (!is_ok (error)) {
792 g_free (data->friendly_name);
793 goto leave;
796 g_free (shadow_location);
797 #endif
799 create_domain_objects (data);
801 MONO_HANDLE_ASSIGN (result, ad);
802 leave:
803 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
807 * mono_domain_has_type_resolve:
808 * \param domain application domain being looked up
810 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
812 gboolean
813 mono_domain_has_type_resolve (MonoDomain *domain)
815 // Check whether managed code is running, and if the managed AppDomain object doesn't exist neither does the event handler
816 if (!domain->domain)
817 return FALSE;
819 #ifdef ENABLE_NETCORE
820 return TRUE;
821 #else
822 MonoObject *o;
824 MONO_STATIC_POINTER_INIT (MonoClassField, field)
826 field = mono_class_get_field_from_name_full (mono_defaults.appdomain_class, "TypeResolve", NULL);
827 g_assert (field);
829 MONO_STATIC_POINTER_INIT_END (MonoClassField, field)
831 mono_field_get_value_internal ((MonoObject*)(domain->domain), field, &o);
832 return o != NULL;
833 #endif
837 * mono_domain_try_type_resolve:
838 * \param domain application domain in which to resolve the type
839 * \param name the name of the type to resolve or NULL.
840 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
842 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
843 * the assembly that matches name, or ((TypeBuilder)typebuilder).FullName.
845 * \returns A \c MonoReflectionAssembly or NULL if not found
847 MonoReflectionAssembly *
848 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *typebuilder_raw)
850 HANDLE_FUNCTION_ENTER ();
852 g_assert (domain);
853 g_assert (name || typebuilder_raw);
855 ERROR_DECL (error);
857 MonoReflectionAssemblyHandle ret = NULL_HANDLE_INIT;
859 // This will not work correctly on netcore
860 if (name) {
861 MonoStringHandle name_handle = mono_string_new_handle (mono_domain_get (), name, error);
862 goto_if_nok (error, exit);
863 ret = mono_domain_try_type_resolve_name (domain, NULL, name_handle, error);
864 } else {
865 #ifndef ENABLE_NETCORE
866 MONO_HANDLE_DCL (MonoObject, typebuilder);
867 ret = mono_domain_try_type_resolve_typebuilder (domain, MONO_HANDLE_CAST (MonoReflectionTypeBuilder, typebuilder), error);
868 #else
869 // TODO: make this work on netcore when working on SRE.TypeBuilder
870 g_assert_not_reached ();
871 #endif
874 exit:
875 mono_error_cleanup (error);
876 HANDLE_FUNCTION_RETURN_OBJ (ret);
879 #ifdef ENABLE_NETCORE
880 MonoReflectionAssemblyHandle
881 mono_domain_try_type_resolve_name (MonoDomain *domain, MonoAssembly *assembly, MonoStringHandle name, MonoError *error)
883 MonoObjectHandle ret;
884 MonoReflectionAssemblyHandle assembly_handle;
886 HANDLE_FUNCTION_ENTER ();
888 MONO_STATIC_POINTER_INIT (MonoMethod, method)
890 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
891 g_assert (alc_class);
892 method = mono_class_get_method_from_name_checked (alc_class, "OnTypeResolve", -1, 0, error);
894 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
896 goto_if_nok (error, return_null);
898 g_assert (domain);
899 g_assert (MONO_HANDLE_BOOL (name));
901 if (mono_runtime_get_no_exec ())
902 goto return_null;
904 if (assembly) {
905 assembly_handle = mono_assembly_get_object_handle (domain, assembly, error);
906 goto_if_nok (error, return_null);
909 gpointer args [2];
910 args [0] = assembly ? MONO_HANDLE_RAW (assembly_handle) : NULL;
911 args [1] = MONO_HANDLE_RAW (name);
912 ret = mono_runtime_try_invoke_handle (method, NULL_HANDLE, args, error);
913 goto_if_nok (error, return_null);
914 goto exit;
916 return_null:
917 ret = NULL_HANDLE;
919 exit:
920 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
922 #else
924 * mono_class_get_appdomain_do_type_resolve_method:
926 * This routine returns System.AppDomain.DoTypeResolve.
928 static MonoMethod *
929 mono_class_get_appdomain_do_type_resolve_method (MonoError *error)
931 MONO_STATIC_POINTER_INIT (MonoMethod, method)
933 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoTypeResolve", -1, 0, error);
935 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
937 if (method == NULL)
938 g_warning ("%s method AppDomain.DoTypeResolve not found. %s\n", __func__, mono_error_get_message (error));
940 return method;
944 * mono_class_get_appdomain_do_type_builder_resolve_method:
946 * This routine returns System.AppDomain.DoTypeBuilderResolve.
948 static MonoMethod *
949 mono_class_get_appdomain_do_type_builder_resolve_method (MonoError *error)
951 MONO_STATIC_POINTER_INIT (MonoMethod, method)
953 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoTypeBuilderResolve", -1, 0, error);
955 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
957 if (method == NULL)
958 g_warning ("%s method AppDomain.DoTypeBuilderResolve not found. %s\n", __func__, mono_error_get_message (error));
960 return method;
964 * mono_domain_try_type_resolve_name:
965 * \param domain application domain in which to resolve the type
966 * \param name the name of the type to resolve.
968 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
969 * the assembly that matches name.
971 * \returns A \c MonoReflectionAssembly or NULL if not found
973 MonoReflectionAssemblyHandle
974 mono_domain_try_type_resolve_name (MonoDomain *domain, MonoAssembly *assembly, MonoStringHandle name, MonoError *error)
976 HANDLE_FUNCTION_ENTER ();
978 void *params [1] = { 0 };
980 g_assert (domain);
981 g_assert (MONO_HANDLE_BOOL (name));
982 g_assert (error);
984 error_init (error);
986 MonoMethod *method;
987 method = mono_class_get_appdomain_do_type_resolve_method (error);
988 goto_if_nok (error, return_null);
990 MonoAppDomainHandle appdomain;
991 appdomain = MONO_HANDLE_NEW (MonoAppDomain, domain->domain);
993 MonoObjectHandle ret;
994 params [0] = MONO_HANDLE_RAW (name);
995 ret = mono_runtime_invoke_handle (method, MONO_HANDLE_CAST (MonoObject, appdomain), params, error);
996 goto_if_nok (error, return_null);
997 goto exit;
998 return_null:
999 ret = NULL_HANDLE;
1000 exit:
1001 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
1005 * mono_domain_try_type_resolve_typebuilder:
1006 * \param domain application domain in which to resolve the type
1007 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder; typebuilder.FullName is the name of the type to resolve.
1009 * This routine invokes the internal \c System.AppDomain.DoTypeBuilderResolve and returns
1010 * the assembly that matches typebuilder.FullName.
1012 * \returns A \c MonoReflectionAssembly or NULL_HANDLE if not found
1014 MonoReflectionAssemblyHandle
1015 mono_domain_try_type_resolve_typebuilder (MonoDomain *domain, MonoReflectionTypeBuilderHandle typebuilder, MonoError *error)
1017 HANDLE_FUNCTION_ENTER ();
1019 g_assert (domain);
1020 g_assert (MONO_HANDLE_BOOL (typebuilder));
1021 g_assert (error);
1023 error_init (error);
1025 MonoMethod * const method = mono_class_get_appdomain_do_type_builder_resolve_method (error);
1026 goto_if_nok (error, return_null);
1028 MonoAppDomainHandle appdomain;
1029 appdomain = MONO_HANDLE_NEW (MonoAppDomain, domain->domain);
1030 void *args [1];
1031 args [0] = MONO_HANDLE_RAW (typebuilder);
1033 MonoObjectHandle ret;
1034 ret = mono_runtime_invoke_handle (method, MONO_HANDLE_CAST (MonoObject, appdomain), args, error);
1035 goto_if_nok (error, return_null);
1036 goto exit;
1037 return_null:
1038 ret = NULL_HANDLE;
1039 exit:
1040 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
1042 #endif
1045 * mono_domain_owns_vtable_slot:
1046 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
1048 gboolean
1049 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
1051 gboolean res;
1053 mono_domain_lock (domain);
1054 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
1055 mono_domain_unlock (domain);
1056 return res;
1059 gboolean
1060 mono_domain_set_fast (MonoDomain *domain, gboolean force)
1062 MONO_REQ_GC_UNSAFE_MODE;
1063 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
1064 return FALSE;
1066 mono_domain_set_internal_with_options (domain, TRUE);
1067 return TRUE;
1070 #ifndef ENABLE_NETCORE
1071 MonoObjectHandle
1072 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
1074 error_init (error);
1076 if (MONO_HANDLE_IS_NULL (name)) {
1077 mono_error_set_argument_null (error, "name", "");
1078 return NULL_HANDLE;
1081 g_assert (!MONO_HANDLE_IS_NULL (ad));
1082 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
1083 g_assert (add);
1085 char *str = mono_string_handle_to_utf8 (name, error);
1086 return_val_if_nok (error, NULL_HANDLE);
1088 mono_domain_lock (add);
1090 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
1091 MonoStringHandle o;
1092 if (!strcmp (str, "APPBASE"))
1093 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
1094 else if (!strcmp (str, "APP_CONFIG_FILE"))
1095 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
1096 else if (!strcmp (str, "DYNAMIC_BASE"))
1097 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
1098 else if (!strcmp (str, "APP_NAME"))
1099 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
1100 else if (!strcmp (str, "CACHE_BASE"))
1101 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
1102 else if (!strcmp (str, "PRIVATE_BINPATH"))
1103 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
1104 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
1105 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
1106 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
1107 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
1108 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
1109 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
1110 else
1111 o = MONO_HANDLE_NEW (MonoString, (MonoString*)mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
1113 mono_domain_unlock (add);
1114 g_free (str);
1116 return MONO_HANDLE_CAST (MonoObject, o);
1119 void
1120 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
1122 error_init (error);
1124 if (MONO_HANDLE_IS_NULL (name)) {
1125 mono_error_set_argument_null (error, "name", "");
1126 return;
1129 g_assert (!MONO_HANDLE_IS_NULL (ad));
1130 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
1131 g_assert (add);
1133 mono_domain_lock (add);
1135 mono_g_hash_table_insert_internal (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
1137 mono_domain_unlock (add);
1140 MonoAppDomainSetupHandle
1141 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
1143 error_init (error);
1144 g_assert (!MONO_HANDLE_IS_NULL (ad));
1145 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1146 g_assert (domain);
1148 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
1151 MonoStringHandle
1152 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
1154 error_init (error);
1155 g_assert (!MONO_HANDLE_IS_NULL (ad));
1156 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1157 g_assert (domain);
1159 return mono_string_new_handle (domain, domain->friendly_name, error);
1162 MonoAppDomainHandle
1163 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
1165 error_init (error);
1166 MonoDomain *add = mono_domain_get ();
1168 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
1171 MonoAppDomainHandle
1172 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
1174 error_init (error);
1175 MonoDomain *root = mono_get_root_domain ();
1177 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
1180 MonoBoolean
1181 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions (MonoError *error)
1183 MonoDomain *domain = mono_domain_get ();
1185 return domain->throw_unobserved_task_exceptions;
1187 #endif
1189 static char*
1190 get_attribute_value (const gchar **attribute_names,
1191 const gchar **attribute_values,
1192 const char *att_name)
1194 int n;
1195 for (n = 0; attribute_names [n] != NULL; n++) {
1196 if (strcmp (attribute_names [n], att_name) == 0)
1197 return g_strdup (attribute_values [n]);
1199 return NULL;
1202 static void
1203 start_element (GMarkupParseContext *context,
1204 const gchar *element_name,
1205 const gchar **attribute_names,
1206 const gchar **attribute_values,
1207 gpointer user_data,
1208 GError **gerror)
1210 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
1212 if (strcmp (element_name, "runtime") == 0) {
1213 runtime_config->runtime_count++;
1214 return;
1217 if (strcmp (element_name, "assemblyBinding") == 0) {
1218 runtime_config->assemblybinding_count++;
1219 return;
1222 if (runtime_config->runtime_count != 1)
1223 return;
1225 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
1226 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
1228 if (value && g_ascii_strcasecmp (value, "true") == 0)
1229 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
1232 if (runtime_config->assemblybinding_count != 1)
1233 return;
1235 if (strcmp (element_name, "probing") != 0)
1236 return;
1238 g_free (runtime_config->domain->private_bin_path);
1239 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
1240 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
1241 g_free (runtime_config->domain->private_bin_path);
1242 runtime_config->domain->private_bin_path = NULL;
1243 return;
1247 static void
1248 end_element (GMarkupParseContext *context,
1249 const gchar *element_name,
1250 gpointer user_data,
1251 GError **gerror)
1253 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
1254 if (strcmp (element_name, "runtime") == 0)
1255 runtime_config->runtime_count--;
1256 else if (strcmp (element_name, "assemblyBinding") == 0)
1257 runtime_config->assemblybinding_count--;
1260 static void
1261 parse_error (GMarkupParseContext *context, GError *gerror, gpointer user_data)
1263 RuntimeConfig *state = (RuntimeConfig *)user_data;
1264 const gchar *msg;
1265 const gchar *filename;
1267 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
1268 msg = gerror && gerror->message ? gerror->message : "";
1269 g_warning ("Error parsing %s: %s", filename, msg);
1272 static const GMarkupParser
1273 mono_parser = {
1274 start_element,
1275 end_element,
1276 NULL,
1277 NULL,
1278 parse_error
1281 void
1282 mono_domain_set_options_from_config (MonoDomain *domain)
1284 ERROR_DECL (error);
1285 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
1286 gsize len;
1287 GMarkupParseContext *context;
1288 RuntimeConfig runtime_config;
1289 gint offset;
1291 if (!domain || !domain->setup || !domain->setup->configuration_file)
1292 return;
1294 config_file_name = mono_string_to_utf8_checked_internal (domain->setup->configuration_file, error);
1295 if (!is_ok (error)) {
1296 mono_error_cleanup (error);
1297 goto free_and_out;
1300 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1301 if (!config_file_path)
1302 config_file_path = config_file_name;
1304 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1305 goto free_and_out;
1307 runtime_config.runtime_count = 0;
1308 runtime_config.assemblybinding_count = 0;
1309 runtime_config.domain = domain;
1310 runtime_config.filename = config_file_path;
1312 offset = 0;
1313 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1314 offset = 3; /* Skip UTF-8 BOM */
1316 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1317 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1318 g_markup_parse_context_end_parse (context, NULL);
1319 g_markup_parse_context_free (context);
1321 free_and_out:
1322 g_free (text);
1323 if (config_file_name != config_file_path)
1324 g_free (config_file_name);
1325 g_free (config_file_path);
1328 #ifndef ENABLE_NETCORE
1329 MonoAppDomainHandle
1330 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1332 error_init (error);
1333 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1335 #ifdef DISABLE_APPDOMAINS
1336 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1337 #else
1338 char *fname;
1340 fname = mono_string_handle_to_utf8 (friendly_name, error);
1341 return_val_if_nok (error, ad);
1342 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1343 g_free (fname);
1344 #endif
1345 return ad;
1347 #endif
1349 static gboolean
1350 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1352 HANDLE_FUNCTION_ENTER ();
1353 error_init (error);
1354 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1355 goto_if_nok (error, leave);
1356 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1357 leave:
1358 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1361 static MonoArrayHandle
1362 get_assembly_array_from_domain (MonoDomain *domain, MonoBoolean refonly, MonoError *error)
1364 int i;
1365 GPtrArray *assemblies;
1367 assemblies = mono_domain_get_assemblies (domain, refonly);
1369 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1370 goto_if_nok (error, leave);
1371 for (i = 0; i < assemblies->len; ++i) {
1372 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1373 goto leave;
1376 leave:
1377 g_ptr_array_free (assemblies, TRUE);
1378 return res;
1381 #ifdef ENABLE_NETCORE
1382 MonoArrayHandle
1383 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalGetLoadedAssemblies (MonoError *error)
1385 MonoDomain *domain = mono_domain_get ();
1386 return get_assembly_array_from_domain (domain, FALSE, error);
1388 #else
1389 MonoArrayHandle
1390 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1392 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1393 return get_assembly_array_from_domain (domain, refonly, error);
1395 #endif
1397 MonoAssembly*
1398 mono_try_assembly_resolve (MonoAssemblyLoadContext *alc, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1400 HANDLE_FUNCTION_ENTER ();
1401 error_init (error);
1402 MonoAssembly *result = NULL;
1403 MonoStringHandle fname = mono_string_new_handle (mono_alc_domain (alc), fname_raw, error);
1404 goto_if_nok (error, leave);
1405 result = mono_try_assembly_resolve_handle (alc, fname, requesting, refonly, error);
1406 leave:
1407 HANDLE_FUNCTION_RETURN_VAL (result);
1410 MonoAssembly*
1411 mono_try_assembly_resolve_handle (MonoAssemblyLoadContext *alc, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1413 HANDLE_FUNCTION_ENTER ();
1414 MonoAssembly *ret = NULL;
1415 MonoDomain *domain = mono_alc_domain (alc);
1417 if (mono_runtime_get_no_exec ())
1418 goto leave;
1420 #ifndef ENABLE_NETCORE
1422 static MonoMethod *method;
1423 MonoBoolean isrefonly;
1424 gpointer params [3];
1426 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1428 // FIXME cache?
1430 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1, 0, error);
1431 g_assert (method != NULL);
1433 isrefonly = refonly ? 1 : 0;
1434 MonoReflectionAssemblyHandle requesting_handle;
1435 if (requesting) {
1436 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1437 goto_if_nok (error, leave);
1439 params [0] = MONO_HANDLE_RAW (fname);
1440 params [1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1441 params [2] = &isrefonly;
1442 MonoObject *exc;
1443 exc = NULL;
1444 MonoReflectionAssemblyHandle result;
1445 result = MONO_HANDLE_CAST (MonoReflectionAssembly, MONO_HANDLE_NEW (MonoObject, mono_runtime_try_invoke (method, domain->domain, params, &exc, error)));
1446 if (!is_ok (error) || exc != NULL) {
1447 if (is_ok (error))
1448 mono_error_set_exception_instance (error, (MonoException*)exc);
1449 goto leave;
1451 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1453 if (ret && !refonly && mono_asmctx_get_kind (&ret->context) == MONO_ASMCTX_REFONLY) {
1454 /* .NET Framework throws System.IO.FileNotFoundException in this case */
1455 mono_error_set_file_not_found (error, NULL, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only");
1456 ret = NULL;
1457 goto leave;
1459 #else
1460 MONO_STATIC_POINTER_INIT (MonoMethod, method)
1462 ERROR_DECL (local_error);
1463 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
1464 g_assert (alc_class);
1465 method = mono_class_get_method_from_name_checked (alc_class, "OnAssemblyResolve", -1, 0, local_error);
1466 mono_error_assert_ok (local_error);
1468 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
1470 g_assert (method);
1472 MonoReflectionAssemblyHandle requesting_handle;
1473 if (requesting) {
1474 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1475 goto_if_nok (error, leave);
1478 gpointer params [2];
1479 params [0] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1480 params [1] = MONO_HANDLE_RAW (fname);
1481 MonoReflectionAssemblyHandle result;
1482 result = MONO_HANDLE_CAST (MonoReflectionAssembly, mono_runtime_try_invoke_handle (method, NULL_HANDLE, params, error));
1483 goto_if_nok (error, leave);
1485 if (MONO_HANDLE_BOOL (result))
1486 ret = MONO_HANDLE_GETVAL (result, assembly);
1487 #endif
1489 leave:
1490 HANDLE_FUNCTION_RETURN_VAL (ret);
1493 MonoAssembly *
1494 mono_domain_assembly_postload_search (MonoAssemblyLoadContext *alc, MonoAssembly *requesting,
1495 MonoAssemblyName *aname,
1496 gboolean refonly, gboolean postload,
1497 gpointer user_data,
1498 MonoError *error_out)
1500 ERROR_DECL (error);
1501 MonoAssembly *assembly;
1502 char *aname_str;
1504 aname_str = mono_stringify_assembly_name (aname);
1506 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1508 assembly = mono_try_assembly_resolve (alc, aname_str, requesting, refonly, error);
1509 g_free (aname_str);
1510 mono_error_cleanup (error);
1512 return assembly;
1516 * LOCKING: assumes assemblies_lock in the domain is already locked.
1518 static void
1519 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1521 gint i;
1522 GSList *tmp;
1523 gboolean destroy_ht = FALSE;
1525 g_assert (ass != NULL);
1527 if (!ass->aname.name)
1528 return;
1530 if (!ht) {
1531 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1532 destroy_ht = TRUE;
1533 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1534 g_hash_table_insert (ht, tmp->data, tmp->data);
1538 /* FIXME: handle lazy loaded assemblies */
1540 if (!g_hash_table_lookup (ht, ass)) {
1541 mono_assembly_addref (ass);
1542 g_hash_table_insert (ht, ass, ass);
1543 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1544 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);
1547 if (ass->image->references) {
1548 for (i = 0; i < ass->image->nreferences; i++) {
1549 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1550 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1551 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1556 if (destroy_ht)
1557 g_hash_table_destroy (ht);
1560 #ifdef ENABLE_NETCORE
1561 static void
1562 add_assembly_to_alc (MonoAssemblyLoadContext *alc, MonoAssembly *ass)
1564 gint i;
1565 GSList *tmp;
1567 g_assert (ass != NULL);
1569 if (!ass->aname.name)
1570 return;
1572 mono_alc_assemblies_lock (alc);
1574 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
1575 if (tmp->data == ass) {
1576 mono_alc_assemblies_unlock (alc);
1577 return;
1581 mono_assembly_addref (ass);
1582 // Prepending here will break the test suite with frequent InvalidCastExceptions, so we have to append
1583 alc->loaded_assemblies = g_slist_append (alc->loaded_assemblies, ass);
1584 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);
1586 if (ass->image->references) {
1587 for (i = 0; i < ass->image->nreferences; i++) {
1588 // TODO: remove all this after we're confident this assert isn't hit
1589 g_assertf (!ass->image->references [i], "Did not expect reference %d of %s to be resolved", i, ass->image->name);
1593 mono_alc_assemblies_unlock (alc);
1595 #endif
1597 static void
1598 mono_domain_fire_assembly_load_event (MonoDomain *domain, MonoAssembly *assembly, MonoError *error)
1600 HANDLE_FUNCTION_ENTER ();
1602 g_assert (domain);
1603 g_assert (assembly);
1605 #ifdef ENABLE_NETCORE
1606 MONO_STATIC_POINTER_INIT (MonoMethod, method)
1608 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
1609 g_assert (alc_class);
1610 method = mono_class_get_method_from_name_checked (alc_class, "OnAssemblyLoad", -1, 0, error);
1612 MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
1613 goto_if_nok (error, exit);
1615 MonoReflectionAssemblyHandle assembly_handle = mono_assembly_get_object_handle (domain, assembly, error);
1616 goto_if_nok (error, exit);
1618 gpointer args [1];
1619 args [0] = MONO_HANDLE_RAW (assembly_handle);
1620 mono_runtime_try_invoke_handle (method, NULL_HANDLE, args, error);
1621 #else
1622 MonoObjectHandle appdomain = MONO_HANDLE_NEW (MonoObject, &domain->domain->mbr.obj);
1623 MonoClass *klass = mono_handle_class (appdomain);
1625 MONO_STATIC_POINTER_INIT (MonoClassField, assembly_load_field)
1627 assembly_load_field = mono_class_get_field_from_name_full (klass, "AssemblyLoad", NULL);
1628 g_assert (assembly_load_field);
1630 MONO_STATIC_POINTER_INIT_END (MonoClassField, assembly_load_field)
1632 if (!MONO_HANDLE_GET_FIELD_BOOL (appdomain, MonoObject*, assembly_load_field))
1633 goto exit; // No events waiting to be triggered
1635 MonoReflectionAssemblyHandle reflection_assembly;
1636 reflection_assembly = mono_assembly_get_object_handle (domain, assembly, error);
1637 goto_if_nok (error, exit);
1639 MONO_STATIC_POINTER_INIT (MonoMethod, assembly_load_method)
1641 assembly_load_method = mono_class_get_method_from_name_checked (klass, "DoAssemblyLoad", -1, 0, error);
1642 g_assert (assembly_load_method);
1644 MONO_STATIC_POINTER_INIT_END (MonoMethod, assembly_load_method)
1646 void *params [1];
1647 params [0] = MONO_HANDLE_RAW (reflection_assembly);
1648 mono_runtime_invoke_handle_void (assembly_load_method, appdomain, params, error);
1649 #endif
1651 exit:
1652 HANDLE_FUNCTION_RETURN ();
1655 static void
1656 mono_domain_fire_assembly_load (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer user_data, MonoError *error_out)
1658 ERROR_DECL (error);
1659 MonoDomain *domain = mono_alc_domain (alc);
1661 g_assert (assembly);
1662 g_assert (domain);
1664 if (!MONO_BOOL (domain->domain))
1665 goto leave; // This can happen during startup
1667 if (mono_runtime_get_no_exec ())
1668 goto leave;
1670 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Loading assembly %s (%p) into domain %s (%p) and ALC %p", assembly->aname.name, assembly, domain->friendly_name, domain, alc);
1672 mono_domain_assemblies_lock (domain);
1673 add_assemblies_to_domain (domain, assembly, NULL);
1674 mono_domain_assemblies_unlock (domain);
1675 #ifdef ENABLE_NETCORE
1676 add_assembly_to_alc (alc, assembly);
1677 #endif
1679 mono_domain_fire_assembly_load_event (domain, assembly, error_out);
1681 leave:
1682 mono_error_cleanup (error);
1685 static gboolean
1686 mono_domain_asmctx_from_path (const char *fname, MonoAssembly *requesting_assembly, gpointer user_data, MonoAssemblyContextKind *out_asmctx)
1688 MonoDomain *domain = mono_domain_get ();
1689 char **search_path = NULL;
1691 for (search_path = domain->search_path; search_path && *search_path; search_path++) {
1692 if (mono_path_filename_in_basedir (fname, *search_path)) {
1693 *out_asmctx = MONO_ASMCTX_DEFAULT;
1694 return TRUE;
1697 return FALSE;
1701 * LOCKING: Acquires the domain assemblies lock.
1703 static void
1704 set_domain_search_path (MonoDomain *domain)
1706 HANDLE_FUNCTION_ENTER ();
1707 ERROR_DECL (error);
1708 MonoAppDomainSetupHandle setup;
1709 gchar **tmp;
1710 gchar *search_path = NULL;
1711 gint npaths = 1;
1712 gchar **pvt_split = NULL;
1713 GError *gerror = NULL;
1714 gint appbaselen = -1;
1717 * We use the low-level domain assemblies lock, since this is called from
1718 * assembly loads hooks, which means this thread might hold the loader lock.
1720 mono_domain_assemblies_lock (domain);
1722 if (!MONO_BOOL (domain->setup))
1723 goto exit;
1725 setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
1727 if (domain->search_path && !MONO_HANDLE_GET_BOOL (setup, path_changed))
1728 goto exit;
1730 if (!MONO_HANDLE_GET_BOOL (setup, application_base))
1731 goto exit; // Must set application base to get private path working
1733 if (MONO_HANDLE_GET_BOOL (setup, private_bin_path)) {
1734 search_path = mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString, setup, private_bin_path), error);
1735 if (!is_ok (error)) { /*FIXME maybe we should bubble up the error.*/
1736 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1737 goto exit;
1741 if (domain->private_bin_path) {
1742 if (search_path == NULL)
1743 search_path = domain->private_bin_path;
1744 else {
1745 gchar *tmp2 = search_path;
1746 search_path = g_strjoin (";", search_path, domain->private_bin_path, (const char*)NULL);
1747 g_free (tmp2);
1751 if (search_path) {
1753 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1754 * directories relative to ApplicationBase separated by semicolons (see
1755 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1756 * The loop below copes with the fact that some Unix applications may use ':' (or
1757 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1758 * ';' for the subsequent split.
1760 * The issue was reported in bug #81446
1762 #ifndef TARGET_WIN32
1763 g_strdelimit (search_path, ':', ';');
1764 #endif
1765 pvt_split = g_strsplit (search_path, ";", 1000);
1766 g_free (search_path);
1767 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1770 g_strfreev (domain->search_path);
1771 domain->search_path = NULL;
1773 tmp = g_new (gchar*, npaths + 1);
1774 tmp [npaths] = NULL;
1776 *tmp = mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString, setup, application_base), error);
1777 if (!is_ok (error)) {
1778 g_free (tmp);
1779 goto exit;
1782 domain->search_path = tmp;
1784 /* FIXME: is this needed? */
1785 if (strncmp (*tmp, "file://", 7) == 0) {
1786 gchar *file = *tmp;
1787 gchar *uri = *tmp;
1788 gchar *tmpuri;
1790 if (uri [7] != '/')
1791 uri = g_strdup_printf ("file:///%s", uri + 7);
1793 tmpuri = uri;
1794 uri = mono_escape_uri_string (tmpuri);
1795 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1796 g_free (uri);
1798 if (tmpuri != file)
1799 g_free (tmpuri);
1801 if (gerror != NULL) {
1802 g_warning ("%s\n", gerror->message);
1803 g_error_free (gerror);
1804 *tmp = file;
1805 } else {
1806 g_free (file);
1810 for (gsize i = 1; pvt_split && i < npaths; i++) {
1811 if (g_path_is_absolute (pvt_split [i - 1])) {
1812 tmp [i] = g_strdup (pvt_split [i - 1]);
1813 } else {
1814 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], (const char*)NULL);
1817 if (strchr (tmp [i], '.')) {
1818 gchar *reduced;
1819 gchar *freeme;
1821 reduced = mono_path_canonicalize (tmp [i]);
1822 if (appbaselen == -1)
1823 appbaselen = strlen (tmp [0]);
1825 if (strncmp (tmp [0], reduced, appbaselen)) {
1826 g_free (reduced);
1827 g_free (tmp [i]);
1828 tmp [i] = g_strdup ("");
1829 continue;
1832 freeme = tmp [i];
1833 tmp [i] = reduced;
1834 g_free (freeme);
1838 if (MONO_HANDLE_GET_BOOL (setup, private_bin_path_probe)) {
1839 g_free (tmp [0]);
1840 tmp [0] = g_strdup ("");
1843 MONO_HANDLE_SETVAL (setup, path_changed, MonoBoolean, FALSE);
1844 exit:
1845 mono_error_cleanup (error);
1846 g_strfreev (pvt_split);
1847 mono_domain_assemblies_unlock (domain);
1848 HANDLE_FUNCTION_RETURN ();
1851 #ifdef DISABLE_SHADOW_COPY
1852 gboolean
1853 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1855 return FALSE;
1858 char *
1859 mono_make_shadow_copy (const char *filename, MonoError *error)
1861 error_init (error);
1862 return (char *) filename;
1864 #else
1866 typedef enum {
1867 SHADOW_COPY_SIBLING_EXT_APPEND,
1868 SHADOW_COPY_SIBLING_EXT_REPLACE,
1869 } ShadowCopySiblingExt;
1871 static
1872 gchar *
1873 make_sibling_path (const gchar *path, gint pathlen, const char *extension, ShadowCopySiblingExt extopt)
1875 gchar *result = NULL;
1876 switch (extopt) {
1877 case SHADOW_COPY_SIBLING_EXT_APPEND: {
1878 result = g_strconcat (path, extension, (const char*)NULL);
1879 break;
1881 case SHADOW_COPY_SIBLING_EXT_REPLACE: {
1882 /* expect path to be a .dll or .exe (or some case insensitive variant) */
1883 g_assert (pathlen >= 4 && path[pathlen - 4] == '.');
1884 GString *s = g_string_sized_new (pathlen - 4 + strlen (extension));
1885 g_string_append_len (s, path, pathlen - 4);
1886 g_string_append (s, extension);
1887 result = g_string_free (s, FALSE);
1888 break;
1890 default:
1891 g_assert_not_reached ();
1893 return result;
1896 static gboolean
1897 shadow_copy_sibling (const gchar *src_pristine, gint srclen, const char *extension, ShadowCopySiblingExt extopt, const gchar *target_pristine, gint targetlen)
1899 gchar *file = NULL;
1900 gunichar2 *orig = NULL;
1901 gunichar2 *dest = NULL;
1902 gboolean copy_result = TRUE;
1903 gchar *target = NULL;
1905 char *src = make_sibling_path (src_pristine, srclen, extension, extopt);
1907 if (IS_PORTABILITY_CASE) {
1908 file = mono_portability_find_file (src, TRUE);
1909 if (file == NULL)
1910 goto exit;
1911 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR))
1912 goto exit;
1914 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1916 target = make_sibling_path (target_pristine, targetlen, extension, extopt);
1918 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1920 mono_w32file_delete (dest);
1922 gint32 copy_error;
1923 copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1925 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1926 * overwritten when updated in their original locations. */
1927 if (copy_result)
1928 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1930 exit:
1931 g_free (file);
1932 g_free (orig);
1933 g_free (dest);
1934 g_free (src);
1935 g_free (target);
1936 return copy_result;
1939 static gint32
1940 get_cstring_hash (const char *str)
1942 const char *p;
1943 gint32 h = 0;
1945 if (!str || !str [0])
1946 return 0;
1948 gsize const len = strlen (str);
1949 p = str;
1950 for (gsize i = 0; i < len; i++) {
1951 h = (h << 5) - h + *p;
1952 p++;
1955 return h;
1959 * Returned memory is malloc'd. Called must free it
1961 static char *
1962 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1964 MonoAppDomainSetup *setup;
1965 char *cache_path = NULL;
1966 char *appname = NULL;
1967 char *userdir = NULL;
1968 char *location;
1970 error_init (error);
1972 setup = domain->setup;
1973 if (setup->cache_path != NULL && setup->application_name != NULL) {
1974 cache_path = mono_string_to_utf8_checked_internal (setup->cache_path, error);
1975 return_val_if_nok (error, NULL);
1977 #ifndef TARGET_WIN32
1979 gint i;
1980 for (i = strlen (cache_path) - 1; i >= 0; i--)
1981 if (cache_path [i] == '\\')
1982 cache_path [i] = '/';
1984 #endif
1986 appname = mono_string_to_utf8_checked_internal (setup->application_name, error);
1987 if (!is_ok (error)) {
1988 g_free (cache_path);
1989 return NULL;
1992 location = g_build_filename (cache_path, appname, "assembly", "shadow", (const char*)NULL);
1993 } else {
1994 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1995 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", (const char*)NULL);
1997 g_free (appname);
1998 g_free (cache_path);
1999 g_free (userdir);
2000 return location;
2003 static char *
2004 get_shadow_assembly_location (const char *filename, MonoError *error)
2006 gint32 hash = 0, hash2 = 0;
2007 char name_hash [9];
2008 char path_hash [30];
2009 char *bname = g_path_get_basename (filename);
2010 char *dirname = g_path_get_dirname (filename);
2011 char *location, *tmploc;
2012 MonoDomain *domain = mono_domain_get ();
2014 error_init (error);
2016 hash = get_cstring_hash (bname);
2017 hash2 = get_cstring_hash (dirname);
2018 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
2019 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
2020 tmploc = get_shadow_assembly_location_base (domain, error);
2021 if (!is_ok (error)) {
2022 g_free (bname);
2023 g_free (dirname);
2024 return NULL;
2027 location = g_build_filename (tmploc, name_hash, path_hash, bname, (const char*)NULL);
2028 g_free (tmploc);
2029 g_free (bname);
2030 g_free (dirname);
2031 return location;
2034 static gboolean
2035 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
2037 struct stat sbuf_dest;
2038 gchar *stat_src;
2039 gchar *real_src = mono_portability_find_file (src, TRUE);
2041 if (!real_src)
2042 stat_src = (gchar*)src;
2043 else
2044 stat_src = real_src;
2046 if (stat (stat_src, sbuf_src) == -1) {
2047 time_t tnow = time (NULL);
2049 if (real_src)
2050 g_free (real_src);
2052 memset (sbuf_src, 0, sizeof (*sbuf_src));
2053 sbuf_src->st_mtime = tnow;
2054 sbuf_src->st_atime = tnow;
2055 return TRUE;
2058 if (real_src)
2059 g_free (real_src);
2061 if (stat (dest, &sbuf_dest) == -1)
2062 return TRUE;
2064 if (sbuf_src->st_size == sbuf_dest.st_size &&
2065 sbuf_src->st_mtime == sbuf_dest.st_mtime)
2066 return FALSE;
2068 return TRUE;
2071 static gboolean
2072 shadow_copy_create_ini (const char *shadow, const char *filename)
2074 gunichar2 *u16_ini = NULL;
2075 gboolean result = FALSE;
2076 guint32 n;
2077 HANDLE handle = INVALID_HANDLE_VALUE;
2078 gchar *full_path = NULL;
2080 char *dir_name = g_path_get_dirname (shadow);
2081 char *ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", (const char*)NULL);
2082 g_free (dir_name);
2083 result = g_file_test (ini_file, G_FILE_TEST_IS_REGULAR);
2084 if (result)
2085 goto exit;
2087 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
2088 if (!u16_ini)
2089 goto exit;
2091 handle = mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
2092 if (handle == INVALID_HANDLE_VALUE)
2093 goto exit;
2095 full_path = mono_path_resolve_symlinks (filename);
2096 gint32 win32error;
2097 win32error = 0;
2098 result = mono_w32file_write (handle, full_path, strlen (full_path), &n, &win32error);
2099 exit:
2100 if (handle != INVALID_HANDLE_VALUE)
2101 mono_w32file_close (handle);
2102 g_free (u16_ini);
2103 g_free (full_path);
2104 g_free (ini_file);
2105 return result;
2108 gboolean
2109 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
2111 ERROR_DECL (error);
2112 MonoAppDomainSetup *setup;
2113 gchar *all_dirs = NULL;
2114 gchar **dir_ptr;
2115 gchar **directories = NULL;
2116 gchar *shadow_status_string;
2117 gchar *base_dir = NULL;
2118 gboolean shadow_enabled;
2119 gboolean found = FALSE;
2121 if (domain == NULL)
2122 goto exit;
2124 setup = domain->setup;
2125 if (setup == NULL || setup->shadow_copy_files == NULL)
2126 goto exit;
2128 shadow_status_string = mono_string_to_utf8_checked_internal (setup->shadow_copy_files, error);
2129 if (!is_ok (error))
2130 goto exit;
2132 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
2133 g_free (shadow_status_string);
2135 if (!shadow_enabled)
2136 goto exit;
2138 found = (setup->shadow_copy_directories == NULL);
2139 if (found)
2140 goto exit;
2142 /* Is dir_name a shadow_copy destination already? */
2143 base_dir = get_shadow_assembly_location_base (domain, error);
2144 if (!is_ok (error))
2145 goto exit;
2147 found = !!strstr (dir_name, base_dir);
2148 if (found)
2149 goto exit;
2151 all_dirs = mono_string_to_utf8_checked_internal (setup->shadow_copy_directories, error);
2152 if (!is_ok (error))
2153 goto exit;
2155 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
2156 dir_ptr = directories;
2157 while (!found && *dir_ptr) {
2158 found = (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name));
2159 dir_ptr++;
2161 exit:
2162 mono_error_cleanup (error);
2163 g_free (base_dir);
2164 g_strfreev (directories);
2165 g_free (all_dirs);
2166 return found;
2170 This function raises exceptions so it can cause as sorts of nasty stuff if called
2171 while holding a lock.
2172 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
2173 or NULL if source file not found.
2174 FIXME bubble up the error instead of raising it here
2176 char *
2177 mono_make_shadow_copy (const char *filename, MonoError *oerror)
2179 ERROR_DECL (error);
2180 gint filename_len, shadow_len;
2181 gunichar2 *orig, *dest;
2182 guint32 attrs;
2183 char *shadow;
2184 gboolean copy_result;
2185 struct stat src_sbuf;
2186 struct utimbuf utbuf;
2187 char *dir_name = g_path_get_dirname (filename);
2188 MonoDomain *domain = mono_domain_get ();
2189 char *shadow_dir;
2190 gint32 copy_error;
2192 #ifndef ENABLE_NETCORE
2193 set_domain_search_path (domain);
2194 #endif
2196 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
2197 g_free (dir_name);
2198 return (char *) filename;
2201 /* Is dir_name a shadow_copy destination already? */
2202 shadow_dir = get_shadow_assembly_location_base (domain, error);
2203 if (!is_ok (error)) {
2204 mono_error_cleanup (error);
2205 g_free (dir_name);
2206 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
2207 return NULL;
2210 if (strstr (dir_name, shadow_dir)) {
2211 g_free (shadow_dir);
2212 g_free (dir_name);
2213 return (char *) filename;
2215 g_free (shadow_dir);
2216 g_free (dir_name);
2218 shadow = get_shadow_assembly_location (filename, error);
2219 if (!is_ok (error)) {
2220 mono_error_cleanup (error);
2221 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
2222 return NULL;
2225 if (g_ensure_directory_exists (shadow) == FALSE) {
2226 g_free (shadow);
2227 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
2228 return NULL;
2231 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
2232 return (char*) shadow;
2234 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
2235 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
2236 mono_w32file_delete (dest);
2238 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
2239 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
2240 * and not have it runtime error" */
2241 attrs = mono_w32file_get_attributes (orig);
2242 if (attrs == INVALID_FILE_ATTRIBUTES) {
2243 g_free (shadow);
2244 return (char *)filename;
2247 copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
2249 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
2250 * overwritten when updated in their original locations. */
2251 if (copy_result)
2252 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
2254 g_free (dest);
2255 g_free (orig);
2257 if (copy_result == FALSE) {
2258 g_free (shadow);
2260 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
2261 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
2262 return NULL; /* file not found, shadow copy failed */
2264 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
2265 return NULL;
2268 /* attempt to copy .mdb, .pdb and .config if they exist */
2269 filename_len = strlen (filename);
2270 shadow_len = strlen (shadow);
2272 copy_result = shadow_copy_sibling (filename, filename_len, ".mdb", SHADOW_COPY_SIBLING_EXT_APPEND, shadow, shadow_len);
2273 if (copy_result)
2274 copy_result = shadow_copy_sibling (filename, filename_len, ".pdb", SHADOW_COPY_SIBLING_EXT_REPLACE, shadow, shadow_len);
2275 if (copy_result)
2276 copy_result = shadow_copy_sibling (filename, filename_len, ".config", SHADOW_COPY_SIBLING_EXT_APPEND, shadow, shadow_len);
2278 if (!copy_result) {
2279 g_free (shadow);
2280 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
2281 return NULL;
2284 /* Create a .ini file containing the original assembly location */
2285 if (!shadow_copy_create_ini (shadow, filename)) {
2286 g_free (shadow);
2287 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
2288 return NULL;
2291 utbuf.actime = src_sbuf.st_atime;
2292 utbuf.modtime = src_sbuf.st_mtime;
2293 utime (shadow, &utbuf);
2295 return shadow;
2297 #endif /* DISABLE_SHADOW_COPY */
2300 * mono_domain_from_appdomain:
2302 MonoDomain *
2303 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
2305 HANDLE_FUNCTION_ENTER ();
2306 MonoDomain *result;
2307 MONO_ENTER_GC_UNSAFE;
2308 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
2309 result = mono_domain_from_appdomain_handle (appdomain);
2310 MONO_EXIT_GC_UNSAFE;
2311 HANDLE_FUNCTION_RETURN_VAL (result);
2314 MonoDomain *
2315 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
2317 HANDLE_FUNCTION_ENTER ();
2318 MonoDomain *dom = NULL;
2319 if (MONO_HANDLE_IS_NULL (appdomain))
2320 goto leave;
2322 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
2323 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
2324 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
2326 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
2327 } else
2328 dom = MONO_HANDLE_GETVAL (appdomain, data);
2330 leave:
2331 HANDLE_FUNCTION_RETURN_VAL (dom);
2335 static gboolean
2336 try_load_from (MonoAssembly **assembly,
2337 const gchar *path1, const gchar *path2,
2338 const gchar *path3, const gchar *path4,
2339 const MonoAssemblyOpenRequest *req)
2341 gchar *fullpath;
2342 gboolean found = FALSE;
2344 *assembly = NULL;
2345 fullpath = g_build_filename (path1, path2, path3, path4, (const char*)NULL);
2347 if (IS_PORTABILITY_SET) {
2348 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
2349 if (new_fullpath) {
2350 g_free (fullpath);
2351 fullpath = new_fullpath;
2352 found = TRUE;
2354 } else
2355 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
2357 if (found) {
2358 *assembly = mono_assembly_request_open (fullpath, req, NULL);
2361 g_free (fullpath);
2362 return (*assembly != NULL);
2365 static MonoAssembly *
2366 real_load (gchar **search_path, const gchar *culture, const gchar *name, const MonoAssemblyOpenRequest *req)
2368 MonoAssembly *result = NULL;
2369 gchar **path;
2370 gchar *filename;
2371 const gchar *local_culture;
2372 gint len;
2374 if (!culture || *culture == '\0') {
2375 local_culture = "";
2376 } else {
2377 local_culture = culture;
2380 filename = g_strconcat (name, ".dll", (const char*)NULL);
2381 len = strlen (filename);
2383 for (path = search_path; *path; path++) {
2384 if (**path == '\0') {
2385 continue; /* Ignore empty ApplicationBase */
2388 /* See test cases in bug #58992 and bug #57710 */
2389 /* 1st try: [culture]/[name].dll (culture may be empty) */
2390 strcpy (filename + len - 4, ".dll");
2391 if (try_load_from (&result, *path, local_culture, "", filename, req))
2392 break;
2394 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2395 strcpy (filename + len - 4, ".exe");
2396 if (try_load_from (&result, *path, local_culture, "", filename, req))
2397 break;
2399 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2400 strcpy (filename + len - 4, ".dll");
2401 if (try_load_from (&result, *path, local_culture, name, filename, req))
2402 break;
2404 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2405 strcpy (filename + len - 4, ".exe");
2406 if (try_load_from (&result, *path, local_culture, name, filename, req))
2407 break;
2410 g_free (filename);
2411 return result;
2414 static char *
2415 get_app_context_base_directory (MonoError *error)
2417 MONO_STATIC_POINTER_INIT (MonoMethod, get_basedir)
2419 ERROR_DECL (local_error);
2420 MonoClass *app_context = mono_class_get_app_context_class ();
2421 g_assert (app_context);
2422 get_basedir = mono_class_get_method_from_name_checked (app_context, "get_BaseDirectory", -1, 0, local_error);
2423 mono_error_assert_ok (local_error);
2425 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_basedir)
2427 HANDLE_FUNCTION_ENTER ();
2429 MonoStringHandle result = MONO_HANDLE_CAST (MonoString, mono_runtime_try_invoke_handle (get_basedir, NULL_HANDLE, NULL, error));
2430 char *base_dir = mono_string_handle_to_utf8 (result, error);
2432 HANDLE_FUNCTION_RETURN_VAL (base_dir);
2436 * Try loading the assembly from ApplicationBase and PrivateBinPath
2437 * and then from assemblies_path if any.
2438 * LOCKING: This is called from the assembly loading code, which means the caller
2439 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2441 static MonoAssembly *
2442 mono_domain_assembly_preload (MonoAssemblyLoadContext *alc,
2443 MonoAssemblyName *aname,
2444 gchar **assemblies_path,
2445 gboolean refonly,
2446 gpointer user_data,
2447 MonoError *error)
2449 MonoDomain *domain = mono_alc_domain (alc);
2450 MonoAssembly *result = NULL;
2451 #ifdef ENABLE_NETCORE
2452 g_assert (alc);
2453 g_assert (domain == mono_domain_get ());
2454 #endif
2456 #ifndef ENABLE_NETCORE
2457 set_domain_search_path (domain);
2458 #endif
2460 MonoAssemblyCandidatePredicate predicate = NULL;
2461 void* predicate_ud = NULL;
2462 if (mono_loader_get_strict_assembly_name_check ()) {
2463 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2464 predicate_ud = aname;
2466 MonoAssemblyOpenRequest req;
2467 mono_assembly_request_prepare_open (&req, refonly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_DEFAULT, alc);
2468 req.request.predicate = predicate;
2469 req.request.predicate_ud = predicate_ud;
2471 #ifdef ENABLE_NETCORE
2472 if (!mono_runtime_get_no_exec ()) {
2473 char *search_path [2];
2474 search_path [1] = NULL;
2476 char *base_dir = get_app_context_base_directory (error);
2477 search_path [0] = base_dir;
2478 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s (%p) ApplicationBase is %s\n", domain->friendly_name, domain, base_dir);
2480 result = real_load (search_path, aname->culture, aname->name, &req);
2482 g_free (base_dir);
2484 #else
2485 if (domain->search_path && domain->search_path [0] != NULL) {
2486 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2487 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2488 for (int i = 0; domain->search_path [i]; i++) {
2489 const char *p = domain->search_path[i];
2490 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2492 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2494 result = real_load (domain->search_path, aname->culture, aname->name, &req);
2496 #endif
2498 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2499 result = real_load (assemblies_path, aname->culture, aname->name, &req);
2502 return result;
2506 * mono_assembly_load_from_assemblies_path:
2508 * \param assemblies_path directories to search for given assembly name, terminated by NULL
2509 * \param aname assembly name to look for
2510 * \param asmctx assembly load context for this load operation
2512 * Given a NULL-terminated array of paths, look for \c name.ext, \c name, \c
2513 * culture/name.ext, \c culture/name/name.ext where \c ext is \c dll and \c
2514 * exe and try to load it in the given assembly load context.
2516 * \returns A \c MonoAssembly if probing was successful, or NULL otherwise.
2518 MonoAssembly*
2519 mono_assembly_load_from_assemblies_path (gchar **assemblies_path, MonoAssemblyName *aname, MonoAssemblyContextKind asmctx)
2521 MonoAssemblyCandidatePredicate predicate = NULL;
2522 void* predicate_ud = NULL;
2523 if (mono_loader_get_strict_assembly_name_check ()) {
2524 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2525 predicate_ud = aname;
2527 MonoAssemblyOpenRequest req;
2528 mono_assembly_request_prepare_open (&req, asmctx, mono_domain_default_alc (mono_domain_get ()));
2529 req.request.predicate = predicate;
2530 req.request.predicate_ud = predicate_ud;
2531 MonoAssembly *result = NULL;
2532 if (assemblies_path && assemblies_path[0] != NULL) {
2533 result = real_load (assemblies_path, aname->culture, aname->name, &req);
2535 return result;
2539 * Check whenever a given assembly was already loaded in the current appdomain.
2541 static MonoAssembly *
2542 mono_domain_assembly_search (MonoAssemblyLoadContext *alc, MonoAssembly *requesting,
2543 MonoAssemblyName *aname,
2544 gboolean refonly,
2545 gboolean postload,
2546 gpointer user_data,
2547 MonoError *error)
2549 g_assert (aname != NULL);
2550 GSList *tmp;
2551 MonoAssembly *ass;
2553 #ifdef ENABLE_NETCORE
2554 const MonoAssemblyNameEqFlags eq_flags = MONO_ANAME_EQ_IGNORE_PUBKEY | MONO_ANAME_EQ_IGNORE_VERSION | MONO_ANAME_EQ_IGNORE_CASE;
2556 mono_alc_assemblies_lock (alc);
2557 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
2558 ass = (MonoAssembly *)tmp->data;
2559 g_assert (ass != NULL);
2560 // FIXME: Can dynamic assemblies match here for netcore?
2561 if (assembly_is_dynamic (ass) || !mono_assembly_names_equal_flags (aname, &ass->aname, eq_flags))
2562 continue;
2564 mono_alc_assemblies_unlock (alc);
2565 return ass;
2567 mono_alc_assemblies_unlock (alc);
2568 #else
2569 MonoDomain *domain = mono_alc_domain (alc);
2571 const gboolean strong_name = aname->public_key_token[0] != 0;
2572 /* If it's not a strong name, any version that has the right simple
2573 * name is good enough to satisfy the request. .NET Framework also
2574 * ignores case differences in this case. */
2575 const MonoAssemblyNameEqFlags eq_flags = (MonoAssemblyNameEqFlags)(strong_name ? MONO_ANAME_EQ_IGNORE_CASE :
2576 (MONO_ANAME_EQ_IGNORE_PUBKEY | MONO_ANAME_EQ_IGNORE_VERSION | MONO_ANAME_EQ_IGNORE_CASE));
2578 mono_domain_assemblies_lock (domain);
2579 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2580 ass = (MonoAssembly *)tmp->data;
2581 g_assert (ass != NULL);
2582 /* Dynamic assemblies can't match here in MS.NET */
2583 gboolean ass_ref_only = mono_asmctx_get_kind (&ass->context) == MONO_ASMCTX_REFONLY;
2584 if (assembly_is_dynamic (ass) || refonly != ass_ref_only || !mono_assembly_names_equal_flags (aname, &ass->aname, eq_flags))
2585 continue;
2587 mono_domain_assemblies_unlock (domain);
2588 return ass;
2590 mono_domain_assemblies_unlock (domain);
2591 #endif
2593 return NULL;
2596 #if ENABLE_NETCORE
2597 MonoReflectionAssemblyHandle
2598 ves_icall_System_Reflection_Assembly_InternalLoad (MonoStringHandle name_handle, MonoStackCrawlMark *stack_mark, gpointer load_Context, MonoError *error)
2600 error_init (error);
2601 MonoAssembly *ass = NULL;
2602 MonoAssemblyName aname;
2603 MonoAssemblyByNameRequest req;
2604 MonoAssemblyContextKind asmctx;
2605 MonoImageOpenStatus status = MONO_IMAGE_OK;
2606 gboolean parsed;
2607 char *name;
2609 MonoAssembly *requesting_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2610 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)load_Context;
2612 if (!alc)
2613 alc = mono_assembly_get_alc (requesting_assembly);
2614 if (!alc)
2615 g_assert_not_reached ();
2617 MonoDomain *domain = mono_alc_domain (alc);
2618 g_assert (alc);
2619 asmctx = MONO_ASMCTX_DEFAULT;
2620 mono_assembly_request_prepare_byname (&req, asmctx, alc);
2621 req.basedir = NULL;
2622 /* Everything currently goes through this function, and the postload hook (aka the AppDomain.AssemblyResolve event)
2623 * is triggered under some scenarios. It's not completely obvious to me in what situations (if any) this should be disabled,
2624 * other than for corlib satellite assemblies (which I've dealt with further down the call stack).
2626 //req.no_postload_search = TRUE;
2627 req.requesting_assembly = requesting_assembly;
2629 name = mono_string_handle_to_utf8 (name_handle, error);
2630 goto_if_nok (error, fail);
2631 parsed = mono_assembly_name_parse (name, &aname);
2632 g_free (name);
2633 if (!parsed)
2634 goto fail;
2636 MonoAssemblyCandidatePredicate predicate = NULL;
2637 void* predicate_ud = NULL;
2638 if (mono_loader_get_strict_assembly_name_check ()) {
2639 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2640 predicate_ud = &aname;
2642 req.request.predicate = predicate;
2643 req.request.predicate_ud = predicate_ud;
2645 ass = mono_assembly_request_byname (&aname, &req, &status);
2646 if (!ass)
2647 goto fail;
2649 MonoReflectionAssemblyHandle refass;
2650 refass = mono_assembly_get_object_handle (domain, ass, error);
2651 goto_if_nok (error, fail);
2652 return refass;
2654 fail:
2655 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2657 #endif
2659 #ifndef ENABLE_NETCORE
2660 MonoReflectionAssemblyHandle
2661 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoStackCrawlMark *stack_mark, MonoError *error)
2663 error_init (error);
2664 MonoDomain *domain = mono_domain_get ();
2665 char *name, *filename;
2666 MonoImageOpenStatus status = MONO_IMAGE_OK;
2667 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2669 name = NULL;
2671 if (MONO_HANDLE_IS_NULL (fname)) {
2672 mono_error_set_argument_null (error, "assemblyFile", "");
2673 goto leave;
2676 name = filename = mono_string_handle_to_utf8 (fname, error);
2677 goto_if_nok (error, leave);
2679 MonoAssembly *requesting_assembly;
2680 requesting_assembly = NULL;
2681 if (!refOnly)
2682 requesting_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2684 MonoAssembly *ass;
2685 MonoAssemblyOpenRequest req;
2686 mono_assembly_request_prepare_open (&req, refOnly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_LOADFROM, mono_domain_default_alc (domain));
2687 req.requesting_assembly = requesting_assembly;
2688 ass = mono_assembly_request_open (filename, &req, &status);
2690 if (!ass) {
2691 if (status == MONO_IMAGE_IMAGE_INVALID)
2692 mono_error_set_bad_image_by_name (error, name, "Invalid Image");
2693 else
2694 mono_error_set_file_not_found (error, name, "Invalid Image");
2695 goto leave;
2698 result = mono_assembly_get_object_handle (domain, ass, error);
2700 leave:
2701 g_free (name);
2702 return result;
2704 #endif
2706 static
2707 MonoAssembly *
2708 mono_alc_load_file (MonoAssemblyLoadContext *alc, MonoStringHandle fname, MonoAssembly *executing_assembly, MonoAssemblyContextKind asmctx, MonoError *error)
2710 MonoAssembly *ass = NULL;
2711 HANDLE_FUNCTION_ENTER ();
2712 char *filename = NULL;
2713 if (MONO_HANDLE_IS_NULL (fname)) {
2714 mono_error_set_argument_null (error, "assemblyFile", "");
2715 goto leave;
2718 filename = mono_string_handle_to_utf8 (fname, error);
2719 goto_if_nok (error, leave);
2721 if (!g_path_is_absolute (filename)) {
2722 mono_error_set_argument (error, "assemblyFile", "Absolute path information is required.");
2723 goto leave;
2726 MonoImageOpenStatus status;
2727 MonoAssemblyOpenRequest req;
2728 mono_assembly_request_prepare_open (&req, asmctx, alc);
2729 req.requesting_assembly = executing_assembly;
2730 ass = mono_assembly_request_open (filename, &req, &status);
2731 if (!ass) {
2732 if (status == MONO_IMAGE_IMAGE_INVALID)
2733 mono_error_set_bad_image_by_name (error, filename, "Invalid Image");
2734 else
2735 mono_error_set_file_not_found (error, filename, "Invalid Image");
2738 leave:
2739 g_free (filename);
2740 HANDLE_FUNCTION_RETURN_VAL (ass);
2743 #ifndef ENABLE_NETCORE
2744 MonoReflectionAssemblyHandle
2745 ves_icall_System_Reflection_Assembly_LoadFile_internal (MonoStringHandle fname, MonoStackCrawlMark *stack_mark, MonoError *error)
2747 MonoDomain *domain = mono_domain_get ();
2748 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2749 MonoAssembly *executing_assembly;
2750 executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2751 MonoAssembly *ass = mono_alc_load_file (mono_domain_default_alc (domain), fname, executing_assembly, MONO_ASMCTX_INDIVIDUAL, error);
2752 goto_if_nok (error, leave);
2754 result = mono_assembly_get_object_handle (domain, ass, error);
2755 leave:
2756 return result;
2758 #else
2759 MonoReflectionAssemblyHandle
2760 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalLoadFile (gpointer alc_ptr, MonoStringHandle fname, MonoStackCrawlMark *stack_mark, MonoError *error)
2762 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2763 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)alc_ptr;
2764 MonoDomain *domain = mono_alc_domain (alc);
2766 MonoAssembly *executing_assembly;
2767 executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2768 MonoAssembly *ass = mono_alc_load_file (alc, fname, executing_assembly, mono_alc_is_default (alc) ? MONO_ASMCTX_LOADFROM : MONO_ASMCTX_INDIVIDUAL, error);
2769 goto_if_nok (error, leave);
2771 result = mono_assembly_get_object_handle (domain, ass, error);
2773 leave:
2774 return result;
2776 #endif
2778 static MonoAssembly*
2779 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);
2781 #ifdef ENABLE_NETCORE
2782 MonoReflectionAssemblyHandle
2783 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)
2785 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)native_alc;
2786 MonoDomain *domain = mono_alc_domain (alc);
2787 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2788 MonoAssembly *assm = NULL;
2789 assm = mono_alc_load_raw_bytes (alc, (guint8 *)raw_assembly_ptr, raw_assembly_len, (guint8 *)raw_symbols_ptr, raw_symbols_len, FALSE, error);
2790 goto_if_nok (error, leave);
2792 result = mono_assembly_get_object_handle (domain, assm, error);
2794 leave:
2795 return result;
2797 #else
2798 MonoReflectionAssemblyHandle
2799 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2800 MonoArrayHandle raw_assembly,
2801 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2802 MonoBoolean refonly,
2803 MonoError *error)
2805 MonoAssembly *ass;
2806 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2807 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2808 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2810 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2811 guint8 *assembly_data = (guint8*) g_try_malloc (raw_assembly_len);
2812 if (!assembly_data) {
2813 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2814 return refass;
2816 uint32_t gchandle;
2817 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2818 memcpy (assembly_data, raw_data, raw_assembly_len);
2819 mono_gchandle_free_internal (gchandle); /* unpin */
2820 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2822 MonoAssemblyLoadContext *alc = mono_domain_default_alc (domain);
2824 mono_byte *raw_symbol_data = NULL;
2825 guint32 symbol_len = 0;
2826 uint32_t symbol_gchandle = 0;
2827 if (!MONO_HANDLE_IS_NULL (raw_symbol_store)) {
2828 symbol_len = mono_array_handle_length (raw_symbol_store);
2829 raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2832 ass = mono_alc_load_raw_bytes (alc, assembly_data, raw_assembly_len, raw_symbol_data, symbol_len, refonly, error);
2833 mono_gchandle_free_internal (symbol_gchandle);
2834 goto_if_nok (error, leave);
2836 refass = mono_assembly_get_object_handle (domain, ass, error);
2837 if (!MONO_HANDLE_IS_NULL (refass))
2838 MONO_HANDLE_SET (refass, evidence, evidence);
2840 leave:
2841 return refass;
2843 #endif /* ENABLE_NETCORE */
2845 static MonoAssembly*
2846 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)
2848 MonoAssembly *ass = NULL;
2849 MonoImageOpenStatus status;
2850 MonoImage *image = mono_image_open_from_data_internal (alc, (char*)assembly_data, raw_assembly_len, FALSE, NULL, refonly, FALSE, NULL);
2852 if (!image) {
2853 mono_error_set_bad_image_by_name (error, "In memory assembly", "0x%p", assembly_data);
2854 return ass;
2857 if (raw_symbol_data)
2858 mono_debug_open_image_from_memory (image, raw_symbol_data, raw_symbol_len);
2860 MonoAssembly* redirected_asm = NULL;
2861 MonoImageOpenStatus new_status = MONO_IMAGE_OK;
2862 // http://blogs.microsoft.co.il/sasha/2010/06/09/assemblyreflectiononlyload-ignores-assembly-binding-redirects/
2863 if (!refonly && (redirected_asm = mono_assembly_binding_applies_to_image (alc, image, &new_status))) {
2864 mono_image_close (image);
2865 image = redirected_asm->image;
2866 mono_image_addref (image); /* so that mono_image close, below, has something to do */
2867 } else if (new_status != MONO_IMAGE_OK) {
2868 mono_image_close (image);
2869 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);
2870 return ass;
2873 MonoAssemblyLoadRequest req;
2874 mono_assembly_request_prepare_load (&req, refonly? MONO_ASMCTX_REFONLY : MONO_ASMCTX_INDIVIDUAL, alc);
2875 ass = mono_assembly_request_load_from (image, "", &req, &status);
2877 if (!ass) {
2878 mono_image_close (image);
2879 mono_error_set_bad_image_by_name (error, "In Memory assembly", "0x%p", assembly_data);
2880 return ass;
2883 /* Clear the reference added by mono_image_open_from_data_internal above */
2884 mono_image_close (image);
2886 return ass;
2889 #ifndef ENABLE_NETCORE
2890 MonoReflectionAssemblyHandle
2891 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoStackCrawlMark *stack_mark, MonoError *error)
2893 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2894 MonoImageOpenStatus status = MONO_IMAGE_OK;
2895 MonoAssembly *ass;
2896 MonoAssemblyName aname;
2897 gchar *name = NULL;
2898 gboolean parsed;
2900 g_assert (!MONO_HANDLE_IS_NULL (assRef));
2902 name = mono_string_handle_to_utf8 (assRef, error);
2903 goto_if_nok (error, fail);
2904 parsed = mono_assembly_name_parse (name, &aname);
2905 g_free (name);
2907 if (!parsed) {
2908 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2909 /* This is a parse error... */
2910 if (!refOnly) {
2911 MonoAssembly *assm = mono_try_assembly_resolve_handle (mono_domain_default_alc (domain), assRef, NULL, refOnly, error);
2912 goto_if_nok (error, fail);
2913 if (assm) {
2914 refass = mono_assembly_get_object_handle (domain, assm, error);
2915 goto_if_nok (error, fail);
2918 return refass;
2921 MonoAssemblyContextKind asmctx;
2922 asmctx = refOnly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_DEFAULT;
2923 const char *basedir;
2924 basedir = NULL;
2925 if (!refOnly) {
2926 /* Determine if the current assembly is in LoadFrom context.
2927 * If it is, we must include the executing assembly's basedir
2928 * when probing for the given assembly name, and also load the
2929 * requested assembly in LoadFrom context.
2931 MonoAssembly *executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2932 if (executing_assembly && mono_asmctx_get_kind (&executing_assembly->context) == MONO_ASMCTX_LOADFROM) {
2933 asmctx = MONO_ASMCTX_LOADFROM;
2934 basedir = executing_assembly->basedir;
2939 MonoAssemblyByNameRequest req;
2940 mono_assembly_request_prepare_byname (&req, asmctx, mono_domain_default_alc (domain));
2941 req.basedir = basedir;
2942 req.no_postload_search = TRUE;
2943 ass = mono_assembly_request_byname (&aname, &req, &status);
2944 mono_assembly_name_free_internal (&aname);
2946 if (!ass) {
2947 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2948 if (!refOnly) {
2949 ass = mono_try_assembly_resolve_handle (mono_domain_default_alc (domain), assRef, NULL, refOnly, error);
2950 goto_if_nok (error, fail);
2952 if (!ass)
2953 goto fail;
2956 g_assert (ass);
2957 MonoReflectionAssemblyHandle refass;
2958 refass = mono_assembly_get_object_handle (domain, ass, error);
2959 goto_if_nok (error, fail);
2961 MONO_HANDLE_SET (refass, evidence, evidence);
2963 return refass;
2964 fail:
2965 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2968 void
2969 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2971 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2973 if (NULL == domain) {
2974 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2975 return;
2978 if (domain == mono_get_root_domain ()) {
2979 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2980 return;
2984 * Unloading seems to cause problems when running NUnit/NAnt, hence
2985 * this workaround.
2987 if (g_hasenv ("MONO_NO_UNLOAD"))
2988 return;
2990 MonoException *exc = NULL;
2991 mono_domain_try_unload (domain, (MonoObject**)&exc);
2992 if (exc)
2993 mono_error_set_exception_instance (error, exc);
2996 MonoBoolean
2997 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2999 MonoDomain *domain = mono_domain_get_by_id (domain_id);
3001 if (!domain)
3002 return TRUE;
3004 return mono_domain_is_unloading (domain);
3007 void
3008 ves_icall_System_AppDomain_DoUnhandledException (MonoAppDomainHandle ad, MonoExceptionHandle exc, MonoError *error)
3010 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
3011 mono_error_assert_ok (error);
3014 gint32
3015 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
3016 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
3017 MonoError *error)
3019 MonoImage *image;
3020 MonoMethod *method;
3022 g_assert (!MONO_HANDLE_IS_NULL (refass));
3023 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
3024 image = assembly->image;
3025 g_assert (image);
3027 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
3029 if (!method)
3030 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
3032 if (MONO_HANDLE_IS_NULL (args)) {
3033 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
3034 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
3035 mono_error_assert_ok (error);
3038 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
3039 return res;
3042 MonoAppDomainHandle
3043 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
3045 error_init (error);
3046 MonoDomain *old_domain = mono_domain_get ();
3048 if (!mono_domain_set_fast (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
3049 mono_error_set_appdomain_unloaded (error);
3050 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
3053 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
3056 MonoAppDomainHandle
3057 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
3059 MonoDomain *current_domain = mono_domain_get ();
3060 MonoDomain *domain = mono_domain_get_by_id (domainid);
3062 if (!domain || !mono_domain_set_fast (domain, FALSE)) {
3063 mono_error_set_appdomain_unloaded (error);
3064 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
3067 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
3070 void
3071 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
3073 error_init (error);
3074 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
3077 void
3078 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
3080 error_init (error);
3081 MonoDomain *domain = mono_domain_get_by_id (domain_id);
3083 if (!domain) {
3085 * Raise an exception to prevent the managed code from executing a pop
3086 * later.
3088 mono_error_set_appdomain_unloaded (error);
3089 return;
3092 mono_thread_push_appdomain_ref (domain);
3095 void
3096 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
3098 error_init (error);
3099 mono_thread_pop_appdomain_ref ();
3102 MonoAppContextHandle
3103 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
3105 error_init (error);
3106 return mono_context_get_handle ();
3109 MonoAppContextHandle
3110 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
3112 error_init (error);
3113 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
3116 MonoAppContextHandle
3117 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
3119 error_init (error);
3120 MonoAppContextHandle old_context = mono_context_get_handle ();
3122 mono_context_set_handle (mc);
3124 return old_context;
3127 MonoStringHandle
3128 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
3130 error_init (error);
3131 MonoDomain* mono_root_domain = mono_get_root_domain ();
3132 mono_domain_lock (mono_root_domain);
3133 if (process_guid_set) {
3134 mono_domain_unlock (mono_root_domain);
3135 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
3137 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
3138 memcpy (process_guid, mono_string_chars_internal (MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
3139 mono_gchandle_free_internal (gchandle);
3140 process_guid_set = TRUE;
3141 mono_domain_unlock (mono_root_domain);
3142 return newguid;
3144 #endif
3147 * mono_domain_is_unloading:
3149 gboolean
3150 mono_domain_is_unloading (MonoDomain *domain)
3152 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
3153 return TRUE;
3154 else
3155 return FALSE;
3158 #ifndef ENABLE_NETCORE
3160 static void
3161 clear_cached_vtable (MonoVTable *vtable)
3163 MonoClass *klass = vtable->klass;
3164 MonoDomain *domain = vtable->domain;
3165 MonoClassRuntimeInfo *runtime_info;
3166 void *data;
3168 runtime_info = m_class_get_runtime_info (klass);
3169 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
3170 runtime_info->domain_vtables [domain->domain_id] = NULL;
3171 if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable)))
3172 mono_gc_free_fixed (data);
3175 static G_GNUC_UNUSED void
3176 zero_static_data (MonoVTable *vtable)
3178 MonoClass *klass = vtable->klass;
3179 void *data;
3181 if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable)))
3182 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
3185 typedef struct unload_data {
3186 gboolean done;
3187 MonoDomain *domain;
3188 char *failure_reason;
3189 gint32 refcount;
3190 } unload_data;
3192 static void
3193 unload_data_unref (unload_data *data)
3195 if (!data)
3196 return;
3197 gint32 count;
3198 do {
3199 mono_atomic_load_acquire (count, gint32, &data->refcount);
3200 g_assert (count >= 1 && count <= 2);
3201 if (count == 1) {
3202 g_free (data);
3203 return;
3205 } while (mono_atomic_cas_i32 (&data->refcount, count - 1, count) != count);
3208 static void
3209 deregister_reflection_info_roots_from_list (MonoImage *image)
3211 GSList *list = image->reflection_info_unregister_classes;
3213 while (list) {
3214 MonoClass *klass = (MonoClass *)list->data;
3216 mono_class_free_ref_info (klass);
3218 list = list->next;
3221 image->reflection_info_unregister_classes = NULL;
3224 static void
3225 deregister_reflection_info_roots (MonoDomain *domain)
3227 GSList *list;
3229 mono_domain_assemblies_lock (domain);
3230 for (list = domain->domain_assemblies; list; list = list->next) {
3231 MonoAssembly *assembly = (MonoAssembly *)list->data;
3232 MonoImage *image = assembly->image;
3233 int i;
3236 * No need to take the image lock here since dynamic images are appdomain bound and
3237 * at this point the mutator is gone. Taking the image lock here would mean
3238 * promoting it from a simple lock to a complex lock, which we better avoid if
3239 * possible.
3241 if (image_is_dynamic (image))
3242 deregister_reflection_info_roots_from_list (image);
3244 for (i = 0; i < image->module_count; ++i) {
3245 MonoImage *module = image->modules [i];
3246 if (module && image_is_dynamic (module))
3247 deregister_reflection_info_roots_from_list (module);
3250 mono_domain_assemblies_unlock (domain);
3253 static gsize WINAPI
3254 unload_thread_main (void *arg)
3256 unload_data *data = (unload_data*)arg;
3257 MonoDomain *domain = data->domain;
3258 int i;
3259 gsize result = 1; // failure
3261 mono_thread_set_name_constant_ignore_error (mono_thread_internal_current (), "Domain unloader", MonoSetThreadNameFlag_Permanent);
3264 * FIXME: Abort our parent thread last, so we can return a failure
3265 * indication if aborting times out.
3267 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
3268 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
3269 goto failure;
3272 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
3273 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
3274 goto failure;
3277 /* Finalize all finalizable objects in the doomed appdomain */
3278 if (!mono_domain_finalize (domain, -1)) {
3279 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
3280 goto failure;
3283 /* Clear references to our vtables in class->runtime_info.
3284 * We also hold the loader lock because we're going to change
3285 * class->runtime_info.
3288 mono_loader_lock ();
3289 mono_domain_lock (domain);
3291 * We need to make sure that we don't have any remsets
3292 * pointing into static data of the to-be-freed domain because
3293 * at the next collections they would be invalid. So what we
3294 * do is we first zero all static data and then do a minor
3295 * collection. Because all references in the static data will
3296 * now be null we won't do any unnecessary copies and after
3297 * the collection there won't be any more remsets.
3299 for (i = 0; i < domain->class_vtable_array->len; ++i)
3300 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
3301 mono_gc_collect (0);
3302 for (i = 0; i < domain->class_vtable_array->len; ++i)
3303 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
3304 deregister_reflection_info_roots (domain);
3306 mono_assembly_cleanup_domain_bindings (domain->domain_id);
3308 mono_domain_unlock (domain);
3309 mono_loader_unlock ();
3311 domain->state = MONO_APPDOMAIN_UNLOADED;
3313 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
3315 /* remove from the handle table the items related to this domain */
3316 mono_gchandle_free_domain (domain);
3318 mono_domain_free (domain, FALSE);
3320 mono_gc_collect (mono_gc_max_generation ());
3322 result = 0; // success
3323 exit:
3324 mono_atomic_store_release (&data->done, TRUE);
3325 unload_data_unref (data);
3326 return result;
3328 failure:
3329 result = 1;
3330 goto exit;
3334 * mono_domain_unload:
3335 * \param domain The domain to unload
3337 * Unloads an appdomain. Follows the process outlined in the comment
3338 * for \c mono_domain_try_unload.
3340 void
3341 mono_domain_unload (MonoDomain *domain)
3343 MONO_ENTER_GC_UNSAFE;
3344 MonoObject *exc = NULL;
3345 mono_domain_try_unload (domain, &exc);
3346 MONO_EXIT_GC_UNSAFE;
3349 static MonoThreadInfoWaitRet
3350 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
3352 MonoThreadInfoWaitRet result;
3354 MONO_ENTER_GC_SAFE;
3355 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
3356 MONO_EXIT_GC_SAFE;
3358 return result;
3362 * mono_domain_unload:
3363 * \param domain The domain to unload
3364 * \param exc Exception information
3366 * Unloads an appdomain. Follows the process outlined in:
3367 * http://blogs.gotdotnet.com/cbrumme
3369 * If doing things the 'right' way is too hard or complex, we do it the
3370 * 'simple' way, which means do everything needed to avoid crashes and
3371 * memory leaks, but not much else.
3373 * It is required to pass a valid reference to the exc argument, upon return
3374 * from this function *exc will be set to the exception thrown, if any.
3376 * If this method is not called from an icall (embedded scenario for instance),
3377 * it must not be called with any managed frames on the stack, since the unload
3378 * process could end up trying to abort the current thread.
3380 void
3381 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
3383 HANDLE_FUNCTION_ENTER ();
3384 ERROR_DECL (error);
3385 MonoThreadHandle *thread_handle = NULL;
3386 MonoAppDomainState prev_state;
3387 MonoMethod *method;
3388 unload_data *thread_data = NULL;
3389 MonoInternalThreadHandle internal;
3390 MonoDomain *caller_domain = mono_domain_get ();
3392 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
3394 /* Atomically change our state to UNLOADING */
3395 prev_state = (MonoAppDomainState)mono_atomic_cas_i32 ((gint32*)&domain->state,
3396 MONO_APPDOMAIN_UNLOADING_START,
3397 MONO_APPDOMAIN_CREATED);
3398 if (prev_state != MONO_APPDOMAIN_CREATED) {
3399 switch (prev_state) {
3400 case MONO_APPDOMAIN_UNLOADING_START:
3401 case MONO_APPDOMAIN_UNLOADING:
3402 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
3403 goto exit;
3404 case MONO_APPDOMAIN_UNLOADED:
3405 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
3406 goto exit;
3407 default:
3408 g_warning ("Invalid appdomain state %d", prev_state);
3409 g_assert_not_reached ();
3413 mono_domain_set_fast (domain, FALSE);
3414 /* Notify OnDomainUnload listeners */
3415 method = mono_class_get_method_from_name_checked (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1, 0, error);
3416 g_assert (method);
3418 mono_runtime_try_invoke (method, domain->domain, NULL, exc, error);
3420 if (!is_ok (error)) {
3421 if (*exc)
3422 mono_error_cleanup (error);
3423 else
3424 *exc = (MonoObject*)mono_error_convert_to_exception (error);
3427 if (*exc) {
3428 /* Roll back the state change */
3429 domain->state = MONO_APPDOMAIN_CREATED;
3430 mono_domain_set_fast (caller_domain, FALSE);
3431 goto exit;
3433 mono_domain_set_fast (caller_domain, FALSE);
3435 thread_data = g_new0 (unload_data, 1);
3436 thread_data->domain = domain;
3437 thread_data->failure_reason = NULL;
3438 thread_data->done = FALSE;
3439 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
3441 /*The managed callback finished successfully, now we start tearing down the appdomain*/
3442 domain->state = MONO_APPDOMAIN_UNLOADING;
3444 * First we create a separate thread for unloading, since
3445 * we might have to abort some threads, including the current one.
3447 * Have to attach to the runtime so shutdown can wait for this thread.
3449 * Force it to be attached to avoid racing during shutdown.
3451 internal = mono_thread_create_internal_handle (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, error);
3452 mono_error_assert_ok (error);
3454 thread_handle = mono_threads_open_thread_handle (MONO_HANDLE_GETVAL (internal, handle));
3456 /* Wait for the thread */
3457 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
3458 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
3459 /* The unload thread tries to abort us */
3460 /* The icall wrapper will execute the abort */
3461 goto exit;
3465 if (thread_data->failure_reason) {
3466 /* Roll back the state change */
3467 domain->state = MONO_APPDOMAIN_CREATED;
3469 g_warning ("%s", thread_data->failure_reason);
3471 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
3473 g_free (thread_data->failure_reason);
3474 thread_data->failure_reason = NULL;
3477 exit:
3478 mono_threads_close_thread_handle (thread_handle);
3479 unload_data_unref (thread_data);
3480 HANDLE_FUNCTION_RETURN ();
3483 #endif /* ENABLE_NETCORE */
3485 #ifdef ENABLE_NETCORE
3487 /* Remember properties so they can be be installed in AppContext during runtime init */
3488 void
3489 mono_runtime_register_appctx_properties (int nprops, const char **keys, const char **values)
3491 n_appctx_props = nprops;
3492 appctx_keys = g_new0 (gunichar2*, nprops);
3493 appctx_values = g_new0 (gunichar2*, nprops);
3495 for (int i = 0; i < nprops; ++i) {
3496 appctx_keys [i] = g_utf8_to_utf16 (keys [i], strlen (keys [i]), NULL, NULL, NULL);
3497 appctx_values [i] = g_utf8_to_utf16 (values [i], strlen (values [i]), NULL, NULL, NULL);
3501 static GENERATE_GET_CLASS_WITH_CACHE (appctx, "System", "AppContext")
3503 /* Install properties into AppContext */
3504 void
3505 mono_runtime_install_appctx_properties (void)
3507 ERROR_DECL (error);
3508 gpointer args [3];
3510 MonoMethod *setup = mono_class_get_method_from_name_checked (mono_class_get_appctx_class (), "Setup", 3, 0, error);
3511 g_assert (setup);
3513 // FIXME: TRUSTED_PLATFORM_ASSEMBLIES is very large
3515 /* internal static unsafe void Setup(char** pNames, char** pValues, int count) */
3516 args [0] = appctx_keys;
3517 args [1] = appctx_values;
3518 args [2] = &n_appctx_props;
3520 mono_runtime_invoke_checked (setup, NULL, args, error);
3521 mono_error_assert_ok (error);
3523 /* No longer needed */
3524 for (int i = 0; i < n_appctx_props; ++i) {
3525 g_free (appctx_keys [i]);
3526 g_free (appctx_values [i]);
3528 g_free (appctx_keys);
3529 g_free (appctx_values);
3530 appctx_keys = NULL;
3531 appctx_values = NULL;
3534 #endif