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