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