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