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