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