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