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