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