[runtime] Use MonoError for copy_app_domain_setup
[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)
973 {
974         MonoError error;
975         MonoReflectionAssembly *ret;
976         MonoClass *klass;
977         MonoMethod *method;
978         MonoBoolean isrefonly;
979         gpointer params [3];
980
981         if (mono_runtime_get_no_exec ())
982                 return NULL;
983
984         g_assert (domain != NULL && fname != NULL);
985
986         klass = domain->domain->mbr.obj.vtable->klass;
987         g_assert (klass);
988         
989         method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
990         if (method == NULL) {
991                 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
992                 return NULL;
993         }
994
995         isrefonly = refonly ? 1 : 0;
996         params [0] = fname;
997         if (requesting) {
998                 params[1] = mono_assembly_get_object_checked (domain, requesting, &error);
999                 if (!mono_error_ok (&error))
1000                         mono_error_raise_exception (&error); /* FIXME don't raise here */
1001         } else
1002                 params [1] = NULL;
1003         params [2] = &isrefonly;
1004
1005         ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, &error);
1006         mono_error_raise_exception (&error); /* FIXME don't raise here */
1007
1008         return ret;
1009 }
1010
1011 MonoAssembly *
1012 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1013                                                                           gboolean refonly)
1014 {
1015         MonoReflectionAssembly *assembly;
1016         MonoDomain *domain = mono_domain_get ();
1017         char *aname_str;
1018         MonoString *str;
1019
1020         aname_str = mono_stringify_assembly_name (aname);
1021
1022         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1023         str = mono_string_new (domain, aname_str);
1024         if (!str) {
1025                 g_free (aname_str);
1026                 return NULL;
1027         }
1028         assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
1029         g_free (aname_str);
1030
1031         if (assembly)
1032                 return assembly->assembly;
1033         else
1034                 return NULL;
1035 }
1036         
1037 /*
1038  * LOCKING: assumes assemblies_lock in the domain is already locked.
1039  */
1040 static void
1041 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1042 {
1043         gint i;
1044         GSList *tmp;
1045         gboolean destroy_ht = FALSE;
1046
1047         if (!ass->aname.name)
1048                 return;
1049
1050         if (!ht) {
1051                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1052                 destroy_ht = TRUE;
1053         }
1054
1055         /* FIXME: handle lazy loaded assemblies */
1056         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1057                 g_hash_table_insert (ht, tmp->data, tmp->data);
1058         }
1059         if (!g_hash_table_lookup (ht, ass)) {
1060                 mono_assembly_addref (ass);
1061                 g_hash_table_insert (ht, ass, ass);
1062                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1063                 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);
1064         }
1065
1066         if (ass->image->references) {
1067                 for (i = 0; ass->image->references [i] != NULL; i++) {
1068                         if (ass->image->references [i] != REFERENCE_MISSING)
1069                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1070                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
1071                                 }
1072                 }
1073         }
1074         if (destroy_ht)
1075                 g_hash_table_destroy (ht);
1076 }
1077
1078 static void
1079 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1080 {
1081         static MonoClassField *assembly_load_field;
1082         static MonoMethod *assembly_load_method;
1083         MonoError error;
1084         MonoDomain *domain = mono_domain_get ();
1085         MonoReflectionAssembly *ref_assembly;
1086         MonoClass *klass;
1087         gpointer load_value;
1088         void *params [1];
1089
1090         if (!domain->domain)
1091                 /* This can happen during startup */
1092                 return;
1093 #ifdef ASSEMBLY_LOAD_DEBUG
1094         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1095 #endif
1096         klass = domain->domain->mbr.obj.vtable->klass;
1097
1098         mono_domain_assemblies_lock (domain);
1099         add_assemblies_to_domain (domain, assembly, NULL);
1100         mono_domain_assemblies_unlock (domain);
1101
1102         if (assembly_load_field == NULL) {
1103                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1104                 g_assert (assembly_load_field);
1105         }
1106
1107         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1108         if (load_value == NULL) {
1109                 /* No events waiting to be triggered */
1110                 return;
1111         }
1112
1113         ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1114         mono_error_assert_ok (&error);
1115
1116         if (assembly_load_method == NULL) {
1117                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1118                 g_assert (assembly_load_method);
1119         }
1120
1121         *params = ref_assembly;
1122
1123         mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1124         mono_error_raise_exception (&error); /* FIXME don't raise here */
1125 }
1126
1127 /*
1128  * LOCKING: Acquires the domain assemblies lock.
1129  */
1130 static void
1131 set_domain_search_path (MonoDomain *domain)
1132 {
1133         MonoError error;
1134         MonoAppDomainSetup *setup;
1135         gchar **tmp;
1136         gchar *search_path = NULL;
1137         gint i;
1138         gint npaths = 0;
1139         gchar **pvt_split = NULL;
1140         GError *gerror = NULL;
1141         gint appbaselen = -1;
1142
1143         /* 
1144          * We use the low-level domain assemblies lock, since this is called from
1145          * assembly loads hooks, which means this thread might hold the loader lock.
1146          */
1147         mono_domain_assemblies_lock (domain);
1148
1149         if (!domain->setup) {
1150                 mono_domain_assemblies_unlock (domain);
1151                 return;
1152         }
1153
1154         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1155                 mono_domain_assemblies_unlock (domain);
1156                 return;
1157         }
1158         setup = domain->setup;
1159         if (!setup->application_base) {
1160                 mono_domain_assemblies_unlock (domain);
1161                 return; /* Must set application base to get private path working */
1162         }
1163
1164         npaths++;
1165         
1166         if (setup->private_bin_path) {
1167                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1168                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1169                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1170                         mono_error_cleanup (&error);
1171                         mono_domain_assemblies_unlock (domain);
1172                         return;
1173                 }
1174         }
1175         
1176         if (domain->private_bin_path) {
1177                 if (search_path == NULL)
1178                         search_path = domain->private_bin_path;
1179                 else {
1180                         gchar *tmp2 = search_path;
1181                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1182                         g_free (tmp2);
1183                 }
1184         }
1185         
1186         if (search_path) {
1187                 /*
1188                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1189                  * directories relative to ApplicationBase separated by semicolons (see
1190                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1191                  * The loop below copes with the fact that some Unix applications may use ':' (or
1192                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1193                  * ';' for the subsequent split.
1194                  *
1195                  * The issue was reported in bug #81446
1196                  */
1197
1198 #ifndef TARGET_WIN32
1199                 gint slen;
1200
1201                 slen = strlen (search_path);
1202                 for (i = 0; i < slen; i++)
1203                         if (search_path [i] == ':')
1204                                 search_path [i] = ';';
1205 #endif
1206                 
1207                 pvt_split = g_strsplit (search_path, ";", 1000);
1208                 g_free (search_path);
1209                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1210         }
1211
1212         if (!npaths) {
1213                 if (pvt_split)
1214                         g_strfreev (pvt_split);
1215                 /*
1216                  * Don't do this because the first time is called, the domain
1217                  * setup is not finished.
1218                  *
1219                  * domain->search_path = g_malloc (sizeof (char *));
1220                  * domain->search_path [0] = NULL;
1221                 */
1222                 mono_domain_assemblies_unlock (domain);
1223                 return;
1224         }
1225
1226         if (domain->search_path)
1227                 g_strfreev (domain->search_path);
1228
1229         tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1230         tmp [npaths] = NULL;
1231
1232         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1233         if (!mono_error_ok (&error)) {
1234                 mono_error_cleanup (&error);
1235                 g_strfreev (pvt_split);
1236                 g_free (tmp);
1237
1238                 mono_domain_assemblies_unlock (domain);
1239                 return;
1240         }
1241
1242         domain->search_path = tmp;
1243
1244         /* FIXME: is this needed? */
1245         if (strncmp (*tmp, "file://", 7) == 0) {
1246                 gchar *file = *tmp;
1247                 gchar *uri = *tmp;
1248                 gchar *tmpuri;
1249
1250                 if (uri [7] != '/')
1251                         uri = g_strdup_printf ("file:///%s", uri + 7);
1252
1253                 tmpuri = uri;
1254                 uri = mono_escape_uri_string (tmpuri);
1255                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1256                 g_free (uri);
1257
1258                 if (tmpuri != file)
1259                         g_free (tmpuri);
1260
1261                 if (gerror != NULL) {
1262                         g_warning ("%s\n", gerror->message);
1263                         g_error_free (gerror);
1264                         *tmp = file;
1265                 } else {
1266                         g_free (file);
1267                 }
1268         }
1269
1270         for (i = 1; pvt_split && i < npaths; i++) {
1271                 if (g_path_is_absolute (pvt_split [i - 1])) {
1272                         tmp [i] = g_strdup (pvt_split [i - 1]);
1273                 } else {
1274                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1275                 }
1276
1277                 if (strchr (tmp [i], '.')) {
1278                         gchar *reduced;
1279                         gchar *freeme;
1280
1281                         reduced = mono_path_canonicalize (tmp [i]);
1282                         if (appbaselen == -1)
1283                                 appbaselen = strlen (tmp [0]);
1284
1285                         if (strncmp (tmp [0], reduced, appbaselen)) {
1286                                 g_free (reduced);
1287                                 g_free (tmp [i]);
1288                                 tmp [i] = g_strdup ("");
1289                                 continue;
1290                         }
1291
1292                         freeme = tmp [i];
1293                         tmp [i] = reduced;
1294                         g_free (freeme);
1295                 }
1296         }
1297         
1298         if (setup->private_bin_path_probe != NULL) {
1299                 g_free (tmp [0]);
1300                 tmp [0] = g_strdup ("");
1301         }
1302                 
1303         domain->setup->path_changed = FALSE;
1304
1305         g_strfreev (pvt_split);
1306
1307         mono_domain_assemblies_unlock (domain);
1308 }
1309
1310 #ifdef DISABLE_SHADOW_COPY
1311 gboolean
1312 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1313 {
1314         return FALSE;
1315 }
1316
1317 char *
1318 mono_make_shadow_copy (const char *filename, MonoError *error)
1319 {
1320         mono_error_init (error);
1321         return (char *) filename;
1322 }
1323 #else
1324 static gboolean
1325 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1326 {
1327         guint16 *orig, *dest;
1328         gboolean copy_result;
1329         
1330         strcpy (src + srclen - tail_len, extension);
1331
1332         if (IS_PORTABILITY_CASE) {
1333                 gchar *file = mono_portability_find_file (src, TRUE);
1334
1335                 if (file == NULL)
1336                         return TRUE;
1337
1338                 g_free (file);
1339         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1340                 return TRUE;
1341         }
1342
1343         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1344
1345         strcpy (target + targetlen - tail_len, extension);
1346         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1347         
1348         DeleteFile (dest);
1349         copy_result = CopyFile (orig, dest, FALSE);
1350
1351         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1352          * overwritten when updated in their original locations. */
1353         if (copy_result)
1354                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1355
1356         g_free (orig);
1357         g_free (dest);
1358         
1359         return copy_result;
1360 }
1361
1362 static gint32 
1363 get_cstring_hash (const char *str)
1364 {
1365         int len, i;
1366         const char *p;
1367         gint32 h = 0;
1368         
1369         if (!str || !str [0])
1370                 return 0;
1371                 
1372         len = strlen (str);
1373         p = str;
1374         for (i = 0; i < len; i++) {
1375                 h = (h << 5) - h + *p;
1376                 p++;
1377         }
1378         
1379         return h;
1380 }
1381
1382 /*
1383  * Returned memory is malloc'd. Called must free it 
1384  */
1385 static char *
1386 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1387 {
1388         MonoAppDomainSetup *setup;
1389         char *cache_path, *appname;
1390         char *userdir;
1391         char *location;
1392
1393         mono_error_init (error);
1394         
1395         setup = domain->setup;
1396         if (setup->cache_path != NULL && setup->application_name != NULL) {
1397                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1398                 return_val_if_nok (error, NULL);
1399
1400 #ifndef TARGET_WIN32
1401                 {
1402                         gint i;
1403                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1404                                 if (cache_path [i] == '\\')
1405                                         cache_path [i] = '/';
1406                 }
1407 #endif
1408
1409                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1410                 if (!mono_error_ok (error)) {
1411                         g_free (cache_path);
1412                         return NULL;
1413                 }
1414
1415                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1416                 g_free (appname);
1417                 g_free (cache_path);
1418         } else {
1419                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1420                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1421                 g_free (userdir);
1422         }
1423         return location;
1424 }
1425
1426 static char *
1427 get_shadow_assembly_location (const char *filename, MonoError *error)
1428 {
1429         gint32 hash = 0, hash2 = 0;
1430         char name_hash [9];
1431         char path_hash [30];
1432         char *bname = g_path_get_basename (filename);
1433         char *dirname = g_path_get_dirname (filename);
1434         char *location, *tmploc;
1435         MonoDomain *domain = mono_domain_get ();
1436
1437         mono_error_init (error);
1438         
1439         hash = get_cstring_hash (bname);
1440         hash2 = get_cstring_hash (dirname);
1441         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1442         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1443         tmploc = get_shadow_assembly_location_base (domain, error);
1444         if (!mono_error_ok (error)) {
1445                 g_free (bname);
1446                 g_free (dirname);
1447                 return NULL;
1448         }
1449
1450         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1451         g_free (tmploc);
1452         g_free (bname);
1453         g_free (dirname);
1454         return location;
1455 }
1456
1457 static gboolean
1458 ensure_directory_exists (const char *filename)
1459 {
1460 #ifdef HOST_WIN32
1461         gchar *dir_utf8 = g_path_get_dirname (filename);
1462         gunichar2 *p;
1463         gunichar2 *dir_utf16 = NULL;
1464         int retval;
1465         
1466         if (!dir_utf8 || !dir_utf8 [0])
1467                 return FALSE;
1468
1469         dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1470         g_free (dir_utf8);
1471
1472         if (!dir_utf16)
1473                 return FALSE;
1474
1475         p = dir_utf16;
1476
1477         /* make life easy and only use one directory seperator */
1478         while (*p != '\0')
1479         {
1480                 if (*p == '/')
1481                         *p = '\\';
1482                 p++;
1483         }
1484
1485         p = dir_utf16;
1486
1487         /* get past C:\ )*/
1488         while (*p++ != '\\')    
1489         {
1490         }
1491
1492         while (1) {
1493                 BOOL bRet = FALSE;
1494                 p = wcschr (p, '\\');
1495                 if (p)
1496                         *p = '\0';
1497                 retval = _wmkdir (dir_utf16);
1498                 if (retval != 0 && errno != EEXIST) {
1499                         g_free (dir_utf16);
1500                         return FALSE;
1501                 }
1502                 if (!p)
1503                         break;
1504                 *p++ = '\\';
1505         }
1506         
1507         g_free (dir_utf16);
1508         return TRUE;
1509 #else
1510         char *p;
1511         gchar *dir = g_path_get_dirname (filename);
1512         int retval;
1513         struct stat sbuf;
1514         
1515         if (!dir || !dir [0]) {
1516                 g_free (dir);
1517                 return FALSE;
1518         }
1519         
1520         if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1521                 g_free (dir);
1522                 return TRUE;
1523         }
1524         
1525         p = dir;
1526         while (*p == '/')
1527                 p++;
1528
1529         while (1) {
1530                 p = strchr (p, '/');
1531                 if (p)
1532                         *p = '\0';
1533                 retval = mkdir (dir, 0777);
1534                 if (retval != 0 && errno != EEXIST) {
1535                         g_free (dir);
1536                         return FALSE;
1537                 }
1538                 if (!p)
1539                         break;
1540                 *p++ = '/';
1541         }
1542         
1543         g_free (dir);
1544         return TRUE;
1545 #endif
1546 }
1547
1548 static gboolean
1549 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1550 {
1551         struct stat sbuf_dest;
1552         gchar *stat_src;
1553         gchar *real_src = mono_portability_find_file (src, TRUE);
1554
1555         if (!real_src)
1556                 stat_src = (gchar*)src;
1557         else
1558                 stat_src = real_src;
1559
1560         if (stat (stat_src, sbuf_src) == -1) {
1561                 time_t tnow = time (NULL);
1562
1563                 if (real_src)
1564                         g_free (real_src);
1565
1566                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1567                 sbuf_src->st_mtime = tnow;
1568                 sbuf_src->st_atime = tnow;
1569                 return TRUE;
1570         }
1571
1572         if (real_src)
1573                 g_free (real_src);
1574
1575         if (stat (dest, &sbuf_dest) == -1)
1576                 return TRUE;
1577         
1578         if (sbuf_src->st_size == sbuf_dest.st_size &&
1579             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1580                 return FALSE;
1581
1582         return TRUE;
1583 }
1584
1585 static gboolean
1586 shadow_copy_create_ini (const char *shadow, const char *filename)
1587 {
1588         char *dir_name;
1589         char *ini_file;
1590         guint16 *u16_ini;
1591         gboolean result;
1592         guint32 n;
1593         HANDLE *handle;
1594         gchar *full_path;
1595
1596         dir_name = g_path_get_dirname (shadow);
1597         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1598         g_free (dir_name);
1599         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1600                 g_free (ini_file);
1601                 return TRUE;
1602         }
1603
1604         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1605         g_free (ini_file);
1606         if (!u16_ini) {
1607                 return FALSE;
1608         }
1609         handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1610                                 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1611         g_free (u16_ini);
1612         if (handle == INVALID_HANDLE_VALUE) {
1613                 return FALSE;
1614         }
1615
1616         full_path = mono_path_resolve_symlinks (filename);
1617         result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1618         g_free (full_path);
1619         CloseHandle (handle);
1620         return result;
1621 }
1622
1623 gboolean
1624 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1625 {
1626         MonoError error;
1627         MonoAppDomainSetup *setup;
1628         gchar *all_dirs;
1629         gchar **dir_ptr;
1630         gchar **directories;
1631         gchar *shadow_status_string;
1632         gchar *base_dir;
1633         gboolean shadow_enabled;
1634         gboolean found = FALSE;
1635
1636         if (domain == NULL)
1637                 return FALSE;
1638
1639         setup = domain->setup;
1640         if (setup == NULL || setup->shadow_copy_files == NULL)
1641                 return FALSE;
1642
1643         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1644         if (!mono_error_ok (&error)) {
1645                 mono_error_cleanup (&error);
1646                 return FALSE;
1647         }
1648         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1649         g_free (shadow_status_string);
1650
1651         if (!shadow_enabled)
1652                 return FALSE;
1653
1654         if (setup->shadow_copy_directories == NULL)
1655                 return TRUE;
1656
1657         /* Is dir_name a shadow_copy destination already? */
1658         base_dir = get_shadow_assembly_location_base (domain, &error);
1659         if (!mono_error_ok (&error)) {
1660                 mono_error_cleanup (&error);
1661                 return FALSE;
1662         }
1663
1664         if (strstr (dir_name, base_dir)) {
1665                 g_free (base_dir);
1666                 return TRUE;
1667         }
1668         g_free (base_dir);
1669
1670         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1671         if (!mono_error_ok (&error)) {
1672                 mono_error_cleanup (&error);
1673                 return FALSE;
1674         }
1675
1676         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1677         dir_ptr = directories;
1678         while (*dir_ptr) {
1679                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1680                         found = TRUE;
1681                         break;
1682                 }
1683                 dir_ptr++;
1684         }
1685         g_strfreev (directories);
1686         g_free (all_dirs);
1687         return found;
1688 }
1689
1690 /*
1691 This function raises exceptions so it can cause as sorts of nasty stuff if called
1692 while holding a lock.
1693 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1694 or NULL if source file not found.
1695 FIXME bubble up the error instead of raising it here
1696 */
1697 char *
1698 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1699 {
1700         MonoError error;
1701         gchar *sibling_source, *sibling_target;
1702         gint sibling_source_len, sibling_target_len;
1703         guint16 *orig, *dest;
1704         guint32 attrs;
1705         char *shadow;
1706         gboolean copy_result;
1707         struct stat src_sbuf;
1708         struct utimbuf utbuf;
1709         char *dir_name = g_path_get_dirname (filename);
1710         MonoDomain *domain = mono_domain_get ();
1711         char *shadow_dir;
1712
1713         mono_error_init (oerror);
1714
1715         set_domain_search_path (domain);
1716
1717         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1718                 g_free (dir_name);
1719                 return (char *) filename;
1720         }
1721
1722         /* Is dir_name a shadow_copy destination already? */
1723         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1724         if (!mono_error_ok (&error)) {
1725                 mono_error_cleanup (&error);
1726                 g_free (dir_name);
1727                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in shadow directory name).");
1728                 return NULL;
1729         }
1730
1731         if (strstr (dir_name, shadow_dir)) {
1732                 g_free (shadow_dir);
1733                 g_free (dir_name);
1734                 return (char *) filename;
1735         }
1736         g_free (shadow_dir);
1737         g_free (dir_name);
1738
1739         shadow = get_shadow_assembly_location (filename, &error);
1740         if (!mono_error_ok (&error)) {
1741                 mono_error_cleanup (&error);
1742                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (invalid characters in file name).");
1743                 return NULL;
1744         }
1745
1746         if (ensure_directory_exists (shadow) == FALSE) {
1747                 g_free (shadow);
1748                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (ensure directory exists).");
1749                 return NULL;
1750         }       
1751
1752         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1753                 return (char*) shadow;
1754
1755         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1756         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1757         DeleteFile (dest);
1758
1759         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1760          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1761          * and not have it runtime error" */
1762         attrs = GetFileAttributes (orig);
1763         if (attrs == INVALID_FILE_ATTRIBUTES) {
1764                 g_free (shadow);
1765                 return (char *)filename;
1766         }
1767
1768         copy_result = CopyFile (orig, dest, FALSE);
1769
1770         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1771          * overwritten when updated in their original locations. */
1772         if (copy_result)
1773                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1774
1775         g_free (dest);
1776         g_free (orig);
1777
1778         if (copy_result == FALSE) {
1779                 g_free (shadow);
1780
1781                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1782                 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1783                         return NULL; /* file not found, shadow copy failed */
1784
1785                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy (CopyFile).");
1786                 return NULL;
1787         }
1788
1789         /* attempt to copy .mdb, .config if they exist */
1790         sibling_source = g_strconcat (filename, ".config", NULL);
1791         sibling_source_len = strlen (sibling_source);
1792         sibling_target = g_strconcat (shadow, ".config", NULL);
1793         sibling_target_len = strlen (sibling_target);
1794         
1795         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1796         if (copy_result == TRUE)
1797                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1798         
1799         g_free (sibling_source);
1800         g_free (sibling_target);
1801         
1802         if (copy_result == FALSE)  {
1803                 g_free (shadow);
1804                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy of sibling data (CopyFile).");
1805                 return NULL;
1806         }
1807
1808         /* Create a .ini file containing the original assembly location */
1809         if (!shadow_copy_create_ini (shadow, filename)) {
1810                 g_free (shadow);
1811                 mono_error_set_generic_error (oerror, "System", "ExecutionEngineException", "Failed to create shadow copy .ini file.");
1812                 return NULL;
1813         }
1814
1815         utbuf.actime = src_sbuf.st_atime;
1816         utbuf.modtime = src_sbuf.st_mtime;
1817         utime (shadow, &utbuf);
1818         
1819         return shadow;
1820 }
1821 #endif /* DISABLE_SHADOW_COPY */
1822
1823 MonoDomain *
1824 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1825 {
1826         if (appdomain == NULL)
1827                 return NULL;
1828         
1829         return appdomain->data;
1830 }
1831
1832 static gboolean
1833 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1834                                         const gchar *path3, const gchar *path4,
1835                                         gboolean refonly, gboolean is_private)
1836 {
1837         gchar *fullpath;
1838         gboolean found = FALSE;
1839         
1840         *assembly = NULL;
1841         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1842
1843         if (IS_PORTABILITY_SET) {
1844                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1845                 if (new_fullpath) {
1846                         g_free (fullpath);
1847                         fullpath = new_fullpath;
1848                         found = TRUE;
1849                 }
1850         } else
1851                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1852         
1853         if (found)
1854                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1855
1856         g_free (fullpath);
1857         return (*assembly != NULL);
1858 }
1859
1860 static MonoAssembly *
1861 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1862 {
1863         MonoAssembly *result = NULL;
1864         gchar **path;
1865         gchar *filename;
1866         const gchar *local_culture;
1867         gint len;
1868         gboolean is_private = FALSE;
1869
1870         if (!culture || *culture == '\0') {
1871                 local_culture = "";
1872         } else {
1873                 local_culture = culture;
1874         }
1875
1876         filename =  g_strconcat (name, ".dll", NULL);
1877         len = strlen (filename);
1878
1879         for (path = search_path; *path; path++) {
1880                 if (**path == '\0') {
1881                         is_private = TRUE;
1882                         continue; /* Ignore empty ApplicationBase */
1883                 }
1884
1885                 /* See test cases in bug #58992 and bug #57710 */
1886                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1887                 strcpy (filename + len - 4, ".dll");
1888                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1889                         break;
1890
1891                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1892                 strcpy (filename + len - 4, ".exe");
1893                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1894                         break;
1895
1896                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1897                 strcpy (filename + len - 4, ".dll");
1898                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1899                         break;
1900
1901                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1902                 strcpy (filename + len - 4, ".exe");
1903                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1904                         break;
1905         }
1906
1907         g_free (filename);
1908         return result;
1909 }
1910
1911 /*
1912  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1913  * and then from assemblies_path if any.
1914  * LOCKING: This is called from the assembly loading code, which means the caller
1915  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1916  */
1917 static MonoAssembly *
1918 mono_domain_assembly_preload (MonoAssemblyName *aname,
1919                               gchar **assemblies_path,
1920                               gpointer user_data)
1921 {
1922         MonoDomain *domain = mono_domain_get ();
1923         MonoAssembly *result = NULL;
1924         gboolean refonly = GPOINTER_TO_UINT (user_data);
1925
1926         set_domain_search_path (domain);
1927
1928         if (domain->search_path && domain->search_path [0] != NULL) {
1929                 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1930         }
1931
1932         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1933                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1934         }
1935
1936         return result;
1937 }
1938
1939 /*
1940  * Check whenever a given assembly was already loaded in the current appdomain.
1941  */
1942 static MonoAssembly *
1943 mono_domain_assembly_search (MonoAssemblyName *aname,
1944                                                          gpointer user_data)
1945 {
1946         MonoDomain *domain = mono_domain_get ();
1947         GSList *tmp;
1948         MonoAssembly *ass;
1949         gboolean refonly = GPOINTER_TO_UINT (user_data);
1950
1951         mono_domain_assemblies_lock (domain);
1952         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1953                 ass = (MonoAssembly *)tmp->data;
1954                 /* Dynamic assemblies can't match here in MS.NET */
1955                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1956                         continue;
1957
1958                 mono_domain_assemblies_unlock (domain);
1959                 return ass;
1960         }
1961         mono_domain_assemblies_unlock (domain);
1962
1963         return NULL;
1964 }
1965
1966 MonoReflectionAssembly *
1967 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1968 {
1969         MonoError error;
1970         MonoReflectionAssembly *result;
1971         MonoDomain *domain = mono_domain_get ();
1972         char *name, *filename;
1973         MonoImageOpenStatus status = MONO_IMAGE_OK;
1974         MonoAssembly *ass;
1975
1976         if (fname == NULL) {
1977                 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1978                 mono_set_pending_exception (exc);
1979                 return NULL;
1980         }
1981                 
1982         name = filename = mono_string_to_utf8 (fname);
1983         
1984         ass = mono_assembly_open_full (filename, &status, refOnly);
1985         
1986         if (!ass) {
1987                 MonoException *exc;
1988
1989                 if (status == MONO_IMAGE_IMAGE_INVALID)
1990                         exc = mono_get_exception_bad_image_format2 (NULL, fname);
1991                 else
1992                         exc = mono_get_exception_file_not_found2 (NULL, fname);
1993                 g_free (name);
1994                 mono_set_pending_exception (exc);
1995                 return NULL;
1996         }
1997
1998         g_free (name);
1999
2000         result = mono_assembly_get_object_checked (domain, ass, &error);
2001         if (!result)
2002                 mono_error_set_pending_exception (&error);
2003         return result;
2004 }
2005
2006 MonoReflectionAssembly *
2007 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
2008                                             MonoArray *raw_assembly,
2009                                             MonoArray *raw_symbol_store, MonoObject *evidence,
2010                                             MonoBoolean refonly)
2011 {
2012         MonoError error;
2013         MonoAssembly *ass;
2014         MonoReflectionAssembly *refass = NULL;
2015         MonoDomain *domain = ad->data;
2016         MonoImageOpenStatus status;
2017         guint32 raw_assembly_len = mono_array_length (raw_assembly);
2018         MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2019
2020         if (!image) {
2021                 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2022                 return NULL;
2023         }
2024
2025         if (raw_symbol_store != NULL)
2026                 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2027
2028         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2029
2030
2031         if (!ass) {
2032                 mono_image_close (image);
2033                 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2034                 return NULL; 
2035         }
2036
2037         refass = mono_assembly_get_object_checked (domain, ass, &error);
2038         if (!refass)
2039                 mono_error_set_pending_exception (&error);
2040         else
2041                 MONO_OBJECT_SETREF (refass, evidence, evidence);
2042         return refass;
2043 }
2044
2045 MonoReflectionAssembly *
2046 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2047 {
2048         MonoError error;
2049         MonoDomain *domain = ad->data; 
2050         MonoImageOpenStatus status = MONO_IMAGE_OK;
2051         MonoAssembly *ass;
2052         MonoAssemblyName aname;
2053         MonoReflectionAssembly *refass = NULL;
2054         gchar *name;
2055         gboolean parsed;
2056
2057         g_assert (assRef);
2058
2059         name = mono_string_to_utf8 (assRef);
2060         parsed = mono_assembly_name_parse (name, &aname);
2061         g_free (name);
2062
2063         if (!parsed) {
2064                 /* This is a parse error... */
2065                 if (!refOnly)
2066                         refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2067                 return refass;
2068         }
2069
2070         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2071         mono_assembly_name_free (&aname);
2072
2073         if (!ass) {
2074                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2075                 if (!refOnly)
2076                         refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
2077                 else
2078                         refass = NULL;
2079                 if (!refass) {
2080                         return NULL;
2081                 }
2082         }
2083
2084         if (refass == NULL)
2085                 refass = mono_assembly_get_object_checked (domain, ass, &error);
2086
2087         if (refass == NULL)
2088                 mono_error_set_pending_exception (&error);
2089         else
2090                 MONO_OBJECT_SETREF (refass, evidence, evidence);
2091         return refass;
2092 }
2093
2094 void
2095 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2096 {
2097         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2098
2099         if (NULL == domain) {
2100                 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2101                 mono_set_pending_exception (exc);
2102                 return;
2103         }
2104         
2105         if (domain == mono_get_root_domain ()) {
2106                 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2107                 return;
2108         }
2109
2110         /* 
2111          * Unloading seems to cause problems when running NUnit/NAnt, hence
2112          * this workaround.
2113          */
2114         if (g_getenv ("MONO_NO_UNLOAD"))
2115                 return;
2116 #ifdef __native_client__
2117         return;
2118 #endif
2119
2120         mono_domain_unload (domain);
2121 }
2122
2123 gboolean
2124 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2125 {
2126         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2127
2128         if (!domain)
2129                 return TRUE;
2130
2131         return mono_domain_is_unloading (domain);
2132 }
2133
2134 void
2135 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2136 {
2137         mono_unhandled_exception ((MonoObject*) exc);
2138 }
2139
2140 gint32
2141 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, 
2142                                                                                         MonoReflectionAssembly *refass, MonoArray *args)
2143 {
2144         MonoError error;
2145         MonoImage *image;
2146         MonoMethod *method;
2147
2148         g_assert (refass);
2149         image = refass->assembly->image;
2150         g_assert (image);
2151
2152         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2153
2154         if (!method)
2155                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2156
2157         if (!args)
2158                 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2159
2160         return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2161 }
2162
2163 gint32 
2164 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2165 {
2166         return ad->data->domain_id;
2167 }
2168
2169 MonoAppDomain * 
2170 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2171 {
2172         MonoDomain *old_domain = mono_domain_get();
2173
2174         if (!mono_domain_set (ad->data, FALSE)) {
2175                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2176                 return NULL;
2177         }
2178
2179         return old_domain->domain;
2180 }
2181
2182 MonoAppDomain * 
2183 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2184 {
2185         MonoDomain *current_domain = mono_domain_get ();
2186         MonoDomain *domain = mono_domain_get_by_id (domainid);
2187
2188         if (!domain || !mono_domain_set (domain, FALSE)) {
2189                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2190                 return NULL;
2191         }
2192
2193         return current_domain->domain;
2194 }
2195
2196 void
2197 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2198 {
2199         mono_thread_push_appdomain_ref (ad->data);
2200 }
2201
2202 void
2203 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2204 {
2205         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2206
2207         if (!domain) {
2208                 /* 
2209                  * Raise an exception to prevent the managed code from executing a pop
2210                  * later.
2211                  */
2212                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2213                 return;
2214         }
2215
2216         mono_thread_push_appdomain_ref (domain);
2217 }
2218
2219 void
2220 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2221 {
2222         mono_thread_pop_appdomain_ref ();
2223 }
2224
2225 MonoAppContext * 
2226 ves_icall_System_AppDomain_InternalGetContext ()
2227 {
2228         return mono_context_get ();
2229 }
2230
2231 MonoAppContext * 
2232 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2233 {
2234         return mono_domain_get ()->default_context;
2235 }
2236
2237 MonoAppContext * 
2238 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2239 {
2240         MonoAppContext *old_context = mono_context_get ();
2241
2242         mono_context_set (mc);
2243
2244         return old_context;
2245 }
2246
2247 MonoString *
2248 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2249 {
2250         MonoDomain* mono_root_domain = mono_get_root_domain ();
2251         mono_domain_lock (mono_root_domain);
2252         if (process_guid_set) {
2253                 mono_domain_unlock (mono_root_domain);
2254                 MonoError error;
2255                 MonoString *res = NULL;
2256                 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2257                 mono_error_raise_exception (&error);
2258                 return res;
2259         }
2260         memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2261         process_guid_set = TRUE;
2262         mono_domain_unlock (mono_root_domain);
2263         return newguid;
2264 }
2265
2266 gboolean
2267 mono_domain_is_unloading (MonoDomain *domain)
2268 {
2269         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2270                 return TRUE;
2271         else
2272                 return FALSE;
2273 }
2274
2275 static void
2276 clear_cached_vtable (MonoVTable *vtable)
2277 {
2278         MonoClass *klass = vtable->klass;
2279         MonoDomain *domain = vtable->domain;
2280         MonoClassRuntimeInfo *runtime_info;
2281         void *data;
2282
2283         runtime_info = klass->runtime_info;
2284         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2285                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2286         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2287                 mono_gc_free_fixed (data);
2288 }
2289
2290 static G_GNUC_UNUSED void
2291 zero_static_data (MonoVTable *vtable)
2292 {
2293         MonoClass *klass = vtable->klass;
2294         void *data;
2295
2296         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2297                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2298 }
2299
2300 typedef struct unload_data {
2301         gboolean done;
2302         MonoDomain *domain;
2303         char *failure_reason;
2304         gint32 refcount;
2305 } unload_data;
2306
2307 static void
2308 unload_data_unref (unload_data *data)
2309 {
2310         gint32 count;
2311         do {
2312                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2313                 g_assert (count >= 1 && count <= 2);
2314                 if (count == 1) {
2315                         g_free (data);
2316                         return;
2317                 }
2318         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2319 }
2320
2321 static void
2322 deregister_reflection_info_roots_from_list (MonoImage *image)
2323 {
2324         GSList *list = image->reflection_info_unregister_classes;
2325
2326         while (list) {
2327                 MonoClass *klass = (MonoClass *)list->data;
2328
2329                 mono_class_free_ref_info (klass);
2330
2331                 list = list->next;
2332         }
2333
2334         image->reflection_info_unregister_classes = NULL;
2335 }
2336
2337 static void
2338 deregister_reflection_info_roots (MonoDomain *domain)
2339 {
2340         GSList *list;
2341
2342         mono_domain_assemblies_lock (domain);
2343         for (list = domain->domain_assemblies; list; list = list->next) {
2344                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2345                 MonoImage *image = assembly->image;
2346                 int i;
2347
2348                 /*
2349                  * No need to take the image lock here since dynamic images are appdomain bound and
2350                  * at this point the mutator is gone.  Taking the image lock here would mean
2351                  * promoting it from a simple lock to a complex lock, which we better avoid if
2352                  * possible.
2353                  */
2354                 if (image_is_dynamic (image))
2355                         deregister_reflection_info_roots_from_list (image);
2356
2357                 for (i = 0; i < image->module_count; ++i) {
2358                         MonoImage *module = image->modules [i];
2359                         if (module && image_is_dynamic (module))
2360                                 deregister_reflection_info_roots_from_list (module);
2361                 }
2362         }
2363         mono_domain_assemblies_unlock (domain);
2364 }
2365
2366 static guint32 WINAPI
2367 unload_thread_main (void *arg)
2368 {
2369         MonoError error;
2370         unload_data *data = (unload_data*)arg;
2371         MonoDomain *domain = data->domain;
2372         MonoThread *thread;
2373         int i;
2374
2375         /* Have to attach to the runtime so shutdown can wait for this thread */
2376         /* Force it to be attached to avoid racing during shutdown. */
2377         thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2378         mono_error_raise_exception (&error); /* FIXME don't raise here */
2379
2380         /* 
2381          * FIXME: Abort our parent thread last, so we can return a failure 
2382          * indication if aborting times out.
2383          */
2384         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2385                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2386                 goto failure;
2387         }
2388
2389         if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2390                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2391                 goto failure;
2392         }
2393
2394         /* Finalize all finalizable objects in the doomed appdomain */
2395         if (!mono_domain_finalize (domain, -1)) {
2396                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2397                 goto failure;
2398         }
2399
2400         /* Clear references to our vtables in class->runtime_info.
2401          * We also hold the loader lock because we're going to change
2402          * class->runtime_info.
2403          */
2404
2405         mono_loader_lock (); //FIXME why do we need the loader lock here?
2406         mono_domain_lock (domain);
2407 #ifdef HAVE_SGEN_GC
2408         /*
2409          * We need to make sure that we don't have any remsets
2410          * pointing into static data of the to-be-freed domain because
2411          * at the next collections they would be invalid.  So what we
2412          * do is we first zero all static data and then do a minor
2413          * collection.  Because all references in the static data will
2414          * now be null we won't do any unnecessary copies and after
2415          * the collection there won't be any more remsets.
2416          */
2417         for (i = 0; i < domain->class_vtable_array->len; ++i)
2418                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2419         mono_gc_collect (0);
2420 #endif
2421         for (i = 0; i < domain->class_vtable_array->len; ++i)
2422                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2423         deregister_reflection_info_roots (domain);
2424
2425         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2426
2427         mono_domain_unlock (domain);
2428         mono_loader_unlock ();
2429
2430         mono_threads_clear_cached_culture (domain);
2431
2432         domain->state = MONO_APPDOMAIN_UNLOADED;
2433
2434         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2435
2436         /* remove from the handle table the items related to this domain */
2437         mono_gchandle_free_domain (domain);
2438
2439         mono_domain_free (domain, FALSE);
2440
2441         mono_gc_collect (mono_gc_max_generation ());
2442
2443         mono_atomic_store_release (&data->done, TRUE);
2444         unload_data_unref (data);
2445         mono_thread_detach (thread);
2446         return 0;
2447
2448 failure:
2449         mono_atomic_store_release (&data->done, TRUE);
2450         unload_data_unref (data);
2451         mono_thread_detach (thread);
2452         return 1;
2453 }
2454
2455 /*
2456  * mono_domain_unload:
2457  * @domain: The domain to unload
2458  *
2459  *  Unloads an appdomain. Follows the process outlined in the comment
2460  *  for mono_domain_try_unload.
2461  */
2462 void
2463 mono_domain_unload (MonoDomain *domain)
2464 {
2465         MonoObject *exc = NULL;
2466         mono_domain_try_unload (domain, &exc);
2467         if (exc)
2468                 mono_raise_exception ((MonoException*)exc);
2469 }
2470
2471 static guint32
2472 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2473 {
2474         guint32 result;
2475
2476         MONO_PREPARE_BLOCKING;
2477         result = WaitForSingleObjectEx (handle, timeout, alertable);
2478         MONO_FINISH_BLOCKING;
2479
2480         return result;
2481 }
2482
2483 /*
2484  * mono_domain_unload:
2485  * @domain: The domain to unload
2486  * @exc: Exception information
2487  *
2488  *  Unloads an appdomain. Follows the process outlined in:
2489  *  http://blogs.gotdotnet.com/cbrumme
2490  *
2491  *  If doing things the 'right' way is too hard or complex, we do it the 
2492  *  'simple' way, which means do everything needed to avoid crashes and
2493  *  memory leaks, but not much else.
2494  *
2495  *  It is required to pass a valid reference to the exc argument, upon return
2496  *  from this function *exc will be set to the exception thrown, if any.
2497  *
2498  *  If this method is not called from an icall (embedded scenario for instance),
2499  *  it must not be called with any managed frames on the stack, since the unload
2500  *  process could end up trying to abort the current thread.
2501  */
2502 void
2503 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2504 {
2505         MonoError error;
2506         HANDLE thread_handle;
2507         MonoAppDomainState prev_state;
2508         MonoMethod *method;
2509         unload_data *thread_data;
2510         MonoNativeThreadId tid;
2511         MonoDomain *caller_domain = mono_domain_get ();
2512         char *name;
2513
2514         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2515
2516         /* Atomically change our state to UNLOADING */
2517         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2518                 MONO_APPDOMAIN_UNLOADING_START,
2519                 MONO_APPDOMAIN_CREATED);
2520         if (prev_state != MONO_APPDOMAIN_CREATED) {
2521                 switch (prev_state) {
2522                 case MONO_APPDOMAIN_UNLOADING_START:
2523                 case MONO_APPDOMAIN_UNLOADING:
2524                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2525                         return;
2526                 case MONO_APPDOMAIN_UNLOADED:
2527                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2528                         return;
2529                 default:
2530                         g_warning ("Invalid appdomain state %d", prev_state);
2531                         g_assert_not_reached ();
2532                 }
2533         }
2534
2535         mono_domain_set (domain, FALSE);
2536         /* Notify OnDomainUnload listeners */
2537         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2538         g_assert (method);
2539
2540         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2541
2542         if (!mono_error_ok (&error)) {
2543                 if (*exc)
2544                         mono_error_cleanup (&error);
2545                 else
2546                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2547         }
2548
2549         if (*exc) {
2550                 /* Roll back the state change */
2551                 domain->state = MONO_APPDOMAIN_CREATED;
2552                 mono_domain_set (caller_domain, FALSE);
2553                 return;
2554         }
2555         mono_domain_set (caller_domain, FALSE);
2556
2557         thread_data = g_new0 (unload_data, 1);
2558         thread_data->domain = domain;
2559         thread_data->failure_reason = NULL;
2560         thread_data->done = FALSE;
2561         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2562
2563         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2564         domain->state = MONO_APPDOMAIN_UNLOADING;
2565         /* 
2566          * First we create a separate thread for unloading, since
2567          * we might have to abort some threads, including the current one.
2568          */
2569         thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2570         if (thread_handle == NULL)
2571                 return;
2572         name = g_strdup_printf ("Unload thread for domain %x", domain);
2573         mono_thread_info_set_name (tid, name);
2574         mono_thread_info_resume (tid);
2575         g_free (name);
2576
2577         /* Wait for the thread */       
2578         while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2579                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2580                         /* The unload thread tries to abort us */
2581                         /* The icall wrapper will execute the abort */
2582                         CloseHandle (thread_handle);
2583                         unload_data_unref (thread_data);
2584                         return;
2585                 }
2586         }
2587         CloseHandle (thread_handle);
2588
2589         if (thread_data->failure_reason) {
2590                 /* Roll back the state change */
2591                 domain->state = MONO_APPDOMAIN_CREATED;
2592
2593                 g_warning ("%s", thread_data->failure_reason);
2594
2595                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2596
2597                 g_free (thread_data->failure_reason);
2598                 thread_data->failure_reason = NULL;
2599         }
2600
2601         unload_data_unref (thread_data);
2602 }