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