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