Merge pull request #2820 from kumpera/license-change-rebased
[mono.git] / mono / metadata / appdomain.c
1 /*
2  * appdomain.c: AppDomain functions
3  *
4  * Authors:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  * Copyright 2012 Xamarin Inc
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14 #undef ASSEMBLY_LOAD_DEBUG
15 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #ifdef HAVE_SYS_TIME_H
23 #include <sys/time.h>
24 #endif
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #ifdef HAVE_UTIME_H
29 #include <utime.h>
30 #else
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
33 #endif
34 #endif
35
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/domain-internals.h>
39 #include "mono/metadata/metadata-internals.h"
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/exception.h>
42 #include <mono/metadata/threads.h>
43 #include <mono/metadata/threadpool-ms.h>
44 #include <mono/metadata/socket-io.h>
45 #include <mono/metadata/tabledefs.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/mono-gc.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/monitor.h>
50 #include <mono/metadata/mono-debug.h>
51 #include <mono/metadata/mono-debug-debugger.h>
52 #include <mono/metadata/attach.h>
53 #include <mono/metadata/file-io.h>
54 #include <mono/metadata/lock-tracer.h>
55 #include <mono/metadata/console-io.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/tokentype.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/utils/mono-uri.h>
61 #include <mono/utils/mono-logger-internals.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-stdlib.h>
64 #include <mono/utils/mono-io-portability.h>
65 #include <mono/utils/mono-error-internals.h>
66 #include <mono/utils/atomic.h>
67 #include <mono/utils/mono-memory-model.h>
68 #include <mono/utils/mono-threads.h>
69 #ifdef HOST_WIN32
70 #include <direct.h>
71 #endif
72
73 /*
74  * This is the version number of the corlib-runtime interface. When
75  * making changes to this interface (by changing the layout
76  * of classes the runtime knows about, changing icall signature or
77  * semantics etc), increment this variable. Also increment the
78  * pair of this variable in mscorlib in:
79  *       mcs/class/corlib/System/Environment.cs
80  *
81  * Changes which are already detected at runtime, like the addition
82  * of icalls, do not require an increment.
83  */
84 #define MONO_CORLIB_VERSION 143
85
86 typedef struct
87 {
88         int runtime_count;
89         int assemblybinding_count;
90         MonoDomain *domain;
91         gchar *filename;
92 } RuntimeConfig;
93
94 static gunichar2 process_guid [36];
95 static gboolean process_guid_set = FALSE;
96
97 static gboolean no_exec = FALSE;
98
99 static MonoAssembly *
100 mono_domain_assembly_preload (MonoAssemblyName *aname,
101                               gchar **assemblies_path,
102                               gpointer user_data);
103
104 static MonoAssembly *
105 mono_domain_assembly_search (MonoAssemblyName *aname,
106                                                          gpointer user_data);
107
108 static void
109 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
110
111 static void
112 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
113
114 static MonoAppDomain *
115 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
116
117 static char *
118 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
119
120 static MonoLoadFunc load_function = NULL;
121
122 /* Lazy class loading functions */
123 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
124
125 void
126 mono_install_runtime_load (MonoLoadFunc func)
127 {
128         load_function = func;
129 }
130
131 MonoDomain*
132 mono_runtime_load (const char *filename, const char *runtime_version)
133 {
134         g_assert (load_function);
135         return load_function (filename, runtime_version);
136 }
137
138 /**
139  * mono_runtime_set_no_exec:
140  *
141  * Instructs the runtime to operate in static mode, i.e. avoid/do not
142  * allow managed code execution. This is useful for running the AOT
143  * compiler on platforms which allow full-aot execution only.  This
144  * should be called before mono_runtime_init ().
145  */
146 void
147 mono_runtime_set_no_exec (gboolean val)
148 {
149         no_exec = val;
150 }
151
152 /**
153  * mono_runtime_get_no_exec:
154  *
155  * If true, then the runtime will not allow managed code execution.
156  */
157 gboolean
158 mono_runtime_get_no_exec (void)
159 {
160         return no_exec;
161 }
162
163 static void
164 create_domain_objects (MonoDomain *domain)
165 {
166         MonoError error;
167         MonoDomain *old_domain = mono_domain_get ();
168         MonoString *arg;
169         MonoVTable *string_vt;
170         MonoClassField *string_empty_fld;
171
172         if (domain != old_domain) {
173                 mono_thread_push_appdomain_ref (domain);
174                 mono_domain_set_internal_with_options (domain, FALSE);
175         }
176
177         /*
178          * Initialize String.Empty. This enables the removal of
179          * the static cctor of the String class.
180          */
181         string_vt = mono_class_vtable (domain, mono_defaults.string_class);
182         string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
183         g_assert (string_empty_fld);
184         MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
185         mono_error_assert_ok (&error);
186         mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
187
188         /*
189          * Create an instance early since we can't do it when there is no memory.
190          */
191         arg = mono_string_new (domain, "Out of memory");
192         domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
193
194         /* 
195          * These two are needed because the signal handlers might be executing on
196          * an alternate stack, and Boehm GC can't handle that.
197          */
198         arg = mono_string_new (domain, "A null value was found where an object instance was required");
199         domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
200         arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
201         domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
202
203         /*The ephemeron tombstone i*/
204         domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
205         mono_error_assert_ok (&error);
206
207         if (domain != old_domain) {
208                 mono_thread_pop_appdomain_ref ();
209                 mono_domain_set_internal_with_options (old_domain, FALSE);
210         }
211
212         /* 
213          * This class is used during exception handling, so initialize it here, to prevent
214          * stack overflows while handling stack overflows.
215          */
216         mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
217 }
218
219 /**
220  * mono_runtime_init:
221  * @domain: domain returned by mono_init ()
222  *
223  * Initialize the core AppDomain: this function will run also some
224  * IL initialization code, so it needs the execution engine to be fully 
225  * operational.
226  *
227  * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
228  * we know the entry_assembly.
229  *
230  */
231 void
232 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
233 {
234         MonoError error;
235         mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
236         mono_error_cleanup (&error);
237 }
238
239 void
240 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
241 {
242         MonoAppDomainSetup *setup;
243         MonoAppDomain *ad;
244         MonoClass *klass;
245
246         mono_error_init (error);
247
248         mono_portability_helpers_init ();
249         
250         mono_gc_base_init ();
251         mono_monitor_init ();
252         mono_marshal_init ();
253
254         mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
255         mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
256         mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
257         mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
258         mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
259         mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
260         mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
261
262         mono_thread_init (start_cb, attach_cb);
263
264         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
265         setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
266         return_if_nok (error);
267
268         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
269
270         ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
271         return_if_nok (error);
272
273         ad->data = domain;
274         domain->domain = ad;
275         domain->setup = setup;
276
277         mono_thread_attach (domain);
278
279         mono_type_initialization_init ();
280
281         if (!mono_runtime_get_no_exec ())
282                 create_domain_objects (domain);
283
284         /* GC init has to happen after thread init */
285         mono_gc_init ();
286
287         /* contexts use GC handles, so they must be initialized after the GC */
288         mono_context_init_checked (domain, error);
289         return_if_nok (error);
290         mono_context_set (domain->default_context);
291
292 #ifndef DISABLE_SOCKETS
293         mono_network_init ();
294 #endif
295         
296         mono_console_init ();
297         mono_attach_init ();
298
299         mono_locks_tracer_init ();
300
301         /* mscorlib is loaded before we install the load hook */
302         mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
303
304         return;
305 }
306
307 static int
308 mono_get_corlib_version (void)
309 {
310         MonoError error;
311         MonoClass *klass;
312         MonoClassField *field;
313         MonoObject *value;
314
315         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
316         mono_class_init (klass);
317         field = mono_class_get_field_from_name (klass, "mono_corlib_version");
318         if (!field)
319                 return -1;
320         if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
321                 return -1;
322         value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
323         mono_error_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         MonoException *exc = NULL;
2150         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2151
2152         if (NULL == domain) {
2153                 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2154                 mono_set_pending_exception (exc);
2155                 return;
2156         }
2157         
2158         if (domain == mono_get_root_domain ()) {
2159                 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2160                 return;
2161         }
2162
2163         /* 
2164          * Unloading seems to cause problems when running NUnit/NAnt, hence
2165          * this workaround.
2166          */
2167         if (g_getenv ("MONO_NO_UNLOAD"))
2168                 return;
2169 #ifdef __native_client__
2170         return;
2171 #endif
2172
2173         mono_domain_try_unload (domain, (MonoObject**)&exc);
2174         if (exc)
2175                 mono_set_pending_exception (exc);
2176 }
2177
2178 gboolean
2179 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2180 {
2181         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2182
2183         if (!domain)
2184                 return TRUE;
2185
2186         return mono_domain_is_unloading (domain);
2187 }
2188
2189 void
2190 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2191 {
2192         mono_unhandled_exception ((MonoObject*) exc);
2193 }
2194
2195 gint32
2196 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, 
2197                                                                                         MonoReflectionAssembly *refass, MonoArray *args)
2198 {
2199         MonoError error;
2200         MonoImage *image;
2201         MonoMethod *method;
2202
2203         g_assert (refass);
2204         image = refass->assembly->image;
2205         g_assert (image);
2206
2207         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2208
2209         if (!method)
2210                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2211
2212         if (!args)
2213                 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2214
2215         return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2216 }
2217
2218 gint32 
2219 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2220 {
2221         return ad->data->domain_id;
2222 }
2223
2224 MonoAppDomain * 
2225 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2226 {
2227         MonoDomain *old_domain = mono_domain_get();
2228
2229         if (!mono_domain_set (ad->data, FALSE)) {
2230                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2231                 return NULL;
2232         }
2233
2234         return old_domain->domain;
2235 }
2236
2237 MonoAppDomain * 
2238 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2239 {
2240         MonoDomain *current_domain = mono_domain_get ();
2241         MonoDomain *domain = mono_domain_get_by_id (domainid);
2242
2243         if (!domain || !mono_domain_set (domain, FALSE)) {
2244                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2245                 return NULL;
2246         }
2247
2248         return current_domain->domain;
2249 }
2250
2251 void
2252 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2253 {
2254         mono_thread_push_appdomain_ref (ad->data);
2255 }
2256
2257 void
2258 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2259 {
2260         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2261
2262         if (!domain) {
2263                 /* 
2264                  * Raise an exception to prevent the managed code from executing a pop
2265                  * later.
2266                  */
2267                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2268                 return;
2269         }
2270
2271         mono_thread_push_appdomain_ref (domain);
2272 }
2273
2274 void
2275 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2276 {
2277         mono_thread_pop_appdomain_ref ();
2278 }
2279
2280 MonoAppContext * 
2281 ves_icall_System_AppDomain_InternalGetContext ()
2282 {
2283         return mono_context_get ();
2284 }
2285
2286 MonoAppContext * 
2287 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2288 {
2289         return mono_domain_get ()->default_context;
2290 }
2291
2292 MonoAppContext * 
2293 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2294 {
2295         MonoAppContext *old_context = mono_context_get ();
2296
2297         mono_context_set (mc);
2298
2299         return old_context;
2300 }
2301
2302 MonoString *
2303 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2304 {
2305         MonoDomain* mono_root_domain = mono_get_root_domain ();
2306         mono_domain_lock (mono_root_domain);
2307         if (process_guid_set) {
2308                 mono_domain_unlock (mono_root_domain);
2309                 MonoError error;
2310                 MonoString *res = NULL;
2311                 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2312                 mono_error_raise_exception (&error);
2313                 return res;
2314         }
2315         memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2316         process_guid_set = TRUE;
2317         mono_domain_unlock (mono_root_domain);
2318         return newguid;
2319 }
2320
2321 gboolean
2322 mono_domain_is_unloading (MonoDomain *domain)
2323 {
2324         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2325                 return TRUE;
2326         else
2327                 return FALSE;
2328 }
2329
2330 static void
2331 clear_cached_vtable (MonoVTable *vtable)
2332 {
2333         MonoClass *klass = vtable->klass;
2334         MonoDomain *domain = vtable->domain;
2335         MonoClassRuntimeInfo *runtime_info;
2336         void *data;
2337
2338         runtime_info = klass->runtime_info;
2339         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2340                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2341         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2342                 mono_gc_free_fixed (data);
2343 }
2344
2345 static G_GNUC_UNUSED void
2346 zero_static_data (MonoVTable *vtable)
2347 {
2348         MonoClass *klass = vtable->klass;
2349         void *data;
2350
2351         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2352                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2353 }
2354
2355 typedef struct unload_data {
2356         gboolean done;
2357         MonoDomain *domain;
2358         char *failure_reason;
2359         gint32 refcount;
2360 } unload_data;
2361
2362 static void
2363 unload_data_unref (unload_data *data)
2364 {
2365         gint32 count;
2366         do {
2367                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2368                 g_assert (count >= 1 && count <= 2);
2369                 if (count == 1) {
2370                         g_free (data);
2371                         return;
2372                 }
2373         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2374 }
2375
2376 static void
2377 deregister_reflection_info_roots_from_list (MonoImage *image)
2378 {
2379         GSList *list = image->reflection_info_unregister_classes;
2380
2381         while (list) {
2382                 MonoClass *klass = (MonoClass *)list->data;
2383
2384                 mono_class_free_ref_info (klass);
2385
2386                 list = list->next;
2387         }
2388
2389         image->reflection_info_unregister_classes = NULL;
2390 }
2391
2392 static void
2393 deregister_reflection_info_roots (MonoDomain *domain)
2394 {
2395         GSList *list;
2396
2397         mono_domain_assemblies_lock (domain);
2398         for (list = domain->domain_assemblies; list; list = list->next) {
2399                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2400                 MonoImage *image = assembly->image;
2401                 int i;
2402
2403                 /*
2404                  * No need to take the image lock here since dynamic images are appdomain bound and
2405                  * at this point the mutator is gone.  Taking the image lock here would mean
2406                  * promoting it from a simple lock to a complex lock, which we better avoid if
2407                  * possible.
2408                  */
2409                 if (image_is_dynamic (image))
2410                         deregister_reflection_info_roots_from_list (image);
2411
2412                 for (i = 0; i < image->module_count; ++i) {
2413                         MonoImage *module = image->modules [i];
2414                         if (module && image_is_dynamic (module))
2415                                 deregister_reflection_info_roots_from_list (module);
2416                 }
2417         }
2418         mono_domain_assemblies_unlock (domain);
2419 }
2420
2421 static guint32 WINAPI
2422 unload_thread_main (void *arg)
2423 {
2424         MonoError error;
2425         unload_data *data = (unload_data*)arg;
2426         MonoDomain *domain = data->domain;
2427         MonoThread *thread;
2428         int i;
2429
2430         /* Have to attach to the runtime so shutdown can wait for this thread */
2431         /* Force it to be attached to avoid racing during shutdown. */
2432         thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2433         mono_error_raise_exception (&error); /* FIXME don't raise here */
2434
2435         /* 
2436          * FIXME: Abort our parent thread last, so we can return a failure 
2437          * indication if aborting times out.
2438          */
2439         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2440                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2441                 goto failure;
2442         }
2443
2444         if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2445                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2446                 goto failure;
2447         }
2448
2449         /* Finalize all finalizable objects in the doomed appdomain */
2450         if (!mono_domain_finalize (domain, -1)) {
2451                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2452                 goto failure;
2453         }
2454
2455         /* Clear references to our vtables in class->runtime_info.
2456          * We also hold the loader lock because we're going to change
2457          * class->runtime_info.
2458          */
2459
2460         mono_loader_lock (); //FIXME why do we need the loader lock here?
2461         mono_domain_lock (domain);
2462 #ifdef HAVE_SGEN_GC
2463         /*
2464          * We need to make sure that we don't have any remsets
2465          * pointing into static data of the to-be-freed domain because
2466          * at the next collections they would be invalid.  So what we
2467          * do is we first zero all static data and then do a minor
2468          * collection.  Because all references in the static data will
2469          * now be null we won't do any unnecessary copies and after
2470          * the collection there won't be any more remsets.
2471          */
2472         for (i = 0; i < domain->class_vtable_array->len; ++i)
2473                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2474         mono_gc_collect (0);
2475 #endif
2476         for (i = 0; i < domain->class_vtable_array->len; ++i)
2477                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2478         deregister_reflection_info_roots (domain);
2479
2480         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2481
2482         mono_domain_unlock (domain);
2483         mono_loader_unlock ();
2484
2485         mono_threads_clear_cached_culture (domain);
2486
2487         domain->state = MONO_APPDOMAIN_UNLOADED;
2488
2489         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2490
2491         /* remove from the handle table the items related to this domain */
2492         mono_gchandle_free_domain (domain);
2493
2494         mono_domain_free (domain, FALSE);
2495
2496         mono_gc_collect (mono_gc_max_generation ());
2497
2498         mono_atomic_store_release (&data->done, TRUE);
2499         unload_data_unref (data);
2500         mono_thread_detach (thread);
2501         return 0;
2502
2503 failure:
2504         mono_atomic_store_release (&data->done, TRUE);
2505         unload_data_unref (data);
2506         mono_thread_detach (thread);
2507         return 1;
2508 }
2509
2510 /*
2511  * mono_domain_unload:
2512  * @domain: The domain to unload
2513  *
2514  *  Unloads an appdomain. Follows the process outlined in the comment
2515  *  for mono_domain_try_unload.
2516  */
2517 void
2518 mono_domain_unload (MonoDomain *domain)
2519 {
2520         MonoObject *exc = NULL;
2521         mono_domain_try_unload (domain, &exc);
2522 }
2523
2524 static guint32
2525 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2526 {
2527         guint32 result;
2528
2529         MONO_PREPARE_BLOCKING;
2530         result = WaitForSingleObjectEx (handle, timeout, alertable);
2531         MONO_FINISH_BLOCKING;
2532
2533         return result;
2534 }
2535
2536 /*
2537  * mono_domain_unload:
2538  * @domain: The domain to unload
2539  * @exc: Exception information
2540  *
2541  *  Unloads an appdomain. Follows the process outlined in:
2542  *  http://blogs.gotdotnet.com/cbrumme
2543  *
2544  *  If doing things the 'right' way is too hard or complex, we do it the 
2545  *  'simple' way, which means do everything needed to avoid crashes and
2546  *  memory leaks, but not much else.
2547  *
2548  *  It is required to pass a valid reference to the exc argument, upon return
2549  *  from this function *exc will be set to the exception thrown, if any.
2550  *
2551  *  If this method is not called from an icall (embedded scenario for instance),
2552  *  it must not be called with any managed frames on the stack, since the unload
2553  *  process could end up trying to abort the current thread.
2554  */
2555 void
2556 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2557 {
2558         MonoError error;
2559         HANDLE thread_handle;
2560         MonoAppDomainState prev_state;
2561         MonoMethod *method;
2562         unload_data *thread_data;
2563         MonoNativeThreadId tid;
2564         MonoDomain *caller_domain = mono_domain_get ();
2565         char *name;
2566
2567         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2568
2569         /* Atomically change our state to UNLOADING */
2570         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2571                 MONO_APPDOMAIN_UNLOADING_START,
2572                 MONO_APPDOMAIN_CREATED);
2573         if (prev_state != MONO_APPDOMAIN_CREATED) {
2574                 switch (prev_state) {
2575                 case MONO_APPDOMAIN_UNLOADING_START:
2576                 case MONO_APPDOMAIN_UNLOADING:
2577                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2578                         return;
2579                 case MONO_APPDOMAIN_UNLOADED:
2580                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2581                         return;
2582                 default:
2583                         g_warning ("Invalid appdomain state %d", prev_state);
2584                         g_assert_not_reached ();
2585                 }
2586         }
2587
2588         mono_domain_set (domain, FALSE);
2589         /* Notify OnDomainUnload listeners */
2590         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2591         g_assert (method);
2592
2593         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2594
2595         if (!mono_error_ok (&error)) {
2596                 if (*exc)
2597                         mono_error_cleanup (&error);
2598                 else
2599                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2600         }
2601
2602         if (*exc) {
2603                 /* Roll back the state change */
2604                 domain->state = MONO_APPDOMAIN_CREATED;
2605                 mono_domain_set (caller_domain, FALSE);
2606                 return;
2607         }
2608         mono_domain_set (caller_domain, FALSE);
2609
2610         thread_data = g_new0 (unload_data, 1);
2611         thread_data->domain = domain;
2612         thread_data->failure_reason = NULL;
2613         thread_data->done = FALSE;
2614         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2615
2616         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2617         domain->state = MONO_APPDOMAIN_UNLOADING;
2618         /* 
2619          * First we create a separate thread for unloading, since
2620          * we might have to abort some threads, including the current one.
2621          */
2622         thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2623         if (thread_handle == NULL)
2624                 return;
2625         name = g_strdup_printf ("Unload thread for domain %x", domain);
2626         mono_thread_info_set_name (tid, name);
2627         mono_thread_info_resume (tid);
2628         g_free (name);
2629
2630         /* Wait for the thread */       
2631         while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2632                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2633                         /* The unload thread tries to abort us */
2634                         /* The icall wrapper will execute the abort */
2635                         CloseHandle (thread_handle);
2636                         unload_data_unref (thread_data);
2637                         return;
2638                 }
2639         }
2640         CloseHandle (thread_handle);
2641
2642         if (thread_data->failure_reason) {
2643                 /* Roll back the state change */
2644                 domain->state = MONO_APPDOMAIN_CREATED;
2645
2646                 g_warning ("%s", thread_data->failure_reason);
2647
2648                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2649
2650                 g_free (thread_data->failure_reason);
2651                 thread_data->failure_reason = NULL;
2652         }
2653
2654         unload_data_unref (thread_data);
2655 }