[io-layer] Extract error (#4279)
[mono.git] / mono / metadata / appdomain.c
1 /*
2  * appdomain.c: AppDomain functions
3  *
4  * Authors:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  * Copyright 2012 Xamarin Inc
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14 #undef ASSEMBLY_LOAD_DEBUG
15 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #ifdef HAVE_SYS_TIME_H
23 #include <sys/time.h>
24 #endif
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #ifdef HAVE_UTIME_H
29 #include <utime.h>
30 #else
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
33 #endif
34 #endif
35
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/appdomain-icalls.h>
39 #include <mono/metadata/domain-internals.h>
40 #include "mono/metadata/metadata-internals.h"
41 #include <mono/metadata/assembly.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/exception-internals.h>
44 #include <mono/metadata/threads.h>
45 #include <mono/metadata/threadpool.h>
46 #include <mono/metadata/tabledefs.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/monitor.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/w32file.h>
55 #include <mono/metadata/lock-tracer.h>
56 #include <mono/metadata/console-io.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/tokentype.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/reflection-internals.h>
61 #include <mono/metadata/abi-details.h>
62 #include <mono/metadata/w32socket.h>
63 #include <mono/utils/mono-uri.h>
64 #include <mono/utils/mono-logger-internals.h>
65 #include <mono/utils/mono-path.h>
66 #include <mono/utils/mono-stdlib.h>
67 #include <mono/utils/mono-io-portability.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/atomic.h>
70 #include <mono/utils/mono-memory-model.h>
71 #include <mono/utils/mono-threads.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/metadata/w32error.h>
74 #include <mono/utils/w32api.h>
75 #ifdef HOST_WIN32
76 #include <direct.h>
77 #endif
78
79 /*
80  * This is the version number of the corlib-runtime interface. When
81  * making changes to this interface (by changing the layout
82  * of classes the runtime knows about, changing icall signature or
83  * semantics etc), increment this variable. Also increment the
84  * pair of this variable in mscorlib in:
85  *       mcs/class/corlib/System/Environment.cs
86  *
87  * Changes which are already detected at runtime, like the addition
88  * of icalls, do not require an increment.
89  */
90 #define MONO_CORLIB_VERSION 164
91
92 typedef struct
93 {
94         int runtime_count;
95         int assemblybinding_count;
96         MonoDomain *domain;
97         gchar *filename;
98 } RuntimeConfig;
99
100 static gunichar2 process_guid [36];
101 static gboolean process_guid_set = FALSE;
102
103 static gboolean no_exec = FALSE;
104
105 static MonoAssembly *
106 mono_domain_assembly_preload (MonoAssemblyName *aname,
107                               gchar **assemblies_path,
108                               gpointer user_data);
109
110 static MonoAssembly *
111 mono_domain_assembly_search (MonoAssemblyName *aname,
112                                                          gpointer user_data);
113
114 static void
115 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
116
117 static void
118 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
119
120 static MonoAppDomain *
121 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
122
123 static char *
124 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
125
126 static MonoLoadFunc load_function = NULL;
127
128 /* Lazy class loading functions */
129 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly);
130
131 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, System, AppDomain);
132
133 void
134 mono_install_runtime_load (MonoLoadFunc func)
135 {
136         load_function = func;
137 }
138
139 MonoDomain*
140 mono_runtime_load (const char *filename, const char *runtime_version)
141 {
142         g_assert (load_function);
143         return load_function (filename, runtime_version);
144 }
145
146 /**
147  * mono_runtime_set_no_exec:
148  *
149  * Instructs the runtime to operate in static mode, i.e. avoid/do not
150  * allow managed code execution. This is useful for running the AOT
151  * compiler on platforms which allow full-aot execution only.  This
152  * should be called before mono_runtime_init ().
153  */
154 void
155 mono_runtime_set_no_exec (gboolean val)
156 {
157         no_exec = val;
158 }
159
160 /**
161  * mono_runtime_get_no_exec:
162  *
163  * If true, then the runtime will not allow managed code execution.
164  */
165 gboolean
166 mono_runtime_get_no_exec (void)
167 {
168         return no_exec;
169 }
170
171 static void
172 create_domain_objects (MonoDomain *domain)
173 {
174         MonoError error;
175         MonoDomain *old_domain = mono_domain_get ();
176         MonoString *arg;
177         MonoVTable *string_vt;
178         MonoClassField *string_empty_fld;
179
180         if (domain != old_domain) {
181                 mono_thread_push_appdomain_ref (domain);
182                 mono_domain_set_internal_with_options (domain, FALSE);
183         }
184
185         /*
186          * Initialize String.Empty. This enables the removal of
187          * the static cctor of the String class.
188          */
189         string_vt = mono_class_vtable (domain, mono_defaults.string_class);
190         string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
191         g_assert (string_empty_fld);
192         MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
193         mono_error_assert_ok (&error);
194         mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
195         domain->empty_string = empty_str;
196
197         /*
198          * Create an instance early since we can't do it when there is no memory.
199          */
200         arg = mono_string_new (domain, "Out of memory");
201         domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
202         mono_error_assert_ok (&error);
203
204         /* 
205          * These two are needed because the signal handlers might be executing on
206          * an alternate stack, and Boehm GC can't handle that.
207          */
208         arg = mono_string_new (domain, "A null value was found where an object instance was required");
209         domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
210         mono_error_assert_ok (&error);
211         arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
212         domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
213         mono_error_assert_ok (&error);
214
215         /*The ephemeron tombstone i*/
216         domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
217         mono_error_assert_ok (&error);
218
219         if (domain != old_domain) {
220                 mono_thread_pop_appdomain_ref ();
221                 mono_domain_set_internal_with_options (old_domain, FALSE);
222         }
223
224         /* 
225          * This class is used during exception handling, so initialize it here, to prevent
226          * stack overflows while handling stack overflows.
227          */
228         mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
229 }
230
231 /**
232  * mono_runtime_init:
233  * @domain: domain returned by mono_init ()
234  *
235  * Initialize the core AppDomain: this function will run also some
236  * IL initialization code, so it needs the execution engine to be fully 
237  * operational.
238  *
239  * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
240  * we know the entry_assembly.
241  *
242  */
243 void
244 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
245 {
246         MonoError error;
247         mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
248         mono_error_cleanup (&error);
249 }
250
251 void
252 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
253 {
254         MonoAppDomainSetup *setup;
255         MonoAppDomain *ad;
256         MonoClass *klass;
257
258         mono_error_init (error);
259
260         mono_portability_helpers_init ();
261         
262         mono_gc_base_init ();
263         mono_monitor_init ();
264         mono_marshal_init ();
265
266         mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
267         mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
268         mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
269         mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
270         mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
271         mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
272         mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
273
274         mono_thread_init (start_cb, attach_cb);
275
276         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
277         setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
278         return_if_nok (error);
279
280         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
281
282         ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
283         return_if_nok (error);
284
285         ad->data = domain;
286         domain->domain = ad;
287         domain->setup = setup;
288
289         mono_thread_attach (domain);
290
291         mono_type_initialization_init ();
292
293         if (!mono_runtime_get_no_exec ())
294                 create_domain_objects (domain);
295
296         /* GC init has to happen after thread init */
297         mono_gc_init ();
298
299         /* contexts use GC handles, so they must be initialized after the GC */
300         mono_context_init_checked (domain, error);
301         return_if_nok (error);
302         mono_context_set (domain->default_context);
303
304 #ifndef DISABLE_SOCKETS
305         mono_network_init ();
306 #endif
307         
308         mono_console_init ();
309         mono_attach_init ();
310
311         mono_locks_tracer_init ();
312
313         /* mscorlib is loaded before we install the load hook */
314         mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
315
316         return;
317 }
318
319 static int
320 mono_get_corlib_version (void)
321 {
322         MonoError error;
323         MonoClass *klass;
324         MonoClassField *field;
325         MonoObject *value;
326
327         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
328         mono_class_init (klass);
329         field = mono_class_get_field_from_name (klass, "mono_corlib_version");
330         if (!field)
331                 return -1;
332         if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
333                 return -1;
334         value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
335         mono_error_assert_ok (&error);
336         return *(gint32*)((gchar*)value + sizeof (MonoObject));
337 }
338
339 /**
340  * mono_check_corlib_version
341  *
342  * Checks that the corlib that is loaded matches the version of this runtime.
343  *
344  * Returns: NULL if the runtime will work with the corlib, or a g_malloc
345  * allocated string with the error otherwise.
346  */
347 const char*
348 mono_check_corlib_version (void)
349 {
350         int version = mono_get_corlib_version ();
351         if (version != MONO_CORLIB_VERSION)
352                 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
353
354         /* Check that the managed and unmanaged layout of MonoInternalThread matches */
355         guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
356         guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
357         if (native_offset != managed_offset)
358                 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
359
360         return NULL;
361 }
362
363 /**
364  * mono_context_init:
365  * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
366  *
367  * Initializes the @domain's default System.Runtime.Remoting's Context.
368  */
369 void
370 mono_context_init (MonoDomain *domain)
371 {
372         MonoError error;
373         mono_context_init_checked (domain, &error);
374         mono_error_cleanup (&error);
375 }
376
377 void
378 mono_context_init_checked (MonoDomain *domain, MonoError *error)
379 {
380         MonoClass *klass;
381         MonoAppContext *context;
382
383         mono_error_init (error);
384
385         klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
386         context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
387         return_if_nok (error);
388
389         context->domain_id = domain->domain_id;
390         context->context_id = 0;
391         ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
392         domain->default_context = context;
393 }
394
395 /**
396  * mono_runtime_cleanup:
397  * @domain: unused.
398  *
399  * Internal routine.
400  *
401  * This must not be called while there are still running threads executing
402  * managed code.
403  */
404 void
405 mono_runtime_cleanup (MonoDomain *domain)
406 {
407         mono_attach_cleanup ();
408
409         /* This ends up calling any pending pending (for at most 2 seconds) */
410         mono_gc_cleanup ();
411
412         mono_thread_cleanup ();
413
414 #ifndef DISABLE_SOCKETS
415         mono_network_cleanup ();
416 #endif
417         mono_marshal_cleanup ();
418
419         mono_type_initialization_cleanup ();
420
421         mono_monitor_cleanup ();
422 }
423
424 static MonoDomainFunc quit_function = NULL;
425
426 void
427 mono_install_runtime_cleanup (MonoDomainFunc func)
428 {
429         quit_function = func;
430 }
431
432 void
433 mono_runtime_quit ()
434 {
435         if (quit_function != NULL)
436                 quit_function (mono_get_root_domain (), NULL);
437 }
438
439 /**
440  * mono_domain_create_appdomain:
441  * @friendly_name: The friendly name of the appdomain to create
442  * @configuration_file: The configuration file to initialize the appdomain with
443  * 
444  * Returns a MonoDomain initialized with the appdomain
445  */
446 MonoDomain *
447 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
448 {
449         MonoError error;
450         MonoAppDomain *ad;
451         MonoAppDomainSetup *setup;
452         MonoClass *klass;
453
454         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
455         setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
456         if (!is_ok (&error))
457                 goto fail;
458         setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
459
460         ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
461         if (!is_ok (&error))
462                 goto fail;
463
464         return mono_domain_from_appdomain (ad);
465 fail:
466         mono_error_cleanup (&error);
467         return NULL;
468 }
469
470 /**
471  * mono_domain_set_config:
472  * @domain: MonoDomain initialized with the appdomain we want to change
473  * @base_dir: new base directory for the appdomain
474  * @config_file_name: path to the new configuration for the app domain
475  *
476  * Used to set the system configuration for an appdomain
477  *
478  * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException: 
479  * Error Initializing the configuration system. ---> System.ArgumentException: 
480  * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
481  */
482 void
483 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
484 {
485         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
486         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
487 }
488
489 static MonoAppDomainSetup*
490 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
491 {
492         MonoDomain *caller_domain;
493         MonoClass *ads_class;
494         MonoAppDomainSetup *copy;
495
496         mono_error_init (error);
497
498         caller_domain = mono_domain_get ();
499         ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
500
501         copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
502         return_val_if_nok (error, NULL);
503
504         mono_domain_set_internal (domain);
505
506 #define XCOPY_FIELD(dst,field,src,error)                                        \
507         do {                                                            \
508                 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
509                 return_val_if_nok (error, NULL);                        \
510                 MONO_OBJECT_SETREF ((dst),field,copied_val);            \
511         } while (0)
512
513         XCOPY_FIELD (copy, application_base, setup->application_base, error);
514         XCOPY_FIELD (copy, application_name, setup->application_name, error);
515         XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
516         XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
517         XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
518         XCOPY_FIELD (copy, license_file, setup->license_file, error);
519         XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
520         XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
521         XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
522         XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
523         copy->publisher_policy = setup->publisher_policy;
524         copy->path_changed = setup->path_changed;
525         copy->loader_optimization = setup->loader_optimization;
526         copy->disallow_binding_redirects = setup->disallow_binding_redirects;
527         copy->disallow_code_downloads = setup->disallow_code_downloads;
528         XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
529         copy->disallow_appbase_probe = setup->disallow_appbase_probe;
530         XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
531         XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
532         XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
533
534 #undef COPY_FIELD
535         
536         mono_domain_set_internal (caller_domain);
537
538         return copy;
539 }
540
541 static MonoAppDomain *
542 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
543 {
544         MonoClass *adclass;
545         MonoAppDomain *ad;
546         MonoDomain *data;
547         char *shadow_location;
548
549         mono_error_init (error);
550
551         adclass = mono_class_get_appdomain_class ();
552
553         /* FIXME: pin all those objects */
554         data = mono_domain_create();
555
556         ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
557         return_val_if_nok (error, NULL);
558         ad->data = data;
559         data->domain = ad;
560         data->friendly_name = g_strdup (friendly_name);
561
562         mono_profiler_appdomain_name (data, data->friendly_name);
563
564         if (!setup->application_base) {
565                 /* Inherit from the root domain since MS.NET does this */
566                 MonoDomain *root = mono_get_root_domain ();
567                 if (root->setup->application_base) {
568                         MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
569                         mono_error_assert_ok (error); /* FIXME don't swallow the error */
570                         MONO_OBJECT_SETREF (setup, application_base, s);
571                 }
572         }
573
574         mono_context_init_checked (data, error);
575         return_val_if_nok (error, NULL);
576
577         data->setup = copy_app_domain_setup (data, setup, error);
578         if (!mono_error_ok (error)) {
579                 g_free (data->friendly_name);
580                 return NULL;
581         }
582
583         mono_domain_set_options_from_config (data);
584         add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
585
586 #ifndef DISABLE_SHADOW_COPY
587         /*FIXME, guard this for when the debugger is not running */
588         shadow_location = get_shadow_assembly_location_base (data, error);
589         if (!mono_error_ok (error)) {
590                 g_free (data->friendly_name);
591                 return NULL;
592         }
593
594         g_free (shadow_location);
595 #endif
596
597         create_domain_objects (data);
598
599         return ad;
600 }
601
602 /**
603  * mono_domain_has_type_resolve:
604  * @domain: application domains being looked up
605  *
606  * Returns: TRUE if the AppDomain.TypeResolve field has been
607  * set.
608  */
609 gboolean
610 mono_domain_has_type_resolve (MonoDomain *domain)
611 {
612         static MonoClassField *field = NULL;
613         MonoObject *o;
614
615         if (field == NULL) {
616                 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
617                 g_assert (field);
618         }
619
620         /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
621         if (!domain->domain)
622                 return FALSE;
623
624         mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
625         return o != NULL;
626 }
627
628 /**
629  * mono_domain_try_type_resolve:
630  * @domain: application domainwhere the name where the type is going to be resolved
631  * @name: the name of the type to resolve or NULL.
632  * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
633  *
634  * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
635  * the assembly that matches name.
636  *
637  * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
638  *
639  * Returns: A MonoReflectionAssembly or NULL if not found
640  */
641 MonoReflectionAssembly *
642 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
643 {
644         MonoError error;
645         MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
646         mono_error_cleanup (&error);
647
648         return ret;
649 }
650
651 MonoReflectionAssembly *
652 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
653 {
654         static MonoMethod *method = NULL;
655         MonoReflectionAssembly *ret;
656         void *params [1];
657
658         mono_error_init (error);
659
660         g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
661
662         if (method == NULL) {
663                 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
664                 if (method == NULL) {
665                         g_warning ("Method AppDomain.DoTypeResolve not found.\n");
666                         return NULL;
667                 }
668         }
669
670         if (name)
671                 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
672         else
673                 *params = tb;
674
675         ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
676         return_val_if_nok (error, NULL);
677
678         return ret;
679 }
680
681 /**
682  * mono_domain_owns_vtable_slot:
683  *
684  *  Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
685  */
686 gboolean
687 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
688 {
689         gboolean res;
690
691         mono_domain_lock (domain);
692         res = mono_mempool_contains_addr (domain->mp, vtable_slot);
693         mono_domain_unlock (domain);
694         return res;
695 }
696
697 /**
698  * mono_domain_set:
699  * @domain: domain
700  * @force: force setting.
701  *
702  * Set the current appdomain to @domain. If @force is set, set it even
703  * if it is being unloaded.
704  *
705  * Returns:
706  *   TRUE on success;
707  *   FALSE if the domain is unloaded
708  */
709 gboolean
710 mono_domain_set (MonoDomain *domain, gboolean force)
711 {
712         if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
713                 return FALSE;
714
715         mono_domain_set_internal (domain);
716
717         return TRUE;
718 }
719
720 MonoObject *
721 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
722 {
723         MonoError error;
724         MonoDomain *add;
725         MonoObject *o;
726         char *str;
727
728         MONO_CHECK_ARG_NULL (name, NULL);
729
730         g_assert (ad);
731         add = ad->data;
732         g_assert (add);
733
734         str = mono_string_to_utf8_checked (name, &error);
735         if (mono_error_set_pending_exception (&error))
736                 return NULL;
737
738         mono_domain_lock (add);
739
740         if (!strcmp (str, "APPBASE"))
741                 o = (MonoObject *)add->setup->application_base;
742         else if (!strcmp (str, "APP_CONFIG_FILE"))
743                 o = (MonoObject *)add->setup->configuration_file;
744         else if (!strcmp (str, "DYNAMIC_BASE"))
745                 o = (MonoObject *)add->setup->dynamic_base;
746         else if (!strcmp (str, "APP_NAME"))
747                 o = (MonoObject *)add->setup->application_name;
748         else if (!strcmp (str, "CACHE_BASE"))
749                 o = (MonoObject *)add->setup->cache_path;
750         else if (!strcmp (str, "PRIVATE_BINPATH"))
751                 o = (MonoObject *)add->setup->private_bin_path;
752         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
753                 o = (MonoObject *)add->setup->private_bin_path_probe;
754         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
755                 o = (MonoObject *)add->setup->shadow_copy_directories;
756         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
757                 o = (MonoObject *)add->setup->shadow_copy_files;
758         else 
759                 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
760
761         mono_domain_unlock (add);
762         g_free (str);
763
764         if (!o)
765                 return NULL;
766
767         return o;
768 }
769
770 void
771 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
772 {
773         MonoDomain *add;
774
775         MONO_CHECK_ARG_NULL (name,);
776
777         g_assert (ad);
778         add = ad->data;
779         g_assert (add);
780
781         mono_domain_lock (add);
782
783         mono_g_hash_table_insert (add->env, name, data);
784
785         mono_domain_unlock (add);
786 }
787
788 MonoAppDomainSetup *
789 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
790 {
791         g_assert (ad);
792         g_assert (ad->data);
793
794         return ad->data->setup;
795 }
796
797 MonoString *
798 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
799 {
800         g_assert (ad);
801         g_assert (ad->data);
802
803         return mono_string_new (ad->data, ad->data->friendly_name);
804 }
805
806 MonoAppDomain *
807 ves_icall_System_AppDomain_getCurDomain ()
808 {
809         MonoDomain *add = mono_domain_get ();
810
811         return add->domain;
812 }
813
814 MonoAppDomain *
815 ves_icall_System_AppDomain_getRootDomain ()
816 {
817         MonoDomain *root = mono_get_root_domain ();
818
819         return root->domain;
820 }
821
822 MonoBoolean
823 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
824 {
825         MonoDomain *domain = mono_domain_get ();
826
827         return domain->throw_unobserved_task_exceptions;
828 }
829
830 static char*
831 get_attribute_value (const gchar **attribute_names, 
832                      const gchar **attribute_values, 
833                      const char *att_name)
834 {
835         int n;
836         for (n = 0; attribute_names [n] != NULL; n++) {
837                 if (strcmp (attribute_names [n], att_name) == 0)
838                         return g_strdup (attribute_values [n]);
839         }
840         return NULL;
841 }
842
843 static void
844 start_element (GMarkupParseContext *context, 
845                const gchar         *element_name,
846                const gchar        **attribute_names,
847                const gchar        **attribute_values,
848                gpointer             user_data,
849                GError             **error)
850 {
851         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
852         
853         if (strcmp (element_name, "runtime") == 0) {
854                 runtime_config->runtime_count++;
855                 return;
856         }
857
858         if (strcmp (element_name, "assemblyBinding") == 0) {
859                 runtime_config->assemblybinding_count++;
860                 return;
861         }
862
863         if (runtime_config->runtime_count != 1)
864                 return;
865
866         if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
867                 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
868
869                 if (value && g_ascii_strcasecmp (value, "true") == 0)
870                         runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
871         }
872
873         if (runtime_config->assemblybinding_count != 1)
874                 return;
875
876         if (strcmp (element_name, "probing") != 0)
877                 return;
878
879         g_free (runtime_config->domain->private_bin_path);
880         runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
881         if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
882                 g_free (runtime_config->domain->private_bin_path);
883                 runtime_config->domain->private_bin_path = NULL;
884                 return;
885         }
886 }
887
888 static void
889 end_element (GMarkupParseContext *context,
890              const gchar         *element_name,
891              gpointer             user_data,
892              GError             **error)
893 {
894         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
895         if (strcmp (element_name, "runtime") == 0)
896                 runtime_config->runtime_count--;
897         else if (strcmp (element_name, "assemblyBinding") == 0)
898                 runtime_config->assemblybinding_count--;
899 }
900
901 static void
902 parse_error   (GMarkupParseContext *context, GError *error, gpointer user_data)
903 {
904         RuntimeConfig *state = (RuntimeConfig *)user_data;
905         const gchar *msg;
906         const gchar *filename;
907
908         filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
909         msg = error && error->message ? error->message : "";
910         g_warning ("Error parsing %s: %s", filename, msg);
911 }
912
913 static const GMarkupParser
914 mono_parser = {
915         start_element,
916         end_element,
917         NULL,
918         NULL,
919         parse_error
920 };
921
922 void
923 mono_domain_set_options_from_config (MonoDomain *domain)
924 {
925         MonoError error;
926         gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
927         gsize len;
928         GMarkupParseContext *context;
929         RuntimeConfig runtime_config;
930         gint offset;
931         
932         if (!domain || !domain->setup || !domain->setup->configuration_file)
933                 return;
934
935         config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
936         if (!mono_error_ok (&error)) {
937                 mono_error_cleanup (&error);
938                 goto free_and_out;
939         }
940
941         config_file_path = mono_portability_find_file (config_file_name, TRUE);
942         if (!config_file_path)
943                 config_file_path = config_file_name;
944
945         if (!g_file_get_contents (config_file_path, &text, &len, NULL))
946                 goto free_and_out;
947
948         runtime_config.runtime_count = 0;
949         runtime_config.assemblybinding_count = 0;
950         runtime_config.domain = domain;
951         runtime_config.filename = config_file_path;
952         
953         offset = 0;
954         if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
955                 offset = 3; /* Skip UTF-8 BOM */
956
957         context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
958         if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
959                 g_markup_parse_context_end_parse (context, NULL);
960         g_markup_parse_context_free (context);
961
962   free_and_out:
963         g_free (text);
964         if (config_file_name != config_file_path)
965                 g_free (config_file_name);
966         g_free (config_file_path);
967 }
968
969 MonoAppDomain *
970 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
971 {
972         MonoError error;
973         MonoAppDomain *ad = NULL;
974
975 #ifdef DISABLE_APPDOMAINS
976         mono_error_init (&error);
977         mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
978 #else
979         char *fname;
980
981         fname = mono_string_to_utf8_checked (friendly_name, &error);
982         if (mono_error_set_pending_exception (&error))
983                 return NULL;
984         ad = mono_domain_create_appdomain_internal (fname, setup, &error);
985
986         g_free (fname);
987 #endif
988         mono_error_set_pending_exception (&error);
989         return ad;
990 }
991
992 static gboolean
993 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
994 {
995         HANDLE_FUNCTION_ENTER ();
996         mono_error_init (error);
997         MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
998         if (!is_ok (error))
999                 goto leave;
1000         MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1001 leave:
1002         HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1003 }
1004
1005 MonoArrayHandle
1006 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1007 {
1008         mono_error_init (error);
1009         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1010         MonoAssembly* ass;
1011         GSList *tmp;
1012         int i;
1013         GPtrArray *assemblies;
1014
1015         /* 
1016          * Make a copy of the list of assemblies because we can't hold the assemblies
1017          * lock while creating objects etc.
1018          */
1019         assemblies = g_ptr_array_new ();
1020         /* Need to skip internal assembly builders created by remoting */
1021         mono_domain_assemblies_lock (domain);
1022         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1023                 ass = (MonoAssembly *)tmp->data;
1024                 if (refonly != ass->ref_only)
1025                         continue;
1026                 if (ass->corlib_internal)
1027                         continue;
1028                 g_ptr_array_add (assemblies, ass);
1029         }
1030         mono_domain_assemblies_unlock (domain);
1031
1032         MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1033         if (!is_ok (error))
1034                 goto leave;
1035         for (i = 0; i < assemblies->len; ++i) {
1036                 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1037                         goto leave;
1038         }
1039
1040 leave:
1041         g_ptr_array_free (assemblies, TRUE);
1042         return res;
1043 }
1044
1045 MonoAssembly*
1046 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1047 {
1048         HANDLE_FUNCTION_ENTER ();
1049         mono_error_init (error);
1050         MonoAssembly *result = NULL;
1051         MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1052         if (!is_ok (error))
1053                 goto leave;
1054         result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1055 leave:
1056         HANDLE_FUNCTION_RETURN_VAL (result);
1057 }
1058
1059 MonoAssembly*
1060 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1061 {
1062         MonoAssembly *ret = NULL;
1063         MonoMethod *method;
1064         MonoBoolean isrefonly;
1065         gpointer params [3];
1066
1067         mono_error_init (error);
1068
1069         if (mono_runtime_get_no_exec ())
1070                 return ret;
1071
1072         g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1073
1074         method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1075         g_assert (method != NULL);
1076
1077         isrefonly = refonly ? 1 : 0;
1078         MonoReflectionAssemblyHandle requesting_handle;
1079         if (requesting) {
1080                 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1081                 return_val_if_nok (error, ret);
1082         }
1083         params [0] = MONO_HANDLE_RAW (fname);
1084         params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1085         params [2] = &isrefonly;
1086         MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1087         ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1088         return ret;
1089 }
1090
1091 MonoAssembly *
1092 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1093                                                                           gboolean refonly)
1094 {
1095         MonoError error;
1096         MonoAssembly *assembly;
1097         MonoDomain *domain = mono_domain_get ();
1098         char *aname_str;
1099
1100         aname_str = mono_stringify_assembly_name (aname);
1101
1102         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1103
1104         assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1105         g_free (aname_str);
1106         mono_error_cleanup (&error);
1107
1108         return assembly;
1109 }
1110         
1111 /*
1112  * LOCKING: assumes assemblies_lock in the domain is already locked.
1113  */
1114 static void
1115 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1116 {
1117         gint i;
1118         GSList *tmp;
1119         gboolean destroy_ht = FALSE;
1120
1121         if (!ass->aname.name)
1122                 return;
1123
1124         if (!ht) {
1125                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1126                 destroy_ht = TRUE;
1127         }
1128
1129         /* FIXME: handle lazy loaded assemblies */
1130         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1131                 g_hash_table_insert (ht, tmp->data, tmp->data);
1132         }
1133         if (!g_hash_table_lookup (ht, ass)) {
1134                 mono_assembly_addref (ass);
1135                 g_hash_table_insert (ht, ass, ass);
1136                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1137                 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);
1138         }
1139
1140         if (ass->image->references) {
1141                 for (i = 0; ass->image->references [i] != NULL; i++) {
1142                         if (ass->image->references [i] != REFERENCE_MISSING)
1143                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1144                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
1145                                 }
1146                 }
1147         }
1148         if (destroy_ht)
1149                 g_hash_table_destroy (ht);
1150 }
1151
1152 static void
1153 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1154 {
1155         static MonoClassField *assembly_load_field;
1156         static MonoMethod *assembly_load_method;
1157         MonoError error;
1158         MonoDomain *domain = mono_domain_get ();
1159         MonoClass *klass;
1160         gpointer load_value;
1161         void *params [1];
1162
1163         if (!domain->domain)
1164                 /* This can happen during startup */
1165                 return;
1166 #ifdef ASSEMBLY_LOAD_DEBUG
1167         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1168 #endif
1169         klass = domain->domain->mbr.obj.vtable->klass;
1170
1171         mono_domain_assemblies_lock (domain);
1172         add_assemblies_to_domain (domain, assembly, NULL);
1173         mono_domain_assemblies_unlock (domain);
1174
1175         if (assembly_load_field == NULL) {
1176                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1177                 g_assert (assembly_load_field);
1178         }
1179
1180         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1181         if (load_value == NULL) {
1182                 /* No events waiting to be triggered */
1183                 return;
1184         }
1185
1186         MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1187         mono_error_assert_ok (&error);
1188
1189         if (assembly_load_method == NULL) {
1190                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1191                 g_assert (assembly_load_method);
1192         }
1193
1194         *params = MONO_HANDLE_RAW(ref_assembly);
1195
1196         mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1197         mono_error_cleanup (&error);
1198 }
1199
1200 /*
1201  * LOCKING: Acquires the domain assemblies lock.
1202  */
1203 static void
1204 set_domain_search_path (MonoDomain *domain)
1205 {
1206         MonoError error;
1207         MonoAppDomainSetup *setup;
1208         gchar **tmp;
1209         gchar *search_path = NULL;
1210         gint i;
1211         gint npaths = 0;
1212         gchar **pvt_split = NULL;
1213         GError *gerror = NULL;
1214         gint appbaselen = -1;
1215
1216         /* 
1217          * We use the low-level domain assemblies lock, since this is called from
1218          * assembly loads hooks, which means this thread might hold the loader lock.
1219          */
1220         mono_domain_assemblies_lock (domain);
1221
1222         if (!domain->setup) {
1223                 mono_domain_assemblies_unlock (domain);
1224                 return;
1225         }
1226
1227         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1228                 mono_domain_assemblies_unlock (domain);
1229                 return;
1230         }
1231         setup = domain->setup;
1232         if (!setup->application_base) {
1233                 mono_domain_assemblies_unlock (domain);
1234                 return; /* Must set application base to get private path working */
1235         }
1236
1237         npaths++;
1238         
1239         if (setup->private_bin_path) {
1240                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1241                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1242                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1243                         mono_error_cleanup (&error);
1244                         mono_domain_assemblies_unlock (domain);
1245                         return;
1246                 }
1247         }
1248         
1249         if (domain->private_bin_path) {
1250                 if (search_path == NULL)
1251                         search_path = domain->private_bin_path;
1252                 else {
1253                         gchar *tmp2 = search_path;
1254                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1255                         g_free (tmp2);
1256                 }
1257         }
1258         
1259         if (search_path) {
1260                 /*
1261                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1262                  * directories relative to ApplicationBase separated by semicolons (see
1263                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1264                  * The loop below copes with the fact that some Unix applications may use ':' (or
1265                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1266                  * ';' for the subsequent split.
1267                  *
1268                  * The issue was reported in bug #81446
1269                  */
1270
1271 #ifndef TARGET_WIN32
1272                 gint slen;
1273
1274                 slen = strlen (search_path);
1275                 for (i = 0; i < slen; i++)
1276                         if (search_path [i] == ':')
1277                                 search_path [i] = ';';
1278 #endif
1279                 
1280                 pvt_split = g_strsplit (search_path, ";", 1000);
1281                 g_free (search_path);
1282                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1283         }
1284
1285         if (!npaths) {
1286                 if (pvt_split)
1287                         g_strfreev (pvt_split);
1288                 /*
1289                  * Don't do this because the first time is called, the domain
1290                  * setup is not finished.
1291                  *
1292                  * domain->search_path = g_malloc (sizeof (char *));
1293                  * domain->search_path [0] = NULL;
1294                 */
1295                 mono_domain_assemblies_unlock (domain);
1296                 return;
1297         }
1298
1299         if (domain->search_path)
1300                 g_strfreev (domain->search_path);
1301
1302         tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1303         tmp [npaths] = NULL;
1304
1305         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1306         if (!mono_error_ok (&error)) {
1307                 mono_error_cleanup (&error);
1308                 g_strfreev (pvt_split);
1309                 g_free (tmp);
1310
1311                 mono_domain_assemblies_unlock (domain);
1312                 return;
1313         }
1314
1315         domain->search_path = tmp;
1316
1317         /* FIXME: is this needed? */
1318         if (strncmp (*tmp, "file://", 7) == 0) {
1319                 gchar *file = *tmp;
1320                 gchar *uri = *tmp;
1321                 gchar *tmpuri;
1322
1323                 if (uri [7] != '/')
1324                         uri = g_strdup_printf ("file:///%s", uri + 7);
1325
1326                 tmpuri = uri;
1327                 uri = mono_escape_uri_string (tmpuri);
1328                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1329                 g_free (uri);
1330
1331                 if (tmpuri != file)
1332                         g_free (tmpuri);
1333
1334                 if (gerror != NULL) {
1335                         g_warning ("%s\n", gerror->message);
1336                         g_error_free (gerror);
1337                         *tmp = file;
1338                 } else {
1339                         g_free (file);
1340                 }
1341         }
1342
1343         for (i = 1; pvt_split && i < npaths; i++) {
1344                 if (g_path_is_absolute (pvt_split [i - 1])) {
1345                         tmp [i] = g_strdup (pvt_split [i - 1]);
1346                 } else {
1347                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1348                 }
1349
1350                 if (strchr (tmp [i], '.')) {
1351                         gchar *reduced;
1352                         gchar *freeme;
1353
1354                         reduced = mono_path_canonicalize (tmp [i]);
1355                         if (appbaselen == -1)
1356                                 appbaselen = strlen (tmp [0]);
1357
1358                         if (strncmp (tmp [0], reduced, appbaselen)) {
1359                                 g_free (reduced);
1360                                 g_free (tmp [i]);
1361                                 tmp [i] = g_strdup ("");
1362                                 continue;
1363                         }
1364
1365                         freeme = tmp [i];
1366                         tmp [i] = reduced;
1367                         g_free (freeme);
1368                 }
1369         }
1370         
1371         if (setup->private_bin_path_probe != NULL) {
1372                 g_free (tmp [0]);
1373                 tmp [0] = g_strdup ("");
1374         }
1375                 
1376         domain->setup->path_changed = FALSE;
1377
1378         g_strfreev (pvt_split);
1379
1380         mono_domain_assemblies_unlock (domain);
1381 }
1382
1383 #ifdef DISABLE_SHADOW_COPY
1384 gboolean
1385 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1386 {
1387         return FALSE;
1388 }
1389
1390 char *
1391 mono_make_shadow_copy (const char *filename, MonoError *error)
1392 {
1393         mono_error_init (error);
1394         return (char *) filename;
1395 }
1396 #else
1397 static gboolean
1398 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1399 {
1400         guint16 *orig, *dest;
1401         gboolean copy_result;
1402         gint32 copy_error;
1403         
1404         strcpy (src + srclen - tail_len, extension);
1405
1406         if (IS_PORTABILITY_CASE) {
1407                 gchar *file = mono_portability_find_file (src, TRUE);
1408
1409                 if (file == NULL)
1410                         return TRUE;
1411
1412                 g_free (file);
1413         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1414                 return TRUE;
1415         }
1416
1417         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1418
1419         strcpy (target + targetlen - tail_len, extension);
1420         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1421         
1422         mono_w32file_delete (dest);
1423
1424         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1425
1426         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1427          * overwritten when updated in their original locations. */
1428         if (copy_result)
1429                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1430
1431         g_free (orig);
1432         g_free (dest);
1433         
1434         return copy_result;
1435 }
1436
1437 static gint32 
1438 get_cstring_hash (const char *str)
1439 {
1440         int len, i;
1441         const char *p;
1442         gint32 h = 0;
1443         
1444         if (!str || !str [0])
1445                 return 0;
1446                 
1447         len = strlen (str);
1448         p = str;
1449         for (i = 0; i < len; i++) {
1450                 h = (h << 5) - h + *p;
1451                 p++;
1452         }
1453         
1454         return h;
1455 }
1456
1457 /*
1458  * Returned memory is malloc'd. Called must free it 
1459  */
1460 static char *
1461 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1462 {
1463         MonoAppDomainSetup *setup;
1464         char *cache_path, *appname;
1465         char *userdir;
1466         char *location;
1467
1468         mono_error_init (error);
1469         
1470         setup = domain->setup;
1471         if (setup->cache_path != NULL && setup->application_name != NULL) {
1472                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1473                 return_val_if_nok (error, NULL);
1474
1475 #ifndef TARGET_WIN32
1476                 {
1477                         gint i;
1478                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1479                                 if (cache_path [i] == '\\')
1480                                         cache_path [i] = '/';
1481                 }
1482 #endif
1483
1484                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1485                 if (!mono_error_ok (error)) {
1486                         g_free (cache_path);
1487                         return NULL;
1488                 }
1489
1490                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1491                 g_free (appname);
1492                 g_free (cache_path);
1493         } else {
1494                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1495                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1496                 g_free (userdir);
1497         }
1498         return location;
1499 }
1500
1501 static char *
1502 get_shadow_assembly_location (const char *filename, MonoError *error)
1503 {
1504         gint32 hash = 0, hash2 = 0;
1505         char name_hash [9];
1506         char path_hash [30];
1507         char *bname = g_path_get_basename (filename);
1508         char *dirname = g_path_get_dirname (filename);
1509         char *location, *tmploc;
1510         MonoDomain *domain = mono_domain_get ();
1511
1512         mono_error_init (error);
1513         
1514         hash = get_cstring_hash (bname);
1515         hash2 = get_cstring_hash (dirname);
1516         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1517         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1518         tmploc = get_shadow_assembly_location_base (domain, error);
1519         if (!mono_error_ok (error)) {
1520                 g_free (bname);
1521                 g_free (dirname);
1522                 return NULL;
1523         }
1524
1525         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1526         g_free (tmploc);
1527         g_free (bname);
1528         g_free (dirname);
1529         return location;
1530 }
1531
1532 static gboolean
1533 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1534 {
1535         struct stat sbuf_dest;
1536         gchar *stat_src;
1537         gchar *real_src = mono_portability_find_file (src, TRUE);
1538
1539         if (!real_src)
1540                 stat_src = (gchar*)src;
1541         else
1542                 stat_src = real_src;
1543
1544         if (stat (stat_src, sbuf_src) == -1) {
1545                 time_t tnow = time (NULL);
1546
1547                 if (real_src)
1548                         g_free (real_src);
1549
1550                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1551                 sbuf_src->st_mtime = tnow;
1552                 sbuf_src->st_atime = tnow;
1553                 return TRUE;
1554         }
1555
1556         if (real_src)
1557                 g_free (real_src);
1558
1559         if (stat (dest, &sbuf_dest) == -1)
1560                 return TRUE;
1561         
1562         if (sbuf_src->st_size == sbuf_dest.st_size &&
1563             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1564                 return FALSE;
1565
1566         return TRUE;
1567 }
1568
1569 static gboolean
1570 shadow_copy_create_ini (const char *shadow, const char *filename)
1571 {
1572         char *dir_name;
1573         char *ini_file;
1574         guint16 *u16_ini;
1575         gboolean result;
1576         guint32 n;
1577         HANDLE *handle;
1578         gchar *full_path;
1579
1580         dir_name = g_path_get_dirname (shadow);
1581         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1582         g_free (dir_name);
1583         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1584                 g_free (ini_file);
1585                 return TRUE;
1586         }
1587
1588         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1589         g_free (ini_file);
1590         if (!u16_ini) {
1591                 return FALSE;
1592         }
1593         handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1594         g_free (u16_ini);
1595         if (handle == INVALID_HANDLE_VALUE) {
1596                 return FALSE;
1597         }
1598
1599         full_path = mono_path_resolve_symlinks (filename);
1600         result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1601         g_free (full_path);
1602         mono_w32file_close (handle);
1603         return result;
1604 }
1605
1606 gboolean
1607 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1608 {
1609         MonoError error;
1610         MonoAppDomainSetup *setup;
1611         gchar *all_dirs;
1612         gchar **dir_ptr;
1613         gchar **directories;
1614         gchar *shadow_status_string;
1615         gchar *base_dir;
1616         gboolean shadow_enabled;
1617         gboolean found = FALSE;
1618
1619         if (domain == NULL)
1620                 return FALSE;
1621
1622         setup = domain->setup;
1623         if (setup == NULL || setup->shadow_copy_files == NULL)
1624                 return FALSE;
1625
1626         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1627         if (!mono_error_ok (&error)) {
1628                 mono_error_cleanup (&error);
1629                 return FALSE;
1630         }
1631         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1632         g_free (shadow_status_string);
1633
1634         if (!shadow_enabled)
1635                 return FALSE;
1636
1637         if (setup->shadow_copy_directories == NULL)
1638                 return TRUE;
1639
1640         /* Is dir_name a shadow_copy destination already? */
1641         base_dir = get_shadow_assembly_location_base (domain, &error);
1642         if (!mono_error_ok (&error)) {
1643                 mono_error_cleanup (&error);
1644                 return FALSE;
1645         }
1646
1647         if (strstr (dir_name, base_dir)) {
1648                 g_free (base_dir);
1649                 return TRUE;
1650         }
1651         g_free (base_dir);
1652
1653         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1654         if (!mono_error_ok (&error)) {
1655                 mono_error_cleanup (&error);
1656                 return FALSE;
1657         }
1658
1659         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1660         dir_ptr = directories;
1661         while (*dir_ptr) {
1662                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1663                         found = TRUE;
1664                         break;
1665                 }
1666                 dir_ptr++;
1667         }
1668         g_strfreev (directories);
1669         g_free (all_dirs);
1670         return found;
1671 }
1672
1673 /*
1674 This function raises exceptions so it can cause as sorts of nasty stuff if called
1675 while holding a lock.
1676 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1677 or NULL if source file not found.
1678 FIXME bubble up the error instead of raising it here
1679 */
1680 char *
1681 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1682 {
1683         MonoError error;
1684         gchar *sibling_source, *sibling_target;
1685         gint sibling_source_len, sibling_target_len;
1686         guint16 *orig, *dest;
1687         guint32 attrs;
1688         char *shadow;
1689         gboolean copy_result;
1690         struct stat src_sbuf;
1691         struct utimbuf utbuf;
1692         char *dir_name = g_path_get_dirname (filename);
1693         MonoDomain *domain = mono_domain_get ();
1694         char *shadow_dir;
1695         gint32 copy_error;
1696
1697         mono_error_init (oerror);
1698
1699         set_domain_search_path (domain);
1700
1701         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1702                 g_free (dir_name);
1703                 return (char *) filename;
1704         }
1705
1706         /* Is dir_name a shadow_copy destination already? */
1707         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1708         if (!mono_error_ok (&error)) {
1709                 mono_error_cleanup (&error);
1710                 g_free (dir_name);
1711                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1712                 return NULL;
1713         }
1714
1715         if (strstr (dir_name, shadow_dir)) {
1716                 g_free (shadow_dir);
1717                 g_free (dir_name);
1718                 return (char *) filename;
1719         }
1720         g_free (shadow_dir);
1721         g_free (dir_name);
1722
1723         shadow = get_shadow_assembly_location (filename, &error);
1724         if (!mono_error_ok (&error)) {
1725                 mono_error_cleanup (&error);
1726                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1727                 return NULL;
1728         }
1729
1730         if (g_ensure_directory_exists (shadow) == FALSE) {
1731                 g_free (shadow);
1732                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1733                 return NULL;
1734         }       
1735
1736         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1737                 return (char*) shadow;
1738
1739         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1740         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1741         mono_w32file_delete (dest);
1742
1743         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1744          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1745          * and not have it runtime error" */
1746         attrs = mono_w32file_get_attributes (orig);
1747         if (attrs == INVALID_FILE_ATTRIBUTES) {
1748                 g_free (shadow);
1749                 return (char *)filename;
1750         }
1751
1752         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1753
1754         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1755          * overwritten when updated in their original locations. */
1756         if (copy_result)
1757                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1758
1759         g_free (dest);
1760         g_free (orig);
1761
1762         if (copy_result == FALSE) {
1763                 g_free (shadow);
1764
1765                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1766                 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1767                         return NULL; /* file not found, shadow copy failed */
1768
1769                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1770                 return NULL;
1771         }
1772
1773         /* attempt to copy .mdb, .config if they exist */
1774         sibling_source = g_strconcat (filename, ".config", NULL);
1775         sibling_source_len = strlen (sibling_source);
1776         sibling_target = g_strconcat (shadow, ".config", NULL);
1777         sibling_target_len = strlen (sibling_target);
1778         
1779         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1780         if (copy_result)
1781                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1782         
1783         g_free (sibling_source);
1784         g_free (sibling_target);
1785         
1786         if (!copy_result)  {
1787                 g_free (shadow);
1788                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1789                 return NULL;
1790         }
1791
1792         /* Create a .ini file containing the original assembly location */
1793         if (!shadow_copy_create_ini (shadow, filename)) {
1794                 g_free (shadow);
1795                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1796                 return NULL;
1797         }
1798
1799         utbuf.actime = src_sbuf.st_atime;
1800         utbuf.modtime = src_sbuf.st_mtime;
1801         utime (shadow, &utbuf);
1802         
1803         return shadow;
1804 }
1805 #endif /* DISABLE_SHADOW_COPY */
1806
1807 MonoDomain *
1808 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1809 {
1810         if (appdomain == NULL)
1811                 return NULL;
1812
1813         if (mono_object_is_transparent_proxy (&appdomain->mbr.obj)) {
1814                 MonoTransparentProxy *tp = (MonoTransparentProxy*)appdomain;
1815                 return mono_domain_get_by_id (tp->rp->target_domain_id);
1816         }
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_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 }