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