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