[Mono.Runtime.Tests] Exclude simd tests
[mono-project.git] / mono / metadata / appdomain.c
blobd3467bef69b0a91d83d1449b66e10b98393b50c7
1 /**
2 * \file
3 * AppDomain functions
5 * Authors:
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Patrik Torstensson
8 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2012 Xamarin Inc
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #undef ASSEMBLY_LOAD_DEBUG
16 #include <config.h>
17 #include <glib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <time.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_UTIME_H
30 #include <utime.h>
31 #else
32 #ifdef HAVE_SYS_UTIME_H
33 #include <sys/utime.h>
34 #endif
35 #endif
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/object.h>
39 #include <mono/metadata/appdomain-icalls.h>
40 #include <mono/metadata/class-init.h>
41 #include <mono/metadata/domain-internals.h>
42 #include "mono/metadata/metadata-internals.h"
43 #include <mono/metadata/assembly-internals.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/exception-internals.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/mono-gc.h>
50 #include <mono/metadata/marshal.h>
51 #include <mono/metadata/marshal-internals.h>
52 #include <mono/metadata/monitor.h>
53 #include <mono/metadata/mono-debug.h>
54 #include <mono/metadata/attach.h>
55 #include <mono/metadata/w32file.h>
56 #include <mono/metadata/lock-tracer.h>
57 #include <mono/metadata/console-io.h>
58 #include <mono/metadata/threads-types.h>
59 #include <mono/metadata/tokentype.h>
60 #include <mono/metadata/profiler-private.h>
61 #include <mono/metadata/reflection-internals.h>
62 #include <mono/metadata/abi-details.h>
63 #include <mono/metadata/w32socket.h>
64 #include <mono/utils/mono-uri.h>
65 #include <mono/utils/mono-logger-internals.h>
66 #include <mono/utils/mono-path.h>
67 #include <mono/utils/mono-stdlib.h>
68 #include <mono/utils/mono-io-portability.h>
69 #include <mono/utils/mono-error-internals.h>
70 #include <mono/utils/atomic.h>
71 #include <mono/utils/mono-memory-model.h>
72 #include <mono/utils/mono-threads.h>
73 #include <mono/metadata/w32handle.h>
74 #include <mono/metadata/w32error.h>
75 #include <mono/utils/w32api.h>
76 #ifdef HOST_WIN32
77 #include <direct.h>
78 #endif
79 #include "object-internals.h"
80 #include "icall-decl.h"
82 typedef struct
84 int runtime_count;
85 int assemblybinding_count;
86 MonoDomain *domain;
87 gchar *filename;
88 } RuntimeConfig;
90 static gunichar2 process_guid [36];
91 static gboolean process_guid_set = FALSE;
93 static gboolean no_exec = FALSE;
95 static const char *
96 mono_check_corlib_version_internal (void);
98 static MonoAssembly *
99 mono_domain_assembly_preload (MonoAssemblyName *aname,
100 gchar **assemblies_path,
101 gpointer user_data);
103 static MonoAssembly *
104 mono_domain_assembly_search (MonoAssemblyName *aname,
105 gpointer user_data);
107 static void
108 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
110 static gboolean
111 mono_domain_asmctx_from_path (const char *fname, MonoAssembly *requesting_assembly, gpointer user_data, MonoAssemblyContextKind *out_asmctx);
113 static void
114 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
116 static MonoAppDomainHandle
117 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
119 static MonoDomain *
120 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
123 static void
124 mono_context_set_default_context (MonoDomain *domain);
126 static char *
127 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
129 static MonoLoadFunc load_function = NULL;
131 /* Lazy class loading functions */
132 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
134 GENERATE_GET_CLASS_WITH_CACHE (appdomain, MONO_APPDOMAIN_CLASS_NAME_SPACE, MONO_APPDOMAIN_CLASS_NAME);
135 GENERATE_GET_CLASS_WITH_CACHE (appdomain_setup, MONO_APPDOMAIN_SETUP_CLASS_NAME_SPACE, MONO_APPDOMAIN_SETUP_CLASS_NAME);
137 static MonoDomain *
138 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
140 static void
141 mono_error_set_appdomain_unloaded (MonoError *error)
143 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
146 void
147 mono_install_runtime_load (MonoLoadFunc func)
149 load_function = func;
152 MonoDomain*
153 mono_runtime_load (const char *filename, const char *runtime_version)
155 g_assert (load_function);
156 return load_function (filename, runtime_version);
160 * mono_runtime_set_no_exec:
162 * Instructs the runtime to operate in static mode, i.e. avoid/do not
163 * allow managed code execution. This is useful for running the AOT
164 * compiler on platforms which allow full-aot execution only. This
165 * should be called before mono_runtime_init ().
167 void
168 mono_runtime_set_no_exec (gboolean val)
170 no_exec = val;
174 * mono_runtime_get_no_exec:
176 * If true, then the runtime will not allow managed code execution.
178 gboolean
179 mono_runtime_get_no_exec (void)
181 return no_exec;
184 static void
185 create_domain_objects (MonoDomain *domain)
187 HANDLE_FUNCTION_ENTER ();
188 ERROR_DECL (error);
190 MonoDomain *old_domain = mono_domain_get ();
191 MonoStringHandle arg;
192 MonoVTable *string_vt;
193 MonoClassField *string_empty_fld;
195 if (domain != old_domain) {
196 mono_thread_push_appdomain_ref (domain);
197 mono_domain_set_internal_with_options (domain, FALSE);
201 * Initialize String.Empty. This enables the removal of
202 * the static cctor of the String class.
204 string_vt = mono_class_vtable_checked (domain, mono_defaults.string_class, error);
205 mono_error_assert_ok (error);
206 string_empty_fld = mono_class_get_field_from_name_full (mono_defaults.string_class, "Empty", NULL);
207 g_assert (string_empty_fld);
208 MonoStringHandle empty_str = mono_string_new_handle (domain, "", error);
209 mono_error_assert_ok (error);
210 empty_str = mono_string_intern_checked (empty_str, error);
211 mono_error_assert_ok (error);
212 mono_field_static_set_value_internal (string_vt, string_empty_fld, MONO_HANDLE_RAW (empty_str));
213 domain->empty_string = MONO_HANDLE_RAW (empty_str);
216 * Create an instance early since we can't do it when there is no memory.
218 arg = mono_string_new_handle (domain, "Out of memory", error);
219 mono_error_assert_ok (error);
220 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));
221 mono_error_assert_ok (error);
224 * These two are needed because the signal handlers might be executing on
225 * an alternate stack, and Boehm GC can't handle that.
227 arg = mono_string_new_handle (domain, "A null value was found where an object instance was required", error);
228 mono_error_assert_ok (error);
229 domain->null_reference_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL_HANDLE_STRING, error));
230 mono_error_assert_ok (error);
231 arg = mono_string_new_handle (domain, "The requested operation caused a stack overflow.", error);
232 mono_error_assert_ok (error);
233 domain->stack_overflow_ex = MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL_HANDLE_STRING, error));
234 mono_error_assert_ok (error);
236 /*The ephemeron tombstone i*/
237 domain->ephemeron_tombstone = MONO_HANDLE_RAW (mono_object_new_handle (domain, mono_defaults.object_class, error));
238 mono_error_assert_ok (error);
240 if (domain != old_domain) {
241 mono_thread_pop_appdomain_ref ();
242 mono_domain_set_internal_with_options (old_domain, FALSE);
246 * This class is used during exception handling, so initialize it here, to prevent
247 * stack overflows while handling stack overflows.
249 mono_class_init_internal (mono_class_create_array (mono_defaults.int_class, 1));
250 HANDLE_FUNCTION_RETURN ();
254 * mono_runtime_init:
255 * \param domain domain returned by \c mono_init
257 * Initialize the core AppDomain: this function will run also some
258 * IL initialization code, so it needs the execution engine to be fully
259 * operational.
261 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
262 * we know the \c entry_assembly.
265 void
266 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
268 ERROR_DECL (error);
269 mono_runtime_init_checked (domain, start_cb, attach_cb, error);
270 mono_error_cleanup (error);
273 void
274 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
276 HANDLE_FUNCTION_ENTER ();
278 MonoAppDomainSetupHandle setup;
279 MonoAppDomainHandle ad;
281 error_init (error);
283 mono_portability_helpers_init ();
285 mono_gc_base_init ();
286 mono_monitor_init ();
287 mono_marshal_init ();
288 mono_gc_init_icalls ();
290 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
291 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
292 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
293 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
294 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
295 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
296 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
297 mono_install_assembly_asmctx_from_path_hook (mono_domain_asmctx_from_path, NULL);
299 mono_thread_init (start_cb, attach_cb);
301 if (!mono_runtime_get_no_exec ()) {
302 MonoClass *klass = mono_class_get_appdomain_setup_class ();
303 setup = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_pinned_handle (domain, klass, error));
304 goto_if_nok (error, exit);
306 klass = mono_class_get_appdomain_class ();
308 ad = MONO_HANDLE_CAST (MonoAppDomain, mono_object_new_pinned_handle (domain, klass, error));
309 goto_if_nok (error, exit);
311 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, domain);
312 domain->domain = MONO_HANDLE_RAW (ad);
313 domain->setup = MONO_HANDLE_RAW (setup);
316 mono_thread_attach (domain);
318 mono_type_initialization_init ();
320 if (!mono_runtime_get_no_exec ())
321 create_domain_objects (domain);
323 /* GC init has to happen after thread init */
324 mono_gc_init ();
326 /* contexts use GC handles, so they must be initialized after the GC */
327 mono_context_init_checked (domain, error);
328 goto_if_nok (error, exit);
329 mono_context_set_default_context (domain);
331 #ifndef DISABLE_SOCKETS
332 mono_network_init ();
333 #endif
335 mono_console_init ();
336 mono_attach_init ();
338 mono_locks_tracer_init ();
340 /* mscorlib is loaded before we install the load hook */
341 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
343 exit:
344 HANDLE_FUNCTION_RETURN ();
347 static void
348 mono_context_set_default_context (MonoDomain *domain)
350 if (mono_runtime_get_no_exec ())
351 return;
353 HANDLE_FUNCTION_ENTER ();
354 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext, domain->default_context));
355 HANDLE_FUNCTION_RETURN ();
358 static char*
359 mono_get_corlib_version (void)
361 ERROR_DECL (error);
363 MonoClass *klass;
364 MonoClassField *field;
366 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
367 mono_class_init_internal (klass);
368 field = mono_class_get_field_from_name_full (klass, "mono_corlib_version", NULL);
369 if (!field)
370 return NULL;
372 if (! (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_LITERAL)))
373 return NULL;
375 char *value;
376 MonoTypeEnum field_type;
377 const char *data = mono_class_get_field_default_value (field, &field_type);
378 if (field_type != MONO_TYPE_STRING)
379 return NULL;
380 mono_metadata_read_constant_value (data, field_type, &value, error);
381 mono_error_assert_ok (error);
383 char *res = mono_string_from_blob (value, error);
384 mono_error_assert_ok (error);
386 return res;
390 * mono_check_corlib_version:
391 * Checks that the corlib that is loaded matches the version of this runtime.
392 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
393 * allocated string with the error otherwise.
395 const char*
396 mono_check_corlib_version (void)
398 const char* res;
399 MONO_ENTER_GC_UNSAFE;
400 res = mono_check_corlib_version_internal ();
401 MONO_EXIT_GC_UNSAFE;
402 return res;
405 static const char *
406 mono_check_corlib_version_internal (void)
408 #if defined(MONO_CROSS_COMPILE)
409 /* Can't read the corlib version because we only have the target class layouts */
410 return NULL;
411 #endif
413 char *result = NULL;
414 char *version = mono_get_corlib_version ();
415 if (!version) {
416 result = g_strdup_printf ("expected corlib string (%s) but not found or not string", MONO_CORLIB_VERSION);
417 goto exit;
419 if (strcmp (version, MONO_CORLIB_VERSION) != 0) {
420 result = g_strdup_printf ("The runtime did not find the mscorlib.dll it expected. "
421 "Expected interface version %s but found %s. Check that "
422 "your runtime and class libraries are matching.",
423 MONO_CORLIB_VERSION, version);
424 goto exit;
427 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
428 guint32 native_offset;
429 guint32 managed_offset;
430 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
431 managed_offset = mono_field_get_offset (mono_class_get_field_from_name_full (mono_defaults.internal_thread_class, "last", NULL));
432 if (native_offset != managed_offset)
433 result = g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
434 exit:
435 g_free (version);
436 return result;
440 * mono_context_init:
441 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
442 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
444 void
445 mono_context_init (MonoDomain *domain)
447 ERROR_DECL (error);
448 mono_context_init_checked (domain, error);
449 mono_error_cleanup (error);
452 void
453 mono_context_init_checked (MonoDomain *domain, MonoError *error)
455 HANDLE_FUNCTION_ENTER ();
457 MonoClass *klass;
458 MonoAppContextHandle context;
460 error_init (error);
461 if (mono_runtime_get_no_exec ())
462 goto exit;
464 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
465 context = MONO_HANDLE_CAST (MonoAppContext, mono_object_new_pinned_handle (domain, klass, error));
466 goto_if_nok (error, exit);
468 MONO_HANDLE_SETVAL (context, domain_id, gint32, domain->domain_id);
469 MONO_HANDLE_SETVAL (context, context_id, gint32, 0);
470 mono_threads_register_app_context (context, error);
471 mono_error_assert_ok (error);
472 domain->default_context = MONO_HANDLE_RAW (context);
473 exit:
474 HANDLE_FUNCTION_RETURN ();
478 * mono_runtime_cleanup:
479 * \param domain unused.
481 * Internal routine.
483 * This must not be called while there are still running threads executing
484 * managed code.
486 void
487 mono_runtime_cleanup (MonoDomain *domain)
489 mono_attach_cleanup ();
491 /* This ends up calling any pending pending (for at most 2 seconds) */
492 mono_gc_cleanup ();
494 mono_thread_cleanup ();
496 #ifndef DISABLE_SOCKETS
497 mono_network_cleanup ();
498 #endif
499 mono_marshal_cleanup ();
501 mono_type_initialization_cleanup ();
503 mono_monitor_cleanup ();
506 static MonoDomainFunc quit_function = NULL;
509 * mono_install_runtime_cleanup:
511 void
512 mono_install_runtime_cleanup (MonoDomainFunc func)
514 quit_function = func;
518 * mono_runtime_quit:
520 void
521 mono_runtime_quit ()
523 if (quit_function != NULL)
524 quit_function (mono_get_root_domain (), NULL);
528 * mono_domain_create_appdomain:
529 * \param friendly_name The friendly name of the appdomain to create
530 * \param configuration_file The configuration file to initialize the appdomain with
531 * \returns a \c MonoDomain initialized with the appdomain
533 MonoDomain *
534 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
536 HANDLE_FUNCTION_ENTER ();
537 MonoDomain *domain;
538 MONO_ENTER_GC_UNSAFE;
539 ERROR_DECL (error);
540 domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, error);
541 mono_error_cleanup (error);
542 MONO_EXIT_GC_UNSAFE;
543 HANDLE_FUNCTION_RETURN_VAL (domain);
547 * mono_domain_create_appdomain_checked:
548 * \param friendly_name The friendly name of the appdomain to create
549 * \param configuration_file The configuration file to initialize the appdomain with
550 * \param error Set on error.
552 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
554 MonoDomain *
555 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
557 HANDLE_FUNCTION_ENTER ();
558 error_init (error);
559 MonoDomain *result = NULL;
561 MonoClass *klass = mono_class_get_appdomain_setup_class ();
562 MonoAppDomainSetupHandle setup = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_handle (mono_domain_get (), klass, error));
563 goto_if_nok (error, leave);
564 MonoStringHandle config_file;
565 if (configuration_file != NULL) {
566 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
567 goto_if_nok (error, leave);
568 } else {
569 config_file = MONO_HANDLE_NEW (MonoString, NULL);
571 MONO_HANDLE_SET (setup, configuration_file, config_file);
573 MonoAppDomainHandle ad;
574 ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
575 goto_if_nok (error, leave);
577 result = mono_domain_from_appdomain_handle (ad);
578 leave:
579 HANDLE_FUNCTION_RETURN_VAL (result);
583 * mono_domain_set_config:
584 * \param domain \c MonoDomain initialized with the appdomain we want to change
585 * \param base_dir new base directory for the appdomain
586 * \param config_file_name path to the new configuration for the app domain
588 * Used to set the system configuration for an appdomain
590 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
591 * Error Initializing the configuration system. ---> System.ArgumentException:
592 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
594 void
595 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
597 HANDLE_FUNCTION_ENTER ();
598 MONO_ENTER_GC_UNSAFE;
599 ERROR_DECL (error);
600 mono_domain_set_config_checked (domain, base_dir, config_file_name, error);
601 mono_error_cleanup (error);
602 MONO_EXIT_GC_UNSAFE;
603 HANDLE_FUNCTION_RETURN ();
606 gboolean
607 mono_domain_set_config_checked (MonoDomain *domain, const char *base_dir, const char *config_file_name, MonoError *error)
609 error_init (error);
610 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
611 MonoStringHandle base_dir_str = mono_string_new_handle (domain, base_dir, error);
612 goto_if_nok (error, leave);
613 MONO_HANDLE_SET (setup, application_base, base_dir_str);
614 MonoStringHandle config_file_name_str;
615 config_file_name_str = mono_string_new_handle (domain, config_file_name, error);
616 goto_if_nok (error, leave);
617 MONO_HANDLE_SET (setup, configuration_file, config_file_name_str);
618 leave:
619 return is_ok (error);
622 static MonoAppDomainSetupHandle
623 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
625 HANDLE_FUNCTION_ENTER ();
626 MonoDomain *caller_domain;
627 MonoClass *ads_class;
628 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
630 error_init (error);
632 caller_domain = mono_domain_get ();
633 ads_class = mono_class_get_appdomain_setup_class ();
635 MonoAppDomainSetupHandle copy = MONO_HANDLE_CAST (MonoAppDomainSetup, mono_object_new_handle(domain, ads_class, error));
636 goto_if_nok (error, leave);
638 mono_domain_set_internal (domain);
640 #define XCOPY_FIELD(type, dst, field, src, error) \
641 do { \
642 TYPED_HANDLE_NAME (type) src_val = MONO_HANDLE_NEW_GET (type, (src), field); \
643 TYPED_HANDLE_NAME (type) copied_val = MONO_HANDLE_CAST (type, mono_marshal_xdomain_copy_value_handle (MONO_HANDLE_CAST (MonoObject, src_val), error)); \
644 goto_if_nok (error, leave); \
645 MONO_HANDLE_SET ((dst),field,copied_val); \
646 } while (0)
648 #define COPY_VAL(dst,field,type,src) \
649 do { \
650 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
651 } while (0)
653 XCOPY_FIELD (MonoString, copy, application_base, setup, error);
654 XCOPY_FIELD (MonoString, copy, application_name, setup, error);
655 XCOPY_FIELD (MonoString, copy, cache_path, setup, error);
656 XCOPY_FIELD (MonoString, copy, configuration_file, setup, error);
657 XCOPY_FIELD (MonoString, copy, dynamic_base, setup, error);
658 XCOPY_FIELD (MonoString, copy, license_file, setup, error);
659 XCOPY_FIELD (MonoString, copy, private_bin_path, setup, error);
660 XCOPY_FIELD (MonoString, copy, private_bin_path_probe, setup, error);
661 XCOPY_FIELD (MonoString, copy, shadow_copy_directories, setup, error);
662 XCOPY_FIELD (MonoString, copy, shadow_copy_files, setup, error);
663 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
664 COPY_VAL (copy, path_changed, MonoBoolean, setup);
665 COPY_VAL (copy, loader_optimization, int, setup);
666 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
667 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
668 XCOPY_FIELD (MonoArray, copy, domain_initializer_args, setup, error);
669 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
670 XCOPY_FIELD (MonoObject, copy, application_trust, setup, error);
671 XCOPY_FIELD (MonoArray, copy, configuration_bytes, setup, error);
672 XCOPY_FIELD (MonoArray, copy, serialized_non_primitives, setup, error);
674 #undef XCOPY_FIELD
675 #undef COPY_VAL
677 mono_domain_set_internal (caller_domain);
679 MONO_HANDLE_ASSIGN (result, copy);
680 leave:
681 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
684 static MonoAppDomainHandle
685 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
687 HANDLE_FUNCTION_ENTER ();
688 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
689 MonoClass *adclass;
690 MonoDomain *data;
692 error_init (error);
694 adclass = mono_class_get_appdomain_class ();
696 /* FIXME: pin all those objects */
697 data = mono_domain_create();
699 MonoAppDomainHandle ad = MONO_HANDLE_CAST (MonoAppDomain, mono_object_new_handle (data, adclass, error));
700 goto_if_nok (error, leave);
701 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
702 data->domain = MONO_HANDLE_RAW (ad);
703 data->friendly_name = g_strdup (friendly_name);
705 MONO_PROFILER_RAISE (domain_name, (data, data->friendly_name));
707 MonoStringHandle app_base;
708 app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
709 if (MONO_HANDLE_IS_NULL (app_base)) {
710 /* Inherit from the root domain since MS.NET does this */
711 MonoDomain *root = mono_get_root_domain ();
712 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
713 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
714 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
715 /* N.B. new string is in the new domain */
716 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
717 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);
718 mono_gchandle_free_internal (gchandle);
719 if (!is_ok (error)) {
720 g_free (data->friendly_name);
721 goto leave;
723 MONO_HANDLE_SET (setup, application_base, s);
727 mono_context_init_checked (data, error);
728 goto_if_nok (error, leave);
730 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
731 if (!mono_error_ok (error)) {
732 g_free (data->friendly_name);
733 goto leave;
736 mono_domain_set_options_from_config (data);
737 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
739 #ifndef DISABLE_SHADOW_COPY
740 /*FIXME, guard this for when the debugger is not running */
741 char *shadow_location;
742 shadow_location = get_shadow_assembly_location_base (data, error);
743 if (!mono_error_ok (error)) {
744 g_free (data->friendly_name);
745 goto leave;
748 g_free (shadow_location);
749 #endif
751 create_domain_objects (data);
753 MONO_HANDLE_ASSIGN (result, ad);
754 leave:
755 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
759 * mono_domain_has_type_resolve:
760 * \param domain application domain being looked up
762 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
764 gboolean
765 mono_domain_has_type_resolve (MonoDomain *domain)
767 static MonoClassField *field = NULL;
768 MonoObject *o;
770 if (field == NULL) {
771 field = mono_class_get_field_from_name_full (mono_defaults.appdomain_class, "TypeResolve", NULL);
772 g_assert (field);
775 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
776 if (!domain->domain)
777 return FALSE;
779 mono_field_get_value_internal ((MonoObject*)(domain->domain), field, &o);
780 return o != NULL;
784 * mono_domain_try_type_resolve:
785 * \param domain application domain in which to resolve the type
786 * \param name the name of the type to resolve or NULL.
787 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
789 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
790 * the assembly that matches name, or ((TypeBuilder)typebuilder).FullName.
792 * \returns A \c MonoReflectionAssembly or NULL if not found
794 MonoReflectionAssembly *
795 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *typebuilder_raw)
797 HANDLE_FUNCTION_ENTER ();
799 g_assert (domain);
800 g_assert (name || typebuilder_raw);
802 ERROR_DECL (error);
804 MonoReflectionAssemblyHandle ret = NULL_HANDLE_INIT;
806 if (name) {
807 MonoStringHandle name_handle = mono_string_new_handle (mono_domain_get (), name, error);
808 goto_if_nok (error, exit);
809 ret = mono_domain_try_type_resolve_name (domain, name_handle, error);
810 } else {
811 MONO_HANDLE_DCL (MonoObject, typebuilder);
812 ret = mono_domain_try_type_resolve_typebuilder (domain, MONO_HANDLE_CAST (MonoReflectionTypeBuilder, typebuilder), error);
815 exit:
816 mono_error_cleanup (error);
817 HANDLE_FUNCTION_RETURN_OBJ (ret);
821 * mono_class_get_appdomain_do_type_resolve_method:
823 * This routine returns System.AppDomain.DoTypeResolve.
825 static MonoMethod *
826 mono_class_get_appdomain_do_type_resolve_method (MonoError *error)
828 static MonoMethod *method; // cache
830 if (method)
831 return method;
833 // not cached yet, fill cache under caller's lock
835 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoTypeResolve", -1, 0, error);
837 if (method == NULL)
838 g_warning ("%s method AppDomain.DoTypeResolve not found. %s\n", __func__, mono_error_get_message (error));
840 return method;
844 * mono_domain_try_type_resolve_name:
845 * \param domain application domain in which to resolve the type
846 * \param name the name of the type to resolve.
848 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
849 * the assembly that matches name.
851 * \returns A \c MonoReflectionAssembly or NULL if not found
853 MonoReflectionAssemblyHandle
854 mono_domain_try_type_resolve_name (MonoDomain *domain, MonoStringHandle name, MonoError *error)
856 HANDLE_FUNCTION_ENTER ();
858 void *params [1] = { 0 };
860 g_assert (domain);
861 g_assert (MONO_HANDLE_BOOL (name));
862 g_assert (error);
864 error_init (error);
866 MonoMethod *method;
867 method = mono_class_get_appdomain_do_type_resolve_method (error);
868 goto_if_nok (error, return_null);
870 MonoAppDomainHandle appdomain;
871 appdomain = MONO_HANDLE_NEW (MonoAppDomain, domain->domain);
873 MonoObjectHandle ret;
874 params [0] = MONO_HANDLE_RAW (name);
875 ret = mono_runtime_invoke_handle (method, MONO_HANDLE_CAST (MonoObject, appdomain), params, error);
876 goto_if_nok (error, return_null);
877 goto exit;
878 return_null:
879 ret = NULL_HANDLE;
880 exit:
881 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
885 * mono_domain_try_type_resolve_typebuilder:
886 * \param domain application domain in which to resolve the type
887 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder; typebuilder.FullName is the name of the type to resolve.
889 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
890 * the assembly that matches typebuilder.FullName.
892 * \returns A \c MonoReflectionAssembly or NULL_HANDLE if not found
894 MonoReflectionAssemblyHandle
895 mono_domain_try_type_resolve_typebuilder (MonoDomain *domain, MonoReflectionTypeBuilderHandle typebuilder, MonoError *error)
897 HANDLE_FUNCTION_ENTER ();
899 g_assert (domain);
900 g_assert (MONO_HANDLE_BOOL (typebuilder));
901 g_assert (error);
903 error_init (error);
905 MonoMethod * const method = mono_class_get_appdomain_do_type_resolve_method (error);
906 goto_if_nok (error, return_null);
908 MonoAppDomainHandle appdomain;
909 appdomain = MONO_HANDLE_NEW (MonoAppDomain, domain->domain);
910 void *args [1];
911 args [0] = MONO_HANDLE_RAW (typebuilder);
913 MonoObjectHandle ret;
914 ret = mono_runtime_invoke_handle (method, MONO_HANDLE_CAST (MonoObject, appdomain), args, error);
915 goto_if_nok (error, return_null);
916 goto exit;
917 return_null:
918 ret = NULL_HANDLE;
919 exit:
920 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly, MONO_HANDLE_CAST (MonoReflectionAssembly, ret));
924 * mono_domain_owns_vtable_slot:
925 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
927 gboolean
928 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
930 gboolean res;
932 mono_domain_lock (domain);
933 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
934 mono_domain_unlock (domain);
935 return res;
939 * mono_domain_set:
940 * \param domain domain
941 * \param force force setting.
943 * Set the current appdomain to \p domain. If \p force is set, set it even
944 * if it is being unloaded.
946 * \returns TRUE on success; FALSE if the domain is unloaded
948 gboolean
949 mono_domain_set (MonoDomain *domain, gboolean force)
951 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
952 return FALSE;
954 MONO_ENTER_GC_UNSAFE;
955 mono_domain_set_internal (domain);
956 MONO_EXIT_GC_UNSAFE;
957 return TRUE;
960 MonoObjectHandle
961 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
963 error_init (error);
965 if (MONO_HANDLE_IS_NULL (name)) {
966 mono_error_set_argument_null (error, "name", "");
967 return NULL_HANDLE;
970 g_assert (!MONO_HANDLE_IS_NULL (ad));
971 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
972 g_assert (add);
974 char *str = mono_string_handle_to_utf8 (name, error);
975 return_val_if_nok (error, NULL_HANDLE);
977 mono_domain_lock (add);
979 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
980 MonoStringHandle o;
981 if (!strcmp (str, "APPBASE"))
982 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
983 else if (!strcmp (str, "APP_CONFIG_FILE"))
984 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
985 else if (!strcmp (str, "DYNAMIC_BASE"))
986 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
987 else if (!strcmp (str, "APP_NAME"))
988 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
989 else if (!strcmp (str, "CACHE_BASE"))
990 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
991 else if (!strcmp (str, "PRIVATE_BINPATH"))
992 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
993 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
994 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
995 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
996 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
997 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
998 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
999 else
1000 o = MONO_HANDLE_NEW (MonoString, (MonoString*)mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
1002 mono_domain_unlock (add);
1003 g_free (str);
1005 return MONO_HANDLE_CAST (MonoObject, o);
1008 void
1009 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
1011 error_init (error);
1013 if (MONO_HANDLE_IS_NULL (name)) {
1014 mono_error_set_argument_null (error, "name", "");
1015 return;
1018 g_assert (!MONO_HANDLE_IS_NULL (ad));
1019 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
1020 g_assert (add);
1022 mono_domain_lock (add);
1024 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
1026 mono_domain_unlock (add);
1029 MonoAppDomainSetupHandle
1030 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
1032 error_init (error);
1033 g_assert (!MONO_HANDLE_IS_NULL (ad));
1034 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1035 g_assert (domain);
1037 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
1040 MonoStringHandle
1041 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
1043 error_init (error);
1044 g_assert (!MONO_HANDLE_IS_NULL (ad));
1045 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1046 g_assert (domain);
1048 return mono_string_new_handle (domain, domain->friendly_name, error);
1051 MonoAppDomainHandle
1052 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
1054 error_init (error);
1055 MonoDomain *add = mono_domain_get ();
1057 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
1060 MonoAppDomainHandle
1061 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
1063 error_init (error);
1064 MonoDomain *root = mono_get_root_domain ();
1066 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
1069 MonoBoolean
1070 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions (MonoError *error)
1072 MonoDomain *domain = mono_domain_get ();
1074 return domain->throw_unobserved_task_exceptions;
1077 static char*
1078 get_attribute_value (const gchar **attribute_names,
1079 const gchar **attribute_values,
1080 const char *att_name)
1082 int n;
1083 for (n = 0; attribute_names [n] != NULL; n++) {
1084 if (strcmp (attribute_names [n], att_name) == 0)
1085 return g_strdup (attribute_values [n]);
1087 return NULL;
1090 static void
1091 start_element (GMarkupParseContext *context,
1092 const gchar *element_name,
1093 const gchar **attribute_names,
1094 const gchar **attribute_values,
1095 gpointer user_data,
1096 GError **gerror)
1098 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
1100 if (strcmp (element_name, "runtime") == 0) {
1101 runtime_config->runtime_count++;
1102 return;
1105 if (strcmp (element_name, "assemblyBinding") == 0) {
1106 runtime_config->assemblybinding_count++;
1107 return;
1110 if (runtime_config->runtime_count != 1)
1111 return;
1113 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
1114 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
1116 if (value && g_ascii_strcasecmp (value, "true") == 0)
1117 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
1120 if (runtime_config->assemblybinding_count != 1)
1121 return;
1123 if (strcmp (element_name, "probing") != 0)
1124 return;
1126 g_free (runtime_config->domain->private_bin_path);
1127 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
1128 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
1129 g_free (runtime_config->domain->private_bin_path);
1130 runtime_config->domain->private_bin_path = NULL;
1131 return;
1135 static void
1136 end_element (GMarkupParseContext *context,
1137 const gchar *element_name,
1138 gpointer user_data,
1139 GError **gerror)
1141 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
1142 if (strcmp (element_name, "runtime") == 0)
1143 runtime_config->runtime_count--;
1144 else if (strcmp (element_name, "assemblyBinding") == 0)
1145 runtime_config->assemblybinding_count--;
1148 static void
1149 parse_error (GMarkupParseContext *context, GError *gerror, gpointer user_data)
1151 RuntimeConfig *state = (RuntimeConfig *)user_data;
1152 const gchar *msg;
1153 const gchar *filename;
1155 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
1156 msg = gerror && gerror->message ? gerror->message : "";
1157 g_warning ("Error parsing %s: %s", filename, msg);
1160 static const GMarkupParser
1161 mono_parser = {
1162 start_element,
1163 end_element,
1164 NULL,
1165 NULL,
1166 parse_error
1169 void
1170 mono_domain_set_options_from_config (MonoDomain *domain)
1172 ERROR_DECL (error);
1173 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
1174 gsize len;
1175 GMarkupParseContext *context;
1176 RuntimeConfig runtime_config;
1177 gint offset;
1179 if (!domain || !domain->setup || !domain->setup->configuration_file)
1180 return;
1182 config_file_name = mono_string_to_utf8_checked_internal (domain->setup->configuration_file, error);
1183 if (!mono_error_ok (error)) {
1184 mono_error_cleanup (error);
1185 goto free_and_out;
1188 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1189 if (!config_file_path)
1190 config_file_path = config_file_name;
1192 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1193 goto free_and_out;
1195 runtime_config.runtime_count = 0;
1196 runtime_config.assemblybinding_count = 0;
1197 runtime_config.domain = domain;
1198 runtime_config.filename = config_file_path;
1200 offset = 0;
1201 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1202 offset = 3; /* Skip UTF-8 BOM */
1204 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1205 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1206 g_markup_parse_context_end_parse (context, NULL);
1207 g_markup_parse_context_free (context);
1209 free_and_out:
1210 g_free (text);
1211 if (config_file_name != config_file_path)
1212 g_free (config_file_name);
1213 g_free (config_file_path);
1216 MonoAppDomainHandle
1217 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1219 error_init (error);
1220 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1222 #ifdef DISABLE_APPDOMAINS
1223 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1224 #else
1225 char *fname;
1227 fname = mono_string_handle_to_utf8 (friendly_name, error);
1228 return_val_if_nok (error, ad);
1229 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1230 g_free (fname);
1231 #endif
1232 return ad;
1235 static gboolean
1236 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1238 HANDLE_FUNCTION_ENTER ();
1239 error_init (error);
1240 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1241 goto_if_nok (error, leave);
1242 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1243 leave:
1244 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1247 MonoArrayHandle
1248 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1250 error_init (error);
1251 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1252 MonoAssembly* ass;
1253 GSList *tmp;
1254 int i;
1255 GPtrArray *assemblies;
1258 * Make a copy of the list of assemblies because we can't hold the assemblies
1259 * lock while creating objects etc.
1261 assemblies = g_ptr_array_new ();
1262 /* Need to skip internal assembly builders created by remoting */
1263 mono_domain_assemblies_lock (domain);
1264 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1265 ass = (MonoAssembly *)tmp->data;
1266 MonoBoolean ass_refonly = mono_asmctx_get_kind (&ass->context) == MONO_ASMCTX_REFONLY;
1267 /* .NET Framework GetAssemblies() includes LoadFrom and Load(byte[]) assemblies, too */
1268 if (refonly != ass_refonly)
1269 continue;
1270 if (ass->corlib_internal)
1271 continue;
1272 g_ptr_array_add (assemblies, ass);
1274 mono_domain_assemblies_unlock (domain);
1276 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1277 goto_if_nok (error, leave);
1278 for (i = 0; i < assemblies->len; ++i) {
1279 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1280 goto leave;
1283 leave:
1284 g_ptr_array_free (assemblies, TRUE);
1285 return res;
1288 MonoAssembly*
1289 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1291 HANDLE_FUNCTION_ENTER ();
1292 error_init (error);
1293 MonoAssembly *result = NULL;
1294 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1295 goto_if_nok (error, leave);
1296 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1297 leave:
1298 HANDLE_FUNCTION_RETURN_VAL (result);
1301 MonoAssembly*
1302 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1304 HANDLE_FUNCTION_ENTER ();
1305 MonoAssembly *ret = NULL;
1306 MonoMethod *method;
1307 MonoBoolean isrefonly;
1308 gpointer params [3];
1310 error_init (error);
1312 if (mono_runtime_get_no_exec ())
1313 goto leave;
1315 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1317 method = mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1, 0, error);
1318 g_assert (method != NULL);
1320 isrefonly = refonly ? 1 : 0;
1321 MonoReflectionAssemblyHandle requesting_handle;
1322 if (requesting) {
1323 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1324 goto_if_nok (error, leave);
1326 params [0] = MONO_HANDLE_RAW (fname);
1327 params [1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1328 params [2] = &isrefonly;
1329 MonoObject *exc;
1330 exc = NULL;
1331 MonoReflectionAssemblyHandle result;
1332 result = MONO_HANDLE_CAST (MonoReflectionAssembly, MONO_HANDLE_NEW (MonoObject, mono_runtime_try_invoke (method, domain->domain, params, &exc, error)));
1333 if (!is_ok (error) || exc != NULL) {
1334 if (is_ok (error))
1335 mono_error_set_exception_instance (error, (MonoException*)exc);
1336 goto leave;
1338 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1340 if (ret && !refonly && mono_asmctx_get_kind (&ret->context) == MONO_ASMCTX_REFONLY) {
1341 /* .NET Framework throws System.IO.FileNotFoundException in this case */
1342 mono_error_set_file_not_found (error, NULL, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only");
1343 ret = NULL;
1344 goto leave;
1346 leave:
1347 HANDLE_FUNCTION_RETURN_VAL (ret);
1350 MonoAssembly *
1351 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1352 gboolean refonly)
1354 ERROR_DECL (error);
1355 MonoAssembly *assembly;
1356 MonoDomain *domain = mono_domain_get ();
1357 char *aname_str;
1359 aname_str = mono_stringify_assembly_name (aname);
1361 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1363 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, error);
1364 g_free (aname_str);
1365 mono_error_cleanup (error);
1367 return assembly;
1371 * LOCKING: assumes assemblies_lock in the domain is already locked.
1373 static void
1374 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1376 gint i;
1377 GSList *tmp;
1378 gboolean destroy_ht = FALSE;
1380 g_assert (ass != NULL);
1382 if (!ass->aname.name)
1383 return;
1385 if (!ht) {
1386 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1387 destroy_ht = TRUE;
1388 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1389 g_hash_table_insert (ht, tmp->data, tmp->data);
1393 /* FIXME: handle lazy loaded assemblies */
1395 if (!g_hash_table_lookup (ht, ass)) {
1396 mono_assembly_addref (ass);
1397 g_hash_table_insert (ht, ass, ass);
1398 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1399 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);
1402 if (ass->image->references) {
1403 for (i = 0; i < ass->image->nreferences; i++) {
1404 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1405 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1406 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1411 if (destroy_ht)
1412 g_hash_table_destroy (ht);
1415 static void
1416 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1418 HANDLE_FUNCTION_ENTER ();
1419 static MonoClassField *assembly_load_field;
1420 static MonoMethod *assembly_load_method;
1421 ERROR_DECL (error);
1422 MonoDomain *domain = mono_domain_get ();
1423 MonoClass *klass;
1424 MonoObjectHandle appdomain;
1426 if (!MONO_BOOL (domain->domain))
1427 goto leave; // This can happen during startup
1429 if (mono_runtime_get_no_exec ())
1430 goto leave;
1432 #ifdef ASSEMBLY_LOAD_DEBUG
1433 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1434 #endif
1435 appdomain = MONO_HANDLE_NEW (MonoObject, &domain->domain->mbr.obj);
1436 klass = mono_handle_class (appdomain);
1438 mono_domain_assemblies_lock (domain);
1439 add_assemblies_to_domain (domain, assembly, NULL);
1440 mono_domain_assemblies_unlock (domain);
1442 if (assembly_load_field == NULL) {
1443 assembly_load_field = mono_class_get_field_from_name_full (klass, "AssemblyLoad", NULL);
1444 g_assert (assembly_load_field);
1447 if (!MONO_HANDLE_GET_FIELD_BOOL (appdomain, MonoObject*, assembly_load_field))
1448 goto leave; // No events waiting to be triggered
1450 MonoReflectionAssemblyHandle reflection_assembly;
1451 reflection_assembly = mono_assembly_get_object_handle (domain, assembly, error);
1452 mono_error_assert_ok (error);
1454 if (assembly_load_method == NULL) {
1455 assembly_load_method = mono_class_get_method_from_name_checked (klass, "DoAssemblyLoad", -1, 0, error);
1456 g_assert (assembly_load_method);
1459 void *params [1];
1460 params [0] = MONO_HANDLE_RAW (reflection_assembly);
1461 mono_runtime_invoke_handle (assembly_load_method, appdomain, params, error);
1462 leave:
1463 mono_error_cleanup (error);
1464 HANDLE_FUNCTION_RETURN ();
1467 static gboolean
1468 mono_domain_asmctx_from_path (const char *fname, MonoAssembly *requesting_assembly, gpointer user_data, MonoAssemblyContextKind *out_asmctx)
1470 MonoDomain *domain = mono_domain_get ();
1471 char **search_path = NULL;
1473 for (search_path = domain->search_path; search_path && *search_path; search_path++) {
1474 if (mono_path_filename_in_basedir (fname, *search_path)) {
1475 *out_asmctx = MONO_ASMCTX_DEFAULT;
1476 return TRUE;
1479 return FALSE;
1483 * LOCKING: Acquires the domain assemblies lock.
1485 static void
1486 set_domain_search_path (MonoDomain *domain)
1488 HANDLE_FUNCTION_ENTER ();
1489 ERROR_DECL (error);
1490 MonoAppDomainSetupHandle setup;
1491 gchar **tmp;
1492 gchar *search_path = NULL;
1493 gint npaths = 1;
1494 gchar **pvt_split = NULL;
1495 GError *gerror = NULL;
1496 gint appbaselen = -1;
1499 * We use the low-level domain assemblies lock, since this is called from
1500 * assembly loads hooks, which means this thread might hold the loader lock.
1502 mono_domain_assemblies_lock (domain);
1504 if (!MONO_BOOL (domain->setup))
1505 goto exit;
1507 setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
1509 if (domain->search_path && !MONO_HANDLE_GET_BOOL (setup, path_changed))
1510 goto exit;
1512 if (!MONO_HANDLE_GET_BOOL (setup, application_base))
1513 goto exit; // Must set application base to get private path working
1515 if (MONO_HANDLE_GET_BOOL (setup, private_bin_path)) {
1516 search_path = mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString, setup, private_bin_path), error);
1517 if (!mono_error_ok (error)) { /*FIXME maybe we should bubble up the error.*/
1518 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1519 goto exit;
1523 if (domain->private_bin_path) {
1524 if (search_path == NULL)
1525 search_path = domain->private_bin_path;
1526 else {
1527 gchar *tmp2 = search_path;
1528 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1529 g_free (tmp2);
1533 if (search_path) {
1535 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1536 * directories relative to ApplicationBase separated by semicolons (see
1537 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1538 * The loop below copes with the fact that some Unix applications may use ':' (or
1539 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1540 * ';' for the subsequent split.
1542 * The issue was reported in bug #81446
1544 #ifndef TARGET_WIN32
1545 g_strdelimit (search_path, ':', ';');
1546 #endif
1547 pvt_split = g_strsplit (search_path, ";", 1000);
1548 g_free (search_path);
1549 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1552 g_strfreev (domain->search_path);
1553 domain->search_path = NULL;
1555 tmp = g_new (gchar*, npaths + 1);
1556 tmp [npaths] = NULL;
1558 *tmp = mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString, setup, application_base), error);
1559 if (!mono_error_ok (error)) {
1560 g_free (tmp);
1561 goto exit;
1564 domain->search_path = tmp;
1566 /* FIXME: is this needed? */
1567 if (strncmp (*tmp, "file://", 7) == 0) {
1568 gchar *file = *tmp;
1569 gchar *uri = *tmp;
1570 gchar *tmpuri;
1572 if (uri [7] != '/')
1573 uri = g_strdup_printf ("file:///%s", uri + 7);
1575 tmpuri = uri;
1576 uri = mono_escape_uri_string (tmpuri);
1577 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1578 g_free (uri);
1580 if (tmpuri != file)
1581 g_free (tmpuri);
1583 if (gerror != NULL) {
1584 g_warning ("%s\n", gerror->message);
1585 g_error_free (gerror);
1586 *tmp = file;
1587 } else {
1588 g_free (file);
1592 for (gsize i = 1; pvt_split && i < npaths; i++) {
1593 if (g_path_is_absolute (pvt_split [i - 1])) {
1594 tmp [i] = g_strdup (pvt_split [i - 1]);
1595 } else {
1596 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1599 if (strchr (tmp [i], '.')) {
1600 gchar *reduced;
1601 gchar *freeme;
1603 reduced = mono_path_canonicalize (tmp [i]);
1604 if (appbaselen == -1)
1605 appbaselen = strlen (tmp [0]);
1607 if (strncmp (tmp [0], reduced, appbaselen)) {
1608 g_free (reduced);
1609 g_free (tmp [i]);
1610 tmp [i] = g_strdup ("");
1611 continue;
1614 freeme = tmp [i];
1615 tmp [i] = reduced;
1616 g_free (freeme);
1620 if (MONO_HANDLE_GET_BOOL (setup, private_bin_path_probe)) {
1621 g_free (tmp [0]);
1622 tmp [0] = g_strdup ("");
1625 MONO_HANDLE_SETVAL (setup, path_changed, MonoBoolean, FALSE);
1626 exit:
1627 mono_error_cleanup (error);
1628 g_strfreev (pvt_split);
1629 mono_domain_assemblies_unlock (domain);
1630 HANDLE_FUNCTION_RETURN ();
1633 #ifdef DISABLE_SHADOW_COPY
1634 gboolean
1635 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1637 return FALSE;
1640 char *
1641 mono_make_shadow_copy (const char *filename, MonoError *error)
1643 error_init (error);
1644 return (char *) filename;
1646 #else
1648 typedef enum {
1649 SHADOW_COPY_SIBLING_EXT_APPEND,
1650 SHADOW_COPY_SIBLING_EXT_REPLACE,
1651 } ShadowCopySiblingExt;
1653 static
1654 gchar *
1655 make_sibling_path (const gchar *path, gint pathlen, const char *extension, ShadowCopySiblingExt extopt)
1657 gchar *result = NULL;
1658 switch (extopt) {
1659 case SHADOW_COPY_SIBLING_EXT_APPEND: {
1660 result = g_strconcat (path, extension, NULL);
1661 break;
1663 case SHADOW_COPY_SIBLING_EXT_REPLACE: {
1664 /* expect path to be a .dll or .exe (or some case insensitive variant) */
1665 g_assert (pathlen >= 4 && path[pathlen - 4] == '.');
1666 GString *s = g_string_sized_new (pathlen - 4 + strlen (extension));
1667 g_string_append_len (s, path, pathlen - 4);
1668 g_string_append (s, extension);
1669 result = g_string_free (s, FALSE);
1670 break;
1672 default:
1673 g_assert_not_reached ();
1675 return result;
1678 static gboolean
1679 shadow_copy_sibling (const gchar *src_pristine, gint srclen, const char *extension, ShadowCopySiblingExt extopt, const gchar *target_pristine, gint targetlen)
1681 gchar *file = NULL;
1682 gunichar2 *orig = NULL;
1683 gunichar2 *dest = NULL;
1684 gboolean copy_result = TRUE;
1685 gchar *target = NULL;
1687 char *src = make_sibling_path (src_pristine, srclen, extension, extopt);
1689 if (IS_PORTABILITY_CASE) {
1690 file = mono_portability_find_file (src, TRUE);
1691 if (file == NULL)
1692 goto exit;
1693 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR))
1694 goto exit;
1696 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1698 target = make_sibling_path (target_pristine, targetlen, extension, extopt);
1700 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1702 mono_w32file_delete (dest);
1704 gint32 copy_error;
1705 copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1707 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1708 * overwritten when updated in their original locations. */
1709 if (copy_result)
1710 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1712 exit:
1713 g_free (file);
1714 g_free (orig);
1715 g_free (dest);
1716 g_free (src);
1717 g_free (target);
1718 return copy_result;
1721 static gint32
1722 get_cstring_hash (const char *str)
1724 const char *p;
1725 gint32 h = 0;
1727 if (!str || !str [0])
1728 return 0;
1730 gsize const len = strlen (str);
1731 p = str;
1732 for (gsize i = 0; i < len; i++) {
1733 h = (h << 5) - h + *p;
1734 p++;
1737 return h;
1741 * Returned memory is malloc'd. Called must free it
1743 static char *
1744 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1746 MonoAppDomainSetup *setup;
1747 char *cache_path = NULL;
1748 char *appname = NULL;
1749 char *userdir = NULL;
1750 char *location;
1752 error_init (error);
1754 setup = domain->setup;
1755 if (setup->cache_path != NULL && setup->application_name != NULL) {
1756 cache_path = mono_string_to_utf8_checked_internal (setup->cache_path, error);
1757 return_val_if_nok (error, NULL);
1759 #ifndef TARGET_WIN32
1761 gint i;
1762 for (i = strlen (cache_path) - 1; i >= 0; i--)
1763 if (cache_path [i] == '\\')
1764 cache_path [i] = '/';
1766 #endif
1768 appname = mono_string_to_utf8_checked_internal (setup->application_name, error);
1769 if (!mono_error_ok (error)) {
1770 g_free (cache_path);
1771 return NULL;
1774 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1775 } else {
1776 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1777 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1779 g_free (appname);
1780 g_free (cache_path);
1781 g_free (userdir);
1782 return location;
1785 static char *
1786 get_shadow_assembly_location (const char *filename, MonoError *error)
1788 gint32 hash = 0, hash2 = 0;
1789 char name_hash [9];
1790 char path_hash [30];
1791 char *bname = g_path_get_basename (filename);
1792 char *dirname = g_path_get_dirname (filename);
1793 char *location, *tmploc;
1794 MonoDomain *domain = mono_domain_get ();
1796 error_init (error);
1798 hash = get_cstring_hash (bname);
1799 hash2 = get_cstring_hash (dirname);
1800 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1801 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1802 tmploc = get_shadow_assembly_location_base (domain, error);
1803 if (!mono_error_ok (error)) {
1804 g_free (bname);
1805 g_free (dirname);
1806 return NULL;
1809 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1810 g_free (tmploc);
1811 g_free (bname);
1812 g_free (dirname);
1813 return location;
1816 static gboolean
1817 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1819 struct stat sbuf_dest;
1820 gchar *stat_src;
1821 gchar *real_src = mono_portability_find_file (src, TRUE);
1823 if (!real_src)
1824 stat_src = (gchar*)src;
1825 else
1826 stat_src = real_src;
1828 if (stat (stat_src, sbuf_src) == -1) {
1829 time_t tnow = time (NULL);
1831 if (real_src)
1832 g_free (real_src);
1834 memset (sbuf_src, 0, sizeof (*sbuf_src));
1835 sbuf_src->st_mtime = tnow;
1836 sbuf_src->st_atime = tnow;
1837 return TRUE;
1840 if (real_src)
1841 g_free (real_src);
1843 if (stat (dest, &sbuf_dest) == -1)
1844 return TRUE;
1846 if (sbuf_src->st_size == sbuf_dest.st_size &&
1847 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1848 return FALSE;
1850 return TRUE;
1853 static gboolean
1854 shadow_copy_create_ini (const char *shadow, const char *filename)
1856 gunichar2 *u16_ini = NULL;
1857 gboolean result = FALSE;
1858 guint32 n;
1859 HANDLE handle = INVALID_HANDLE_VALUE;
1860 gchar *full_path = NULL;
1862 char *dir_name = g_path_get_dirname (shadow);
1863 char *ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1864 g_free (dir_name);
1865 result = g_file_test (ini_file, G_FILE_TEST_IS_REGULAR);
1866 if (result)
1867 goto exit;
1869 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1870 if (!u16_ini)
1871 goto exit;
1873 handle = mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1874 if (handle == INVALID_HANDLE_VALUE)
1875 goto exit;
1877 full_path = mono_path_resolve_symlinks (filename);
1878 gint32 win32error;
1879 win32error = 0;
1880 result = mono_w32file_write (handle, full_path, strlen (full_path), &n, &win32error);
1881 exit:
1882 if (handle != INVALID_HANDLE_VALUE)
1883 mono_w32file_close (handle);
1884 g_free (u16_ini);
1885 g_free (full_path);
1886 g_free (ini_file);
1887 return result;
1890 gboolean
1891 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1893 ERROR_DECL (error);
1894 MonoAppDomainSetup *setup;
1895 gchar *all_dirs = NULL;
1896 gchar **dir_ptr;
1897 gchar **directories = NULL;
1898 gchar *shadow_status_string;
1899 gchar *base_dir = NULL;
1900 gboolean shadow_enabled;
1901 gboolean found = FALSE;
1903 if (domain == NULL)
1904 goto exit;
1906 setup = domain->setup;
1907 if (setup == NULL || setup->shadow_copy_files == NULL)
1908 goto exit;
1910 shadow_status_string = mono_string_to_utf8_checked_internal (setup->shadow_copy_files, error);
1911 if (!mono_error_ok (error))
1912 goto exit;
1914 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1915 g_free (shadow_status_string);
1917 if (!shadow_enabled)
1918 goto exit;
1920 found = (setup->shadow_copy_directories == NULL);
1921 if (found)
1922 goto exit;
1924 /* Is dir_name a shadow_copy destination already? */
1925 base_dir = get_shadow_assembly_location_base (domain, error);
1926 if (!mono_error_ok (error))
1927 goto exit;
1929 found = !!strstr (dir_name, base_dir);
1930 if (found)
1931 goto exit;
1933 all_dirs = mono_string_to_utf8_checked_internal (setup->shadow_copy_directories, error);
1934 if (!mono_error_ok (error))
1935 goto exit;
1937 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1938 dir_ptr = directories;
1939 while (!found && *dir_ptr) {
1940 found = (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name));
1941 dir_ptr++;
1943 exit:
1944 mono_error_cleanup (error);
1945 g_free (base_dir);
1946 g_strfreev (directories);
1947 g_free (all_dirs);
1948 return found;
1952 This function raises exceptions so it can cause as sorts of nasty stuff if called
1953 while holding a lock.
1954 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1955 or NULL if source file not found.
1956 FIXME bubble up the error instead of raising it here
1958 char *
1959 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1961 ERROR_DECL (error);
1962 gint filename_len, shadow_len;
1963 gunichar2 *orig, *dest;
1964 guint32 attrs;
1965 char *shadow;
1966 gboolean copy_result;
1967 struct stat src_sbuf;
1968 struct utimbuf utbuf;
1969 char *dir_name = g_path_get_dirname (filename);
1970 MonoDomain *domain = mono_domain_get ();
1971 char *shadow_dir;
1972 gint32 copy_error;
1974 error_init (oerror);
1976 set_domain_search_path (domain);
1978 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1979 g_free (dir_name);
1980 return (char *) filename;
1983 /* Is dir_name a shadow_copy destination already? */
1984 shadow_dir = get_shadow_assembly_location_base (domain, error);
1985 if (!mono_error_ok (error)) {
1986 mono_error_cleanup (error);
1987 g_free (dir_name);
1988 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1989 return NULL;
1992 if (strstr (dir_name, shadow_dir)) {
1993 g_free (shadow_dir);
1994 g_free (dir_name);
1995 return (char *) filename;
1997 g_free (shadow_dir);
1998 g_free (dir_name);
2000 shadow = get_shadow_assembly_location (filename, error);
2001 if (!mono_error_ok (error)) {
2002 mono_error_cleanup (error);
2003 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
2004 return NULL;
2007 if (g_ensure_directory_exists (shadow) == FALSE) {
2008 g_free (shadow);
2009 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
2010 return NULL;
2013 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
2014 return (char*) shadow;
2016 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
2017 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
2018 mono_w32file_delete (dest);
2020 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
2021 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
2022 * and not have it runtime error" */
2023 attrs = mono_w32file_get_attributes (orig);
2024 if (attrs == INVALID_FILE_ATTRIBUTES) {
2025 g_free (shadow);
2026 return (char *)filename;
2029 copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
2031 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
2032 * overwritten when updated in their original locations. */
2033 if (copy_result)
2034 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
2036 g_free (dest);
2037 g_free (orig);
2039 if (copy_result == FALSE) {
2040 g_free (shadow);
2042 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
2043 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
2044 return NULL; /* file not found, shadow copy failed */
2046 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
2047 return NULL;
2050 /* attempt to copy .mdb, .pdb and .config if they exist */
2051 filename_len = strlen (filename);
2052 shadow_len = strlen (shadow);
2054 copy_result = shadow_copy_sibling (filename, filename_len, ".mdb", SHADOW_COPY_SIBLING_EXT_APPEND, shadow, shadow_len);
2055 if (copy_result)
2056 copy_result = shadow_copy_sibling (filename, filename_len, ".pdb", SHADOW_COPY_SIBLING_EXT_REPLACE, shadow, shadow_len);
2057 if (copy_result)
2058 copy_result = shadow_copy_sibling (filename, filename_len, ".config", SHADOW_COPY_SIBLING_EXT_APPEND, shadow, shadow_len);
2060 if (!copy_result) {
2061 g_free (shadow);
2062 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
2063 return NULL;
2066 /* Create a .ini file containing the original assembly location */
2067 if (!shadow_copy_create_ini (shadow, filename)) {
2068 g_free (shadow);
2069 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
2070 return NULL;
2073 utbuf.actime = src_sbuf.st_atime;
2074 utbuf.modtime = src_sbuf.st_mtime;
2075 utime (shadow, &utbuf);
2077 return shadow;
2079 #endif /* DISABLE_SHADOW_COPY */
2082 * mono_domain_from_appdomain:
2084 MonoDomain *
2085 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
2087 HANDLE_FUNCTION_ENTER ();
2088 MonoDomain *result;
2089 MONO_ENTER_GC_UNSAFE;
2090 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
2091 result = mono_domain_from_appdomain_handle (appdomain);
2092 MONO_EXIT_GC_UNSAFE;
2093 HANDLE_FUNCTION_RETURN_VAL (result);
2096 MonoDomain *
2097 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
2099 HANDLE_FUNCTION_ENTER ();
2100 MonoDomain *dom = NULL;
2101 if (MONO_HANDLE_IS_NULL (appdomain))
2102 goto leave;
2104 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
2105 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
2106 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
2108 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
2109 } else
2110 dom = MONO_HANDLE_GETVAL (appdomain, data);
2112 leave:
2113 HANDLE_FUNCTION_RETURN_VAL (dom);
2117 static gboolean
2118 try_load_from (MonoAssembly **assembly,
2119 const gchar *path1, const gchar *path2,
2120 const gchar *path3, const gchar *path4,
2121 const MonoAssemblyOpenRequest *req)
2123 gchar *fullpath;
2124 gboolean found = FALSE;
2126 *assembly = NULL;
2127 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
2129 if (IS_PORTABILITY_SET) {
2130 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
2131 if (new_fullpath) {
2132 g_free (fullpath);
2133 fullpath = new_fullpath;
2134 found = TRUE;
2136 } else
2137 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
2139 if (found) {
2140 *assembly = mono_assembly_request_open (fullpath, req, NULL);
2143 g_free (fullpath);
2144 return (*assembly != NULL);
2147 static MonoAssembly *
2148 real_load (gchar **search_path, const gchar *culture, const gchar *name, const MonoAssemblyOpenRequest *req)
2150 MonoAssembly *result = NULL;
2151 gchar **path;
2152 gchar *filename;
2153 const gchar *local_culture;
2154 gint len;
2156 if (!culture || *culture == '\0') {
2157 local_culture = "";
2158 } else {
2159 local_culture = culture;
2162 filename = g_strconcat (name, ".dll", NULL);
2163 len = strlen (filename);
2165 for (path = search_path; *path; path++) {
2166 if (**path == '\0') {
2167 continue; /* Ignore empty ApplicationBase */
2170 /* See test cases in bug #58992 and bug #57710 */
2171 /* 1st try: [culture]/[name].dll (culture may be empty) */
2172 strcpy (filename + len - 4, ".dll");
2173 if (try_load_from (&result, *path, local_culture, "", filename, req))
2174 break;
2176 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2177 strcpy (filename + len - 4, ".exe");
2178 if (try_load_from (&result, *path, local_culture, "", filename, req))
2179 break;
2181 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2182 strcpy (filename + len - 4, ".dll");
2183 if (try_load_from (&result, *path, local_culture, name, filename, req))
2184 break;
2186 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2187 strcpy (filename + len - 4, ".exe");
2188 if (try_load_from (&result, *path, local_culture, name, filename, req))
2189 break;
2192 g_free (filename);
2193 return result;
2197 * Try loading the assembly from ApplicationBase and PrivateBinPath
2198 * and then from assemblies_path if any.
2199 * LOCKING: This is called from the assembly loading code, which means the caller
2200 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2202 static MonoAssembly *
2203 mono_domain_assembly_preload (MonoAssemblyName *aname,
2204 gchar **assemblies_path,
2205 gpointer user_data)
2207 MonoDomain *domain = mono_domain_get ();
2208 MonoAssembly *result = NULL;
2209 gboolean refonly = GPOINTER_TO_UINT (user_data);
2211 set_domain_search_path (domain);
2213 MonoAssemblyCandidatePredicate predicate = NULL;
2214 void* predicate_ud = NULL;
2215 #if !defined(DISABLE_DESKTOP_LOADER)
2216 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2217 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2218 predicate_ud = aname;
2220 #endif
2221 MonoAssemblyOpenRequest req;
2222 mono_assembly_request_prepare (&req.request, sizeof (req), refonly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_DEFAULT);
2223 req.request.predicate = predicate;
2224 req.request.predicate_ud = predicate_ud;
2226 if (domain->search_path && domain->search_path [0] != NULL) {
2227 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2228 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2229 for (int i = 0; domain->search_path [i]; i++) {
2230 const char *p = domain->search_path[i];
2231 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2233 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2235 result = real_load (domain->search_path, aname->culture, aname->name, &req);
2238 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2239 result = real_load (assemblies_path, aname->culture, aname->name, &req);
2242 return result;
2246 * mono_assembly_load_from_assemblies_path:
2248 * \param assemblies_path directories to search for given assembly name, terminated by NULL
2249 * \param aname assembly name to look for
2250 * \param asmctx assembly load context for this load operation
2252 * Given a NULL-terminated array of paths, look for \c name.ext, \c name, \c
2253 * culture/name.ext, \c culture/name/name.ext where \c ext is \c dll and \c
2254 * exe and try to load it in the given assembly load context.
2256 * \returns A \c MonoAssembly if probing was successful, or NULL otherwise.
2258 MonoAssembly*
2259 mono_assembly_load_from_assemblies_path (gchar **assemblies_path, MonoAssemblyName *aname, MonoAssemblyContextKind asmctx)
2261 MonoAssemblyCandidatePredicate predicate = NULL;
2262 void* predicate_ud = NULL;
2263 #if !defined(DISABLE_DESKTOP_LOADER)
2264 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2265 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2266 predicate_ud = aname;
2268 #endif
2269 MonoAssemblyOpenRequest req;
2270 mono_assembly_request_prepare (&req.request, sizeof (req), asmctx);
2271 req.request.predicate = predicate;
2272 req.request.predicate_ud = predicate_ud;
2273 MonoAssembly *result = NULL;
2274 if (assemblies_path && assemblies_path[0] != NULL) {
2275 result = real_load (assemblies_path, aname->culture, aname->name, &req);
2277 return result;
2281 * Check whenever a given assembly was already loaded in the current appdomain.
2283 static MonoAssembly *
2284 mono_domain_assembly_search (MonoAssemblyName *aname,
2285 gpointer user_data)
2287 g_assert (aname != NULL);
2288 MonoDomain *domain = mono_domain_get ();
2289 GSList *tmp;
2290 MonoAssembly *ass;
2291 gboolean refonly = GPOINTER_TO_UINT (user_data);
2292 const gboolean strong_name = aname->public_key_token[0] != 0;
2293 /* If it's not a strong name, any version that has the right simple
2294 * name is good enough to satisfy the request. .NET Framework also
2295 * ignores case differences in this case. */
2296 const MonoAssemblyNameEqFlags eq_flags = (MonoAssemblyNameEqFlags)(strong_name ? MONO_ANAME_EQ_IGNORE_CASE :
2297 (MONO_ANAME_EQ_IGNORE_PUBKEY | MONO_ANAME_EQ_IGNORE_VERSION | MONO_ANAME_EQ_IGNORE_CASE));
2299 mono_domain_assemblies_lock (domain);
2300 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2301 ass = (MonoAssembly *)tmp->data;
2302 g_assert (ass != NULL);
2303 /* Dynamic assemblies can't match here in MS.NET */
2304 gboolean ass_ref_only = mono_asmctx_get_kind (&ass->context) == MONO_ASMCTX_REFONLY;
2305 if (assembly_is_dynamic (ass) || refonly != ass_ref_only || !mono_assembly_names_equal_flags (aname, &ass->aname, eq_flags))
2306 continue;
2308 mono_domain_assemblies_unlock (domain);
2309 return ass;
2311 mono_domain_assemblies_unlock (domain);
2313 return NULL;
2316 MonoReflectionAssemblyHandle
2317 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoStackCrawlMark *stack_mark, MonoError *error)
2319 error_init (error);
2320 MonoDomain *domain = mono_domain_get ();
2321 char *name, *filename;
2322 MonoImageOpenStatus status = MONO_IMAGE_OK;
2323 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2325 name = NULL;
2327 if (MONO_HANDLE_IS_NULL (fname)) {
2328 mono_error_set_argument_null (error, "assemblyFile", "");
2329 goto leave;
2332 name = filename = mono_string_handle_to_utf8 (fname, error);
2333 goto_if_nok (error, leave);
2335 MonoAssembly *requesting_assembly;
2336 requesting_assembly = NULL;
2337 if (!refOnly)
2338 requesting_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2340 MonoAssembly *ass;
2341 MonoAssemblyOpenRequest req;
2342 mono_assembly_request_prepare (&req.request, sizeof (req), refOnly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_LOADFROM);
2343 req.requesting_assembly = requesting_assembly;
2344 ass = mono_assembly_request_open (filename, &req, &status);
2346 if (!ass) {
2347 if (status == MONO_IMAGE_IMAGE_INVALID)
2348 mono_error_set_bad_image_by_name (error, name, "Invalid Image");
2349 else
2350 mono_error_set_file_not_found (error, name, "Invalid Image");
2351 goto leave;
2354 result = mono_assembly_get_object_handle (domain, ass, error);
2356 leave:
2357 g_free (name);
2358 return result;
2361 MonoReflectionAssemblyHandle
2362 ves_icall_System_Reflection_Assembly_LoadFile_internal (MonoStringHandle fname, MonoStackCrawlMark *stack_mark, MonoError *error)
2364 MonoDomain *domain = mono_domain_get ();
2365 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2366 char *filename = NULL;
2367 if (MONO_HANDLE_IS_NULL (fname)) {
2368 mono_error_set_argument_null (error, "assemblyFile", "");
2369 goto leave;
2372 filename = mono_string_handle_to_utf8 (fname, error);
2373 goto_if_nok (error, leave);
2375 if (!g_path_is_absolute (filename)) {
2376 mono_error_set_argument (error, "assemblyFile", "Absolute path information is required.");
2377 goto leave;
2380 MonoImageOpenStatus status;
2381 MonoAssembly *executing_assembly;
2382 executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2383 MonoAssembly *ass;
2384 MonoAssemblyOpenRequest req;
2385 mono_assembly_request_prepare (&req.request, sizeof (req), MONO_ASMCTX_INDIVIDUAL);
2386 req.requesting_assembly = executing_assembly;
2387 ass = mono_assembly_request_open (filename, &req, &status);
2388 if (!ass) {
2389 if (status == MONO_IMAGE_IMAGE_INVALID)
2390 mono_error_set_bad_image_by_name (error, filename, "Invalid Image");
2391 else
2392 mono_error_set_file_not_found (error, filename, "Invalid Image");
2393 goto leave;
2396 result = mono_assembly_get_object_handle (domain, ass, error);
2397 leave:
2398 g_free (filename);
2399 return result;
2402 MonoReflectionAssemblyHandle
2403 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2404 MonoArrayHandle raw_assembly,
2405 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2406 MonoBoolean refonly,
2407 MonoError *error)
2409 MonoAssembly *ass;
2410 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2411 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2412 MonoImageOpenStatus status;
2413 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2415 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2416 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2417 if (!assembly_data) {
2418 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2419 return refass;
2421 uint32_t gchandle;
2422 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2423 memcpy (assembly_data, raw_data, raw_assembly_len);
2424 mono_gchandle_free_internal (gchandle); /* unpin */
2425 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2427 MonoImage *image = mono_image_open_from_data_internal (assembly_data, raw_assembly_len, FALSE, NULL, refonly, FALSE, NULL);
2429 if (!image) {
2430 mono_error_set_bad_image_by_name (error, "In memory assembly", "0x%p", raw_data);
2431 return refass;
2434 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2435 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2436 uint32_t symbol_gchandle;
2437 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2438 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2439 mono_gchandle_free_internal (symbol_gchandle);
2442 MonoAssembly* redirected_asm = NULL;
2443 MonoImageOpenStatus new_status = MONO_IMAGE_OK;
2444 if ((redirected_asm = mono_assembly_binding_applies_to_image (image, &new_status))) {
2445 mono_image_close (image);
2446 image = redirected_asm->image;
2447 mono_image_addref (image); /* so that mono_image close, below, has something to do */
2448 } else if (new_status != MONO_IMAGE_OK) {
2449 mono_image_close (image);
2450 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);
2451 return refass;
2454 MonoAssemblyLoadRequest req;
2455 mono_assembly_request_prepare (&req, sizeof (req), refonly? MONO_ASMCTX_REFONLY : MONO_ASMCTX_INDIVIDUAL);
2456 ass = mono_assembly_request_load_from (image, "", &req, &status);
2458 if (!ass) {
2459 mono_image_close (image);
2460 mono_error_set_bad_image_by_name (error, "In Memory assembly", "0x%p", assembly_data);
2461 return refass;
2464 /* Clear the reference added by mono_image_open_from_data_internal above */
2465 mono_image_close (image);
2467 refass = mono_assembly_get_object_handle (domain, ass, error);
2468 if (!MONO_HANDLE_IS_NULL(refass))
2469 MONO_HANDLE_SET (refass, evidence, evidence);
2470 return refass;
2473 MonoReflectionAssemblyHandle
2474 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoStackCrawlMark *stack_mark, MonoError *error)
2476 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2477 MonoImageOpenStatus status = MONO_IMAGE_OK;
2478 MonoAssembly *ass;
2479 MonoAssemblyName aname;
2480 gchar *name = NULL;
2481 gboolean parsed;
2483 g_assert (!MONO_HANDLE_IS_NULL (assRef));
2485 name = mono_string_handle_to_utf8 (assRef, error);
2486 goto_if_nok (error, fail);
2487 parsed = mono_assembly_name_parse (name, &aname);
2488 g_free (name);
2490 if (!parsed) {
2491 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2492 /* This is a parse error... */
2493 if (!refOnly) {
2494 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2495 goto_if_nok (error, fail);
2496 if (assm) {
2497 refass = mono_assembly_get_object_handle (domain, assm, error);
2498 goto_if_nok (error, fail);
2501 return refass;
2504 MonoAssemblyContextKind asmctx;
2505 asmctx = refOnly ? MONO_ASMCTX_REFONLY : MONO_ASMCTX_DEFAULT;
2506 const char *basedir;
2507 basedir = NULL;
2508 if (!refOnly) {
2509 /* Determine if the current assembly is in LoadFrom context.
2510 * If it is, we must include the executing assembly's basedir
2511 * when probing for the given assembly name, and also load the
2512 * requested assembly in LoadFrom context.
2514 MonoAssembly *executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark);
2515 if (executing_assembly && mono_asmctx_get_kind (&executing_assembly->context) == MONO_ASMCTX_LOADFROM) {
2516 asmctx = MONO_ASMCTX_LOADFROM;
2517 basedir = executing_assembly->basedir;
2522 MonoAssemblyByNameRequest req;
2523 mono_assembly_request_prepare (&req.request, sizeof (req), asmctx);
2524 req.basedir = basedir;
2525 req.no_postload_search = TRUE;
2526 ass = mono_assembly_request_byname (&aname, &req, &status);
2527 mono_assembly_name_free (&aname);
2529 if (!ass) {
2530 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2531 if (!refOnly) {
2532 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2533 goto_if_nok (error, fail);
2535 if (!ass)
2536 goto fail;
2539 g_assert (ass);
2540 MonoReflectionAssemblyHandle refass;
2541 refass = mono_assembly_get_object_handle (domain, ass, error);
2542 goto_if_nok (error, fail);
2544 MONO_HANDLE_SET (refass, evidence, evidence);
2546 return refass;
2547 fail:
2548 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2551 void
2552 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2554 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2556 if (NULL == domain) {
2557 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2558 return;
2561 if (domain == mono_get_root_domain ()) {
2562 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2563 return;
2567 * Unloading seems to cause problems when running NUnit/NAnt, hence
2568 * this workaround.
2570 if (g_hasenv ("MONO_NO_UNLOAD"))
2571 return;
2573 MonoException *exc = NULL;
2574 mono_domain_try_unload (domain, (MonoObject**)&exc);
2575 if (exc)
2576 mono_error_set_exception_instance (error, exc);
2579 MonoBoolean
2580 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2582 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2584 if (!domain)
2585 return TRUE;
2587 return mono_domain_is_unloading (domain);
2590 void
2591 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2593 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2594 mono_error_assert_ok (error);
2597 gint32
2598 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2599 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2600 MonoError *error)
2602 MonoImage *image;
2603 MonoMethod *method;
2605 g_assert (!MONO_HANDLE_IS_NULL (refass));
2606 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2607 image = assembly->image;
2608 g_assert (image);
2610 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2612 if (!method)
2613 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2615 if (MONO_HANDLE_IS_NULL (args)) {
2616 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2617 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2618 mono_error_assert_ok (error);
2621 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2622 return res;
2625 MonoAppDomainHandle
2626 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2628 error_init (error);
2629 MonoDomain *old_domain = mono_domain_get ();
2631 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2632 mono_error_set_appdomain_unloaded (error);
2633 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2636 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2639 MonoAppDomainHandle
2640 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2642 MonoDomain *current_domain = mono_domain_get ();
2643 MonoDomain *domain = mono_domain_get_by_id (domainid);
2645 if (!domain || !mono_domain_set (domain, FALSE)) {
2646 mono_error_set_appdomain_unloaded (error);
2647 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2650 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2653 void
2654 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2656 error_init (error);
2657 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2660 void
2661 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2663 error_init (error);
2664 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2666 if (!domain) {
2668 * Raise an exception to prevent the managed code from executing a pop
2669 * later.
2671 mono_error_set_appdomain_unloaded (error);
2672 return;
2675 mono_thread_push_appdomain_ref (domain);
2678 void
2679 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2681 error_init (error);
2682 mono_thread_pop_appdomain_ref ();
2685 MonoAppContextHandle
2686 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2688 error_init (error);
2689 return mono_context_get_handle ();
2692 MonoAppContextHandle
2693 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2695 error_init (error);
2696 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2699 MonoAppContextHandle
2700 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2702 error_init (error);
2703 MonoAppContextHandle old_context = mono_context_get_handle ();
2705 mono_context_set_handle (mc);
2707 return old_context;
2710 MonoStringHandle
2711 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2713 error_init (error);
2714 MonoDomain* mono_root_domain = mono_get_root_domain ();
2715 mono_domain_lock (mono_root_domain);
2716 if (process_guid_set) {
2717 mono_domain_unlock (mono_root_domain);
2718 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2720 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2721 memcpy (process_guid, mono_string_chars_internal (MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2722 mono_gchandle_free_internal (gchandle);
2723 process_guid_set = TRUE;
2724 mono_domain_unlock (mono_root_domain);
2725 return newguid;
2729 * mono_domain_is_unloading:
2731 gboolean
2732 mono_domain_is_unloading (MonoDomain *domain)
2734 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2735 return TRUE;
2736 else
2737 return FALSE;
2740 static void
2741 clear_cached_vtable (MonoVTable *vtable)
2743 MonoClass *klass = vtable->klass;
2744 MonoDomain *domain = vtable->domain;
2745 MonoClassRuntimeInfo *runtime_info;
2746 void *data;
2748 runtime_info = m_class_get_runtime_info (klass);
2749 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2750 runtime_info->domain_vtables [domain->domain_id] = NULL;
2751 if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable)))
2752 mono_gc_free_fixed (data);
2755 static G_GNUC_UNUSED void
2756 zero_static_data (MonoVTable *vtable)
2758 MonoClass *klass = vtable->klass;
2759 void *data;
2761 if (m_class_has_static_refs (klass) && (data = mono_vtable_get_static_field_data (vtable)))
2762 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2765 typedef struct unload_data {
2766 gboolean done;
2767 MonoDomain *domain;
2768 char *failure_reason;
2769 gint32 refcount;
2770 } unload_data;
2772 static void
2773 unload_data_unref (unload_data *data)
2775 if (!data)
2776 return;
2777 gint32 count;
2778 do {
2779 mono_atomic_load_acquire (count, gint32, &data->refcount);
2780 g_assert (count >= 1 && count <= 2);
2781 if (count == 1) {
2782 g_free (data);
2783 return;
2785 } while (mono_atomic_cas_i32 (&data->refcount, count - 1, count) != count);
2788 static void
2789 deregister_reflection_info_roots_from_list (MonoImage *image)
2791 GSList *list = image->reflection_info_unregister_classes;
2793 while (list) {
2794 MonoClass *klass = (MonoClass *)list->data;
2796 mono_class_free_ref_info (klass);
2798 list = list->next;
2801 image->reflection_info_unregister_classes = NULL;
2804 static void
2805 deregister_reflection_info_roots (MonoDomain *domain)
2807 GSList *list;
2809 mono_domain_assemblies_lock (domain);
2810 for (list = domain->domain_assemblies; list; list = list->next) {
2811 MonoAssembly *assembly = (MonoAssembly *)list->data;
2812 MonoImage *image = assembly->image;
2813 int i;
2816 * No need to take the image lock here since dynamic images are appdomain bound and
2817 * at this point the mutator is gone. Taking the image lock here would mean
2818 * promoting it from a simple lock to a complex lock, which we better avoid if
2819 * possible.
2821 if (image_is_dynamic (image))
2822 deregister_reflection_info_roots_from_list (image);
2824 for (i = 0; i < image->module_count; ++i) {
2825 MonoImage *module = image->modules [i];
2826 if (module && image_is_dynamic (module))
2827 deregister_reflection_info_roots_from_list (module);
2830 mono_domain_assemblies_unlock (domain);
2833 static gsize WINAPI
2834 unload_thread_main (void *arg)
2836 ERROR_DECL (error);
2837 unload_data *data = (unload_data*)arg;
2838 MonoDomain *domain = data->domain;
2839 MonoInternalThread *internal;
2840 int i;
2841 gsize result = 1; // failure
2843 internal = mono_thread_internal_current ();
2845 MonoString *thread_name_str = mono_string_new_checked (mono_domain_get (), "Domain unloader", error);
2846 if (is_ok (error))
2847 mono_thread_set_name_internal (internal, thread_name_str, TRUE, FALSE, error);
2848 if (!is_ok (error)) {
2849 data->failure_reason = g_strdup (mono_error_get_message (error));
2850 goto failure;
2854 * FIXME: Abort our parent thread last, so we can return a failure
2855 * indication if aborting times out.
2857 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2858 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2859 goto failure;
2862 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2863 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2864 goto failure;
2867 /* Finalize all finalizable objects in the doomed appdomain */
2868 if (!mono_domain_finalize (domain, -1)) {
2869 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2870 goto failure;
2873 /* Clear references to our vtables in class->runtime_info.
2874 * We also hold the loader lock because we're going to change
2875 * class->runtime_info.
2878 mono_loader_lock (); //FIXME why do we need the loader lock here?
2879 mono_domain_lock (domain);
2881 * We need to make sure that we don't have any remsets
2882 * pointing into static data of the to-be-freed domain because
2883 * at the next collections they would be invalid. So what we
2884 * do is we first zero all static data and then do a minor
2885 * collection. Because all references in the static data will
2886 * now be null we won't do any unnecessary copies and after
2887 * the collection there won't be any more remsets.
2889 for (i = 0; i < domain->class_vtable_array->len; ++i)
2890 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2891 mono_gc_collect (0);
2892 for (i = 0; i < domain->class_vtable_array->len; ++i)
2893 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2894 deregister_reflection_info_roots (domain);
2896 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2898 mono_domain_unlock (domain);
2899 mono_loader_unlock ();
2901 domain->state = MONO_APPDOMAIN_UNLOADED;
2903 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2905 /* remove from the handle table the items related to this domain */
2906 mono_gchandle_free_domain (domain);
2908 mono_domain_free (domain, FALSE);
2910 mono_gc_collect (mono_gc_max_generation ());
2912 result = 0; // success
2913 exit:
2914 mono_error_cleanup (error);
2915 mono_atomic_store_release (&data->done, TRUE);
2916 unload_data_unref (data);
2917 return result;
2919 failure:
2920 result = 1;
2921 goto exit;
2925 * mono_domain_unload:
2926 * \param domain The domain to unload
2928 * Unloads an appdomain. Follows the process outlined in the comment
2929 * for \c mono_domain_try_unload.
2931 void
2932 mono_domain_unload (MonoDomain *domain)
2934 MONO_ENTER_GC_UNSAFE;
2935 MonoObject *exc = NULL;
2936 mono_domain_try_unload (domain, &exc);
2937 MONO_EXIT_GC_UNSAFE;
2940 static MonoThreadInfoWaitRet
2941 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2943 MonoThreadInfoWaitRet result;
2945 MONO_ENTER_GC_SAFE;
2946 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2947 MONO_EXIT_GC_SAFE;
2949 return result;
2953 * mono_domain_unload:
2954 * \param domain The domain to unload
2955 * \param exc Exception information
2957 * Unloads an appdomain. Follows the process outlined in:
2958 * http://blogs.gotdotnet.com/cbrumme
2960 * If doing things the 'right' way is too hard or complex, we do it the
2961 * 'simple' way, which means do everything needed to avoid crashes and
2962 * memory leaks, but not much else.
2964 * It is required to pass a valid reference to the exc argument, upon return
2965 * from this function *exc will be set to the exception thrown, if any.
2967 * If this method is not called from an icall (embedded scenario for instance),
2968 * it must not be called with any managed frames on the stack, since the unload
2969 * process could end up trying to abort the current thread.
2971 void
2972 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2974 HANDLE_FUNCTION_ENTER ();
2975 ERROR_DECL (error);
2976 MonoThreadHandle *thread_handle = NULL;
2977 MonoAppDomainState prev_state;
2978 MonoMethod *method;
2979 unload_data *thread_data = NULL;
2980 MonoInternalThreadHandle internal;
2981 MonoDomain *caller_domain = mono_domain_get ();
2983 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2985 /* Atomically change our state to UNLOADING */
2986 prev_state = (MonoAppDomainState)mono_atomic_cas_i32 ((gint32*)&domain->state,
2987 MONO_APPDOMAIN_UNLOADING_START,
2988 MONO_APPDOMAIN_CREATED);
2989 if (prev_state != MONO_APPDOMAIN_CREATED) {
2990 switch (prev_state) {
2991 case MONO_APPDOMAIN_UNLOADING_START:
2992 case MONO_APPDOMAIN_UNLOADING:
2993 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2994 goto exit;
2995 case MONO_APPDOMAIN_UNLOADED:
2996 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2997 goto exit;
2998 default:
2999 g_warning ("Invalid appdomain state %d", prev_state);
3000 g_assert_not_reached ();
3004 mono_domain_set (domain, FALSE);
3005 /* Notify OnDomainUnload listeners */
3006 method = mono_class_get_method_from_name_checked (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1, 0, error);
3007 g_assert (method);
3009 mono_runtime_try_invoke (method, domain->domain, NULL, exc, error);
3011 if (!mono_error_ok (error)) {
3012 if (*exc)
3013 mono_error_cleanup (error);
3014 else
3015 *exc = (MonoObject*)mono_error_convert_to_exception (error);
3018 if (*exc) {
3019 /* Roll back the state change */
3020 domain->state = MONO_APPDOMAIN_CREATED;
3021 mono_domain_set (caller_domain, FALSE);
3022 goto exit;
3024 mono_domain_set (caller_domain, FALSE);
3026 thread_data = g_new0 (unload_data, 1);
3027 thread_data->domain = domain;
3028 thread_data->failure_reason = NULL;
3029 thread_data->done = FALSE;
3030 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
3032 /*The managed callback finished successfully, now we start tearing down the appdomain*/
3033 domain->state = MONO_APPDOMAIN_UNLOADING;
3035 * First we create a separate thread for unloading, since
3036 * we might have to abort some threads, including the current one.
3038 * Have to attach to the runtime so shutdown can wait for this thread.
3040 * Force it to be attached to avoid racing during shutdown.
3042 internal = mono_thread_create_internal_handle (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, error);
3043 mono_error_assert_ok (error);
3045 thread_handle = mono_threads_open_thread_handle (MONO_HANDLE_GETVAL (internal, handle));
3047 /* Wait for the thread */
3048 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
3049 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
3050 /* The unload thread tries to abort us */
3051 /* The icall wrapper will execute the abort */
3052 goto exit;
3056 if (thread_data->failure_reason) {
3057 /* Roll back the state change */
3058 domain->state = MONO_APPDOMAIN_CREATED;
3060 g_warning ("%s", thread_data->failure_reason);
3062 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
3064 g_free (thread_data->failure_reason);
3065 thread_data->failure_reason = NULL;
3068 exit:
3069 mono_threads_close_thread_handle (thread_handle);
3070 unload_data_unref (thread_data);
3071 HANDLE_FUNCTION_RETURN ();