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