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