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