[io-layer] Extract socket (#4241)
[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/file-io.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         
1402         strcpy (src + srclen - tail_len, extension);
1403
1404         if (IS_PORTABILITY_CASE) {
1405                 gchar *file = mono_portability_find_file (src, TRUE);
1406
1407                 if (file == NULL)
1408                         return TRUE;
1409
1410                 g_free (file);
1411         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1412                 return TRUE;
1413         }
1414
1415         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1416
1417         strcpy (target + targetlen - tail_len, extension);
1418         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1419         
1420         DeleteFile (dest);
1421
1422 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1423         copy_result = CopyFile (orig, dest, FALSE);
1424 #else
1425         copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1426 #endif
1427
1428         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1429          * overwritten when updated in their original locations. */
1430         if (copy_result)
1431                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1432
1433         g_free (orig);
1434         g_free (dest);
1435         
1436         return copy_result;
1437 }
1438
1439 static gint32 
1440 get_cstring_hash (const char *str)
1441 {
1442         int len, i;
1443         const char *p;
1444         gint32 h = 0;
1445         
1446         if (!str || !str [0])
1447                 return 0;
1448                 
1449         len = strlen (str);
1450         p = str;
1451         for (i = 0; i < len; i++) {
1452                 h = (h << 5) - h + *p;
1453                 p++;
1454         }
1455         
1456         return h;
1457 }
1458
1459 /*
1460  * Returned memory is malloc'd. Called must free it 
1461  */
1462 static char *
1463 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1464 {
1465         MonoAppDomainSetup *setup;
1466         char *cache_path, *appname;
1467         char *userdir;
1468         char *location;
1469
1470         mono_error_init (error);
1471         
1472         setup = domain->setup;
1473         if (setup->cache_path != NULL && setup->application_name != NULL) {
1474                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1475                 return_val_if_nok (error, NULL);
1476
1477 #ifndef TARGET_WIN32
1478                 {
1479                         gint i;
1480                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1481                                 if (cache_path [i] == '\\')
1482                                         cache_path [i] = '/';
1483                 }
1484 #endif
1485
1486                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1487                 if (!mono_error_ok (error)) {
1488                         g_free (cache_path);
1489                         return NULL;
1490                 }
1491
1492                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1493                 g_free (appname);
1494                 g_free (cache_path);
1495         } else {
1496                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1497                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1498                 g_free (userdir);
1499         }
1500         return location;
1501 }
1502
1503 static char *
1504 get_shadow_assembly_location (const char *filename, MonoError *error)
1505 {
1506         gint32 hash = 0, hash2 = 0;
1507         char name_hash [9];
1508         char path_hash [30];
1509         char *bname = g_path_get_basename (filename);
1510         char *dirname = g_path_get_dirname (filename);
1511         char *location, *tmploc;
1512         MonoDomain *domain = mono_domain_get ();
1513
1514         mono_error_init (error);
1515         
1516         hash = get_cstring_hash (bname);
1517         hash2 = get_cstring_hash (dirname);
1518         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1519         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1520         tmploc = get_shadow_assembly_location_base (domain, error);
1521         if (!mono_error_ok (error)) {
1522                 g_free (bname);
1523                 g_free (dirname);
1524                 return NULL;
1525         }
1526
1527         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1528         g_free (tmploc);
1529         g_free (bname);
1530         g_free (dirname);
1531         return location;
1532 }
1533
1534 static gboolean
1535 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1536 {
1537         struct stat sbuf_dest;
1538         gchar *stat_src;
1539         gchar *real_src = mono_portability_find_file (src, TRUE);
1540
1541         if (!real_src)
1542                 stat_src = (gchar*)src;
1543         else
1544                 stat_src = real_src;
1545
1546         if (stat (stat_src, sbuf_src) == -1) {
1547                 time_t tnow = time (NULL);
1548
1549                 if (real_src)
1550                         g_free (real_src);
1551
1552                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1553                 sbuf_src->st_mtime = tnow;
1554                 sbuf_src->st_atime = tnow;
1555                 return TRUE;
1556         }
1557
1558         if (real_src)
1559                 g_free (real_src);
1560
1561         if (stat (dest, &sbuf_dest) == -1)
1562                 return TRUE;
1563         
1564         if (sbuf_src->st_size == sbuf_dest.st_size &&
1565             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1566                 return FALSE;
1567
1568         return TRUE;
1569 }
1570
1571 static gboolean
1572 shadow_copy_create_ini (const char *shadow, const char *filename)
1573 {
1574         char *dir_name;
1575         char *ini_file;
1576         guint16 *u16_ini;
1577         gboolean result;
1578         guint32 n;
1579         HANDLE *handle;
1580         gchar *full_path;
1581
1582         dir_name = g_path_get_dirname (shadow);
1583         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1584         g_free (dir_name);
1585         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1586                 g_free (ini_file);
1587                 return TRUE;
1588         }
1589
1590         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1591         g_free (ini_file);
1592         if (!u16_ini) {
1593                 return FALSE;
1594         }
1595         handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1596                                 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1597         g_free (u16_ini);
1598         if (handle == INVALID_HANDLE_VALUE) {
1599                 return FALSE;
1600         }
1601
1602         full_path = mono_path_resolve_symlinks (filename);
1603         result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1604         g_free (full_path);
1605         CloseHandle (handle);
1606         return result;
1607 }
1608
1609 gboolean
1610 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1611 {
1612         MonoError error;
1613         MonoAppDomainSetup *setup;
1614         gchar *all_dirs;
1615         gchar **dir_ptr;
1616         gchar **directories;
1617         gchar *shadow_status_string;
1618         gchar *base_dir;
1619         gboolean shadow_enabled;
1620         gboolean found = FALSE;
1621
1622         if (domain == NULL)
1623                 return FALSE;
1624
1625         setup = domain->setup;
1626         if (setup == NULL || setup->shadow_copy_files == NULL)
1627                 return FALSE;
1628
1629         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1630         if (!mono_error_ok (&error)) {
1631                 mono_error_cleanup (&error);
1632                 return FALSE;
1633         }
1634         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1635         g_free (shadow_status_string);
1636
1637         if (!shadow_enabled)
1638                 return FALSE;
1639
1640         if (setup->shadow_copy_directories == NULL)
1641                 return TRUE;
1642
1643         /* Is dir_name a shadow_copy destination already? */
1644         base_dir = get_shadow_assembly_location_base (domain, &error);
1645         if (!mono_error_ok (&error)) {
1646                 mono_error_cleanup (&error);
1647                 return FALSE;
1648         }
1649
1650         if (strstr (dir_name, base_dir)) {
1651                 g_free (base_dir);
1652                 return TRUE;
1653         }
1654         g_free (base_dir);
1655
1656         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1657         if (!mono_error_ok (&error)) {
1658                 mono_error_cleanup (&error);
1659                 return FALSE;
1660         }
1661
1662         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1663         dir_ptr = directories;
1664         while (*dir_ptr) {
1665                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1666                         found = TRUE;
1667                         break;
1668                 }
1669                 dir_ptr++;
1670         }
1671         g_strfreev (directories);
1672         g_free (all_dirs);
1673         return found;
1674 }
1675
1676 /*
1677 This function raises exceptions so it can cause as sorts of nasty stuff if called
1678 while holding a lock.
1679 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1680 or NULL if source file not found.
1681 FIXME bubble up the error instead of raising it here
1682 */
1683 char *
1684 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1685 {
1686         MonoError error;
1687         gchar *sibling_source, *sibling_target;
1688         gint sibling_source_len, sibling_target_len;
1689         guint16 *orig, *dest;
1690         guint32 attrs;
1691         char *shadow;
1692         gboolean copy_result;
1693         struct stat src_sbuf;
1694         struct utimbuf utbuf;
1695         char *dir_name = g_path_get_dirname (filename);
1696         MonoDomain *domain = mono_domain_get ();
1697         char *shadow_dir;
1698
1699         mono_error_init (oerror);
1700
1701         set_domain_search_path (domain);
1702
1703         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1704                 g_free (dir_name);
1705                 return (char *) filename;
1706         }
1707
1708         /* Is dir_name a shadow_copy destination already? */
1709         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1710         if (!mono_error_ok (&error)) {
1711                 mono_error_cleanup (&error);
1712                 g_free (dir_name);
1713                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1714                 return NULL;
1715         }
1716
1717         if (strstr (dir_name, shadow_dir)) {
1718                 g_free (shadow_dir);
1719                 g_free (dir_name);
1720                 return (char *) filename;
1721         }
1722         g_free (shadow_dir);
1723         g_free (dir_name);
1724
1725         shadow = get_shadow_assembly_location (filename, &error);
1726         if (!mono_error_ok (&error)) {
1727                 mono_error_cleanup (&error);
1728                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1729                 return NULL;
1730         }
1731
1732         if (g_ensure_directory_exists (shadow) == FALSE) {
1733                 g_free (shadow);
1734                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1735                 return NULL;
1736         }       
1737
1738         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1739                 return (char*) shadow;
1740
1741         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1742         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1743         DeleteFile (dest);
1744
1745         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1746          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1747          * and not have it runtime error" */
1748         attrs = GetFileAttributes (orig);
1749         if (attrs == INVALID_FILE_ATTRIBUTES) {
1750                 g_free (shadow);
1751                 return (char *)filename;
1752         }
1753
1754 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1755         copy_result = CopyFile (orig, dest, FALSE);
1756 #else
1757         copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1758 #endif
1759
1760         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1761          * overwritten when updated in their original locations. */
1762         if (copy_result)
1763                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1764
1765         g_free (dest);
1766         g_free (orig);
1767
1768         if (copy_result == FALSE) {
1769                 g_free (shadow);
1770
1771                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1772                 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1773                         return NULL; /* file not found, shadow copy failed */
1774
1775                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1776                 return NULL;
1777         }
1778
1779         /* attempt to copy .mdb, .config if they exist */
1780         sibling_source = g_strconcat (filename, ".config", NULL);
1781         sibling_source_len = strlen (sibling_source);
1782         sibling_target = g_strconcat (shadow, ".config", NULL);
1783         sibling_target_len = strlen (sibling_target);
1784         
1785         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1786         if (copy_result)
1787                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1788         
1789         g_free (sibling_source);
1790         g_free (sibling_target);
1791         
1792         if (!copy_result)  {
1793                 g_free (shadow);
1794                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1795                 return NULL;
1796         }
1797
1798         /* Create a .ini file containing the original assembly location */
1799         if (!shadow_copy_create_ini (shadow, filename)) {
1800                 g_free (shadow);
1801                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1802                 return NULL;
1803         }
1804
1805         utbuf.actime = src_sbuf.st_atime;
1806         utbuf.modtime = src_sbuf.st_mtime;
1807         utime (shadow, &utbuf);
1808         
1809         return shadow;
1810 }
1811 #endif /* DISABLE_SHADOW_COPY */
1812
1813 MonoDomain *
1814 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1815 {
1816         if (appdomain == NULL)
1817                 return NULL;
1818
1819         if (mono_object_is_transparent_proxy (&appdomain->mbr.obj)) {
1820                 MonoTransparentProxy *tp = (MonoTransparentProxy*)appdomain;
1821                 return mono_domain_get_by_id (tp->rp->target_domain_id);
1822         }
1823         
1824         return appdomain->data;
1825 }
1826
1827 static gboolean
1828 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1829                                         const gchar *path3, const gchar *path4,
1830                                         gboolean refonly, gboolean is_private)
1831 {
1832         gchar *fullpath;
1833         gboolean found = FALSE;
1834         
1835         *assembly = NULL;
1836         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1837
1838         if (IS_PORTABILITY_SET) {
1839                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1840                 if (new_fullpath) {
1841                         g_free (fullpath);
1842                         fullpath = new_fullpath;
1843                         found = TRUE;
1844                 }
1845         } else
1846                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1847         
1848         if (found)
1849                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1850
1851         g_free (fullpath);
1852         return (*assembly != NULL);
1853 }
1854
1855 static MonoAssembly *
1856 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1857 {
1858         MonoAssembly *result = NULL;
1859         gchar **path;
1860         gchar *filename;
1861         const gchar *local_culture;
1862         gint len;
1863         gboolean is_private = FALSE;
1864
1865         if (!culture || *culture == '\0') {
1866                 local_culture = "";
1867         } else {
1868                 local_culture = culture;
1869         }
1870
1871         filename =  g_strconcat (name, ".dll", NULL);
1872         len = strlen (filename);
1873
1874         for (path = search_path; *path; path++) {
1875                 if (**path == '\0') {
1876                         is_private = TRUE;
1877                         continue; /* Ignore empty ApplicationBase */
1878                 }
1879
1880                 /* See test cases in bug #58992 and bug #57710 */
1881                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1882                 strcpy (filename + len - 4, ".dll");
1883                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1884                         break;
1885
1886                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1887                 strcpy (filename + len - 4, ".exe");
1888                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1889                         break;
1890
1891                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1892                 strcpy (filename + len - 4, ".dll");
1893                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1894                         break;
1895
1896                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1897                 strcpy (filename + len - 4, ".exe");
1898                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1899                         break;
1900         }
1901
1902         g_free (filename);
1903         return result;
1904 }
1905
1906 /*
1907  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1908  * and then from assemblies_path if any.
1909  * LOCKING: This is called from the assembly loading code, which means the caller
1910  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1911  */
1912 static MonoAssembly *
1913 mono_domain_assembly_preload (MonoAssemblyName *aname,
1914                               gchar **assemblies_path,
1915                               gpointer user_data)
1916 {
1917         MonoDomain *domain = mono_domain_get ();
1918         MonoAssembly *result = NULL;
1919         gboolean refonly = GPOINTER_TO_UINT (user_data);
1920
1921         set_domain_search_path (domain);
1922
1923         if (domain->search_path && domain->search_path [0] != NULL) {
1924                 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1925         }
1926
1927         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1928                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1929         }
1930
1931         return result;
1932 }
1933
1934 /*
1935  * Check whenever a given assembly was already loaded in the current appdomain.
1936  */
1937 static MonoAssembly *
1938 mono_domain_assembly_search (MonoAssemblyName *aname,
1939                                                          gpointer user_data)
1940 {
1941         MonoDomain *domain = mono_domain_get ();
1942         GSList *tmp;
1943         MonoAssembly *ass;
1944         gboolean refonly = GPOINTER_TO_UINT (user_data);
1945
1946         mono_domain_assemblies_lock (domain);
1947         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1948                 ass = (MonoAssembly *)tmp->data;
1949                 /* Dynamic assemblies can't match here in MS.NET */
1950                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1951                         continue;
1952
1953                 mono_domain_assemblies_unlock (domain);
1954                 return ass;
1955         }
1956         mono_domain_assemblies_unlock (domain);
1957
1958         return NULL;
1959 }
1960
1961 MonoReflectionAssemblyHandle
1962 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
1963 {
1964         mono_error_init (error);
1965         MonoDomain *domain = mono_domain_get ();
1966         char *name, *filename;
1967         MonoImageOpenStatus status = MONO_IMAGE_OK;
1968         MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
1969
1970         name = NULL;
1971         result = NULL;
1972
1973         if (fname == NULL) {
1974                 mono_error_set_argument_null (error, "assemblyFile", "");
1975                 goto leave;
1976         }
1977                 
1978         name = filename = mono_string_handle_to_utf8 (fname, error);
1979         if (!is_ok (error))
1980                 goto leave;
1981         
1982         MonoAssembly *ass = mono_assembly_open_full (filename, &status, refOnly);
1983         
1984         if (!ass) {
1985                 if (status == MONO_IMAGE_IMAGE_INVALID)
1986                         mono_error_set_bad_image_name (error, g_strdup (name), "");
1987                 else
1988                         mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
1989                 goto leave;
1990         }
1991
1992         result = mono_assembly_get_object_handle (domain, ass, error);
1993
1994 leave:
1995         g_free (name);
1996         return result;
1997 }
1998
1999 MonoReflectionAssemblyHandle
2000 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad, 
2001                                             MonoArrayHandle raw_assembly,
2002                                             MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2003                                             MonoBoolean refonly,
2004                                             MonoError *error)
2005 {
2006         mono_error_init (error);
2007         MonoAssembly *ass;
2008         MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2009         MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2010         MonoImageOpenStatus status;
2011         guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2012
2013         /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2014         char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2015         if (!assembly_data) {
2016                 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2017                 return refass;
2018         }
2019         uint32_t gchandle;
2020         mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2021         memcpy (assembly_data, raw_data, raw_assembly_len);
2022         mono_gchandle_free (gchandle); /* unpin */
2023         MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2024         
2025         MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2026
2027         if (!image) {
2028                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2029                 return refass;
2030         }
2031
2032         if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2033                 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2034                 uint32_t symbol_gchandle;
2035                 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2036                 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2037                 mono_gchandle_free (symbol_gchandle);
2038         }
2039
2040         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2041
2042
2043         if (!ass) {
2044                 mono_image_close (image);
2045                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2046                 return refass; 
2047         }
2048
2049         refass = mono_assembly_get_object_handle (domain, ass, error);
2050         if (!MONO_HANDLE_IS_NULL(refass))
2051                 MONO_HANDLE_SET (refass, evidence, evidence);
2052         return refass;
2053 }
2054
2055 MonoReflectionAssemblyHandle
2056 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2057 {
2058         mono_error_init (error);
2059         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2060         MonoImageOpenStatus status = MONO_IMAGE_OK;
2061         MonoAssembly *ass;
2062         MonoAssemblyName aname;
2063         gchar *name = NULL;
2064         gboolean parsed;
2065
2066         g_assert (assRef);
2067
2068         name = mono_string_handle_to_utf8 (assRef, error);
2069         if (!is_ok (error))
2070                 goto fail;
2071         parsed = mono_assembly_name_parse (name, &aname);
2072         g_free (name);
2073
2074         if (!parsed) {
2075                 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2076                 /* This is a parse error... */
2077                 if (!refOnly) {
2078                         MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2079                         if (!is_ok (error))
2080                                 goto fail;
2081                         if (assm) {
2082                                 refass = mono_assembly_get_object_handle (domain, assm, error);
2083                                 if (!is_ok (error))
2084                                         goto fail;
2085                         }
2086                 }
2087                 return refass;
2088         }
2089
2090         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2091         mono_assembly_name_free (&aname);
2092
2093         if (!ass) {
2094                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2095                 if (!refOnly) {
2096                         ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2097                         if (!is_ok (error))
2098                                 goto fail;
2099                 }
2100                 if (!ass)
2101                         goto fail;
2102         }
2103
2104         g_assert (ass);
2105         MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2106         if (!is_ok (error))
2107                 goto fail;
2108
2109         MONO_HANDLE_SET (refass, evidence, evidence);
2110
2111         return refass;
2112 fail:
2113         return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2114 }
2115
2116 void
2117 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2118 {
2119         MonoException *exc = NULL;
2120         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2121
2122         if (NULL == domain) {
2123                 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2124                 mono_set_pending_exception (exc);
2125                 return;
2126         }
2127         
2128         if (domain == mono_get_root_domain ()) {
2129                 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2130                 return;
2131         }
2132
2133         /* 
2134          * Unloading seems to cause problems when running NUnit/NAnt, hence
2135          * this workaround.
2136          */
2137         if (g_getenv ("MONO_NO_UNLOAD"))
2138                 return;
2139 #ifdef __native_client__
2140         return;
2141 #endif
2142
2143         mono_domain_try_unload (domain, (MonoObject**)&exc);
2144         if (exc)
2145                 mono_set_pending_exception (exc);
2146 }
2147
2148 gboolean
2149 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2150 {
2151         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2152
2153         if (!domain)
2154                 return TRUE;
2155
2156         return mono_domain_is_unloading (domain);
2157 }
2158
2159 void
2160 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2161 {
2162         mono_unhandled_exception ((MonoObject*) exc);
2163 }
2164
2165 gint32
2166 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2167                                             MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2168                                             MonoError *error)
2169 {
2170         mono_error_init (error);
2171         MonoImage *image;
2172         MonoMethod *method;
2173
2174         g_assert (!MONO_HANDLE_IS_NULL (refass));
2175         MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2176         image = assembly->image;
2177         g_assert (image);
2178
2179         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2180
2181         if (!method)
2182                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2183
2184         if (MONO_HANDLE_IS_NULL (args)) {
2185                 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2186                 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2187                 mono_error_assert_ok (error);
2188         }
2189
2190         int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2191         return res;
2192 }
2193
2194 gint32 
2195 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2196 {
2197         return ad->data->domain_id;
2198 }
2199
2200 MonoAppDomain * 
2201 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2202 {
2203         MonoDomain *old_domain = mono_domain_get();
2204
2205         if (!mono_domain_set (ad->data, FALSE)) {
2206                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2207                 return NULL;
2208         }
2209
2210         return old_domain->domain;
2211 }
2212
2213 MonoAppDomain * 
2214 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2215 {
2216         MonoDomain *current_domain = mono_domain_get ();
2217         MonoDomain *domain = mono_domain_get_by_id (domainid);
2218
2219         if (!domain || !mono_domain_set (domain, FALSE)) {
2220                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2221                 return NULL;
2222         }
2223
2224         return current_domain->domain;
2225 }
2226
2227 void
2228 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2229 {
2230         mono_thread_push_appdomain_ref (ad->data);
2231 }
2232
2233 void
2234 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2235 {
2236         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2237
2238         if (!domain) {
2239                 /* 
2240                  * Raise an exception to prevent the managed code from executing a pop
2241                  * later.
2242                  */
2243                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2244                 return;
2245         }
2246
2247         mono_thread_push_appdomain_ref (domain);
2248 }
2249
2250 void
2251 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2252 {
2253         mono_thread_pop_appdomain_ref ();
2254 }
2255
2256 MonoAppContext * 
2257 ves_icall_System_AppDomain_InternalGetContext ()
2258 {
2259         return mono_context_get ();
2260 }
2261
2262 MonoAppContext * 
2263 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2264 {
2265         return mono_domain_get ()->default_context;
2266 }
2267
2268 MonoAppContext * 
2269 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2270 {
2271         MonoAppContext *old_context = mono_context_get ();
2272
2273         mono_context_set (mc);
2274
2275         return old_context;
2276 }
2277
2278 MonoString *
2279 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2280 {
2281         MonoDomain* mono_root_domain = mono_get_root_domain ();
2282         mono_domain_lock (mono_root_domain);
2283         if (process_guid_set) {
2284                 mono_domain_unlock (mono_root_domain);
2285                 MonoError error;
2286                 MonoString *res = NULL;
2287                 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2288                 mono_error_set_pending_exception (&error);
2289                 return res;
2290         }
2291         memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2292         process_guid_set = TRUE;
2293         mono_domain_unlock (mono_root_domain);
2294         return newguid;
2295 }
2296
2297 gboolean
2298 mono_domain_is_unloading (MonoDomain *domain)
2299 {
2300         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2301                 return TRUE;
2302         else
2303                 return FALSE;
2304 }
2305
2306 static void
2307 clear_cached_vtable (MonoVTable *vtable)
2308 {
2309         MonoClass *klass = vtable->klass;
2310         MonoDomain *domain = vtable->domain;
2311         MonoClassRuntimeInfo *runtime_info;
2312         void *data;
2313
2314         runtime_info = klass->runtime_info;
2315         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2316                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2317         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2318                 mono_gc_free_fixed (data);
2319 }
2320
2321 static G_GNUC_UNUSED void
2322 zero_static_data (MonoVTable *vtable)
2323 {
2324         MonoClass *klass = vtable->klass;
2325         void *data;
2326
2327         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2328                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2329 }
2330
2331 typedef struct unload_data {
2332         gboolean done;
2333         MonoDomain *domain;
2334         char *failure_reason;
2335         gint32 refcount;
2336 } unload_data;
2337
2338 static void
2339 unload_data_unref (unload_data *data)
2340 {
2341         gint32 count;
2342         do {
2343                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2344                 g_assert (count >= 1 && count <= 2);
2345                 if (count == 1) {
2346                         g_free (data);
2347                         return;
2348                 }
2349         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2350 }
2351
2352 static void
2353 deregister_reflection_info_roots_from_list (MonoImage *image)
2354 {
2355         GSList *list = image->reflection_info_unregister_classes;
2356
2357         while (list) {
2358                 MonoClass *klass = (MonoClass *)list->data;
2359
2360                 mono_class_free_ref_info (klass);
2361
2362                 list = list->next;
2363         }
2364
2365         image->reflection_info_unregister_classes = NULL;
2366 }
2367
2368 static void
2369 deregister_reflection_info_roots (MonoDomain *domain)
2370 {
2371         GSList *list;
2372
2373         mono_domain_assemblies_lock (domain);
2374         for (list = domain->domain_assemblies; list; list = list->next) {
2375                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2376                 MonoImage *image = assembly->image;
2377                 int i;
2378
2379                 /*
2380                  * No need to take the image lock here since dynamic images are appdomain bound and
2381                  * at this point the mutator is gone.  Taking the image lock here would mean
2382                  * promoting it from a simple lock to a complex lock, which we better avoid if
2383                  * possible.
2384                  */
2385                 if (image_is_dynamic (image))
2386                         deregister_reflection_info_roots_from_list (image);
2387
2388                 for (i = 0; i < image->module_count; ++i) {
2389                         MonoImage *module = image->modules [i];
2390                         if (module && image_is_dynamic (module))
2391                                 deregister_reflection_info_roots_from_list (module);
2392                 }
2393         }
2394         mono_domain_assemblies_unlock (domain);
2395 }
2396
2397 static gsize WINAPI
2398 unload_thread_main (void *arg)
2399 {
2400         MonoError error;
2401         unload_data *data = (unload_data*)arg;
2402         MonoDomain *domain = data->domain;
2403         MonoThread *thread;
2404         int i;
2405
2406         /* Have to attach to the runtime so shutdown can wait for this thread */
2407         /* Force it to be attached to avoid racing during shutdown. */
2408         thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2409
2410         mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2411         if (!is_ok (&error)) {
2412                 data->failure_reason = g_strdup (mono_error_get_message (&error));
2413                 mono_error_cleanup (&error);
2414                 goto failure;
2415         }
2416
2417         /* 
2418          * FIXME: Abort our parent thread last, so we can return a failure 
2419          * indication if aborting times out.
2420          */
2421         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2422                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2423                 goto failure;
2424         }
2425
2426         if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2427                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2428                 goto failure;
2429         }
2430
2431         /* Finalize all finalizable objects in the doomed appdomain */
2432         if (!mono_domain_finalize (domain, -1)) {
2433                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2434                 goto failure;
2435         }
2436
2437         /* Clear references to our vtables in class->runtime_info.
2438          * We also hold the loader lock because we're going to change
2439          * class->runtime_info.
2440          */
2441
2442         mono_loader_lock (); //FIXME why do we need the loader lock here?
2443         mono_domain_lock (domain);
2444 #ifdef HAVE_SGEN_GC
2445         /*
2446          * We need to make sure that we don't have any remsets
2447          * pointing into static data of the to-be-freed domain because
2448          * at the next collections they would be invalid.  So what we
2449          * do is we first zero all static data and then do a minor
2450          * collection.  Because all references in the static data will
2451          * now be null we won't do any unnecessary copies and after
2452          * the collection there won't be any more remsets.
2453          */
2454         for (i = 0; i < domain->class_vtable_array->len; ++i)
2455                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2456         mono_gc_collect (0);
2457 #endif
2458         for (i = 0; i < domain->class_vtable_array->len; ++i)
2459                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2460         deregister_reflection_info_roots (domain);
2461
2462         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2463
2464         mono_domain_unlock (domain);
2465         mono_loader_unlock ();
2466
2467         mono_threads_clear_cached_culture (domain);
2468
2469         domain->state = MONO_APPDOMAIN_UNLOADED;
2470
2471         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2472
2473         /* remove from the handle table the items related to this domain */
2474         mono_gchandle_free_domain (domain);
2475
2476         mono_domain_free (domain, FALSE);
2477
2478         mono_gc_collect (mono_gc_max_generation ());
2479
2480         mono_atomic_store_release (&data->done, TRUE);
2481         unload_data_unref (data);
2482         mono_thread_detach (thread);
2483         return 0;
2484
2485 failure:
2486         mono_atomic_store_release (&data->done, TRUE);
2487         unload_data_unref (data);
2488         mono_thread_detach (thread);
2489         return 1;
2490 }
2491
2492 /*
2493  * mono_domain_unload:
2494  * @domain: The domain to unload
2495  *
2496  *  Unloads an appdomain. Follows the process outlined in the comment
2497  *  for mono_domain_try_unload.
2498  */
2499 void
2500 mono_domain_unload (MonoDomain *domain)
2501 {
2502         MonoObject *exc = NULL;
2503         mono_domain_try_unload (domain, &exc);
2504 }
2505
2506 static MonoThreadInfoWaitRet
2507 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2508 {
2509         MonoThreadInfoWaitRet result;
2510
2511         MONO_ENTER_GC_SAFE;
2512         result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2513         MONO_EXIT_GC_SAFE;
2514
2515         return result;
2516 }
2517
2518 /*
2519  * mono_domain_unload:
2520  * @domain: The domain to unload
2521  * @exc: Exception information
2522  *
2523  *  Unloads an appdomain. Follows the process outlined in:
2524  *  http://blogs.gotdotnet.com/cbrumme
2525  *
2526  *  If doing things the 'right' way is too hard or complex, we do it the 
2527  *  'simple' way, which means do everything needed to avoid crashes and
2528  *  memory leaks, but not much else.
2529  *
2530  *  It is required to pass a valid reference to the exc argument, upon return
2531  *  from this function *exc will be set to the exception thrown, if any.
2532  *
2533  *  If this method is not called from an icall (embedded scenario for instance),
2534  *  it must not be called with any managed frames on the stack, since the unload
2535  *  process could end up trying to abort the current thread.
2536  */
2537 void
2538 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2539 {
2540         MonoError error;
2541         MonoThreadHandle *thread_handle;
2542         MonoAppDomainState prev_state;
2543         MonoMethod *method;
2544         unload_data *thread_data;
2545         MonoNativeThreadId tid;
2546         MonoDomain *caller_domain = mono_domain_get ();
2547
2548         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2549
2550         /* Atomically change our state to UNLOADING */
2551         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2552                 MONO_APPDOMAIN_UNLOADING_START,
2553                 MONO_APPDOMAIN_CREATED);
2554         if (prev_state != MONO_APPDOMAIN_CREATED) {
2555                 switch (prev_state) {
2556                 case MONO_APPDOMAIN_UNLOADING_START:
2557                 case MONO_APPDOMAIN_UNLOADING:
2558                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2559                         return;
2560                 case MONO_APPDOMAIN_UNLOADED:
2561                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2562                         return;
2563                 default:
2564                         g_warning ("Invalid appdomain state %d", prev_state);
2565                         g_assert_not_reached ();
2566                 }
2567         }
2568
2569         mono_domain_set (domain, FALSE);
2570         /* Notify OnDomainUnload listeners */
2571         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2572         g_assert (method);
2573
2574         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2575
2576         if (!mono_error_ok (&error)) {
2577                 if (*exc)
2578                         mono_error_cleanup (&error);
2579                 else
2580                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2581         }
2582
2583         if (*exc) {
2584                 /* Roll back the state change */
2585                 domain->state = MONO_APPDOMAIN_CREATED;
2586                 mono_domain_set (caller_domain, FALSE);
2587                 return;
2588         }
2589         mono_domain_set (caller_domain, FALSE);
2590
2591         thread_data = g_new0 (unload_data, 1);
2592         thread_data->domain = domain;
2593         thread_data->failure_reason = NULL;
2594         thread_data->done = FALSE;
2595         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2596
2597         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2598         domain->state = MONO_APPDOMAIN_UNLOADING;
2599         /* 
2600          * First we create a separate thread for unloading, since
2601          * we might have to abort some threads, including the current one.
2602          */
2603         thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, NULL, &tid);
2604         if (thread_handle == NULL)
2605                 return;
2606
2607         /* Wait for the thread */       
2608         while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2609                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2610                         /* The unload thread tries to abort us */
2611                         /* The icall wrapper will execute the abort */
2612                         mono_threads_close_thread_handle (thread_handle);
2613                         unload_data_unref (thread_data);
2614                         return;
2615                 }
2616         }
2617
2618         mono_threads_close_thread_handle (thread_handle);
2619
2620         if (thread_data->failure_reason) {
2621                 /* Roll back the state change */
2622                 domain->state = MONO_APPDOMAIN_CREATED;
2623
2624                 g_warning ("%s", thread_data->failure_reason);
2625
2626                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2627
2628                 g_free (thread_data->failure_reason);
2629                 thread_data->failure_reason = NULL;
2630         }
2631
2632         unload_data_unref (thread_data);
2633 }