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