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