Merge pull request #4621 from alexanderkyte/strdup_env
[mono.git] / mono / metadata / appdomain.c
1 /**
2  * \file
3  * AppDomain functions
4  *
5  * Authors:
6  *      Dietmar Maurer (dietmar@ximian.com)
7  *      Patrik Torstensson
8  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
9  *
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.
14  */
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
36
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/object.h>
39 #include <mono/metadata/appdomain-icalls.h>
40 #include <mono/metadata/domain-internals.h>
41 #include "mono/metadata/metadata-internals.h"
42 #include <mono/metadata/assembly-internals.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/exception-internals.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/marshal-internals.h>
51 #include <mono/metadata/monitor.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/w32file.h>
55 #include <mono/metadata/lock-tracer.h>
56 #include <mono/metadata/console-io.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/tokentype.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/reflection-internals.h>
61 #include <mono/metadata/abi-details.h>
62 #include <mono/metadata/w32socket.h>
63 #include <mono/utils/mono-uri.h>
64 #include <mono/utils/mono-logger-internals.h>
65 #include <mono/utils/mono-path.h>
66 #include <mono/utils/mono-stdlib.h>
67 #include <mono/utils/mono-io-portability.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/atomic.h>
70 #include <mono/utils/mono-memory-model.h>
71 #include <mono/utils/mono-threads.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/metadata/w32error.h>
74 #include <mono/utils/w32api.h>
75 #ifdef HOST_WIN32
76 #include <direct.h>
77 #endif
78
79 typedef struct
80 {
81         int runtime_count;
82         int assemblybinding_count;
83         MonoDomain *domain;
84         gchar *filename;
85 } RuntimeConfig;
86
87 static gunichar2 process_guid [36];
88 static gboolean process_guid_set = FALSE;
89
90 static gboolean no_exec = FALSE;
91
92 static MonoAssembly *
93 mono_domain_assembly_preload (MonoAssemblyName *aname,
94                               gchar **assemblies_path,
95                               gpointer user_data);
96
97 static MonoAssembly *
98 mono_domain_assembly_search (MonoAssemblyName *aname,
99                                                          gpointer user_data);
100
101 static void
102 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
103
104 static void
105 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
106
107 static MonoAppDomainHandle
108 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
109
110 static MonoDomain *
111 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
112
113
114 static char *
115 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
116
117 static MonoLoadFunc load_function = NULL;
118
119 /* Lazy class loading functions */
120 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
121
122 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
123
124 static MonoDomain *
125 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
126
127 static void
128 mono_error_set_appdomain_unloaded (MonoError *error)
129 {
130         mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
131 }
132
133 void
134 mono_install_runtime_load (MonoLoadFunc func)
135 {
136         load_function = func;
137 }
138
139 MonoDomain*
140 mono_runtime_load (const char *filename, const char *runtime_version)
141 {
142         g_assert (load_function);
143         return load_function (filename, runtime_version);
144 }
145
146 /**
147  * mono_runtime_set_no_exec:
148  *
149  * Instructs the runtime to operate in static mode, i.e. avoid/do not
150  * allow managed code execution. This is useful for running the AOT
151  * compiler on platforms which allow full-aot execution only.  This
152  * should be called before mono_runtime_init ().
153  */
154 void
155 mono_runtime_set_no_exec (gboolean val)
156 {
157         no_exec = val;
158 }
159
160 /**
161  * mono_runtime_get_no_exec:
162  *
163  * If true, then the runtime will not allow managed code execution.
164  */
165 gboolean
166 mono_runtime_get_no_exec (void)
167 {
168         return no_exec;
169 }
170
171 static void
172 create_domain_objects (MonoDomain *domain)
173 {
174         MonoError error;
175         MonoDomain *old_domain = mono_domain_get ();
176         MonoString *arg;
177         MonoVTable *string_vt;
178         MonoClassField *string_empty_fld;
179
180         if (domain != old_domain) {
181                 mono_thread_push_appdomain_ref (domain);
182                 mono_domain_set_internal_with_options (domain, FALSE);
183         }
184
185         /*
186          * Initialize String.Empty. This enables the removal of
187          * the static cctor of the String class.
188          */
189         string_vt = mono_class_vtable (domain, mono_defaults.string_class);
190         string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
191         g_assert (string_empty_fld);
192         MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
193         mono_error_assert_ok (&error);
194         mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
195         domain->empty_string = empty_str;
196
197         /*
198          * Create an instance early since we can't do it when there is no memory.
199          */
200         arg = mono_string_new (domain, "Out of memory");
201         domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
202         mono_error_assert_ok (&error);
203
204         /* 
205          * These two are needed because the signal handlers might be executing on
206          * an alternate stack, and Boehm GC can't handle that.
207          */
208         arg = mono_string_new (domain, "A null value was found where an object instance was required");
209         domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
210         mono_error_assert_ok (&error);
211         arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
212         domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
213         mono_error_assert_ok (&error);
214
215         /*The ephemeron tombstone i*/
216         domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
217         mono_error_assert_ok (&error);
218
219         if (domain != old_domain) {
220                 mono_thread_pop_appdomain_ref ();
221                 mono_domain_set_internal_with_options (old_domain, FALSE);
222         }
223
224         /* 
225          * This class is used during exception handling, so initialize it here, to prevent
226          * stack overflows while handling stack overflows.
227          */
228         mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
229 }
230
231 /**
232  * mono_runtime_init:
233  * \param domain domain returned by \c mono_init
234  *
235  * Initialize the core AppDomain: this function will run also some
236  * IL initialization code, so it needs the execution engine to be fully 
237  * operational.
238  *
239  * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
240  * we know the \c entry_assembly.
241  *
242  */
243 void
244 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
245 {
246         MonoError error;
247         mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
248         mono_error_cleanup (&error);
249 }
250
251 void
252 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
253 {
254         MonoAppDomainSetup *setup;
255         MonoAppDomain *ad;
256         MonoClass *klass;
257
258         error_init (error);
259
260         mono_portability_helpers_init ();
261         
262         mono_gc_base_init ();
263         mono_monitor_init ();
264         mono_marshal_init ();
265
266         mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
267         mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
268         mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
269         mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
270         mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
271         mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
272         mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
273
274         mono_thread_init (start_cb, attach_cb);
275
276         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
277         setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
278         return_if_nok (error);
279
280         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
281
282         ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
283         return_if_nok (error);
284
285         ad->data = domain;
286         domain->domain = ad;
287         domain->setup = setup;
288
289         mono_thread_attach (domain);
290
291         mono_type_initialization_init ();
292
293         if (!mono_runtime_get_no_exec ())
294                 create_domain_objects (domain);
295
296         /* GC init has to happen after thread init */
297         mono_gc_init ();
298
299         /* contexts use GC handles, so they must be initialized after the GC */
300         mono_context_init_checked (domain, error);
301         return_if_nok (error);
302         mono_context_set (domain->default_context);
303
304 #ifndef DISABLE_SOCKETS
305         mono_network_init ();
306 #endif
307         
308         mono_console_init ();
309         mono_attach_init ();
310
311         mono_locks_tracer_init ();
312
313         /* mscorlib is loaded before we install the load hook */
314         mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
315
316         return;
317 }
318
319 static int
320 mono_get_corlib_version (void)
321 {
322         MonoError error;
323         MonoClass *klass;
324         MonoClassField *field;
325         MonoObject *value;
326
327         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
328         mono_class_init (klass);
329         field = mono_class_get_field_from_name (klass, "mono_corlib_version");
330         if (!field)
331                 return -1;
332         if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
333                 return -1;
334         value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
335         mono_error_assert_ok (&error);
336         return *(gint32*)((gchar*)value + sizeof (MonoObject));
337 }
338
339 /**
340  * mono_check_corlib_version:
341  * Checks that the corlib that is loaded matches the version of this runtime.
342  * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
343  * allocated string with the error otherwise.
344  */
345 const char*
346 mono_check_corlib_version (void)
347 {
348         int version = mono_get_corlib_version ();
349         if (version != MONO_CORLIB_VERSION)
350                 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
351
352         /* Check that the managed and unmanaged layout of MonoInternalThread matches */
353         guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
354         guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
355         if (native_offset != managed_offset)
356                 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
357
358         return NULL;
359 }
360
361 /**
362  * mono_context_init:
363  * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
364  * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
365  */
366 void
367 mono_context_init (MonoDomain *domain)
368 {
369         MonoError error;
370         mono_context_init_checked (domain, &error);
371         mono_error_cleanup (&error);
372 }
373
374 void
375 mono_context_init_checked (MonoDomain *domain, MonoError *error)
376 {
377         MonoClass *klass;
378         MonoAppContext *context;
379
380         error_init (error);
381
382         klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
383         context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
384         return_if_nok (error);
385
386         context->domain_id = domain->domain_id;
387         context->context_id = 0;
388         ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
389         domain->default_context = context;
390 }
391
392 /**
393  * mono_runtime_cleanup:
394  * \param domain unused.
395  *
396  * Internal routine.
397  *
398  * This must not be called while there are still running threads executing
399  * managed code.
400  */
401 void
402 mono_runtime_cleanup (MonoDomain *domain)
403 {
404         mono_attach_cleanup ();
405
406         /* This ends up calling any pending pending (for at most 2 seconds) */
407         mono_gc_cleanup ();
408
409         mono_thread_cleanup ();
410
411 #ifndef DISABLE_SOCKETS
412         mono_network_cleanup ();
413 #endif
414         mono_marshal_cleanup ();
415
416         mono_type_initialization_cleanup ();
417
418         mono_monitor_cleanup ();
419 }
420
421 static MonoDomainFunc quit_function = NULL;
422
423 /**
424  * mono_install_runtime_cleanup:
425  */
426 void
427 mono_install_runtime_cleanup (MonoDomainFunc func)
428 {
429         quit_function = func;
430 }
431
432 /**
433  * mono_runtime_quit:
434  */
435 void
436 mono_runtime_quit ()
437 {
438         if (quit_function != NULL)
439                 quit_function (mono_get_root_domain (), NULL);
440 }
441
442 /**
443  * mono_domain_create_appdomain:
444  * \param friendly_name The friendly name of the appdomain to create
445  * \param configuration_file The configuration file to initialize the appdomain with
446  * \returns a \c MonoDomain initialized with the appdomain
447  */
448 MonoDomain *
449 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
450 {
451         HANDLE_FUNCTION_ENTER ();
452         MonoError error;
453         MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
454         mono_error_cleanup (&error);
455         HANDLE_FUNCTION_RETURN_VAL (domain);
456 }
457
458 /**
459  * mono_domain_create_appdomain_checked:
460  * \param friendly_name The friendly name of the appdomain to create
461  * \param configuration_file The configuration file to initialize the appdomain with
462  * \param error Set on error.
463  * 
464  * \returns a MonoDomain initialized with the appdomain.  On failure sets \p error and returns NULL.
465  */
466 MonoDomain *
467 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
468 {
469         HANDLE_FUNCTION_ENTER ();
470         error_init (error);
471         MonoDomain *result = NULL;
472
473         MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
474         MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
475         if (!is_ok (error))
476                 goto leave;
477         MonoStringHandle config_file;
478         if (configuration_file != NULL) {
479                 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
480                 if (!is_ok (error))
481                         goto leave;
482         } else {
483                 config_file = MONO_HANDLE_NEW (MonoString, NULL);
484         }
485         MONO_HANDLE_SET (setup, configuration_file, config_file);
486
487         MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
488         if (!is_ok (error))
489                 goto leave;
490
491         result = mono_domain_from_appdomain_handle (ad);
492 leave:
493         HANDLE_FUNCTION_RETURN_VAL (result);
494 }
495
496 /**
497  * mono_domain_set_config:
498  * \param domain \c MonoDomain initialized with the appdomain we want to change
499  * \param base_dir new base directory for the appdomain
500  * \param config_file_name path to the new configuration for the app domain
501  *
502  * Used to set the system configuration for an appdomain
503  *
504  * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException: 
505  * Error Initializing the configuration system. ---> System.ArgumentException: 
506  * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
507  */
508 void
509 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
510 {
511         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
512         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
513 }
514
515 static MonoAppDomainSetupHandle
516 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
517 {
518         HANDLE_FUNCTION_ENTER ();
519         MonoDomain *caller_domain;
520         MonoClass *ads_class;
521         MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
522
523         error_init (error);
524
525         caller_domain = mono_domain_get ();
526         ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
527
528         MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
529         if (!is_ok (error))
530                 goto leave;
531
532         mono_domain_set_internal (domain);
533
534 #define XCOPY_FIELD(dst,field,src,error)                                \
535         do {                                                            \
536                 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
537                 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
538                 if (!is_ok (error))                                     \
539                         goto leave;                                     \
540                 MONO_HANDLE_SET ((dst),field,copied_val);               \
541         } while (0)
542
543 #define COPY_VAL(dst,field,type,src)                                    \
544                 do {                                                    \
545                         MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
546                 } while (0)
547
548         XCOPY_FIELD (copy, application_base, setup, error);
549         XCOPY_FIELD (copy, application_name, setup, error);
550         XCOPY_FIELD (copy, cache_path, setup, error);
551         XCOPY_FIELD (copy, configuration_file, setup, error);
552         XCOPY_FIELD (copy, dynamic_base, setup, error);
553         XCOPY_FIELD (copy, license_file, setup, error);
554         XCOPY_FIELD (copy, private_bin_path, setup, error);
555         XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
556         XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
557         XCOPY_FIELD (copy, shadow_copy_files, setup, error);
558         COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
559         COPY_VAL (copy, path_changed, MonoBoolean, setup);
560         COPY_VAL (copy, loader_optimization, int, setup);
561         COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
562         COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
563         XCOPY_FIELD (copy, domain_initializer_args, setup, error);
564         COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
565         XCOPY_FIELD (copy, application_trust, setup, error);
566         XCOPY_FIELD (copy, configuration_bytes, setup, error);
567         XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
568
569 #undef XCOPY_FIELD
570 #undef COPY_VAL
571         
572         mono_domain_set_internal (caller_domain);
573
574         MONO_HANDLE_ASSIGN (result, copy);
575 leave:
576         HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
577 }
578
579 static MonoAppDomainHandle
580 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
581 {
582         HANDLE_FUNCTION_ENTER ();
583         MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
584         MonoClass *adclass;
585         MonoDomain *data;
586
587         error_init (error);
588
589         adclass = mono_class_get_appdomain_class ();
590
591         /* FIXME: pin all those objects */
592         data = mono_domain_create();
593
594         MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain,  mono_object_new_checked (data, adclass, error));
595         if (!is_ok (error))
596                 goto leave;
597         MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
598         data->domain = MONO_HANDLE_RAW (ad);
599         data->friendly_name = g_strdup (friendly_name);
600
601         mono_profiler_appdomain_name (data, data->friendly_name);
602
603         MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
604         if (MONO_HANDLE_IS_NULL (app_base)) {
605                 /* Inherit from the root domain since MS.NET does this */
606                 MonoDomain *root = mono_get_root_domain ();
607                 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
608                 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
609                 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
610                         /* N.B. new string is in the new domain */
611                         uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
612                         MonoStringHandle s = mono_string_new_utf16_handle (data, mono_string_chars (MONO_HANDLE_RAW (root_app_base)), mono_string_handle_length (root_app_base), error);
613                         mono_gchandle_free (gchandle);
614                         if (!is_ok (error)) {
615                                 g_free (data->friendly_name);
616                                 goto leave;
617                         }
618                         MONO_HANDLE_SET (setup, application_base, s);
619                 }
620         }
621
622         mono_context_init_checked (data, error);
623         if (!is_ok (error))
624                 goto leave;
625
626         data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
627         if (!mono_error_ok (error)) {
628                 g_free (data->friendly_name);
629                 goto leave;
630         }
631
632         mono_domain_set_options_from_config (data);
633         add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
634
635 #ifndef DISABLE_SHADOW_COPY
636         /*FIXME, guard this for when the debugger is not running */
637         char *shadow_location = get_shadow_assembly_location_base (data, error);
638         if (!mono_error_ok (error)) {
639                 g_free (data->friendly_name);
640                 goto leave;
641         }
642
643         g_free (shadow_location);
644 #endif
645
646         create_domain_objects (data);
647
648         MONO_HANDLE_ASSIGN (result, ad);
649 leave:
650         HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
651 }
652
653 /**
654  * mono_domain_has_type_resolve:
655  * \param domain application domain being looked up
656  *
657  * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
658  */
659 gboolean
660 mono_domain_has_type_resolve (MonoDomain *domain)
661 {
662         static MonoClassField *field = NULL;
663         MonoObject *o;
664
665         if (field == NULL) {
666                 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
667                 g_assert (field);
668         }
669
670         /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
671         if (!domain->domain)
672                 return FALSE;
673
674         mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
675         return o != NULL;
676 }
677
678 /**
679  * mono_domain_try_type_resolve:
680  * \param domain application domainwhere the name where the type is going to be resolved
681  * \param name the name of the type to resolve or NULL.
682  * \param tb A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
683  *
684  * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
685  * the assembly that matches name.
686  *
687  * If \p name is null, the value of \c ((TypeBuilder)tb).FullName is used instead
688  *
689  * \returns A \c MonoReflectionAssembly or NULL if not found
690  */
691 MonoReflectionAssembly *
692 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
693 {
694         MonoError error;
695         MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
696         mono_error_cleanup (&error);
697
698         return ret;
699 }
700
701 MonoReflectionAssembly *
702 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
703 {
704         static MonoMethod *method = NULL;
705         MonoReflectionAssembly *ret;
706         void *params [1];
707
708         error_init (error);
709
710         g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
711
712         if (method == NULL) {
713                 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
714                 if (method == NULL) {
715                         g_warning ("Method AppDomain.DoTypeResolve not found.\n");
716                         return NULL;
717                 }
718         }
719
720         if (name)
721                 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
722         else
723                 *params = tb;
724
725         ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
726         return_val_if_nok (error, NULL);
727
728         return ret;
729 }
730
731 /**
732  * mono_domain_owns_vtable_slot:
733  * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
734  */
735 gboolean
736 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
737 {
738         gboolean res;
739
740         mono_domain_lock (domain);
741         res = mono_mempool_contains_addr (domain->mp, vtable_slot);
742         mono_domain_unlock (domain);
743         return res;
744 }
745
746 /**
747  * mono_domain_set:
748  * \param domain domain
749  * \param force force setting.
750  *
751  * Set the current appdomain to \p domain. If \p force is set, set it even
752  * if it is being unloaded.
753  *
754  * \returns TRUE on success; FALSE if the domain is unloaded
755  */
756 gboolean
757 mono_domain_set (MonoDomain *domain, gboolean force)
758 {
759         if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
760                 return FALSE;
761
762         mono_domain_set_internal (domain);
763
764         return TRUE;
765 }
766
767 MonoObjectHandle
768 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
769 {
770         error_init (error);
771
772         if (MONO_HANDLE_IS_NULL (name)) {
773                 mono_error_set_argument_null (error, "name", "");
774                 return NULL_HANDLE;
775         }
776
777         g_assert (!MONO_HANDLE_IS_NULL (ad));
778         MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
779         g_assert (add);
780
781         char *str = mono_string_handle_to_utf8 (name, error);
782         return_val_if_nok (error, NULL_HANDLE);
783
784         mono_domain_lock (add);
785
786         MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
787         MonoStringHandle o;
788         if (!strcmp (str, "APPBASE"))
789                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
790         else if (!strcmp (str, "APP_CONFIG_FILE"))
791                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
792         else if (!strcmp (str, "DYNAMIC_BASE"))
793                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
794         else if (!strcmp (str, "APP_NAME"))
795                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
796         else if (!strcmp (str, "CACHE_BASE"))
797                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
798         else if (!strcmp (str, "PRIVATE_BINPATH"))
799                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
800         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
801                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
802         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
803                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
804         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
805                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
806         else 
807                 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
808
809         mono_domain_unlock (add);
810         g_free (str);
811
812         return MONO_HANDLE_CAST (MonoObject, o);
813 }
814
815 void
816 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
817 {
818         error_init (error);
819
820         if (MONO_HANDLE_IS_NULL (name)) {
821                 mono_error_set_argument_null (error, "name", "");
822                 return;
823         }
824
825         g_assert (!MONO_HANDLE_IS_NULL (ad));
826         MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
827         g_assert (add);
828
829         mono_domain_lock (add);
830
831         mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
832
833         mono_domain_unlock (add);
834 }
835
836 MonoAppDomainSetupHandle
837 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
838 {
839         error_init (error);
840         g_assert (!MONO_HANDLE_IS_NULL (ad));
841         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
842         g_assert (domain);
843
844         return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
845 }
846
847 MonoStringHandle
848 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
849 {
850         error_init (error);
851         g_assert (!MONO_HANDLE_IS_NULL (ad));
852         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
853         g_assert (domain);
854
855         return mono_string_new_handle (domain, domain->friendly_name, error);
856 }
857
858 MonoAppDomainHandle
859 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
860 {
861         error_init (error);
862         MonoDomain *add = mono_domain_get ();
863
864         return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
865 }
866
867 MonoAppDomainHandle
868 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
869 {
870         error_init (error);
871         MonoDomain *root = mono_get_root_domain ();
872
873         return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
874 }
875
876 MonoBoolean
877 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
878 {
879         MonoDomain *domain = mono_domain_get ();
880
881         return domain->throw_unobserved_task_exceptions;
882 }
883
884 static char*
885 get_attribute_value (const gchar **attribute_names, 
886                      const gchar **attribute_values, 
887                      const char *att_name)
888 {
889         int n;
890         for (n = 0; attribute_names [n] != NULL; n++) {
891                 if (strcmp (attribute_names [n], att_name) == 0)
892                         return g_strdup (attribute_values [n]);
893         }
894         return NULL;
895 }
896
897 static void
898 start_element (GMarkupParseContext *context, 
899                const gchar         *element_name,
900                const gchar        **attribute_names,
901                const gchar        **attribute_values,
902                gpointer             user_data,
903                GError             **error)
904 {
905         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
906         
907         if (strcmp (element_name, "runtime") == 0) {
908                 runtime_config->runtime_count++;
909                 return;
910         }
911
912         if (strcmp (element_name, "assemblyBinding") == 0) {
913                 runtime_config->assemblybinding_count++;
914                 return;
915         }
916
917         if (runtime_config->runtime_count != 1)
918                 return;
919
920         if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
921                 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
922
923                 if (value && g_ascii_strcasecmp (value, "true") == 0)
924                         runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
925         }
926
927         if (runtime_config->assemblybinding_count != 1)
928                 return;
929
930         if (strcmp (element_name, "probing") != 0)
931                 return;
932
933         g_free (runtime_config->domain->private_bin_path);
934         runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
935         if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
936                 g_free (runtime_config->domain->private_bin_path);
937                 runtime_config->domain->private_bin_path = NULL;
938                 return;
939         }
940 }
941
942 static void
943 end_element (GMarkupParseContext *context,
944              const gchar         *element_name,
945              gpointer             user_data,
946              GError             **error)
947 {
948         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
949         if (strcmp (element_name, "runtime") == 0)
950                 runtime_config->runtime_count--;
951         else if (strcmp (element_name, "assemblyBinding") == 0)
952                 runtime_config->assemblybinding_count--;
953 }
954
955 static void
956 parse_error   (GMarkupParseContext *context, GError *error, gpointer user_data)
957 {
958         RuntimeConfig *state = (RuntimeConfig *)user_data;
959         const gchar *msg;
960         const gchar *filename;
961
962         filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
963         msg = error && error->message ? error->message : "";
964         g_warning ("Error parsing %s: %s", filename, msg);
965 }
966
967 static const GMarkupParser
968 mono_parser = {
969         start_element,
970         end_element,
971         NULL,
972         NULL,
973         parse_error
974 };
975
976 void
977 mono_domain_set_options_from_config (MonoDomain *domain)
978 {
979         MonoError error;
980         gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
981         gsize len;
982         GMarkupParseContext *context;
983         RuntimeConfig runtime_config;
984         gint offset;
985         
986         if (!domain || !domain->setup || !domain->setup->configuration_file)
987                 return;
988
989         config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
990         if (!mono_error_ok (&error)) {
991                 mono_error_cleanup (&error);
992                 goto free_and_out;
993         }
994
995         config_file_path = mono_portability_find_file (config_file_name, TRUE);
996         if (!config_file_path)
997                 config_file_path = config_file_name;
998
999         if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1000                 goto free_and_out;
1001
1002         runtime_config.runtime_count = 0;
1003         runtime_config.assemblybinding_count = 0;
1004         runtime_config.domain = domain;
1005         runtime_config.filename = config_file_path;
1006         
1007         offset = 0;
1008         if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1009                 offset = 3; /* Skip UTF-8 BOM */
1010
1011         context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1012         if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1013                 g_markup_parse_context_end_parse (context, NULL);
1014         g_markup_parse_context_free (context);
1015
1016   free_and_out:
1017         g_free (text);
1018         if (config_file_name != config_file_path)
1019                 g_free (config_file_name);
1020         g_free (config_file_path);
1021 }
1022
1023 MonoAppDomainHandle
1024 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1025 {
1026         error_init (error);
1027         MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1028
1029 #ifdef DISABLE_APPDOMAINS
1030         mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1031 #else
1032         char *fname;
1033
1034         fname = mono_string_handle_to_utf8 (friendly_name, error);
1035         return_val_if_nok (error, ad);
1036         ad = mono_domain_create_appdomain_internal (fname, setup, error);
1037         g_free (fname);
1038 #endif
1039         return ad;
1040 }
1041
1042 static gboolean
1043 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1044 {
1045         HANDLE_FUNCTION_ENTER ();
1046         error_init (error);
1047         MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1048         if (!is_ok (error))
1049                 goto leave;
1050         MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1051 leave:
1052         HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1053 }
1054
1055 MonoArrayHandle
1056 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1057 {
1058         error_init (error);
1059         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1060         MonoAssembly* ass;
1061         GSList *tmp;
1062         int i;
1063         GPtrArray *assemblies;
1064
1065         /* 
1066          * Make a copy of the list of assemblies because we can't hold the assemblies
1067          * lock while creating objects etc.
1068          */
1069         assemblies = g_ptr_array_new ();
1070         /* Need to skip internal assembly builders created by remoting */
1071         mono_domain_assemblies_lock (domain);
1072         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1073                 ass = (MonoAssembly *)tmp->data;
1074                 if (refonly != ass->ref_only)
1075                         continue;
1076                 if (ass->corlib_internal)
1077                         continue;
1078                 g_ptr_array_add (assemblies, ass);
1079         }
1080         mono_domain_assemblies_unlock (domain);
1081
1082         MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1083         if (!is_ok (error))
1084                 goto leave;
1085         for (i = 0; i < assemblies->len; ++i) {
1086                 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1087                         goto leave;
1088         }
1089
1090 leave:
1091         g_ptr_array_free (assemblies, TRUE);
1092         return res;
1093 }
1094
1095 MonoAssembly*
1096 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1097 {
1098         HANDLE_FUNCTION_ENTER ();
1099         error_init (error);
1100         MonoAssembly *result = NULL;
1101         MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1102         if (!is_ok (error))
1103                 goto leave;
1104         result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1105 leave:
1106         HANDLE_FUNCTION_RETURN_VAL (result);
1107 }
1108
1109 MonoAssembly*
1110 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1111 {
1112         MonoAssembly *ret = NULL;
1113         MonoMethod *method;
1114         MonoBoolean isrefonly;
1115         gpointer params [3];
1116
1117         error_init (error);
1118
1119         if (mono_runtime_get_no_exec ())
1120                 return ret;
1121
1122         g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1123
1124         method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1125         g_assert (method != NULL);
1126
1127         isrefonly = refonly ? 1 : 0;
1128         MonoReflectionAssemblyHandle requesting_handle;
1129         if (requesting) {
1130                 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1131                 return_val_if_nok (error, ret);
1132         }
1133         params [0] = MONO_HANDLE_RAW (fname);
1134         params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1135         params [2] = &isrefonly;
1136         MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1137         ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1138         return ret;
1139 }
1140
1141 MonoAssembly *
1142 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1143                                                                           gboolean refonly)
1144 {
1145         MonoError error;
1146         MonoAssembly *assembly;
1147         MonoDomain *domain = mono_domain_get ();
1148         char *aname_str;
1149
1150         aname_str = mono_stringify_assembly_name (aname);
1151
1152         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1153
1154         assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1155         g_free (aname_str);
1156         mono_error_cleanup (&error);
1157
1158         return assembly;
1159 }
1160         
1161 /*
1162  * LOCKING: assumes assemblies_lock in the domain is already locked.
1163  */
1164 static void
1165 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1166 {
1167         gint i;
1168         GSList *tmp;
1169         gboolean destroy_ht = FALSE;
1170
1171         if (!ass->aname.name)
1172                 return;
1173
1174         if (!ht) {
1175                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1176                 destroy_ht = TRUE;
1177                 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1178                         g_hash_table_insert (ht, tmp->data, tmp->data);
1179                 }
1180         }
1181
1182         /* FIXME: handle lazy loaded assemblies */
1183
1184         if (!g_hash_table_lookup (ht, ass)) {
1185                 mono_assembly_addref (ass);
1186                 g_hash_table_insert (ht, ass, ass);
1187                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1188                 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);
1189         }
1190
1191         if (ass->image->references) {
1192                 for (i = 0; i < ass->image->nreferences; i++) {
1193                         if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1194                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1195                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
1196                                 }
1197                         }
1198                 }
1199         }
1200         if (destroy_ht)
1201                 g_hash_table_destroy (ht);
1202 }
1203
1204 static void
1205 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1206 {
1207         static MonoClassField *assembly_load_field;
1208         static MonoMethod *assembly_load_method;
1209         MonoError error;
1210         MonoDomain *domain = mono_domain_get ();
1211         MonoClass *klass;
1212         gpointer load_value;
1213         void *params [1];
1214
1215         if (!domain->domain)
1216                 /* This can happen during startup */
1217                 return;
1218 #ifdef ASSEMBLY_LOAD_DEBUG
1219         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1220 #endif
1221         klass = domain->domain->mbr.obj.vtable->klass;
1222
1223         mono_domain_assemblies_lock (domain);
1224         add_assemblies_to_domain (domain, assembly, NULL);
1225         mono_domain_assemblies_unlock (domain);
1226
1227         if (assembly_load_field == NULL) {
1228                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1229                 g_assert (assembly_load_field);
1230         }
1231
1232         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1233         if (load_value == NULL) {
1234                 /* No events waiting to be triggered */
1235                 return;
1236         }
1237
1238         MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1239         mono_error_assert_ok (&error);
1240
1241         if (assembly_load_method == NULL) {
1242                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1243                 g_assert (assembly_load_method);
1244         }
1245
1246         *params = MONO_HANDLE_RAW(ref_assembly);
1247
1248         mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1249         mono_error_cleanup (&error);
1250 }
1251
1252 /*
1253  * LOCKING: Acquires the domain assemblies lock.
1254  */
1255 static void
1256 set_domain_search_path (MonoDomain *domain)
1257 {
1258         MonoError error;
1259         MonoAppDomainSetup *setup;
1260         gchar **tmp;
1261         gchar *search_path = NULL;
1262         gint i;
1263         gint npaths = 0;
1264         gchar **pvt_split = NULL;
1265         GError *gerror = NULL;
1266         gint appbaselen = -1;
1267
1268         /* 
1269          * We use the low-level domain assemblies lock, since this is called from
1270          * assembly loads hooks, which means this thread might hold the loader lock.
1271          */
1272         mono_domain_assemblies_lock (domain);
1273
1274         if (!domain->setup) {
1275                 mono_domain_assemblies_unlock (domain);
1276                 return;
1277         }
1278
1279         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1280                 mono_domain_assemblies_unlock (domain);
1281                 return;
1282         }
1283         setup = domain->setup;
1284         if (!setup->application_base) {
1285                 mono_domain_assemblies_unlock (domain);
1286                 return; /* Must set application base to get private path working */
1287         }
1288
1289         npaths++;
1290         
1291         if (setup->private_bin_path) {
1292                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1293                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1294                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1295                         mono_error_cleanup (&error);
1296                         mono_domain_assemblies_unlock (domain);
1297                         return;
1298                 }
1299         }
1300         
1301         if (domain->private_bin_path) {
1302                 if (search_path == NULL)
1303                         search_path = domain->private_bin_path;
1304                 else {
1305                         gchar *tmp2 = search_path;
1306                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1307                         g_free (tmp2);
1308                 }
1309         }
1310         
1311         if (search_path) {
1312                 /*
1313                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1314                  * directories relative to ApplicationBase separated by semicolons (see
1315                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1316                  * The loop below copes with the fact that some Unix applications may use ':' (or
1317                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1318                  * ';' for the subsequent split.
1319                  *
1320                  * The issue was reported in bug #81446
1321                  */
1322
1323 #ifndef TARGET_WIN32
1324                 gint slen;
1325
1326                 slen = strlen (search_path);
1327                 for (i = 0; i < slen; i++)
1328                         if (search_path [i] == ':')
1329                                 search_path [i] = ';';
1330 #endif
1331                 
1332                 pvt_split = g_strsplit (search_path, ";", 1000);
1333                 g_free (search_path);
1334                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1335         }
1336
1337         if (!npaths) {
1338                 if (pvt_split)
1339                         g_strfreev (pvt_split);
1340                 /*
1341                  * Don't do this because the first time is called, the domain
1342                  * setup is not finished.
1343                  *
1344                  * domain->search_path = g_malloc (sizeof (char *));
1345                  * domain->search_path [0] = NULL;
1346                 */
1347                 mono_domain_assemblies_unlock (domain);
1348                 return;
1349         }
1350
1351         if (domain->search_path)
1352                 g_strfreev (domain->search_path);
1353
1354         tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1355         tmp [npaths] = NULL;
1356
1357         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1358         if (!mono_error_ok (&error)) {
1359                 mono_error_cleanup (&error);
1360                 g_strfreev (pvt_split);
1361                 g_free (tmp);
1362
1363                 mono_domain_assemblies_unlock (domain);
1364                 return;
1365         }
1366
1367         domain->search_path = tmp;
1368
1369         /* FIXME: is this needed? */
1370         if (strncmp (*tmp, "file://", 7) == 0) {
1371                 gchar *file = *tmp;
1372                 gchar *uri = *tmp;
1373                 gchar *tmpuri;
1374
1375                 if (uri [7] != '/')
1376                         uri = g_strdup_printf ("file:///%s", uri + 7);
1377
1378                 tmpuri = uri;
1379                 uri = mono_escape_uri_string (tmpuri);
1380                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1381                 g_free (uri);
1382
1383                 if (tmpuri != file)
1384                         g_free (tmpuri);
1385
1386                 if (gerror != NULL) {
1387                         g_warning ("%s\n", gerror->message);
1388                         g_error_free (gerror);
1389                         *tmp = file;
1390                 } else {
1391                         g_free (file);
1392                 }
1393         }
1394
1395         for (i = 1; pvt_split && i < npaths; i++) {
1396                 if (g_path_is_absolute (pvt_split [i - 1])) {
1397                         tmp [i] = g_strdup (pvt_split [i - 1]);
1398                 } else {
1399                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1400                 }
1401
1402                 if (strchr (tmp [i], '.')) {
1403                         gchar *reduced;
1404                         gchar *freeme;
1405
1406                         reduced = mono_path_canonicalize (tmp [i]);
1407                         if (appbaselen == -1)
1408                                 appbaselen = strlen (tmp [0]);
1409
1410                         if (strncmp (tmp [0], reduced, appbaselen)) {
1411                                 g_free (reduced);
1412                                 g_free (tmp [i]);
1413                                 tmp [i] = g_strdup ("");
1414                                 continue;
1415                         }
1416
1417                         freeme = tmp [i];
1418                         tmp [i] = reduced;
1419                         g_free (freeme);
1420                 }
1421         }
1422         
1423         if (setup->private_bin_path_probe != NULL) {
1424                 g_free (tmp [0]);
1425                 tmp [0] = g_strdup ("");
1426         }
1427                 
1428         domain->setup->path_changed = FALSE;
1429
1430         g_strfreev (pvt_split);
1431
1432         mono_domain_assemblies_unlock (domain);
1433 }
1434
1435 #ifdef DISABLE_SHADOW_COPY
1436 gboolean
1437 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1438 {
1439         return FALSE;
1440 }
1441
1442 char *
1443 mono_make_shadow_copy (const char *filename, MonoError *error)
1444 {
1445         error_init (error);
1446         return (char *) filename;
1447 }
1448 #else
1449 static gboolean
1450 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1451 {
1452         guint16 *orig, *dest;
1453         gboolean copy_result;
1454         gint32 copy_error;
1455         
1456         strcpy (src + srclen - tail_len, extension);
1457
1458         if (IS_PORTABILITY_CASE) {
1459                 gchar *file = mono_portability_find_file (src, TRUE);
1460
1461                 if (file == NULL)
1462                         return TRUE;
1463
1464                 g_free (file);
1465         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1466                 return TRUE;
1467         }
1468
1469         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1470
1471         strcpy (target + targetlen - tail_len, extension);
1472         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1473         
1474         mono_w32file_delete (dest);
1475
1476         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1477
1478         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1479          * overwritten when updated in their original locations. */
1480         if (copy_result)
1481                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1482
1483         g_free (orig);
1484         g_free (dest);
1485         
1486         return copy_result;
1487 }
1488
1489 static gint32 
1490 get_cstring_hash (const char *str)
1491 {
1492         int len, i;
1493         const char *p;
1494         gint32 h = 0;
1495         
1496         if (!str || !str [0])
1497                 return 0;
1498                 
1499         len = strlen (str);
1500         p = str;
1501         for (i = 0; i < len; i++) {
1502                 h = (h << 5) - h + *p;
1503                 p++;
1504         }
1505         
1506         return h;
1507 }
1508
1509 /*
1510  * Returned memory is malloc'd. Called must free it 
1511  */
1512 static char *
1513 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1514 {
1515         MonoAppDomainSetup *setup;
1516         char *cache_path, *appname;
1517         char *userdir;
1518         char *location;
1519
1520         error_init (error);
1521         
1522         setup = domain->setup;
1523         if (setup->cache_path != NULL && setup->application_name != NULL) {
1524                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1525                 return_val_if_nok (error, NULL);
1526
1527 #ifndef TARGET_WIN32
1528                 {
1529                         gint i;
1530                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1531                                 if (cache_path [i] == '\\')
1532                                         cache_path [i] = '/';
1533                 }
1534 #endif
1535
1536                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1537                 if (!mono_error_ok (error)) {
1538                         g_free (cache_path);
1539                         return NULL;
1540                 }
1541
1542                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1543                 g_free (appname);
1544                 g_free (cache_path);
1545         } else {
1546                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1547                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1548                 g_free (userdir);
1549         }
1550         return location;
1551 }
1552
1553 static char *
1554 get_shadow_assembly_location (const char *filename, MonoError *error)
1555 {
1556         gint32 hash = 0, hash2 = 0;
1557         char name_hash [9];
1558         char path_hash [30];
1559         char *bname = g_path_get_basename (filename);
1560         char *dirname = g_path_get_dirname (filename);
1561         char *location, *tmploc;
1562         MonoDomain *domain = mono_domain_get ();
1563
1564         error_init (error);
1565         
1566         hash = get_cstring_hash (bname);
1567         hash2 = get_cstring_hash (dirname);
1568         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1569         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1570         tmploc = get_shadow_assembly_location_base (domain, error);
1571         if (!mono_error_ok (error)) {
1572                 g_free (bname);
1573                 g_free (dirname);
1574                 return NULL;
1575         }
1576
1577         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1578         g_free (tmploc);
1579         g_free (bname);
1580         g_free (dirname);
1581         return location;
1582 }
1583
1584 static gboolean
1585 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1586 {
1587         struct stat sbuf_dest;
1588         gchar *stat_src;
1589         gchar *real_src = mono_portability_find_file (src, TRUE);
1590
1591         if (!real_src)
1592                 stat_src = (gchar*)src;
1593         else
1594                 stat_src = real_src;
1595
1596         if (stat (stat_src, sbuf_src) == -1) {
1597                 time_t tnow = time (NULL);
1598
1599                 if (real_src)
1600                         g_free (real_src);
1601
1602                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1603                 sbuf_src->st_mtime = tnow;
1604                 sbuf_src->st_atime = tnow;
1605                 return TRUE;
1606         }
1607
1608         if (real_src)
1609                 g_free (real_src);
1610
1611         if (stat (dest, &sbuf_dest) == -1)
1612                 return TRUE;
1613         
1614         if (sbuf_src->st_size == sbuf_dest.st_size &&
1615             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1616                 return FALSE;
1617
1618         return TRUE;
1619 }
1620
1621 static gboolean
1622 shadow_copy_create_ini (const char *shadow, const char *filename)
1623 {
1624         char *dir_name;
1625         char *ini_file;
1626         guint16 *u16_ini;
1627         gboolean result;
1628         guint32 n;
1629         HANDLE *handle;
1630         gchar *full_path;
1631
1632         dir_name = g_path_get_dirname (shadow);
1633         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1634         g_free (dir_name);
1635         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1636                 g_free (ini_file);
1637                 return TRUE;
1638         }
1639
1640         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1641         g_free (ini_file);
1642         if (!u16_ini) {
1643                 return FALSE;
1644         }
1645         handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1646         g_free (u16_ini);
1647         if (handle == INVALID_HANDLE_VALUE) {
1648                 return FALSE;
1649         }
1650
1651         full_path = mono_path_resolve_symlinks (filename);
1652         result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1653         g_free (full_path);
1654         mono_w32file_close (handle);
1655         return result;
1656 }
1657
1658 gboolean
1659 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1660 {
1661         MonoError error;
1662         MonoAppDomainSetup *setup;
1663         gchar *all_dirs;
1664         gchar **dir_ptr;
1665         gchar **directories;
1666         gchar *shadow_status_string;
1667         gchar *base_dir;
1668         gboolean shadow_enabled;
1669         gboolean found = FALSE;
1670
1671         if (domain == NULL)
1672                 return FALSE;
1673
1674         setup = domain->setup;
1675         if (setup == NULL || setup->shadow_copy_files == NULL)
1676                 return FALSE;
1677
1678         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1679         if (!mono_error_ok (&error)) {
1680                 mono_error_cleanup (&error);
1681                 return FALSE;
1682         }
1683         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1684         g_free (shadow_status_string);
1685
1686         if (!shadow_enabled)
1687                 return FALSE;
1688
1689         if (setup->shadow_copy_directories == NULL)
1690                 return TRUE;
1691
1692         /* Is dir_name a shadow_copy destination already? */
1693         base_dir = get_shadow_assembly_location_base (domain, &error);
1694         if (!mono_error_ok (&error)) {
1695                 mono_error_cleanup (&error);
1696                 return FALSE;
1697         }
1698
1699         if (strstr (dir_name, base_dir)) {
1700                 g_free (base_dir);
1701                 return TRUE;
1702         }
1703         g_free (base_dir);
1704
1705         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1706         if (!mono_error_ok (&error)) {
1707                 mono_error_cleanup (&error);
1708                 return FALSE;
1709         }
1710
1711         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1712         dir_ptr = directories;
1713         while (*dir_ptr) {
1714                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1715                         found = TRUE;
1716                         break;
1717                 }
1718                 dir_ptr++;
1719         }
1720         g_strfreev (directories);
1721         g_free (all_dirs);
1722         return found;
1723 }
1724
1725 /*
1726 This function raises exceptions so it can cause as sorts of nasty stuff if called
1727 while holding a lock.
1728 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1729 or NULL if source file not found.
1730 FIXME bubble up the error instead of raising it here
1731 */
1732 char *
1733 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1734 {
1735         MonoError error;
1736         gchar *sibling_source, *sibling_target;
1737         gint sibling_source_len, sibling_target_len;
1738         guint16 *orig, *dest;
1739         guint32 attrs;
1740         char *shadow;
1741         gboolean copy_result;
1742         struct stat src_sbuf;
1743         struct utimbuf utbuf;
1744         char *dir_name = g_path_get_dirname (filename);
1745         MonoDomain *domain = mono_domain_get ();
1746         char *shadow_dir;
1747         gint32 copy_error;
1748
1749         error_init (oerror);
1750
1751         set_domain_search_path (domain);
1752
1753         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1754                 g_free (dir_name);
1755                 return (char *) filename;
1756         }
1757
1758         /* Is dir_name a shadow_copy destination already? */
1759         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1760         if (!mono_error_ok (&error)) {
1761                 mono_error_cleanup (&error);
1762                 g_free (dir_name);
1763                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1764                 return NULL;
1765         }
1766
1767         if (strstr (dir_name, shadow_dir)) {
1768                 g_free (shadow_dir);
1769                 g_free (dir_name);
1770                 return (char *) filename;
1771         }
1772         g_free (shadow_dir);
1773         g_free (dir_name);
1774
1775         shadow = get_shadow_assembly_location (filename, &error);
1776         if (!mono_error_ok (&error)) {
1777                 mono_error_cleanup (&error);
1778                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1779                 return NULL;
1780         }
1781
1782         if (g_ensure_directory_exists (shadow) == FALSE) {
1783                 g_free (shadow);
1784                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1785                 return NULL;
1786         }       
1787
1788         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1789                 return (char*) shadow;
1790
1791         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1792         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1793         mono_w32file_delete (dest);
1794
1795         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1796          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1797          * and not have it runtime error" */
1798         attrs = mono_w32file_get_attributes (orig);
1799         if (attrs == INVALID_FILE_ATTRIBUTES) {
1800                 g_free (shadow);
1801                 return (char *)filename;
1802         }
1803
1804         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1805
1806         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1807          * overwritten when updated in their original locations. */
1808         if (copy_result)
1809                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1810
1811         g_free (dest);
1812         g_free (orig);
1813
1814         if (copy_result == FALSE) {
1815                 g_free (shadow);
1816
1817                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1818                 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1819                         return NULL; /* file not found, shadow copy failed */
1820
1821                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1822                 return NULL;
1823         }
1824
1825         /* attempt to copy .mdb, .config if they exist */
1826         sibling_source = g_strconcat (filename, ".config", NULL);
1827         sibling_source_len = strlen (sibling_source);
1828         sibling_target = g_strconcat (shadow, ".config", NULL);
1829         sibling_target_len = strlen (sibling_target);
1830         
1831         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1832         if (copy_result)
1833                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1834         
1835         g_free (sibling_source);
1836         g_free (sibling_target);
1837         
1838         if (!copy_result)  {
1839                 g_free (shadow);
1840                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1841                 return NULL;
1842         }
1843
1844         /* Create a .ini file containing the original assembly location */
1845         if (!shadow_copy_create_ini (shadow, filename)) {
1846                 g_free (shadow);
1847                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1848                 return NULL;
1849         }
1850
1851         utbuf.actime = src_sbuf.st_atime;
1852         utbuf.modtime = src_sbuf.st_mtime;
1853         utime (shadow, &utbuf);
1854         
1855         return shadow;
1856 }
1857 #endif /* DISABLE_SHADOW_COPY */
1858
1859 /**
1860  * mono_domain_from_appdomain:
1861  */
1862 MonoDomain *
1863 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1864 {
1865         HANDLE_FUNCTION_ENTER ();
1866         MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1867         MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1868         HANDLE_FUNCTION_RETURN_VAL (result);
1869 }
1870
1871 MonoDomain *
1872 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1873 {
1874         HANDLE_FUNCTION_ENTER ();
1875         MonoDomain *dom = NULL;
1876         if (MONO_HANDLE_IS_NULL (appdomain))
1877                 goto leave;
1878
1879         if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1880                 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1881                 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1882                 
1883                 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1884         } else
1885                 dom = MONO_HANDLE_GETVAL (appdomain, data);
1886
1887 leave:
1888         HANDLE_FUNCTION_RETURN_VAL (dom);
1889 }
1890
1891
1892 static gboolean
1893 try_load_from (MonoAssembly **assembly,
1894                const gchar *path1, const gchar *path2,
1895                const gchar *path3, const gchar *path4,
1896                gboolean refonly, gboolean is_private,
1897                MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1898 {
1899         gchar *fullpath;
1900         gboolean found = FALSE;
1901         
1902         *assembly = NULL;
1903         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1904
1905         if (IS_PORTABILITY_SET) {
1906                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1907                 if (new_fullpath) {
1908                         g_free (fullpath);
1909                         fullpath = new_fullpath;
1910                         found = TRUE;
1911                 }
1912         } else
1913                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1914         
1915         if (found)
1916                 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1917
1918         g_free (fullpath);
1919         return (*assembly != NULL);
1920 }
1921
1922 static MonoAssembly *
1923 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1924 {
1925         MonoAssembly *result = NULL;
1926         gchar **path;
1927         gchar *filename;
1928         const gchar *local_culture;
1929         gint len;
1930         gboolean is_private = FALSE;
1931
1932         if (!culture || *culture == '\0') {
1933                 local_culture = "";
1934         } else {
1935                 local_culture = culture;
1936         }
1937
1938         filename =  g_strconcat (name, ".dll", NULL);
1939         len = strlen (filename);
1940
1941         for (path = search_path; *path; path++) {
1942                 if (**path == '\0') {
1943                         is_private = TRUE;
1944                         continue; /* Ignore empty ApplicationBase */
1945                 }
1946
1947                 /* See test cases in bug #58992 and bug #57710 */
1948                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1949                 strcpy (filename + len - 4, ".dll");
1950                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1951                         break;
1952
1953                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1954                 strcpy (filename + len - 4, ".exe");
1955                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1956                         break;
1957
1958                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1959                 strcpy (filename + len - 4, ".dll");
1960                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1961                         break;
1962
1963                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1964                 strcpy (filename + len - 4, ".exe");
1965                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1966                         break;
1967         }
1968
1969         g_free (filename);
1970         return result;
1971 }
1972
1973 /*
1974  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1975  * and then from assemblies_path if any.
1976  * LOCKING: This is called from the assembly loading code, which means the caller
1977  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1978  */
1979 static MonoAssembly *
1980 mono_domain_assembly_preload (MonoAssemblyName *aname,
1981                               gchar **assemblies_path,
1982                               gpointer user_data)
1983 {
1984         MonoDomain *domain = mono_domain_get ();
1985         MonoAssembly *result = NULL;
1986         gboolean refonly = GPOINTER_TO_UINT (user_data);
1987
1988         set_domain_search_path (domain);
1989
1990         if (domain->search_path && domain->search_path [0] != NULL) {
1991                 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
1992                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
1993                         for (int i = 0; domain->search_path [i]; i++) {
1994                                 const char *p = domain->search_path[i];
1995                                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
1996                         }
1997                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);                    
1998                 }
1999                 result = real_load (domain->search_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2000         }
2001
2002         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2003                 result = real_load (assemblies_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2004         }
2005
2006         return result;
2007 }
2008
2009 /*
2010  * Check whenever a given assembly was already loaded in the current appdomain.
2011  */
2012 static MonoAssembly *
2013 mono_domain_assembly_search (MonoAssemblyName *aname,
2014                                                          gpointer user_data)
2015 {
2016         MonoDomain *domain = mono_domain_get ();
2017         GSList *tmp;
2018         MonoAssembly *ass;
2019         gboolean refonly = GPOINTER_TO_UINT (user_data);
2020
2021         mono_domain_assemblies_lock (domain);
2022         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2023                 ass = (MonoAssembly *)tmp->data;
2024                 /* Dynamic assemblies can't match here in MS.NET */
2025                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2026                         continue;
2027
2028                 mono_domain_assemblies_unlock (domain);
2029                 return ass;
2030         }
2031         mono_domain_assemblies_unlock (domain);
2032
2033         return NULL;
2034 }
2035
2036 MonoReflectionAssemblyHandle
2037 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2038 {
2039         error_init (error);
2040         MonoDomain *domain = mono_domain_get ();
2041         char *name, *filename;
2042         MonoImageOpenStatus status = MONO_IMAGE_OK;
2043         MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2044
2045         name = NULL;
2046         result = NULL;
2047
2048         if (fname == NULL) {
2049                 mono_error_set_argument_null (error, "assemblyFile", "");
2050                 goto leave;
2051         }
2052                 
2053         name = filename = mono_string_handle_to_utf8 (fname, error);
2054         if (!is_ok (error))
2055                 goto leave;
2056         
2057         MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2058         
2059         if (!ass) {
2060                 if (status == MONO_IMAGE_IMAGE_INVALID)
2061                         mono_error_set_bad_image_name (error, g_strdup (name), "");
2062                 else
2063                         mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2064                 goto leave;
2065         }
2066
2067         result = mono_assembly_get_object_handle (domain, ass, error);
2068
2069 leave:
2070         g_free (name);
2071         return result;
2072 }
2073
2074 MonoReflectionAssemblyHandle
2075 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad, 
2076                                             MonoArrayHandle raw_assembly,
2077                                             MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2078                                             MonoBoolean refonly,
2079                                             MonoError *error)
2080 {
2081         error_init (error);
2082         MonoAssembly *ass;
2083         MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2084         MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2085         MonoImageOpenStatus status;
2086         guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2087
2088         /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2089         char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2090         if (!assembly_data) {
2091                 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2092                 return refass;
2093         }
2094         uint32_t gchandle;
2095         mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2096         memcpy (assembly_data, raw_data, raw_assembly_len);
2097         mono_gchandle_free (gchandle); /* unpin */
2098         MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2099         
2100         MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2101
2102         if (!image) {
2103                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2104                 return refass;
2105         }
2106
2107         if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2108                 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2109                 uint32_t symbol_gchandle;
2110                 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2111                 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2112                 mono_gchandle_free (symbol_gchandle);
2113         }
2114
2115         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2116
2117
2118         if (!ass) {
2119                 mono_image_close (image);
2120                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2121                 return refass; 
2122         }
2123
2124         refass = mono_assembly_get_object_handle (domain, ass, error);
2125         if (!MONO_HANDLE_IS_NULL(refass))
2126                 MONO_HANDLE_SET (refass, evidence, evidence);
2127         return refass;
2128 }
2129
2130 MonoReflectionAssemblyHandle
2131 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2132 {
2133         error_init (error);
2134         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2135         MonoImageOpenStatus status = MONO_IMAGE_OK;
2136         MonoAssembly *ass;
2137         MonoAssemblyName aname;
2138         gchar *name = NULL;
2139         gboolean parsed;
2140
2141         g_assert (assRef);
2142
2143         name = mono_string_handle_to_utf8 (assRef, error);
2144         if (!is_ok (error))
2145                 goto fail;
2146         parsed = mono_assembly_name_parse (name, &aname);
2147         g_free (name);
2148
2149         if (!parsed) {
2150                 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2151                 /* This is a parse error... */
2152                 if (!refOnly) {
2153                         MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2154                         if (!is_ok (error))
2155                                 goto fail;
2156                         if (assm) {
2157                                 refass = mono_assembly_get_object_handle (domain, assm, error);
2158                                 if (!is_ok (error))
2159                                         goto fail;
2160                         }
2161                 }
2162                 return refass;
2163         }
2164
2165         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2166         mono_assembly_name_free (&aname);
2167
2168         if (!ass) {
2169                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2170                 if (!refOnly) {
2171                         ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2172                         if (!is_ok (error))
2173                                 goto fail;
2174                 }
2175                 if (!ass)
2176                         goto fail;
2177         }
2178
2179         g_assert (ass);
2180         MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2181         if (!is_ok (error))
2182                 goto fail;
2183
2184         MONO_HANDLE_SET (refass, evidence, evidence);
2185
2186         return refass;
2187 fail:
2188         return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2189 }
2190
2191 void
2192 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2193 {
2194         error_init (error);
2195         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2196
2197         if (NULL == domain) {
2198                 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2199                 return;
2200         }
2201         
2202         if (domain == mono_get_root_domain ()) {
2203                 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2204                 return;
2205         }
2206
2207         /* 
2208          * Unloading seems to cause problems when running NUnit/NAnt, hence
2209          * this workaround.
2210          */
2211         if (g_hasenv ("MONO_NO_UNLOAD"))
2212                 return;
2213
2214 #ifdef __native_client__
2215         return;
2216 #endif
2217
2218         MonoException *exc = NULL;
2219         mono_domain_try_unload (domain, (MonoObject**)&exc);
2220         if (exc)
2221                 mono_error_set_exception_instance (error, exc);
2222 }
2223
2224 gboolean
2225 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2226 {
2227         error_init (error);
2228         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2229
2230         if (!domain)
2231                 return TRUE;
2232
2233         return mono_domain_is_unloading (domain);
2234 }
2235
2236 void
2237 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2238 {
2239         mono_unhandled_exception ((MonoObject*) exc);
2240 }
2241
2242 gint32
2243 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2244                                             MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2245                                             MonoError *error)
2246 {
2247         error_init (error);
2248         MonoImage *image;
2249         MonoMethod *method;
2250
2251         g_assert (!MONO_HANDLE_IS_NULL (refass));
2252         MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2253         image = assembly->image;
2254         g_assert (image);
2255
2256         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2257
2258         if (!method)
2259                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2260
2261         if (MONO_HANDLE_IS_NULL (args)) {
2262                 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2263                 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2264                 mono_error_assert_ok (error);
2265         }
2266
2267         int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2268         return res;
2269 }
2270
2271 gint32 
2272 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2273 {
2274         return ad->data->domain_id;
2275 }
2276
2277 MonoAppDomainHandle
2278 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2279 {
2280         error_init (error);
2281         MonoDomain *old_domain = mono_domain_get ();
2282
2283         if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2284                 mono_error_set_appdomain_unloaded (error);
2285                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2286         }
2287
2288         return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2289 }
2290
2291 MonoAppDomainHandle
2292 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2293 {
2294         MonoDomain *current_domain = mono_domain_get ();
2295         MonoDomain *domain = mono_domain_get_by_id (domainid);
2296
2297         if (!domain || !mono_domain_set (domain, FALSE)) {
2298                 mono_error_set_appdomain_unloaded (error);
2299                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2300         }
2301
2302         return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2303 }
2304
2305 void
2306 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2307 {
2308         error_init (error);
2309         mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2310 }
2311
2312 void
2313 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2314 {
2315         error_init (error);
2316         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2317
2318         if (!domain) {
2319                 /* 
2320                  * Raise an exception to prevent the managed code from executing a pop
2321                  * later.
2322                  */
2323                 mono_error_set_appdomain_unloaded (error);
2324                 return;
2325         }
2326
2327         mono_thread_push_appdomain_ref (domain);
2328 }
2329
2330 void
2331 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2332 {
2333         error_init (error);
2334         mono_thread_pop_appdomain_ref ();
2335 }
2336
2337 MonoAppContext * 
2338 ves_icall_System_AppDomain_InternalGetContext ()
2339 {
2340         return mono_context_get ();
2341 }
2342
2343 MonoAppContext * 
2344 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2345 {
2346         return mono_domain_get ()->default_context;
2347 }
2348
2349 MonoAppContext * 
2350 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2351 {
2352         MonoAppContext *old_context = mono_context_get ();
2353
2354         mono_context_set (mc);
2355
2356         return old_context;
2357 }
2358
2359 MonoStringHandle
2360 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2361 {
2362         error_init (error);
2363         MonoDomain* mono_root_domain = mono_get_root_domain ();
2364         mono_domain_lock (mono_root_domain);
2365         if (process_guid_set) {
2366                 mono_domain_unlock (mono_root_domain);
2367                 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2368         }
2369         uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2370         memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2371         mono_gchandle_free (gchandle);
2372         process_guid_set = TRUE;
2373         mono_domain_unlock (mono_root_domain);
2374         return newguid;
2375 }
2376
2377 /**
2378  * mono_domain_is_unloading:
2379  */
2380 gboolean
2381 mono_domain_is_unloading (MonoDomain *domain)
2382 {
2383         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2384                 return TRUE;
2385         else
2386                 return FALSE;
2387 }
2388
2389 static void
2390 clear_cached_vtable (MonoVTable *vtable)
2391 {
2392         MonoClass *klass = vtable->klass;
2393         MonoDomain *domain = vtable->domain;
2394         MonoClassRuntimeInfo *runtime_info;
2395         void *data;
2396
2397         runtime_info = klass->runtime_info;
2398         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2399                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2400         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2401                 mono_gc_free_fixed (data);
2402 }
2403
2404 static G_GNUC_UNUSED void
2405 zero_static_data (MonoVTable *vtable)
2406 {
2407         MonoClass *klass = vtable->klass;
2408         void *data;
2409
2410         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2411                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2412 }
2413
2414 typedef struct unload_data {
2415         gboolean done;
2416         MonoDomain *domain;
2417         char *failure_reason;
2418         gint32 refcount;
2419 } unload_data;
2420
2421 static void
2422 unload_data_unref (unload_data *data)
2423 {
2424         gint32 count;
2425         do {
2426                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2427                 g_assert (count >= 1 && count <= 2);
2428                 if (count == 1) {
2429                         g_free (data);
2430                         return;
2431                 }
2432         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2433 }
2434
2435 static void
2436 deregister_reflection_info_roots_from_list (MonoImage *image)
2437 {
2438         GSList *list = image->reflection_info_unregister_classes;
2439
2440         while (list) {
2441                 MonoClass *klass = (MonoClass *)list->data;
2442
2443                 mono_class_free_ref_info (klass);
2444
2445                 list = list->next;
2446         }
2447
2448         image->reflection_info_unregister_classes = NULL;
2449 }
2450
2451 static void
2452 deregister_reflection_info_roots (MonoDomain *domain)
2453 {
2454         GSList *list;
2455
2456         mono_domain_assemblies_lock (domain);
2457         for (list = domain->domain_assemblies; list; list = list->next) {
2458                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2459                 MonoImage *image = assembly->image;
2460                 int i;
2461
2462                 /*
2463                  * No need to take the image lock here since dynamic images are appdomain bound and
2464                  * at this point the mutator is gone.  Taking the image lock here would mean
2465                  * promoting it from a simple lock to a complex lock, which we better avoid if
2466                  * possible.
2467                  */
2468                 if (image_is_dynamic (image))
2469                         deregister_reflection_info_roots_from_list (image);
2470
2471                 for (i = 0; i < image->module_count; ++i) {
2472                         MonoImage *module = image->modules [i];
2473                         if (module && image_is_dynamic (module))
2474                                 deregister_reflection_info_roots_from_list (module);
2475                 }
2476         }
2477         mono_domain_assemblies_unlock (domain);
2478 }
2479
2480 static gsize WINAPI
2481 unload_thread_main (void *arg)
2482 {
2483         MonoError error;
2484         unload_data *data = (unload_data*)arg;
2485         MonoDomain *domain = data->domain;
2486         MonoInternalThread *internal;
2487         int i;
2488
2489         internal = mono_thread_internal_current ();
2490
2491         mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2492         if (!is_ok (&error)) {
2493                 data->failure_reason = g_strdup (mono_error_get_message (&error));
2494                 mono_error_cleanup (&error);
2495                 goto failure;
2496         }
2497
2498         /* 
2499          * FIXME: Abort our parent thread last, so we can return a failure 
2500          * indication if aborting times out.
2501          */
2502         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2503                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2504                 goto failure;
2505         }
2506
2507         if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2508                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2509                 goto failure;
2510         }
2511
2512         /* Finalize all finalizable objects in the doomed appdomain */
2513         if (!mono_domain_finalize (domain, -1)) {
2514                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2515                 goto failure;
2516         }
2517
2518         /* Clear references to our vtables in class->runtime_info.
2519          * We also hold the loader lock because we're going to change
2520          * class->runtime_info.
2521          */
2522
2523         mono_loader_lock (); //FIXME why do we need the loader lock here?
2524         mono_domain_lock (domain);
2525 #ifdef HAVE_SGEN_GC
2526         /*
2527          * We need to make sure that we don't have any remsets
2528          * pointing into static data of the to-be-freed domain because
2529          * at the next collections they would be invalid.  So what we
2530          * do is we first zero all static data and then do a minor
2531          * collection.  Because all references in the static data will
2532          * now be null we won't do any unnecessary copies and after
2533          * the collection there won't be any more remsets.
2534          */
2535         for (i = 0; i < domain->class_vtable_array->len; ++i)
2536                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2537         mono_gc_collect (0);
2538 #endif
2539         for (i = 0; i < domain->class_vtable_array->len; ++i)
2540                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2541         deregister_reflection_info_roots (domain);
2542
2543         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2544
2545         mono_domain_unlock (domain);
2546         mono_loader_unlock ();
2547
2548         domain->state = MONO_APPDOMAIN_UNLOADED;
2549
2550         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2551
2552         /* remove from the handle table the items related to this domain */
2553         mono_gchandle_free_domain (domain);
2554
2555         mono_domain_free (domain, FALSE);
2556
2557         mono_gc_collect (mono_gc_max_generation ());
2558
2559         mono_atomic_store_release (&data->done, TRUE);
2560         unload_data_unref (data);
2561         return 0;
2562
2563 failure:
2564         mono_atomic_store_release (&data->done, TRUE);
2565         unload_data_unref (data);
2566         return 1;
2567 }
2568
2569 /**
2570  * mono_domain_unload:
2571  * \param domain The domain to unload
2572  *
2573  * Unloads an appdomain. Follows the process outlined in the comment
2574  * for \c mono_domain_try_unload.
2575  */
2576 void
2577 mono_domain_unload (MonoDomain *domain)
2578 {
2579         MonoObject *exc = NULL;
2580         mono_domain_try_unload (domain, &exc);
2581 }
2582
2583 static MonoThreadInfoWaitRet
2584 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2585 {
2586         MonoThreadInfoWaitRet result;
2587
2588         MONO_ENTER_GC_SAFE;
2589         result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2590         MONO_EXIT_GC_SAFE;
2591
2592         return result;
2593 }
2594
2595 /**
2596  * mono_domain_unload:
2597  * \param domain The domain to unload
2598  * \param exc Exception information
2599  *
2600  *  Unloads an appdomain. Follows the process outlined in:
2601  *  http://blogs.gotdotnet.com/cbrumme
2602  *
2603  *  If doing things the 'right' way is too hard or complex, we do it the 
2604  *  'simple' way, which means do everything needed to avoid crashes and
2605  *  memory leaks, but not much else.
2606  *
2607  *  It is required to pass a valid reference to the exc argument, upon return
2608  *  from this function *exc will be set to the exception thrown, if any.
2609  *
2610  *  If this method is not called from an icall (embedded scenario for instance),
2611  *  it must not be called with any managed frames on the stack, since the unload
2612  *  process could end up trying to abort the current thread.
2613  */
2614 void
2615 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2616 {
2617         MonoError error;
2618         MonoThreadHandle *thread_handle;
2619         MonoAppDomainState prev_state;
2620         MonoMethod *method;
2621         unload_data *thread_data;
2622         MonoInternalThread *internal;
2623         MonoDomain *caller_domain = mono_domain_get ();
2624
2625         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2626
2627         /* Atomically change our state to UNLOADING */
2628         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2629                 MONO_APPDOMAIN_UNLOADING_START,
2630                 MONO_APPDOMAIN_CREATED);
2631         if (prev_state != MONO_APPDOMAIN_CREATED) {
2632                 switch (prev_state) {
2633                 case MONO_APPDOMAIN_UNLOADING_START:
2634                 case MONO_APPDOMAIN_UNLOADING:
2635                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2636                         return;
2637                 case MONO_APPDOMAIN_UNLOADED:
2638                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2639                         return;
2640                 default:
2641                         g_warning ("Invalid appdomain state %d", prev_state);
2642                         g_assert_not_reached ();
2643                 }
2644         }
2645
2646         mono_domain_set (domain, FALSE);
2647         /* Notify OnDomainUnload listeners */
2648         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2649         g_assert (method);
2650
2651         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2652
2653         if (!mono_error_ok (&error)) {
2654                 if (*exc)
2655                         mono_error_cleanup (&error);
2656                 else
2657                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2658         }
2659
2660         if (*exc) {
2661                 /* Roll back the state change */
2662                 domain->state = MONO_APPDOMAIN_CREATED;
2663                 mono_domain_set (caller_domain, FALSE);
2664                 return;
2665         }
2666         mono_domain_set (caller_domain, FALSE);
2667
2668         thread_data = g_new0 (unload_data, 1);
2669         thread_data->domain = domain;
2670         thread_data->failure_reason = NULL;
2671         thread_data->done = FALSE;
2672         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2673
2674         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2675         domain->state = MONO_APPDOMAIN_UNLOADING;
2676         /* 
2677          * First we create a separate thread for unloading, since
2678          * we might have to abort some threads, including the current one.
2679          *
2680          * Have to attach to the runtime so shutdown can wait for this thread.
2681          *
2682          * Force it to be attached to avoid racing during shutdown.
2683          */
2684         internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2685         mono_error_assert_ok (&error);
2686
2687         thread_handle = mono_threads_open_thread_handle (internal->handle);
2688
2689         /* Wait for the thread */       
2690         while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2691                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2692                         /* The unload thread tries to abort us */
2693                         /* The icall wrapper will execute the abort */
2694                         mono_threads_close_thread_handle (thread_handle);
2695                         unload_data_unref (thread_data);
2696                         return;
2697                 }
2698         }
2699
2700         mono_threads_close_thread_handle (thread_handle);
2701
2702         if (thread_data->failure_reason) {
2703                 /* Roll back the state change */
2704                 domain->state = MONO_APPDOMAIN_CREATED;
2705
2706                 g_warning ("%s", thread_data->failure_reason);
2707
2708                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2709
2710                 g_free (thread_data->failure_reason);
2711                 thread_data->failure_reason = NULL;
2712         }
2713
2714         unload_data_unref (thread_data);
2715 }