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