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, ©_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, ©_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