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