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