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