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