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