[runtime] Add a missing mono_error_init () in a DISABLE_APPDOMAINS codepath.
[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
966 #ifdef DISABLE_APPDOMAINS
967         mono_error_init (&error);
968         mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
969 #else
970         char *fname;
971
972         fname = mono_string_to_utf8_checked (friendly_name, &error);
973         if (mono_error_set_pending_exception (&error))
974                 return NULL;
975         ad = mono_domain_create_appdomain_internal (fname, setup, &error);
976
977         g_free (fname);
978 #endif
979         mono_error_set_pending_exception (&error);
980         return ad;
981 }
982
983 MonoArray *
984 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
985 {
986         MonoError error;
987         MonoDomain *domain = ad->data; 
988         MonoAssembly* ass;
989         MonoArray *res;
990         GSList *tmp;
991         int i;
992         GPtrArray *assemblies;
993
994         mono_error_init (&error);
995
996         /* 
997          * Make a copy of the list of assemblies because we can't hold the assemblies
998          * lock while creating objects etc.
999          */
1000         assemblies = g_ptr_array_new ();
1001         /* Need to skip internal assembly builders created by remoting */
1002         mono_domain_assemblies_lock (domain);
1003         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1004                 ass = (MonoAssembly *)tmp->data;
1005                 if (refonly != ass->ref_only)
1006                         continue;
1007                 if (ass->corlib_internal)
1008                         continue;
1009                 g_ptr_array_add (assemblies, ass);
1010         }
1011         mono_domain_assemblies_unlock (domain);
1012
1013         res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1014         if (!is_ok (&error))
1015                 goto leave;
1016         for (i = 0; i < assemblies->len; ++i) {
1017                 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1018                 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1019                 if (!mono_error_ok (&error))
1020                         goto leave;
1021                 mono_array_setref (res, i, ass_obj);
1022         }
1023
1024 leave:
1025         g_ptr_array_free (assemblies, TRUE);
1026         if (!mono_error_ok (&error))
1027                 mono_error_set_pending_exception (&error);
1028         return res;
1029 }
1030
1031 MonoReflectionAssembly *
1032 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1033 {
1034         MonoReflectionAssembly *ret;
1035         MonoClass *klass;
1036         MonoMethod *method;
1037         MonoBoolean isrefonly;
1038         gpointer params [3];
1039
1040         mono_error_init (error);
1041
1042         if (mono_runtime_get_no_exec ())
1043                 return NULL;
1044
1045         g_assert (domain != NULL && fname != NULL);
1046
1047         klass = domain->domain->mbr.obj.vtable->klass;
1048         g_assert (klass);
1049         
1050         method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1051         if (method == NULL) {
1052                 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1053                 return NULL;
1054         }
1055
1056         isrefonly = refonly ? 1 : 0;
1057         params [0] = fname;
1058         if (requesting) {
1059                 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1060                 return_val_if_nok (error, NULL);
1061         } else
1062                 params [1] = NULL;
1063         params [2] = &isrefonly;
1064
1065         ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1066         return_val_if_nok (error, NULL);
1067
1068         return ret;
1069 }
1070
1071 MonoAssembly *
1072 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1073                                                                           gboolean refonly)
1074 {
1075         MonoError error;
1076         MonoReflectionAssembly *assembly;
1077         MonoDomain *domain = mono_domain_get ();
1078         char *aname_str;
1079         MonoString *str;
1080
1081         aname_str = mono_stringify_assembly_name (aname);
1082
1083         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1084         str = mono_string_new (domain, aname_str);
1085         g_free (aname_str);
1086         if (!str) {
1087                 return NULL;
1088         }
1089
1090         assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1091         mono_error_cleanup (&error);
1092
1093         if (assembly)
1094                 return assembly->assembly;
1095         else
1096                 return NULL;
1097 }
1098         
1099 /*
1100  * LOCKING: assumes assemblies_lock in the domain is already locked.
1101  */
1102 static void
1103 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1104 {
1105         gint i;
1106         GSList *tmp;
1107         gboolean destroy_ht = FALSE;
1108
1109         if (!ass->aname.name)
1110                 return;
1111
1112         if (!ht) {
1113                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1114                 destroy_ht = TRUE;
1115         }
1116
1117         /* FIXME: handle lazy loaded assemblies */
1118         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1119                 g_hash_table_insert (ht, tmp->data, tmp->data);
1120         }
1121         if (!g_hash_table_lookup (ht, ass)) {
1122                 mono_assembly_addref (ass);
1123                 g_hash_table_insert (ht, ass, ass);
1124                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1125                 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);
1126         }
1127
1128         if (ass->image->references) {
1129                 for (i = 0; ass->image->references [i] != NULL; i++) {
1130                         if (ass->image->references [i] != REFERENCE_MISSING)
1131                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1132                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
1133                                 }
1134                 }
1135         }
1136         if (destroy_ht)
1137                 g_hash_table_destroy (ht);
1138 }
1139
1140 static void
1141 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1142 {
1143         static MonoClassField *assembly_load_field;
1144         static MonoMethod *assembly_load_method;
1145         MonoError error;
1146         MonoDomain *domain = mono_domain_get ();
1147         MonoReflectionAssembly *ref_assembly;
1148         MonoClass *klass;
1149         gpointer load_value;
1150         void *params [1];
1151
1152         if (!domain->domain)
1153                 /* This can happen during startup */
1154                 return;
1155 #ifdef ASSEMBLY_LOAD_DEBUG
1156         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1157 #endif
1158         klass = domain->domain->mbr.obj.vtable->klass;
1159
1160         mono_domain_assemblies_lock (domain);
1161         add_assemblies_to_domain (domain, assembly, NULL);
1162         mono_domain_assemblies_unlock (domain);
1163
1164         if (assembly_load_field == NULL) {
1165                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1166                 g_assert (assembly_load_field);
1167         }
1168
1169         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1170         if (load_value == NULL) {
1171                 /* No events waiting to be triggered */
1172                 return;
1173         }
1174
1175         ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1176         mono_error_assert_ok (&error);
1177
1178         if (assembly_load_method == NULL) {
1179                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1180                 g_assert (assembly_load_method);
1181         }
1182
1183         *params = ref_assembly;
1184
1185         mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1186         mono_error_cleanup (&error);
1187 }
1188
1189 /*
1190  * LOCKING: Acquires the domain assemblies lock.
1191  */
1192 static void
1193 set_domain_search_path (MonoDomain *domain)
1194 {
1195         MonoError error;
1196         MonoAppDomainSetup *setup;
1197         gchar **tmp;
1198         gchar *search_path = NULL;
1199         gint i;
1200         gint npaths = 0;
1201         gchar **pvt_split = NULL;
1202         GError *gerror = NULL;
1203         gint appbaselen = -1;
1204
1205         /* 
1206          * We use the low-level domain assemblies lock, since this is called from
1207          * assembly loads hooks, which means this thread might hold the loader lock.
1208          */
1209         mono_domain_assemblies_lock (domain);
1210
1211         if (!domain->setup) {
1212                 mono_domain_assemblies_unlock (domain);
1213                 return;
1214         }
1215
1216         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1217                 mono_domain_assemblies_unlock (domain);
1218                 return;
1219         }
1220         setup = domain->setup;
1221         if (!setup->application_base) {
1222                 mono_domain_assemblies_unlock (domain);
1223                 return; /* Must set application base to get private path working */
1224         }
1225
1226         npaths++;
1227         
1228         if (setup->private_bin_path) {
1229                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1230                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1231                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1232                         mono_error_cleanup (&error);
1233                         mono_domain_assemblies_unlock (domain);
1234                         return;
1235                 }
1236         }
1237         
1238         if (domain->private_bin_path) {
1239                 if (search_path == NULL)
1240                         search_path = domain->private_bin_path;
1241                 else {
1242                         gchar *tmp2 = search_path;
1243                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1244                         g_free (tmp2);
1245                 }
1246         }
1247         
1248         if (search_path) {
1249                 /*
1250                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1251                  * directories relative to ApplicationBase separated by semicolons (see
1252                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1253                  * The loop below copes with the fact that some Unix applications may use ':' (or
1254                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1255                  * ';' for the subsequent split.
1256                  *
1257                  * The issue was reported in bug #81446
1258                  */
1259
1260 #ifndef TARGET_WIN32
1261                 gint slen;
1262
1263                 slen = strlen (search_path);
1264                 for (i = 0; i < slen; i++)
1265                         if (search_path [i] == ':')
1266                                 search_path [i] = ';';
1267 #endif
1268                 
1269                 pvt_split = g_strsplit (search_path, ";", 1000);
1270                 g_free (search_path);
1271                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1272         }
1273
1274         if (!npaths) {
1275                 if (pvt_split)
1276                         g_strfreev (pvt_split);
1277                 /*
1278                  * Don't do this because the first time is called, the domain
1279                  * setup is not finished.
1280                  *
1281                  * domain->search_path = g_malloc (sizeof (char *));
1282                  * domain->search_path [0] = NULL;
1283                 */
1284                 mono_domain_assemblies_unlock (domain);
1285                 return;
1286         }
1287
1288         if (domain->search_path)
1289                 g_strfreev (domain->search_path);
1290
1291         tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1292         tmp [npaths] = NULL;
1293
1294         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1295         if (!mono_error_ok (&error)) {
1296                 mono_error_cleanup (&error);
1297                 g_strfreev (pvt_split);
1298                 g_free (tmp);
1299
1300                 mono_domain_assemblies_unlock (domain);
1301                 return;
1302         }
1303
1304         domain->search_path = tmp;
1305
1306         /* FIXME: is this needed? */
1307         if (strncmp (*tmp, "file://", 7) == 0) {
1308                 gchar *file = *tmp;
1309                 gchar *uri = *tmp;
1310                 gchar *tmpuri;
1311
1312                 if (uri [7] != '/')
1313                         uri = g_strdup_printf ("file:///%s", uri + 7);
1314
1315                 tmpuri = uri;
1316                 uri = mono_escape_uri_string (tmpuri);
1317                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1318                 g_free (uri);
1319
1320                 if (tmpuri != file)
1321                         g_free (tmpuri);
1322
1323                 if (gerror != NULL) {
1324                         g_warning ("%s\n", gerror->message);
1325                         g_error_free (gerror);
1326                         *tmp = file;
1327                 } else {
1328                         g_free (file);
1329                 }
1330         }
1331
1332         for (i = 1; pvt_split && i < npaths; i++) {
1333                 if (g_path_is_absolute (pvt_split [i - 1])) {
1334                         tmp [i] = g_strdup (pvt_split [i - 1]);
1335                 } else {
1336                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1337                 }
1338
1339                 if (strchr (tmp [i], '.')) {
1340                         gchar *reduced;
1341                         gchar *freeme;
1342
1343                         reduced = mono_path_canonicalize (tmp [i]);
1344                         if (appbaselen == -1)
1345                                 appbaselen = strlen (tmp [0]);
1346
1347                         if (strncmp (tmp [0], reduced, appbaselen)) {
1348                                 g_free (reduced);
1349                                 g_free (tmp [i]);
1350                                 tmp [i] = g_strdup ("");
1351                                 continue;
1352                         }
1353
1354                         freeme = tmp [i];
1355                         tmp [i] = reduced;
1356                         g_free (freeme);
1357                 }
1358         }
1359         
1360         if (setup->private_bin_path_probe != NULL) {
1361                 g_free (tmp [0]);
1362                 tmp [0] = g_strdup ("");
1363         }
1364                 
1365         domain->setup->path_changed = FALSE;
1366
1367         g_strfreev (pvt_split);
1368
1369         mono_domain_assemblies_unlock (domain);
1370 }
1371
1372 #ifdef DISABLE_SHADOW_COPY
1373 gboolean
1374 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1375 {
1376         return FALSE;
1377 }
1378
1379 char *
1380 mono_make_shadow_copy (const char *filename, MonoError *error)
1381 {
1382         mono_error_init (error);
1383         return (char *) filename;
1384 }
1385 #else
1386 static gboolean
1387 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1388 {
1389         guint16 *orig, *dest;
1390         gboolean copy_result;
1391         
1392         strcpy (src + srclen - tail_len, extension);
1393
1394         if (IS_PORTABILITY_CASE) {
1395                 gchar *file = mono_portability_find_file (src, TRUE);
1396
1397                 if (file == NULL)
1398                         return TRUE;
1399
1400                 g_free (file);
1401         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1402                 return TRUE;
1403         }
1404
1405         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1406
1407         strcpy (target + targetlen - tail_len, extension);
1408         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1409         
1410         DeleteFile (dest);
1411         copy_result = CopyFile (orig, dest, FALSE);
1412
1413         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1414          * overwritten when updated in their original locations. */
1415         if (copy_result)
1416                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1417
1418         g_free (orig);
1419         g_free (dest);
1420         
1421         return copy_result;
1422 }
1423
1424 static gint32 
1425 get_cstring_hash (const char *str)
1426 {
1427         int len, i;
1428         const char *p;
1429         gint32 h = 0;
1430         
1431         if (!str || !str [0])
1432                 return 0;
1433                 
1434         len = strlen (str);
1435         p = str;
1436         for (i = 0; i < len; i++) {
1437                 h = (h << 5) - h + *p;
1438                 p++;
1439         }
1440         
1441         return h;
1442 }
1443
1444 /*
1445  * Returned memory is malloc'd. Called must free it 
1446  */
1447 static char *
1448 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1449 {
1450         MonoAppDomainSetup *setup;
1451         char *cache_path, *appname;
1452         char *userdir;
1453         char *location;
1454
1455         mono_error_init (error);
1456         
1457         setup = domain->setup;
1458         if (setup->cache_path != NULL && setup->application_name != NULL) {
1459                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1460                 return_val_if_nok (error, NULL);
1461
1462 #ifndef TARGET_WIN32
1463                 {
1464                         gint i;
1465                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1466                                 if (cache_path [i] == '\\')
1467                                         cache_path [i] = '/';
1468                 }
1469 #endif
1470
1471                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1472                 if (!mono_error_ok (error)) {
1473                         g_free (cache_path);
1474                         return NULL;
1475                 }
1476
1477                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1478                 g_free (appname);
1479                 g_free (cache_path);
1480         } else {
1481                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1482                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1483                 g_free (userdir);
1484         }
1485         return location;
1486 }
1487
1488 static char *
1489 get_shadow_assembly_location (const char *filename, MonoError *error)
1490 {
1491         gint32 hash = 0, hash2 = 0;
1492         char name_hash [9];
1493         char path_hash [30];
1494         char *bname = g_path_get_basename (filename);
1495         char *dirname = g_path_get_dirname (filename);
1496         char *location, *tmploc;
1497         MonoDomain *domain = mono_domain_get ();
1498
1499         mono_error_init (error);
1500         
1501         hash = get_cstring_hash (bname);
1502         hash2 = get_cstring_hash (dirname);
1503         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1504         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1505         tmploc = get_shadow_assembly_location_base (domain, error);
1506         if (!mono_error_ok (error)) {
1507                 g_free (bname);
1508                 g_free (dirname);
1509                 return NULL;
1510         }
1511
1512         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1513         g_free (tmploc);
1514         g_free (bname);
1515         g_free (dirname);
1516         return location;
1517 }
1518
1519 static gboolean
1520 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1521 {
1522         struct stat sbuf_dest;
1523         gchar *stat_src;
1524         gchar *real_src = mono_portability_find_file (src, TRUE);
1525
1526         if (!real_src)
1527                 stat_src = (gchar*)src;
1528         else
1529                 stat_src = real_src;
1530
1531         if (stat (stat_src, sbuf_src) == -1) {
1532                 time_t tnow = time (NULL);
1533
1534                 if (real_src)
1535                         g_free (real_src);
1536
1537                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1538                 sbuf_src->st_mtime = tnow;
1539                 sbuf_src->st_atime = tnow;
1540                 return TRUE;
1541         }
1542
1543         if (real_src)
1544                 g_free (real_src);
1545
1546         if (stat (dest, &sbuf_dest) == -1)
1547                 return TRUE;
1548         
1549         if (sbuf_src->st_size == sbuf_dest.st_size &&
1550             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1551                 return FALSE;
1552
1553         return TRUE;
1554 }
1555
1556 static gboolean
1557 shadow_copy_create_ini (const char *shadow, const char *filename)
1558 {
1559         char *dir_name;
1560         char *ini_file;
1561         guint16 *u16_ini;
1562         gboolean result;
1563         guint32 n;
1564         HANDLE *handle;
1565         gchar *full_path;
1566
1567         dir_name = g_path_get_dirname (shadow);
1568         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1569         g_free (dir_name);
1570         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1571                 g_free (ini_file);
1572                 return TRUE;
1573         }
1574
1575         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1576         g_free (ini_file);
1577         if (!u16_ini) {
1578                 return FALSE;
1579         }
1580         handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1581                                 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1582         g_free (u16_ini);
1583         if (handle == INVALID_HANDLE_VALUE) {
1584                 return FALSE;
1585         }
1586
1587         full_path = mono_path_resolve_symlinks (filename);
1588         result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1589         g_free (full_path);
1590         CloseHandle (handle);
1591         return result;
1592 }
1593
1594 gboolean
1595 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1596 {
1597         MonoError error;
1598         MonoAppDomainSetup *setup;
1599         gchar *all_dirs;
1600         gchar **dir_ptr;
1601         gchar **directories;
1602         gchar *shadow_status_string;
1603         gchar *base_dir;
1604         gboolean shadow_enabled;
1605         gboolean found = FALSE;
1606
1607         if (domain == NULL)
1608                 return FALSE;
1609
1610         setup = domain->setup;
1611         if (setup == NULL || setup->shadow_copy_files == NULL)
1612                 return FALSE;
1613
1614         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1615         if (!mono_error_ok (&error)) {
1616                 mono_error_cleanup (&error);
1617                 return FALSE;
1618         }
1619         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1620         g_free (shadow_status_string);
1621
1622         if (!shadow_enabled)
1623                 return FALSE;
1624
1625         if (setup->shadow_copy_directories == NULL)
1626                 return TRUE;
1627
1628         /* Is dir_name a shadow_copy destination already? */
1629         base_dir = get_shadow_assembly_location_base (domain, &error);
1630         if (!mono_error_ok (&error)) {
1631                 mono_error_cleanup (&error);
1632                 return FALSE;
1633         }
1634
1635         if (strstr (dir_name, base_dir)) {
1636                 g_free (base_dir);
1637                 return TRUE;
1638         }
1639         g_free (base_dir);
1640
1641         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1642         if (!mono_error_ok (&error)) {
1643                 mono_error_cleanup (&error);
1644                 return FALSE;
1645         }
1646
1647         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1648         dir_ptr = directories;
1649         while (*dir_ptr) {
1650                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1651                         found = TRUE;
1652                         break;
1653                 }
1654                 dir_ptr++;
1655         }
1656         g_strfreev (directories);
1657         g_free (all_dirs);
1658         return found;
1659 }
1660
1661 /*
1662 This function raises exceptions so it can cause as sorts of nasty stuff if called
1663 while holding a lock.
1664 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1665 or NULL if source file not found.
1666 FIXME bubble up the error instead of raising it here
1667 */
1668 char *
1669 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1670 {
1671         MonoError error;
1672         gchar *sibling_source, *sibling_target;
1673         gint sibling_source_len, sibling_target_len;
1674         guint16 *orig, *dest;
1675         guint32 attrs;
1676         char *shadow;
1677         gboolean copy_result;
1678         struct stat src_sbuf;
1679         struct utimbuf utbuf;
1680         char *dir_name = g_path_get_dirname (filename);
1681         MonoDomain *domain = mono_domain_get ();
1682         char *shadow_dir;
1683
1684         mono_error_init (oerror);
1685
1686         set_domain_search_path (domain);
1687
1688         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1689                 g_free (dir_name);
1690                 return (char *) filename;
1691         }
1692
1693         /* Is dir_name a shadow_copy destination already? */
1694         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1695         if (!mono_error_ok (&error)) {
1696                 mono_error_cleanup (&error);
1697                 g_free (dir_name);
1698                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1699                 return NULL;
1700         }
1701
1702         if (strstr (dir_name, shadow_dir)) {
1703                 g_free (shadow_dir);
1704                 g_free (dir_name);
1705                 return (char *) filename;
1706         }
1707         g_free (shadow_dir);
1708         g_free (dir_name);
1709
1710         shadow = get_shadow_assembly_location (filename, &error);
1711         if (!mono_error_ok (&error)) {
1712                 mono_error_cleanup (&error);
1713                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1714                 return NULL;
1715         }
1716
1717         if (g_ensure_directory_exists (shadow) == FALSE) {
1718                 g_free (shadow);
1719                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1720                 return NULL;
1721         }       
1722
1723         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1724                 return (char*) shadow;
1725
1726         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1727         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1728         DeleteFile (dest);
1729
1730         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1731          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1732          * and not have it runtime error" */
1733         attrs = GetFileAttributes (orig);
1734         if (attrs == INVALID_FILE_ATTRIBUTES) {
1735                 g_free (shadow);
1736                 return (char *)filename;
1737         }
1738
1739         copy_result = CopyFile (orig, dest, FALSE);
1740
1741         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1742          * overwritten when updated in their original locations. */
1743         if (copy_result)
1744                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1745
1746         g_free (dest);
1747         g_free (orig);
1748
1749         if (copy_result == FALSE) {
1750                 g_free (shadow);
1751
1752                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1753                 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1754                         return NULL; /* file not found, shadow copy failed */
1755
1756                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1757                 return NULL;
1758         }
1759
1760         /* attempt to copy .mdb, .config if they exist */
1761         sibling_source = g_strconcat (filename, ".config", NULL);
1762         sibling_source_len = strlen (sibling_source);
1763         sibling_target = g_strconcat (shadow, ".config", NULL);
1764         sibling_target_len = strlen (sibling_target);
1765         
1766         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1767         if (copy_result)
1768                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1769         
1770         g_free (sibling_source);
1771         g_free (sibling_target);
1772         
1773         if (!copy_result)  {
1774                 g_free (shadow);
1775                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1776                 return NULL;
1777         }
1778
1779         /* Create a .ini file containing the original assembly location */
1780         if (!shadow_copy_create_ini (shadow, filename)) {
1781                 g_free (shadow);
1782                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1783                 return NULL;
1784         }
1785
1786         utbuf.actime = src_sbuf.st_atime;
1787         utbuf.modtime = src_sbuf.st_mtime;
1788         utime (shadow, &utbuf);
1789         
1790         return shadow;
1791 }
1792 #endif /* DISABLE_SHADOW_COPY */
1793
1794 MonoDomain *
1795 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1796 {
1797         if (appdomain == NULL)
1798                 return NULL;
1799         
1800         return appdomain->data;
1801 }
1802
1803 static gboolean
1804 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1805                                         const gchar *path3, const gchar *path4,
1806                                         gboolean refonly, gboolean is_private)
1807 {
1808         gchar *fullpath;
1809         gboolean found = FALSE;
1810         
1811         *assembly = NULL;
1812         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1813
1814         if (IS_PORTABILITY_SET) {
1815                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1816                 if (new_fullpath) {
1817                         g_free (fullpath);
1818                         fullpath = new_fullpath;
1819                         found = TRUE;
1820                 }
1821         } else
1822                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1823         
1824         if (found)
1825                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1826
1827         g_free (fullpath);
1828         return (*assembly != NULL);
1829 }
1830
1831 static MonoAssembly *
1832 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1833 {
1834         MonoAssembly *result = NULL;
1835         gchar **path;
1836         gchar *filename;
1837         const gchar *local_culture;
1838         gint len;
1839         gboolean is_private = FALSE;
1840
1841         if (!culture || *culture == '\0') {
1842                 local_culture = "";
1843         } else {
1844                 local_culture = culture;
1845         }
1846
1847         filename =  g_strconcat (name, ".dll", NULL);
1848         len = strlen (filename);
1849
1850         for (path = search_path; *path; path++) {
1851                 if (**path == '\0') {
1852                         is_private = TRUE;
1853                         continue; /* Ignore empty ApplicationBase */
1854                 }
1855
1856                 /* See test cases in bug #58992 and bug #57710 */
1857                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1858                 strcpy (filename + len - 4, ".dll");
1859                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1860                         break;
1861
1862                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1863                 strcpy (filename + len - 4, ".exe");
1864                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1865                         break;
1866
1867                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1868                 strcpy (filename + len - 4, ".dll");
1869                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1870                         break;
1871
1872                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1873                 strcpy (filename + len - 4, ".exe");
1874                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1875                         break;
1876         }
1877
1878         g_free (filename);
1879         return result;
1880 }
1881
1882 /*
1883  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1884  * and then from assemblies_path if any.
1885  * LOCKING: This is called from the assembly loading code, which means the caller
1886  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1887  */
1888 static MonoAssembly *
1889 mono_domain_assembly_preload (MonoAssemblyName *aname,
1890                               gchar **assemblies_path,
1891                               gpointer user_data)
1892 {
1893         MonoDomain *domain = mono_domain_get ();
1894         MonoAssembly *result = NULL;
1895         gboolean refonly = GPOINTER_TO_UINT (user_data);
1896
1897         set_domain_search_path (domain);
1898
1899         if (domain->search_path && domain->search_path [0] != NULL) {
1900                 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1901         }
1902
1903         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1904                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1905         }
1906
1907         return result;
1908 }
1909
1910 /*
1911  * Check whenever a given assembly was already loaded in the current appdomain.
1912  */
1913 static MonoAssembly *
1914 mono_domain_assembly_search (MonoAssemblyName *aname,
1915                                                          gpointer user_data)
1916 {
1917         MonoDomain *domain = mono_domain_get ();
1918         GSList *tmp;
1919         MonoAssembly *ass;
1920         gboolean refonly = GPOINTER_TO_UINT (user_data);
1921
1922         mono_domain_assemblies_lock (domain);
1923         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1924                 ass = (MonoAssembly *)tmp->data;
1925                 /* Dynamic assemblies can't match here in MS.NET */
1926                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1927                         continue;
1928
1929                 mono_domain_assemblies_unlock (domain);
1930                 return ass;
1931         }
1932         mono_domain_assemblies_unlock (domain);
1933
1934         return NULL;
1935 }
1936
1937 MonoReflectionAssembly *
1938 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1939 {
1940         MonoError error;
1941         MonoReflectionAssembly *result;
1942         MonoDomain *domain = mono_domain_get ();
1943         char *name, *filename;
1944         MonoImageOpenStatus status = MONO_IMAGE_OK;
1945         MonoAssembly *ass;
1946
1947         if (fname == NULL) {
1948                 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1949                 mono_set_pending_exception (exc);
1950                 return NULL;
1951         }
1952                 
1953         name = filename = mono_string_to_utf8_checked (fname, &error);
1954         if (mono_error_set_pending_exception (&error))
1955                 return NULL;
1956         
1957         ass = mono_assembly_open_full (filename, &status, refOnly);
1958         
1959         if (!ass) {
1960                 MonoException *exc;
1961
1962                 if (status == MONO_IMAGE_IMAGE_INVALID)
1963                         exc = mono_get_exception_bad_image_format2 (NULL, fname);
1964                 else
1965                         exc = mono_get_exception_file_not_found2 (NULL, fname);
1966                 g_free (name);
1967                 mono_set_pending_exception (exc);
1968                 return NULL;
1969         }
1970
1971         g_free (name);
1972
1973         result = mono_assembly_get_object_checked (domain, ass, &error);
1974         if (!result)
1975                 mono_error_set_pending_exception (&error);
1976         return result;
1977 }
1978
1979 MonoReflectionAssembly *
1980 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
1981                                             MonoArray *raw_assembly,
1982                                             MonoArray *raw_symbol_store, MonoObject *evidence,
1983                                             MonoBoolean refonly)
1984 {
1985         MonoError error;
1986         MonoAssembly *ass;
1987         MonoReflectionAssembly *refass = NULL;
1988         MonoDomain *domain = ad->data;
1989         MonoImageOpenStatus status;
1990         guint32 raw_assembly_len = mono_array_length (raw_assembly);
1991         MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1992
1993         if (!image) {
1994                 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1995                 return NULL;
1996         }
1997
1998         if (raw_symbol_store != NULL)
1999                 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2000
2001         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2002
2003
2004         if (!ass) {
2005                 mono_image_close (image);
2006                 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2007                 return NULL; 
2008         }
2009
2010         refass = mono_assembly_get_object_checked (domain, ass, &error);
2011         if (!refass)
2012                 mono_error_set_pending_exception (&error);
2013         else
2014                 MONO_OBJECT_SETREF (refass, evidence, evidence);
2015         return refass;
2016 }
2017
2018 MonoReflectionAssembly *
2019 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2020 {
2021         MonoError error;
2022         MonoDomain *domain = ad->data; 
2023         MonoImageOpenStatus status = MONO_IMAGE_OK;
2024         MonoAssembly *ass;
2025         MonoAssemblyName aname;
2026         MonoReflectionAssembly *refass = NULL;
2027         gchar *name;
2028         gboolean parsed;
2029
2030         g_assert (assRef);
2031
2032         name = mono_string_to_utf8_checked (assRef, &error);
2033         if (mono_error_set_pending_exception (&error))
2034                 return NULL;
2035         parsed = mono_assembly_name_parse (name, &aname);
2036         g_free (name);
2037
2038         if (!parsed) {
2039                 /* This is a parse error... */
2040                 if (!refOnly) {
2041                         refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2042                         if (!mono_error_ok (&error)) {
2043                                 mono_error_set_pending_exception (&error);
2044                                 return NULL;
2045                         }
2046                 }
2047                 return refass;
2048         }
2049
2050         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2051         mono_assembly_name_free (&aname);
2052
2053         if (!ass) {
2054                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2055                 if (!refOnly) {
2056                         refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2057                         if (!mono_error_ok (&error)) {
2058                                 mono_error_set_pending_exception (&error);
2059                                 return NULL;
2060                         }
2061                 }
2062                 else
2063                         refass = NULL;
2064                 if (!refass) {
2065                         return NULL;
2066                 }
2067         }
2068
2069         if (refass == NULL)
2070                 refass = mono_assembly_get_object_checked (domain, ass, &error);
2071
2072         if (refass == NULL)
2073                 mono_error_set_pending_exception (&error);
2074         else
2075                 MONO_OBJECT_SETREF (refass, evidence, evidence);
2076         return refass;
2077 }
2078
2079 void
2080 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2081 {
2082         MonoException *exc = NULL;
2083         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2084
2085         if (NULL == domain) {
2086                 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2087                 mono_set_pending_exception (exc);
2088                 return;
2089         }
2090         
2091         if (domain == mono_get_root_domain ()) {
2092                 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2093                 return;
2094         }
2095
2096         /* 
2097          * Unloading seems to cause problems when running NUnit/NAnt, hence
2098          * this workaround.
2099          */
2100         if (g_getenv ("MONO_NO_UNLOAD"))
2101                 return;
2102 #ifdef __native_client__
2103         return;
2104 #endif
2105
2106         mono_domain_try_unload (domain, (MonoObject**)&exc);
2107         if (exc)
2108                 mono_set_pending_exception (exc);
2109 }
2110
2111 gboolean
2112 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2113 {
2114         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2115
2116         if (!domain)
2117                 return TRUE;
2118
2119         return mono_domain_is_unloading (domain);
2120 }
2121
2122 void
2123 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2124 {
2125         mono_unhandled_exception ((MonoObject*) exc);
2126 }
2127
2128 gint32
2129 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, 
2130                                                                                         MonoReflectionAssembly *refass, MonoArray *args)
2131 {
2132         MonoError error;
2133         MonoImage *image;
2134         MonoMethod *method;
2135
2136         g_assert (refass);
2137         image = refass->assembly->image;
2138         g_assert (image);
2139
2140         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2141
2142         if (!method)
2143                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2144
2145         if (!args) {
2146                 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2147                 mono_error_assert_ok (&error);
2148         }
2149
2150         int res = mono_runtime_exec_main_checked (method, (MonoArray *)args, &error);
2151         mono_error_set_pending_exception (&error);
2152         return res;
2153 }
2154
2155 gint32 
2156 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2157 {
2158         return ad->data->domain_id;
2159 }
2160
2161 MonoAppDomain * 
2162 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2163 {
2164         MonoDomain *old_domain = mono_domain_get();
2165
2166         if (!mono_domain_set (ad->data, FALSE)) {
2167                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2168                 return NULL;
2169         }
2170
2171         return old_domain->domain;
2172 }
2173
2174 MonoAppDomain * 
2175 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2176 {
2177         MonoDomain *current_domain = mono_domain_get ();
2178         MonoDomain *domain = mono_domain_get_by_id (domainid);
2179
2180         if (!domain || !mono_domain_set (domain, FALSE)) {
2181                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2182                 return NULL;
2183         }
2184
2185         return current_domain->domain;
2186 }
2187
2188 void
2189 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2190 {
2191         mono_thread_push_appdomain_ref (ad->data);
2192 }
2193
2194 void
2195 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2196 {
2197         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2198
2199         if (!domain) {
2200                 /* 
2201                  * Raise an exception to prevent the managed code from executing a pop
2202                  * later.
2203                  */
2204                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2205                 return;
2206         }
2207
2208         mono_thread_push_appdomain_ref (domain);
2209 }
2210
2211 void
2212 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2213 {
2214         mono_thread_pop_appdomain_ref ();
2215 }
2216
2217 MonoAppContext * 
2218 ves_icall_System_AppDomain_InternalGetContext ()
2219 {
2220         return mono_context_get ();
2221 }
2222
2223 MonoAppContext * 
2224 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2225 {
2226         return mono_domain_get ()->default_context;
2227 }
2228
2229 MonoAppContext * 
2230 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2231 {
2232         MonoAppContext *old_context = mono_context_get ();
2233
2234         mono_context_set (mc);
2235
2236         return old_context;
2237 }
2238
2239 MonoString *
2240 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2241 {
2242         MonoDomain* mono_root_domain = mono_get_root_domain ();
2243         mono_domain_lock (mono_root_domain);
2244         if (process_guid_set) {
2245                 mono_domain_unlock (mono_root_domain);
2246                 MonoError error;
2247                 MonoString *res = NULL;
2248                 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2249                 mono_error_set_pending_exception (&error);
2250                 return res;
2251         }
2252         memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2253         process_guid_set = TRUE;
2254         mono_domain_unlock (mono_root_domain);
2255         return newguid;
2256 }
2257
2258 gboolean
2259 mono_domain_is_unloading (MonoDomain *domain)
2260 {
2261         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2262                 return TRUE;
2263         else
2264                 return FALSE;
2265 }
2266
2267 static void
2268 clear_cached_vtable (MonoVTable *vtable)
2269 {
2270         MonoClass *klass = vtable->klass;
2271         MonoDomain *domain = vtable->domain;
2272         MonoClassRuntimeInfo *runtime_info;
2273         void *data;
2274
2275         runtime_info = klass->runtime_info;
2276         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2277                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2278         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2279                 mono_gc_free_fixed (data);
2280 }
2281
2282 static G_GNUC_UNUSED void
2283 zero_static_data (MonoVTable *vtable)
2284 {
2285         MonoClass *klass = vtable->klass;
2286         void *data;
2287
2288         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2289                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2290 }
2291
2292 typedef struct unload_data {
2293         gboolean done;
2294         MonoDomain *domain;
2295         char *failure_reason;
2296         gint32 refcount;
2297 } unload_data;
2298
2299 static void
2300 unload_data_unref (unload_data *data)
2301 {
2302         gint32 count;
2303         do {
2304                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2305                 g_assert (count >= 1 && count <= 2);
2306                 if (count == 1) {
2307                         g_free (data);
2308                         return;
2309                 }
2310         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2311 }
2312
2313 static void
2314 deregister_reflection_info_roots_from_list (MonoImage *image)
2315 {
2316         GSList *list = image->reflection_info_unregister_classes;
2317
2318         while (list) {
2319                 MonoClass *klass = (MonoClass *)list->data;
2320
2321                 mono_class_free_ref_info (klass);
2322
2323                 list = list->next;
2324         }
2325
2326         image->reflection_info_unregister_classes = NULL;
2327 }
2328
2329 static void
2330 deregister_reflection_info_roots (MonoDomain *domain)
2331 {
2332         GSList *list;
2333
2334         mono_domain_assemblies_lock (domain);
2335         for (list = domain->domain_assemblies; list; list = list->next) {
2336                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2337                 MonoImage *image = assembly->image;
2338                 int i;
2339
2340                 /*
2341                  * No need to take the image lock here since dynamic images are appdomain bound and
2342                  * at this point the mutator is gone.  Taking the image lock here would mean
2343                  * promoting it from a simple lock to a complex lock, which we better avoid if
2344                  * possible.
2345                  */
2346                 if (image_is_dynamic (image))
2347                         deregister_reflection_info_roots_from_list (image);
2348
2349                 for (i = 0; i < image->module_count; ++i) {
2350                         MonoImage *module = image->modules [i];
2351                         if (module && image_is_dynamic (module))
2352                                 deregister_reflection_info_roots_from_list (module);
2353                 }
2354         }
2355         mono_domain_assemblies_unlock (domain);
2356 }
2357
2358 static guint32 WINAPI
2359 unload_thread_main (void *arg)
2360 {
2361         MonoError error;
2362         unload_data *data = (unload_data*)arg;
2363         MonoDomain *domain = data->domain;
2364         MonoThread *thread;
2365         int i;
2366
2367         /* Have to attach to the runtime so shutdown can wait for this thread */
2368         /* Force it to be attached to avoid racing during shutdown. */
2369         thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2370
2371         mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2372         if (!is_ok (&error)) {
2373                 data->failure_reason = g_strdup (mono_error_get_message (&error));
2374                 mono_error_cleanup (&error);
2375                 goto failure;
2376         }
2377
2378         /* 
2379          * FIXME: Abort our parent thread last, so we can return a failure 
2380          * indication if aborting times out.
2381          */
2382         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2383                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2384                 goto failure;
2385         }
2386
2387         if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2388                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2389                 goto failure;
2390         }
2391
2392         /* Finalize all finalizable objects in the doomed appdomain */
2393         if (!mono_domain_finalize (domain, -1)) {
2394                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2395                 goto failure;
2396         }
2397
2398         /* Clear references to our vtables in class->runtime_info.
2399          * We also hold the loader lock because we're going to change
2400          * class->runtime_info.
2401          */
2402
2403         mono_loader_lock (); //FIXME why do we need the loader lock here?
2404         mono_domain_lock (domain);
2405 #ifdef HAVE_SGEN_GC
2406         /*
2407          * We need to make sure that we don't have any remsets
2408          * pointing into static data of the to-be-freed domain because
2409          * at the next collections they would be invalid.  So what we
2410          * do is we first zero all static data and then do a minor
2411          * collection.  Because all references in the static data will
2412          * now be null we won't do any unnecessary copies and after
2413          * the collection there won't be any more remsets.
2414          */
2415         for (i = 0; i < domain->class_vtable_array->len; ++i)
2416                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2417         mono_gc_collect (0);
2418 #endif
2419         for (i = 0; i < domain->class_vtable_array->len; ++i)
2420                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2421         deregister_reflection_info_roots (domain);
2422
2423         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2424
2425         mono_domain_unlock (domain);
2426         mono_loader_unlock ();
2427
2428         mono_threads_clear_cached_culture (domain);
2429
2430         domain->state = MONO_APPDOMAIN_UNLOADED;
2431
2432         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2433
2434         /* remove from the handle table the items related to this domain */
2435         mono_gchandle_free_domain (domain);
2436
2437         mono_domain_free (domain, FALSE);
2438
2439         mono_gc_collect (mono_gc_max_generation ());
2440
2441         mono_atomic_store_release (&data->done, TRUE);
2442         unload_data_unref (data);
2443         mono_thread_detach (thread);
2444         return 0;
2445
2446 failure:
2447         mono_atomic_store_release (&data->done, TRUE);
2448         unload_data_unref (data);
2449         mono_thread_detach (thread);
2450         return 1;
2451 }
2452
2453 /*
2454  * mono_domain_unload:
2455  * @domain: The domain to unload
2456  *
2457  *  Unloads an appdomain. Follows the process outlined in the comment
2458  *  for mono_domain_try_unload.
2459  */
2460 void
2461 mono_domain_unload (MonoDomain *domain)
2462 {
2463         MonoObject *exc = NULL;
2464         mono_domain_try_unload (domain, &exc);
2465 }
2466
2467 static guint32
2468 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2469 {
2470         guint32 result;
2471
2472         MONO_ENTER_GC_SAFE;
2473         result = WaitForSingleObjectEx (handle, timeout, alertable);
2474         MONO_EXIT_GC_SAFE;
2475
2476         return result;
2477 }
2478
2479 /*
2480  * mono_domain_unload:
2481  * @domain: The domain to unload
2482  * @exc: Exception information
2483  *
2484  *  Unloads an appdomain. Follows the process outlined in:
2485  *  http://blogs.gotdotnet.com/cbrumme
2486  *
2487  *  If doing things the 'right' way is too hard or complex, we do it the 
2488  *  'simple' way, which means do everything needed to avoid crashes and
2489  *  memory leaks, but not much else.
2490  *
2491  *  It is required to pass a valid reference to the exc argument, upon return
2492  *  from this function *exc will be set to the exception thrown, if any.
2493  *
2494  *  If this method is not called from an icall (embedded scenario for instance),
2495  *  it must not be called with any managed frames on the stack, since the unload
2496  *  process could end up trying to abort the current thread.
2497  */
2498 void
2499 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2500 {
2501         MonoError error;
2502         HANDLE thread_handle;
2503         MonoAppDomainState prev_state;
2504         MonoMethod *method;
2505         unload_data *thread_data;
2506         MonoNativeThreadId tid;
2507         MonoDomain *caller_domain = mono_domain_get ();
2508         MonoThreadParm tp;
2509
2510         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2511
2512         /* Atomically change our state to UNLOADING */
2513         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2514                 MONO_APPDOMAIN_UNLOADING_START,
2515                 MONO_APPDOMAIN_CREATED);
2516         if (prev_state != MONO_APPDOMAIN_CREATED) {
2517                 switch (prev_state) {
2518                 case MONO_APPDOMAIN_UNLOADING_START:
2519                 case MONO_APPDOMAIN_UNLOADING:
2520                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2521                         return;
2522                 case MONO_APPDOMAIN_UNLOADED:
2523                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2524                         return;
2525                 default:
2526                         g_warning ("Invalid appdomain state %d", prev_state);
2527                         g_assert_not_reached ();
2528                 }
2529         }
2530
2531         mono_domain_set (domain, FALSE);
2532         /* Notify OnDomainUnload listeners */
2533         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2534         g_assert (method);
2535
2536         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2537
2538         if (!mono_error_ok (&error)) {
2539                 if (*exc)
2540                         mono_error_cleanup (&error);
2541                 else
2542                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2543         }
2544
2545         if (*exc) {
2546                 /* Roll back the state change */
2547                 domain->state = MONO_APPDOMAIN_CREATED;
2548                 mono_domain_set (caller_domain, FALSE);
2549                 return;
2550         }
2551         mono_domain_set (caller_domain, FALSE);
2552
2553         thread_data = g_new0 (unload_data, 1);
2554         thread_data->domain = domain;
2555         thread_data->failure_reason = NULL;
2556         thread_data->done = FALSE;
2557         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2558
2559         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2560         domain->state = MONO_APPDOMAIN_UNLOADING;
2561         /* 
2562          * First we create a separate thread for unloading, since
2563          * we might have to abort some threads, including the current one.
2564          */
2565         tp.priority = 0;
2566         tp.stack_size = 0;
2567         tp.creation_flags = CREATE_SUSPENDED;
2568         thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, &tp, &tid);
2569         if (thread_handle == NULL)
2570                 return;
2571         mono_thread_info_resume (tid);
2572
2573         /* Wait for the thread */       
2574         while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2575                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2576                         /* The unload thread tries to abort us */
2577                         /* The icall wrapper will execute the abort */
2578                         CloseHandle (thread_handle);
2579                         unload_data_unref (thread_data);
2580                         return;
2581                 }
2582         }
2583         CloseHandle (thread_handle);
2584
2585         if (thread_data->failure_reason) {
2586                 /* Roll back the state change */
2587                 domain->state = MONO_APPDOMAIN_CREATED;
2588
2589                 g_warning ("%s", thread_data->failure_reason);
2590
2591                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2592
2593                 g_free (thread_data->failure_reason);
2594                 thread_data->failure_reason = NULL;
2595         }
2596
2597         unload_data_unref (thread_data);
2598 }