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