2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "object-internals.h"
21 #include <mono/metadata/loader.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/metadata-internals.h>
24 #include <mono/metadata/profiler-private.h>
25 #include <mono/metadata/class-internals.h>
26 #include <mono/metadata/domain-internals.h>
27 #include <mono/metadata/reflection-internals.h>
28 #include <mono/metadata/mono-endian.h>
29 #include <mono/metadata/mono-debug.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/utils/mono-uri.h>
32 #include <mono/metadata/mono-config.h>
33 #include <mono/metadata/mono-config-dirs.h>
34 #include <mono/utils/mono-digest.h>
35 #include <mono/utils/mono-logger-internals.h>
36 #include <mono/utils/mono-path.h>
37 #include <mono/metadata/reflection.h>
38 #include <mono/metadata/coree.h>
39 #include <mono/metadata/cil-coff.h>
40 #include <mono/utils/mono-io-portability.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-os-mutex.h>
45 #include <sys/types.h>
50 #ifdef PLATFORM_MACOSX
51 #include <mach-o/dyld.h>
54 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
56 const char* assembly_name;
57 guint8 version_set_index;
58 const char* new_assembly_name;
59 gboolean only_lower_versions;
62 /* the default search path is empty, the first slot is replaced with the computed value */
70 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
71 static char **assemblies_path = NULL;
73 /* Contains the list of directories that point to auxiliary GACs */
74 static char **extra_gac_paths = NULL;
76 #ifndef DISABLE_ASSEMBLY_REMAPPING
77 /* The list of system assemblies what will be remapped to the running
78 * runtime version. WARNING: this list must be sorted.
79 * The integer number is an index in the MonoRuntimeInfo structure, whose
80 * values can be found in domain.c - supported_runtimes. Look there
81 * to understand what remapping will be made.
83 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
86 static const AssemblyVersionMap framework_assemblies [] = {
88 {"Commons.Xml.Relaxng", 0},
95 {"Microsoft.Build.Engine", 2, NULL, TRUE},
96 {"Microsoft.Build.Framework", 2, NULL, TRUE},
97 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
98 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
99 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
100 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
101 {"Microsoft.VisualBasic", 1},
102 {"Microsoft.VisualC", 1},
104 {"Mono.CompilerServices.SymbolWriter", 0},
106 {"Mono.Data.SybaseClient", 0},
107 {"Mono.Data.Tds", 0},
108 {"Mono.Data.TdsClient", 0},
109 {"Mono.GetOptions", 0},
112 {"Mono.Security", 0},
113 {"Mono.Security.Win32", 0},
115 {"Novell.Directory.Ldap", 0},
118 {"System.ComponentModel.Composition", 2},
119 {"System.ComponentModel.DataAnnotations", 2},
120 {"System.Configuration", 0},
121 {"System.Configuration.Install", 0},
124 {"System.Data.Linq", 2},
125 {"System.Data.OracleClient", 0},
126 {"System.Data.Services", 2},
127 {"System.Data.Services.Client", 2},
128 {"System.Data.SqlXml", 0},
129 {"System.Design", 0},
130 {"System.DirectoryServices", 0},
131 {"System.Drawing", 0},
132 {"System.Drawing.Design", 0},
133 {"System.EnterpriseServices", 0},
134 {"System.IdentityModel", 3},
135 {"System.IdentityModel.Selectors", 3},
136 {"System.Management", 0},
137 {"System.Messaging", 0},
139 {"System.Runtime.Remoting", 0},
140 {"System.Runtime.Serialization", 3},
141 {"System.Runtime.Serialization.Formatters.Soap", 0},
142 {"System.Security", 0},
143 {"System.ServiceModel", 3},
144 {"System.ServiceModel.Web", 2},
145 {"System.ServiceProcess", 0},
146 {"System.Transactions", 0},
148 {"System.Web.Abstractions", 2},
149 {"System.Web.DynamicData", 2},
150 {"System.Web.Extensions", 2},
151 {"System.Web.Mobile", 0},
152 {"System.Web.Routing", 2},
153 {"System.Web.Services", 0},
154 {"System.Windows.Forms", 0},
156 {"System.Xml.Linq", 2},
163 * keeps track of loaded assemblies
165 static GList *loaded_assemblies = NULL;
166 static MonoAssembly *corlib;
168 #if defined(__native_client__)
170 /* On Native Client, allow mscorlib to be loaded from memory */
171 /* instead of loaded off disk. If these are not set, default */
172 /* mscorlib loading will take place */
174 /* NOTE: If mscorlib data is passed to mono in this way then */
175 /* it needs to remain allocated during the use of mono. */
177 static void *corlibData = NULL;
178 static size_t corlibSize = 0;
181 mono_set_corlib_data (void *data, size_t size)
189 static char* unquote (const char *str);
191 /* This protects loaded_assemblies and image->references */
192 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
193 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
194 static mono_mutex_t assemblies_mutex;
196 /* If defined, points to the bundled assembly information */
197 const MonoBundledAssembly **bundles;
199 static mono_mutex_t assembly_binding_mutex;
201 /* Loaded assembly binding info */
202 static GSList *loaded_assembly_bindings = NULL;
204 /* Class lazy loading functions */
205 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
206 static GENERATE_TRY_GET_CLASS_WITH_CACHE (reference_assembly, System.Runtime.CompilerServices, ReferenceAssemblyAttribute)
209 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
211 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
213 mono_assembly_is_in_gac (const gchar *filanem);
216 encode_public_tok (const guchar *token, gint32 len)
218 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
222 res = (gchar *)g_malloc (len * 2 + 1);
223 for (i = 0; i < len; i++) {
224 res [i * 2] = allowed [token [i] >> 4];
225 res [i * 2 + 1] = allowed [token [i] & 0xF];
232 * mono_public_tokens_are_equal:
233 * @pubt1: first public key token
234 * @pubt2: second public key token
236 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
240 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
242 return memcmp (pubt1, pubt2, 16) == 0;
246 * mono_set_assemblies_path:
247 * @path: list of paths that contain directories where Mono will look for assemblies
249 * Use this method to override the standard assembly lookup system and
250 * override any assemblies coming from the GAC. This is the method
251 * that supports the MONO_PATH variable.
253 * Notice that MONO_PATH and this method are really a very bad idea as
254 * it prevents the GAC from working and it prevents the standard
255 * resolution mechanisms from working. Nonetheless, for some debugging
256 * situations and bootstrapping setups, this is useful to have.
259 mono_set_assemblies_path (const char* path)
261 char **splitted, **dest;
263 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
265 g_strfreev (assemblies_path);
266 assemblies_path = dest = splitted;
268 char *tmp = *splitted;
270 *dest++ = mono_path_canonicalize (tmp);
276 if (g_getenv ("MONO_DEBUG") == NULL)
279 splitted = assemblies_path;
281 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
282 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
288 /* Native Client can't get this info from an environment variable so */
289 /* it's passed in to the runtime, or set manually by embedding code. */
290 #ifdef __native_client__
291 char* nacl_mono_path = NULL;
295 check_path_env (void)
298 path = g_getenv ("MONO_PATH");
299 #ifdef __native_client__
301 path = nacl_mono_path;
303 if (!path || assemblies_path != NULL)
306 mono_set_assemblies_path(path);
310 check_extra_gac_path_env (void) {
312 char **splitted, **dest;
314 path = g_getenv ("MONO_GAC_PREFIX");
318 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
320 g_strfreev (extra_gac_paths);
321 extra_gac_paths = dest = splitted;
329 if (g_getenv ("MONO_DEBUG") == NULL)
333 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
334 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
341 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
343 if (!info || !info->name)
346 if (strcmp (info->name, aname->name))
349 if (info->major != aname->major || info->minor != aname->minor)
352 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
355 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
358 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
365 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
371 g_free (info->culture);
375 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
378 guint32 cols [MONO_MANIFEST_SIZE];
379 const gchar *filename;
380 gchar *subpath, *fullpath;
382 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
383 /* MS Impl. accepts policy assemblies with more than
384 * one manifest resource, and only takes the first one */
386 binding_info->is_valid = FALSE;
390 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
391 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
392 binding_info->is_valid = FALSE;
396 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
397 g_assert (filename != NULL);
399 subpath = g_path_get_dirname (image->name);
400 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
401 mono_config_parse_publisher_policy (fullpath, binding_info);
405 /* Define the optional elements/attributes before checking */
406 if (!binding_info->culture)
407 binding_info->culture = g_strdup ("");
409 /* Check that the most important elements/attributes exist */
410 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
411 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
412 mono_assembly_binding_info_free (binding_info);
413 binding_info->is_valid = FALSE;
417 binding_info->is_valid = TRUE;
421 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
423 if (v->major > aname->major)
425 else if (v->major < aname->major)
428 if (v->minor > aname->minor)
430 else if (v->minor < aname->minor)
433 if (v->build > aname->build)
435 else if (v->build < aname->build)
438 if (v->revision > aname->revision)
440 else if (v->revision < aname->revision)
447 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
452 /* If has_old_version_top doesn't exist, we don't have an interval */
453 if (!info->has_old_version_top) {
454 if (compare_versions (&info->old_version_bottom, name) == 0)
460 /* Check that the version defined by name is valid for the interval */
461 if (compare_versions (&info->old_version_top, name) < 0)
464 /* We should be greater or equal than the small version */
465 if (compare_versions (&info->old_version_bottom, name) > 0)
472 * mono_assembly_names_equal:
474 * @r: second assembly.
476 * Compares two MonoAssemblyNames and returns whether they are equal.
478 * This compares the names, the cultures, the release version and their
481 * Returns: TRUE if both assembly names are equal.
484 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
486 if (!l->name || !r->name)
489 if (strcmp (l->name, r->name))
492 if (l->culture && r->culture && strcmp (l->culture, r->culture))
495 if (l->major != r->major || l->minor != r->minor ||
496 l->build != r->build || l->revision != r->revision)
497 if (! ((l->major == 0 && l->minor == 0 && l->build == 0 && l->revision == 0) || (r->major == 0 && r->minor == 0 && r->build == 0 && r->revision == 0)))
500 if (!l->public_key_token [0] || !r->public_key_token [0])
503 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
509 static MonoAssembly *
510 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
514 MonoAssembly *result;
516 for (i = 0; search_path [i]; ++i) {
517 fullpath = g_build_filename (search_path [i], basename, NULL);
518 result = mono_assembly_open_full (fullpath, status, refonly);
527 * mono_assembly_setrootdir:
528 * @root_dir: The pathname of the root directory where we will locate assemblies
530 * This routine sets the internal default root directory for looking up
533 * This is used by Windows installations to compute dynamically the
534 * place where the Mono assemblies are located.
538 mono_assembly_setrootdir (const char *root_dir)
541 * Override the MONO_ASSEMBLIES directory configured at compile time.
543 /* Leak if called more than once */
544 default_path [0] = g_strdup (root_dir);
548 * mono_assembly_getrootdir:
550 * Obtains the root directory used for looking up assemblies.
552 * Returns: a string with the directory, this string should not be freed.
554 G_CONST_RETURN gchar *
555 mono_assembly_getrootdir (void)
557 return default_path [0];
562 * @assembly_dir: the base directory for assemblies
563 * @config_dir: the base directory for configuration files
565 * This routine is used internally and by developers embedding
566 * the runtime into their own applications.
568 * There are a number of cases to consider: Mono as a system-installed
569 * package that is available on the location preconfigured or Mono in
570 * a relocated location.
572 * If you are using a system-installed Mono, you can pass NULL
573 * to both parameters. If you are not, you should compute both
574 * directory values and call this routine.
576 * The values for a given PREFIX are:
578 * assembly_dir: PREFIX/lib
579 * config_dir: PREFIX/etc
581 * Notice that embedders that use Mono in a relocated way must
582 * compute the location at runtime, as they will be in control
583 * of where Mono is installed.
586 mono_set_dirs (const char *assembly_dir, const char *config_dir)
588 if (assembly_dir == NULL)
589 assembly_dir = mono_config_get_assemblies_dir ();
590 if (config_dir == NULL)
591 config_dir = mono_config_get_cfg_dir ();
592 mono_assembly_setrootdir (assembly_dir);
593 mono_set_config_dir (config_dir);
599 compute_base (char *path)
601 char *p = strrchr (path, '/');
605 /* Not a well known Mono executable, we are embedded, cant guess the base */
606 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
610 p = strrchr (path, '/');
614 if (strcmp (p, "/bin") != 0)
623 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
626 static G_GNUC_UNUSED void
630 char *config, *lib, *mono;
635 * Only /usr prefix is treated specially
637 bindir = mono_config_get_bin_dir ();
639 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
644 config = g_build_filename (base, "etc", NULL);
645 lib = g_build_filename (base, "lib", NULL);
646 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
647 if (stat (mono, &buf) == -1)
650 mono_set_dirs (lib, config);
658 #endif /* HOST_WIN32 */
663 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
664 * this auto-detects the prefix where Mono was installed.
667 mono_set_rootdir (void)
669 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
670 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
673 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
677 * _NSGetExecutablePath may return -1 to indicate buf is not large
678 * enough, but we ignore that case to avoid having to do extra dynamic
679 * allocation for the path and hope that 4096 is enough - this is
680 * ok in the Linux/Solaris case below at least...
684 guint buf_size = sizeof (buf);
687 if (_NSGetExecutablePath (buf, &buf_size) == 0)
688 name = g_strdup (buf);
697 resolvedname = mono_path_resolve_symlinks (name);
699 bindir = g_path_get_dirname (resolvedname);
700 installdir = g_path_get_dirname (bindir);
701 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
703 config = g_build_filename (root, "..", "etc", NULL);
705 mono_set_dirs (root, config);
707 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
708 mono_set_dirs (root, config);
718 g_free (resolvedname);
719 #elif defined(DISABLE_MONO_AUTODETECTION)
727 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
735 /* Solaris 10 style */
736 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
737 s = readlink (str, buf, sizeof (buf)-1);
749 * mono_assemblies_init:
751 * Initialize global variables used by this module.
754 mono_assemblies_init (void)
757 * Initialize our internal paths if we have not been initialized yet.
758 * This happens when embedders use Mono.
760 if (mono_assembly_getrootdir () == NULL)
764 check_extra_gac_path_env ();
766 mono_os_mutex_init_recursive (&assemblies_mutex);
767 mono_os_mutex_init (&assembly_binding_mutex);
771 mono_assembly_binding_lock (void)
773 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
777 mono_assembly_binding_unlock (void)
779 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
783 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
785 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
786 guint32 cols [MONO_ASSEMBLY_SIZE];
787 gint32 machine, flags;
792 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
795 aname->hash_value = NULL;
796 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
797 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
798 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
799 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
800 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
801 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
802 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
803 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
804 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
805 guchar* token = (guchar *)g_malloc (8);
810 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
811 len = mono_metadata_decode_blob_size (pkey, &pkey);
812 aname->public_key = (guchar*)pkey;
814 mono_digest_get_public_token (token, aname->public_key, len);
815 encoded = encode_public_tok (token, 8);
816 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
822 aname->public_key = NULL;
823 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
826 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
827 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
830 aname->public_key = 0;
832 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
833 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
835 case COFF_MACHINE_I386:
836 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
837 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
838 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
839 else if ((flags & 0x70) == 0x70)
840 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
842 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
844 case COFF_MACHINE_IA64:
845 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
847 case COFF_MACHINE_AMD64:
848 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
850 case COFF_MACHINE_ARM:
851 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
861 * mono_stringify_assembly_name:
862 * @aname: the assembly name.
864 * Convert @aname into its string format. The returned string is dynamically
865 * allocated and should be freed by the caller.
867 * Returns: a newly allocated string with a string representation of
871 mono_stringify_assembly_name (MonoAssemblyName *aname)
873 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
875 return g_strdup_printf (
876 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
877 quote, aname->name, quote,
878 aname->major, aname->minor, aname->build, aname->revision,
879 aname->culture && *aname->culture? aname->culture: "neutral",
880 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
881 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
885 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
887 const gchar *public_tok;
890 public_tok = mono_metadata_blob_heap (image, key_index);
891 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
893 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
895 mono_digest_get_public_token (token, (guchar*)public_tok, len);
896 return encode_public_tok (token, 8);
899 return encode_public_tok ((guchar*)public_tok, len);
903 * mono_assembly_addref:
904 * @assemnly: the assembly to reference
906 * This routine increments the reference count on a MonoAssembly.
907 * The reference count is reduced every time the method mono_assembly_close() is
911 mono_assembly_addref (MonoAssembly *assembly)
913 InterlockedIncrement (&assembly->ref_count);
917 * CAUTION: This table must be kept in sync with
918 * ivkm/reflect/Fusion.cs
921 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
922 #define WINFX_KEY "31bf3856ad364e35"
923 #define ECMA_KEY "b77a5c561934e089"
924 #define MSFINAL_KEY "b03f5f7f11d50a3a"
925 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
933 static KeyRemapEntry key_remap_table[] = {
934 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
935 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
936 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
937 { "System", SILVERLIGHT_KEY, ECMA_KEY },
938 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
939 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
940 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
941 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
942 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
943 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
944 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
945 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
946 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
947 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
948 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
949 { "System.Numerics", WINFX_KEY, ECMA_KEY },
950 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
951 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
952 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
953 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
954 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
955 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
956 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
957 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
958 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
959 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
960 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
961 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
962 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
966 remap_keys (MonoAssemblyName *aname)
969 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
970 const KeyRemapEntry *entry = &key_remap_table [i];
972 if (strcmp (aname->name, entry->name) ||
973 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
976 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
978 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
979 "Remapped public key token of retargetable assembly %s from %s to %s",
980 aname->name, entry->from, entry->to);
985 static MonoAssemblyName *
986 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
988 const MonoRuntimeInfo *current_runtime;
989 int pos, first, last;
991 if (aname->name == NULL) return aname;
993 current_runtime = mono_get_runtime_info ();
995 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
996 const AssemblyVersionSet* vset;
998 /* Remap to current runtime */
999 vset = ¤t_runtime->version_sets [0];
1001 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1002 dest_aname->major = vset->major;
1003 dest_aname->minor = vset->minor;
1004 dest_aname->build = vset->build;
1005 dest_aname->revision = vset->revision;
1006 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1008 /* Remap assembly name */
1009 if (!strcmp (aname->name, "System.Net"))
1010 dest_aname->name = g_strdup ("System");
1012 remap_keys (dest_aname);
1014 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1015 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1017 aname->major, aname->minor, aname->build, aname->revision,
1019 vset->major, vset->minor, vset->build, vset->revision
1025 #ifndef DISABLE_ASSEMBLY_REMAPPING
1027 last = G_N_ELEMENTS (framework_assemblies) - 1;
1029 while (first <= last) {
1031 pos = first + (last - first) / 2;
1032 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1034 const AssemblyVersionSet* vset;
1035 int index = framework_assemblies[pos].version_set_index;
1036 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1037 vset = ¤t_runtime->version_sets [index];
1039 if (aname->major == vset->major && aname->minor == vset->minor &&
1040 aname->build == vset->build && aname->revision == vset->revision)
1043 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1046 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1047 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1048 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1050 aname->major, aname->minor, aname->build, aname->revision,
1051 vset->major, vset->minor, vset->build, vset->revision
1054 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1055 dest_aname->major = vset->major;
1056 dest_aname->minor = vset->minor;
1057 dest_aname->build = vset->build;
1058 dest_aname->revision = vset->revision;
1059 if (framework_assemblies[pos].new_assembly_name != NULL) {
1060 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1061 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1062 "The assembly name %s was remapped to %s",
1067 } else if (res < 0) {
1079 * mono_assembly_get_assemblyref:
1080 * @image: pointer to the MonoImage to extract the information from.
1081 * @index: index to the assembly reference in the image.
1082 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1084 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1087 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1090 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1093 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1095 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1097 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1098 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1099 aname->hash_value = hash;
1100 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1101 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1102 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1103 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1104 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1105 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1106 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1108 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1109 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1110 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1113 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1118 mono_assembly_load_reference (MonoImage *image, int index)
1120 MonoAssembly *reference;
1121 MonoAssemblyName aname;
1122 MonoImageOpenStatus status;
1125 * image->references is shared between threads, so we need to access
1126 * it inside a critical section.
1128 mono_assemblies_lock ();
1129 if (!image->references) {
1130 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1132 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1133 image->nreferences = t->rows;
1135 reference = image->references [index];
1136 mono_assemblies_unlock ();
1140 mono_assembly_get_assemblyref (image, index, &aname);
1142 if (image->assembly && image->assembly->ref_only) {
1143 /* We use the loaded corlib */
1144 if (!strcmp (aname.name, "mscorlib"))
1145 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1147 reference = mono_assembly_loaded_full (&aname, TRUE);
1149 /* Try a postload search hook */
1150 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1154 * Here we must advice that the error was due to
1155 * a non loaded reference using the ReflectionOnly api
1158 reference = (MonoAssembly *)REFERENCE_MISSING;
1160 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1161 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1162 * accordingly, it would fail on the MS runtime before).
1163 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1164 * example bug-349190.2.cs and who knows how much more code in the wild.
1166 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1167 if (!reference && image->assembly)
1168 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1171 if (reference == NULL){
1174 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1175 extra_msg = g_strdup_printf ("The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (%s).\n", image->assembly != NULL ? image->assembly->basedir : "" );
1176 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1177 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1178 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1179 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1180 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1181 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1183 extra_msg = g_strdup ("");
1186 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1187 " Assembly: %s (assemblyref_index=%d)\n"
1188 " Version: %d.%d.%d.%d\n"
1189 " Public Key: %s\n%s",
1190 image->name, aname.name, index,
1191 aname.major, aname.minor, aname.build, aname.revision,
1192 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1195 } else if (!image->assembly->ref_only) {
1197 if (mono_assembly_get_reference_assembly_attribute (reference, &error)) {
1198 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following reference assembly assembly referenced from %s was not loaded. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context:\n"
1199 " Assembly: %s (assemblyref_index=%d)\n"
1200 " Version: %d.%d.%d.%d\n"
1201 " Public Key: %s\n",
1202 image->name, aname.name, index,
1203 aname.major, aname.minor, aname.build, aname.revision,
1204 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token);
1205 reference = NULL; /* don't load reference assemblies for execution */
1207 if (!is_ok (&error)) {
1209 mono_error_cleanup (&error);
1213 mono_assemblies_lock ();
1214 if (reference == NULL) {
1215 /* Flag as not found */
1216 reference = (MonoAssembly *)REFERENCE_MISSING;
1219 if (!image->references [index]) {
1220 if (reference != REFERENCE_MISSING){
1221 mono_assembly_addref (reference);
1222 if (image->assembly)
1223 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1224 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1226 if (image->assembly)
1227 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1228 image->assembly->aname.name, image->assembly);
1231 image->references [index] = reference;
1233 mono_assemblies_unlock ();
1235 if (image->references [index] != reference) {
1236 /* Somebody loaded it before us */
1237 mono_assembly_close (reference);
1242 * mono_assembly_load_references:
1245 * @deprecated: There is no reason to use this method anymore, it does nothing
1247 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1250 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1252 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1253 *status = MONO_IMAGE_OK;
1256 typedef struct AssemblyLoadHook AssemblyLoadHook;
1257 struct AssemblyLoadHook {
1258 AssemblyLoadHook *next;
1259 MonoAssemblyLoadFunc func;
1263 AssemblyLoadHook *assembly_load_hook = NULL;
1266 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1268 AssemblyLoadHook *hook;
1270 for (hook = assembly_load_hook; hook; hook = hook->next) {
1271 hook->func (ass, hook->user_data);
1276 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1278 AssemblyLoadHook *hook;
1280 g_return_if_fail (func != NULL);
1282 hook = g_new0 (AssemblyLoadHook, 1);
1284 hook->user_data = user_data;
1285 hook->next = assembly_load_hook;
1286 assembly_load_hook = hook;
1290 free_assembly_load_hooks (void)
1292 AssemblyLoadHook *hook, *next;
1294 for (hook = assembly_load_hook; hook; hook = next) {
1300 typedef struct AssemblySearchHook AssemblySearchHook;
1301 struct AssemblySearchHook {
1302 AssemblySearchHook *next;
1303 MonoAssemblySearchFunc func;
1309 AssemblySearchHook *assembly_search_hook = NULL;
1311 static MonoAssembly*
1312 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1314 AssemblySearchHook *hook;
1316 for (hook = assembly_search_hook; hook; hook = hook->next) {
1317 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1320 * A little explanation is in order here.
1322 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1323 * The embedding API exposes a search hook that doesn't take such argument.
1325 * The original fix would call the default search hook before all the registered ones and pass
1326 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1327 * rely on. Which is the ordering between user hooks and the default runtime hook.
1329 * Registering the hook after mono_jit_init would let your hook run before the default one and
1330 * when using it to handle non standard app layouts this could save your app from a massive amount
1331 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1332 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1334 * So what's the fix? We register the default hook using regular means and special case it when iterating
1335 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1338 if (hook->func == (void*)mono_domain_assembly_postload_search)
1339 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1341 ass = hook->func (aname, hook->user_data);
1351 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1353 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1357 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1359 AssemblySearchHook *hook;
1361 g_return_if_fail (func != NULL);
1363 hook = g_new0 (AssemblySearchHook, 1);
1365 hook->user_data = user_data;
1366 hook->refonly = refonly;
1367 hook->postload = postload;
1368 hook->next = assembly_search_hook;
1369 assembly_search_hook = hook;
1373 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1375 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1379 free_assembly_search_hooks (void)
1381 AssemblySearchHook *hook, *next;
1383 for (hook = assembly_search_hook; hook; hook = next) {
1390 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1392 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1396 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1398 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1402 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1404 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1407 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1408 struct AssemblyPreLoadHook {
1409 AssemblyPreLoadHook *next;
1410 MonoAssemblyPreLoadFunc func;
1414 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1415 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1417 static MonoAssembly *
1418 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1420 AssemblyPreLoadHook *hook;
1421 MonoAssembly *assembly;
1423 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1424 assembly = hook->func (aname, assemblies_path, hook->user_data);
1425 if (assembly != NULL)
1432 static MonoAssembly *
1433 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1435 AssemblyPreLoadHook *hook;
1436 MonoAssembly *assembly;
1438 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1439 assembly = hook->func (aname, assemblies_path, hook->user_data);
1440 if (assembly != NULL)
1448 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1450 AssemblyPreLoadHook *hook;
1452 g_return_if_fail (func != NULL);
1454 hook = g_new0 (AssemblyPreLoadHook, 1);
1456 hook->user_data = user_data;
1457 hook->next = assembly_preload_hook;
1458 assembly_preload_hook = hook;
1462 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1464 AssemblyPreLoadHook *hook;
1466 g_return_if_fail (func != NULL);
1468 hook = g_new0 (AssemblyPreLoadHook, 1);
1470 hook->user_data = user_data;
1471 hook->next = assembly_refonly_preload_hook;
1472 assembly_refonly_preload_hook = hook;
1476 free_assembly_preload_hooks (void)
1478 AssemblyPreLoadHook *hook, *next;
1480 for (hook = assembly_preload_hook; hook; hook = next) {
1485 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1492 absolute_dir (const gchar *filename)
1503 if (g_path_is_absolute (filename)) {
1504 part = g_path_get_dirname (filename);
1505 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1510 cwd = g_get_current_dir ();
1511 mixed = g_build_filename (cwd, filename, NULL);
1512 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1517 for (i = 0; (part = parts [i]) != NULL; i++) {
1518 if (!strcmp (part, "."))
1521 if (!strcmp (part, "..")) {
1522 if (list && list->next) /* Don't remove root */
1523 list = g_list_delete_link (list, list);
1525 list = g_list_prepend (list, part);
1529 result = g_string_new ("");
1530 list = g_list_reverse (list);
1532 /* Ignores last data pointer, which should be the filename */
1533 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1535 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1540 g_string_free (result, FALSE);
1545 return g_strdup (".");
1552 * mono_assembly_open_from_bundle:
1553 * @filename: Filename requested
1554 * @status: return status code
1556 * This routine tries to open the assembly specified by `filename' from the
1557 * defined bundles, if found, returns the MonoImage for it, if not found
1561 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1565 MonoImage *image = NULL;
1568 * we do a very simple search for bundled assemblies: it's not a general
1569 * purpose assembly loading mechanism.
1575 name = g_path_get_basename (filename);
1577 mono_assemblies_lock ();
1578 for (i = 0; !image && bundles [i]; ++i) {
1579 if (strcmp (bundles [i]->name, name) == 0) {
1580 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1584 mono_assemblies_unlock ();
1586 mono_image_addref (image);
1587 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
1596 * mono_assemblies_open_full:
1597 * @filename: the file to load
1598 * @status: return status code
1599 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1601 * This loads an assembly from the specified @filename. The @filename allows
1602 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1603 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1604 * is treated as a local path.
1606 * First, an attempt is made to load the assembly from the bundled executable (for those
1607 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1608 * assembly has been registered as an embedded assembly). If this is not the case, then
1609 * the assembly is loaded from disk using `api:mono_image_open_full`.
1611 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1612 * the assembly is made.
1614 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1615 * the `System.Reflection` API.
1617 * Returns: NULL on error, with the @status set to an error code, or a pointer
1621 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1625 MonoImageOpenStatus def_status;
1628 gboolean loaded_from_bundle;
1630 g_return_val_if_fail (filename != NULL, NULL);
1633 status = &def_status;
1634 *status = MONO_IMAGE_OK;
1636 if (strncmp (filename, "file://", 7) == 0) {
1637 GError *error = NULL;
1638 gchar *uri = (gchar *) filename;
1642 * MS allows file://c:/... and fails on file://localhost/c:/...
1643 * They also throw an IndexOutOfRangeException if "file://"
1646 uri = g_strdup_printf ("file:///%s", uri + 7);
1649 uri = mono_escape_uri_string (tmpuri);
1650 fname = g_filename_from_uri (uri, NULL, &error);
1653 if (tmpuri != filename)
1656 if (error != NULL) {
1657 g_warning ("%s\n", error->message);
1658 g_error_free (error);
1659 fname = g_strdup (filename);
1662 fname = g_strdup (filename);
1665 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1666 "Assembly Loader probing location: '%s'.", fname);
1669 if (!mono_assembly_is_in_gac (fname)) {
1671 new_fname = mono_make_shadow_copy (fname, &error);
1672 if (!is_ok (&error)) {
1673 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1674 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1675 mono_error_cleanup (&error);
1676 *status = MONO_IMAGE_IMAGE_INVALID;
1681 if (new_fname && new_fname != fname) {
1684 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1685 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1690 // If VM built with mkbundle
1691 loaded_from_bundle = FALSE;
1692 if (bundles != NULL) {
1693 image = mono_assembly_open_from_bundle (fname, status, refonly);
1694 loaded_from_bundle = image != NULL;
1698 image = mono_image_open_full (fname, status, refonly);
1701 if (*status == MONO_IMAGE_OK)
1702 *status = MONO_IMAGE_ERROR_ERRNO;
1707 if (image->assembly) {
1708 /* Already loaded by another appdomain */
1709 mono_assembly_invoke_load_hook (image->assembly);
1710 mono_image_close (image);
1712 return image->assembly;
1715 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1718 if (!loaded_from_bundle)
1719 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1720 "Assembly Loader loaded assembly from location: '%s'.", filename);
1722 mono_config_for_assembly (ass->image);
1725 /* Clear the reference added by mono_image_open */
1726 mono_image_close (image);
1734 free_item (gpointer val, gpointer user_data)
1740 * mono_assembly_load_friends:
1743 * Load the list of friend assemblies that are allowed to access
1744 * the assembly's internal types and members. They are stored as assembly
1745 * names in custom attributes.
1747 * This is an internal method, we need this because when we load mscorlib
1748 * we do not have the internals visible cattr loaded yet,
1749 * so we need to load these after we initialize the runtime.
1751 * LOCKING: Acquires the assemblies lock plus the loader lock.
1754 mono_assembly_load_friends (MonoAssembly* ass)
1758 MonoCustomAttrInfo* attrs;
1761 if (ass->friend_assembly_names_inited)
1764 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1765 mono_error_assert_ok (&error);
1767 mono_assemblies_lock ();
1768 ass->friend_assembly_names_inited = TRUE;
1769 mono_assemblies_unlock ();
1773 mono_assemblies_lock ();
1774 if (ass->friend_assembly_names_inited) {
1775 mono_assemblies_unlock ();
1778 mono_assemblies_unlock ();
1782 * We build the list outside the assemblies lock, the worse that can happen
1783 * is that we'll need to free the allocated list.
1785 for (i = 0; i < attrs->num_attrs; ++i) {
1786 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1787 MonoAssemblyName *aname;
1789 /* Do some sanity checking */
1790 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1792 if (attr->data_size < 4)
1794 data = (const char*)attr->data;
1795 /* 0xFF means null string, see custom attr format */
1796 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1798 mono_metadata_decode_value (data + 2, &data);
1799 aname = g_new0 (MonoAssemblyName, 1);
1800 /*g_print ("friend ass: %s\n", data);*/
1801 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1802 list = g_slist_prepend (list, aname);
1807 mono_custom_attrs_free (attrs);
1809 mono_assemblies_lock ();
1810 if (ass->friend_assembly_names_inited) {
1811 mono_assemblies_unlock ();
1812 g_slist_foreach (list, free_item, NULL);
1813 g_slist_free (list);
1816 ass->friend_assembly_names = list;
1818 /* Because of the double checked locking pattern above */
1819 mono_memory_barrier ();
1820 ass->friend_assembly_names_inited = TRUE;
1821 mono_assemblies_unlock ();
1826 * mono_assembly_get_reference_assembly_attribute:
1827 * @assembly: a MonoAssembly
1828 * @error: set on error.
1830 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1831 * On error returns FALSE and sets @error.
1834 mono_assembly_get_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1836 mono_error_init (error);
1838 MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
1839 return_val_if_nok (error, FALSE);
1842 MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
1843 gboolean result = FALSE;
1844 for (int i = 0; i < attrs->num_attrs; ++i) {
1845 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1846 if (attr->ctor && attr->ctor->klass && attr->ctor->klass == ref_asm_class) {
1851 mono_custom_attrs_free (attrs);
1856 * mono_assembly_open:
1857 * @filename: Opens the assembly pointed out by this name
1858 * @status: return status code
1860 * This loads an assembly from the specified @filename. The @filename allows
1861 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1862 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1863 * is treated as a local path.
1865 * First, an attempt is made to load the assembly from the bundled executable (for those
1866 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1867 * assembly has been registered as an embedded assembly). If this is not the case, then
1868 * the assembly is loaded from disk using `api:mono_image_open_full`.
1870 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1871 * the assembly is made.
1873 * Return: a pointer to the MonoAssembly if @filename contains a valid
1874 * assembly or NULL on error. Details about the error are stored in the
1878 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1880 return mono_assembly_open_full (filename, status, FALSE);
1884 * mono_assembly_load_from_full:
1885 * @image: Image to load the assembly from
1886 * @fname: assembly name to associate with the assembly
1887 * @status: returns the status condition
1888 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1890 * If the provided @image has an assembly reference, it will process the given
1891 * image as an assembly with the given name.
1893 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1895 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1896 * set to #MONO_IMAGE_OK; or NULL on error.
1898 * If there is an error loading the assembly the @status will indicate the
1899 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1900 * image did not contain an assembly reference table.
1903 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1904 MonoImageOpenStatus *status, gboolean refonly)
1906 MonoAssembly *ass, *ass2;
1909 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1910 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1911 *status = MONO_IMAGE_IMAGE_INVALID;
1915 #if defined (HOST_WIN32)
1920 tmp_fn = g_strdup (fname);
1921 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1922 if (tmp_fn [i] == '/')
1926 base_dir = absolute_dir (tmp_fn);
1930 base_dir = absolute_dir (fname);
1934 * Create assembly struct, and enter it into the assembly cache
1936 ass = g_new0 (MonoAssembly, 1);
1937 ass->basedir = base_dir;
1938 ass->ref_only = refonly;
1941 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1943 mono_assembly_fill_assembly_name (image, &ass->aname);
1945 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1946 // MS.NET doesn't support loading other mscorlibs
1949 mono_image_addref (mono_defaults.corlib);
1950 *status = MONO_IMAGE_OK;
1951 return mono_defaults.corlib->assembly;
1954 /* Add a non-temporary reference because of ass->image */
1955 mono_image_addref (image);
1957 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s[%p] -> %s[%p]: %d", ass->aname.name, ass, image->name, image, image->ref_count);
1960 * The load hooks might take locks so we can't call them while holding the
1963 if (ass->aname.name) {
1964 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1968 mono_image_close (image);
1969 *status = MONO_IMAGE_OK;
1974 mono_assemblies_lock ();
1976 if (image->assembly) {
1978 * This means another thread has already loaded the assembly, but not yet
1979 * called the load hooks so the search hook can't find the assembly.
1981 mono_assemblies_unlock ();
1982 ass2 = image->assembly;
1985 mono_image_close (image);
1986 *status = MONO_IMAGE_OK;
1990 image->assembly = ass;
1992 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1993 mono_assemblies_unlock ();
1996 if (image->is_module_handle)
1997 mono_image_fixup_vtable (image);
2000 mono_assembly_invoke_load_hook (ass);
2002 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2008 * mono_assembly_load_from:
2009 * @image: Image to load the assembly from
2010 * @fname: assembly name to associate with the assembly
2011 * @status: return status code
2013 * If the provided @image has an assembly reference, it will process the given
2014 * image as an assembly with the given name.
2016 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2018 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2019 * @refonly parameter set to FALSE.
2020 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2021 * set to #MONO_IMAGE_OK; or NULL on error.
2023 * If there is an error loading the assembly the @status will indicate the
2024 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2025 * image did not contain an assembly reference table.
2029 mono_assembly_load_from (MonoImage *image, const char *fname,
2030 MonoImageOpenStatus *status)
2032 return mono_assembly_load_from_full (image, fname, status, FALSE);
2036 * mono_assembly_name_free:
2037 * @aname: assembly name to free
2039 * Frees the provided assembly name object.
2040 * (it does not frees the object itself, only the name members).
2043 mono_assembly_name_free (MonoAssemblyName *aname)
2048 g_free ((void *) aname->name);
2049 g_free ((void *) aname->culture);
2050 g_free ((void *) aname->hash_value);
2051 g_free ((guint8*) aname->public_key);
2055 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2058 gchar header [16], val, *arr;
2059 gint i, j, offset, bitlen, keylen, pkeylen;
2061 keylen = strlen (key) >> 1;
2065 /* allow the ECMA standard key */
2066 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2068 *pubkey = g_strdup (key);
2074 val = g_ascii_xdigit_value (key [0]) << 4;
2075 val |= g_ascii_xdigit_value (key [1]);
2080 val = g_ascii_xdigit_value (key [24]);
2081 val |= g_ascii_xdigit_value (key [25]);
2093 /* We need the first 16 bytes
2094 * to check whether this key is valid or not */
2095 pkeylen = strlen (pkey) >> 1;
2099 for (i = 0, j = 0; i < 16; i++) {
2100 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2101 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2104 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2105 header [1] != 0x02 || /* Version (0x02) */
2106 header [2] != 0x00 || /* Reserved (word) */
2107 header [3] != 0x00 ||
2108 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2111 /* Based on this length, we _should_ be able to know if the length is right */
2112 bitlen = read32 (header + 12) >> 3;
2113 if ((bitlen + 16 + 4) != pkeylen)
2116 /* parsing is OK and the public key itself is not requested back */
2120 /* Encode the size of the blob */
2122 if (keylen <= 127) {
2123 arr = (gchar *)g_malloc (keylen + 1);
2124 arr [offset++] = keylen;
2126 arr = (gchar *)g_malloc (keylen + 2);
2127 arr [offset++] = 0x80; /* 10bs */
2128 arr [offset++] = keylen;
2131 for (i = offset, j = 0; i < keylen + offset; i++) {
2132 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2133 arr [i] |= g_ascii_xdigit_value (key [j++]);
2142 build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, guint32 arch, MonoAssemblyName *aname, gboolean save_public_key)
2144 gint major, minor, build, revision;
2147 gchar *pkey, *pkeyptr, *encoded, tok [8];
2149 memset (aname, 0, sizeof (MonoAssemblyName));
2152 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2153 if (version_parts < 2 || version_parts > 4)
2156 /* FIXME: we should set build & revision to -1 (instead of 0)
2157 if these are not set in the version string. That way, later on,
2158 we can still determine if these were specified. */
2159 aname->major = major;
2160 aname->minor = minor;
2161 if (version_parts >= 3)
2162 aname->build = build;
2165 if (version_parts == 4)
2166 aname->revision = revision;
2168 aname->revision = 0;
2171 aname->flags = flags;
2173 aname->name = g_strdup (name);
2176 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2177 aname->culture = g_strdup ("");
2179 aname->culture = g_strdup (culture);
2182 if (token && strncmp (token, "null", 4) != 0) {
2185 /* the constant includes the ending NULL, hence the -1 */
2186 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2187 mono_assembly_name_free (aname);
2190 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2191 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2197 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2198 mono_assembly_name_free (aname);
2203 if (save_public_key)
2204 aname->public_key = (guint8*)pkey;
2207 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2211 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2212 // We also need to generate the key token
2213 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2214 encoded = encode_public_tok ((guchar*) tok, 8);
2215 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2218 if (save_public_key)
2219 aname->public_key = (guint8*) pkey;
2228 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2233 parts = g_strsplit (dirname, "_", 3);
2234 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2239 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2245 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2247 char *eqsign = strchr (pair, '=');
2255 *key = (gchar*)pair;
2256 *keylen = eqsign - *key;
2257 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2259 *value = g_strstrip (eqsign + 1);
2264 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2268 gchar *version = NULL;
2270 gchar *culture = NULL;
2272 gchar *token = NULL;
2276 gchar *retargetable = NULL;
2277 gchar *retargetable_uq;
2281 gchar *value, *part_name;
2282 guint32 part_name_len;
2285 gboolean version_defined;
2286 gboolean token_defined;
2288 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2290 if (!is_version_defined)
2291 is_version_defined = &version_defined;
2292 *is_version_defined = FALSE;
2293 if (!is_token_defined)
2294 is_token_defined = &token_defined;
2295 *is_token_defined = FALSE;
2297 parts = tmp = g_strsplit (name, ",", 6);
2298 if (!tmp || !*tmp) {
2303 dllname = g_strstrip (*tmp);
2308 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2309 goto cleanup_and_fail;
2311 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2312 *is_version_defined = TRUE;
2314 if (strlen (version) == 0) {
2315 goto cleanup_and_fail;
2321 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2323 if (strlen (culture) == 0) {
2324 goto cleanup_and_fail;
2330 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2331 *is_token_defined = TRUE;
2333 if (strlen (token) == 0) {
2334 goto cleanup_and_fail;
2340 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2342 if (strlen (key) == 0) {
2343 goto cleanup_and_fail;
2349 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2350 retargetable = value;
2351 retargetable_uq = unquote (retargetable);
2352 if (retargetable_uq != NULL)
2353 retargetable = retargetable_uq;
2355 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2356 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2357 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2358 free (retargetable_uq);
2359 goto cleanup_and_fail;
2362 free (retargetable_uq);
2367 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2369 procarch_uq = unquote (procarch);
2370 if (procarch_uq != NULL)
2371 procarch = procarch_uq;
2373 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2374 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2375 else if (!g_ascii_strcasecmp (procarch, "X86"))
2376 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2377 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2378 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2379 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2380 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2383 goto cleanup_and_fail;
2395 /* if retargetable flag is set, then we must have a fully qualified name */
2396 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2397 goto cleanup_and_fail;
2400 dllname_uq = unquote (dllname);
2401 version_uq = unquote (version);
2402 culture_uq = unquote (culture);
2403 token_uq = unquote (token);
2404 key_uq = unquote (key);
2406 res = build_assembly_name (
2407 dllname_uq == NULL ? dllname : dllname_uq,
2408 version_uq == NULL ? version : version_uq,
2409 culture_uq == NULL ? culture : culture_uq,
2410 token_uq == NULL ? token : token_uq,
2411 key_uq == NULL ? key : key_uq,
2412 flags, arch, aname, save_public_key);
2429 unquote (const char *str)
2437 slen = strlen (str);
2441 if (*str != '\'' && *str != '\"')
2444 end = str + slen - 1;
2448 return g_strndup (str + 1, slen - 2);
2452 * mono_assembly_name_parse:
2453 * @name: name to parse
2454 * @aname: the destination assembly name
2456 * Parses an assembly qualified type name and assigns the name,
2457 * version, culture and token to the provided assembly name object.
2459 * Returns: TRUE if the name could be parsed.
2462 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2464 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2468 * mono_assembly_name_new:
2469 * @name: name to parse
2471 * Allocate a new MonoAssemblyName and fill its values from the
2474 * Returns: a newly allocated structure or NULL if there was any failure.
2477 mono_assembly_name_new (const char *name)
2479 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2480 if (mono_assembly_name_parse (name, aname))
2487 mono_assembly_name_get_name (MonoAssemblyName *aname)
2493 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2495 return aname->culture;
2499 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2501 if (aname->public_key_token [0])
2502 return aname->public_key_token;
2507 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2510 *minor = aname->minor;
2512 *build = aname->build;
2514 *revision = aname->revision;
2515 return aname->major;
2518 static MonoAssembly*
2519 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2521 gchar *fullpath = NULL;
2523 const char* direntry;
2524 MonoAssemblyName gac_aname;
2525 gint major=-1, minor=0, build=0, revision=0;
2526 gboolean exact_version;
2528 dirhandle = g_dir_open (basepath, 0, NULL);
2532 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2534 while ((direntry = g_dir_read_name (dirhandle))) {
2535 gboolean match = TRUE;
2537 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2540 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2543 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2544 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2548 if (exact_version) {
2549 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2550 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2552 else if (gac_aname.major < major)
2554 else if (gac_aname.major == major) {
2555 if (gac_aname.minor < minor)
2557 else if (gac_aname.minor == minor) {
2558 if (gac_aname.build < build)
2560 else if (gac_aname.build == build && gac_aname.revision <= revision)
2567 major = gac_aname.major;
2568 minor = gac_aname.minor;
2569 build = gac_aname.build;
2570 revision = gac_aname.revision;
2572 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2575 mono_assembly_name_free (&gac_aname);
2578 g_dir_close (dirhandle);
2580 if (fullpath == NULL)
2583 MonoAssembly *res = mono_assembly_open (fullpath, status);
2590 * mono_assembly_load_with_partial_name:
2591 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2592 * @status: return status code
2594 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2595 * so it might contain a qualified type name, version, culture and token.
2597 * This will load the assembly from the file whose name is derived from the assembly name
2598 * by appending the .dll extension.
2600 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2601 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2602 * if that fails from the GAC.
2604 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2607 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2611 MonoAssemblyName *aname, base_name;
2612 MonoAssemblyName mapped_aname;
2613 gchar *fullname, *gacpath;
2616 memset (&base_name, 0, sizeof (MonoAssemblyName));
2619 if (!mono_assembly_name_parse (name, aname))
2623 * If no specific version has been requested, make sure we load the
2624 * correct version for system assemblies.
2626 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2627 aname = mono_assembly_remap_version (aname, &mapped_aname);
2629 res = mono_assembly_loaded (aname);
2631 mono_assembly_name_free (aname);
2635 res = invoke_assembly_preload_hook (aname, assemblies_path);
2637 res->in_gac = FALSE;
2638 mono_assembly_name_free (aname);
2642 fullname = g_strdup_printf ("%s.dll", aname->name);
2644 if (extra_gac_paths) {
2645 paths = extra_gac_paths;
2646 while (!res && *paths) {
2647 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2648 res = probe_for_partial_name (gacpath, fullname, aname, status);
2657 mono_assembly_name_free (aname);
2661 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2662 res = probe_for_partial_name (gacpath, fullname, aname, status);
2668 MonoDomain *domain = mono_domain_get ();
2669 MonoReflectionAssembly *refasm;
2671 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2672 if (!is_ok (&error)) {
2674 mono_assembly_name_free (aname);
2675 mono_error_cleanup (&error);
2676 if (*status == MONO_IMAGE_OK)
2677 *status = MONO_IMAGE_IMAGE_INVALID;
2681 res = refasm->assembly;
2685 mono_assembly_name_free (aname);
2691 mono_assembly_is_in_gac (const gchar *filename)
2693 const gchar *rootdir;
2697 if (filename == NULL)
2700 for (paths = extra_gac_paths; paths && *paths; paths++) {
2701 if (strstr (*paths, filename) != *paths)
2704 gp = (gchar *) (filename + strlen (*paths));
2705 if (*gp != G_DIR_SEPARATOR)
2708 if (strncmp (gp, "lib", 3))
2711 if (*gp != G_DIR_SEPARATOR)
2714 if (strncmp (gp, "mono", 4))
2717 if (*gp != G_DIR_SEPARATOR)
2720 if (strncmp (gp, "gac", 3))
2723 if (*gp != G_DIR_SEPARATOR)
2729 rootdir = mono_assembly_getrootdir ();
2730 if (strstr (filename, rootdir) != filename)
2733 gp = (gchar *) (filename + strlen (rootdir));
2734 if (*gp != G_DIR_SEPARATOR)
2737 if (strncmp (gp, "mono", 4))
2740 if (*gp != G_DIR_SEPARATOR)
2743 if (strncmp (gp, "gac", 3))
2746 if (*gp != G_DIR_SEPARATOR)
2752 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2755 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2759 if (strstr (aname->name, ".dll")) {
2760 len = strlen (aname->name) - 4;
2761 name = (gchar *)g_malloc (len + 1);
2762 strncpy (name, aname->name, len);
2765 name = g_strdup (aname->name);
2768 culture = g_utf8_strdown (aname->culture, -1);
2770 culture = g_strdup ("");
2772 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2773 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2777 filename = g_strconcat (pname, ".dll", NULL);
2778 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2784 if (extra_gac_paths) {
2785 paths = extra_gac_paths;
2786 while (!image && *paths) {
2787 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2788 "lib", "mono", "gac", subpath, NULL);
2789 image = mono_image_open (fullpath, NULL);
2800 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2801 "mono", "gac", subpath, NULL);
2802 image = mono_image_open (fullpath, NULL);
2809 static MonoAssemblyName*
2810 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2812 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2813 dest_name->major = info->new_version.major;
2814 dest_name->minor = info->new_version.minor;
2815 dest_name->build = info->new_version.build;
2816 dest_name->revision = info->new_version.revision;
2821 /* LOCKING: assembly_binding lock must be held */
2822 static MonoAssemblyBindingInfo*
2823 search_binding_loaded (MonoAssemblyName *aname)
2827 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2828 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2829 if (assembly_binding_maps_name (info, aname))
2836 static inline gboolean
2837 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2839 if (left->major != right->major || left->minor != right->minor ||
2840 left->build != right->build || left->revision != right->revision)
2846 static inline gboolean
2847 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2849 if (left->has_old_version_bottom != right->has_old_version_bottom)
2852 if (left->has_old_version_top != right->has_old_version_top)
2855 if (left->has_new_version != right->has_new_version)
2858 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2861 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2864 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2870 /* LOCKING: assumes all the necessary locks are held */
2872 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2874 MonoAssemblyBindingInfo *info_copy;
2876 MonoAssemblyBindingInfo *info_tmp;
2877 MonoDomain *domain = (MonoDomain*)user_data;
2882 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2883 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2884 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2888 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2889 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2891 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2893 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2895 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2899 get_version_number (int major, int minor)
2901 return major * 256 + minor;
2904 static inline gboolean
2905 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2907 int aname_version_number = get_version_number (aname->major, aname->minor);
2908 if (!info->has_old_version_bottom)
2911 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2914 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2917 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2918 info->major = aname->major;
2919 info->minor = aname->minor;
2924 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2925 static MonoAssemblyBindingInfo*
2926 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2928 MonoAssemblyBindingInfo *info;
2931 if (!domain->assembly_bindings)
2935 for (list = domain->assembly_bindings; list; list = list->next) {
2936 info = (MonoAssemblyBindingInfo *)list->data;
2937 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2943 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2944 info->has_new_version && assembly_binding_maps_name (info, aname))
2945 info->is_valid = TRUE;
2947 info->is_valid = FALSE;
2953 static MonoAssemblyName*
2954 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2957 MonoAssemblyBindingInfo *info, *info2;
2961 if (aname->public_key_token [0] == 0)
2964 domain = mono_domain_get ();
2966 mono_assembly_binding_lock ();
2967 info = search_binding_loaded (aname);
2968 mono_assembly_binding_unlock ();
2971 mono_domain_lock (domain);
2972 info = get_per_domain_assembly_binding_info (domain, aname);
2973 mono_domain_unlock (domain);
2977 if (!check_policy_versions (info, aname))
2980 mono_assembly_bind_version (info, aname, dest_name);
2984 if (domain && domain->setup && domain->setup->configuration_file) {
2985 mono_domain_lock (domain);
2986 if (!domain->assembly_bindings_parsed) {
2987 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2988 /* expect this to succeed because mono_domain_set_options_from_config () did
2989 * the same thing when the domain was created. */
2990 mono_error_assert_ok (&error);
2992 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2994 if (!domain_config_file_path)
2995 domain_config_file_path = domain_config_file_name;
2997 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2998 domain->assembly_bindings_parsed = TRUE;
2999 if (domain_config_file_name != domain_config_file_path)
3000 g_free (domain_config_file_name);
3001 g_free (domain_config_file_path);
3004 info2 = get_per_domain_assembly_binding_info (domain, aname);
3007 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3008 info->name = g_strdup (info2->name);
3009 info->culture = g_strdup (info2->culture);
3010 info->domain_id = domain->domain_id;
3013 mono_domain_unlock (domain);
3017 info = g_new0 (MonoAssemblyBindingInfo, 1);
3018 info->major = aname->major;
3019 info->minor = aname->minor;
3022 if (!info->is_valid) {
3023 ppimage = mono_assembly_load_publisher_policy (aname);
3025 get_publisher_policy_info (ppimage, aname, info);
3026 mono_image_close (ppimage);
3030 /* Define default error value if needed */
3031 if (!info->is_valid) {
3032 info->name = g_strdup (aname->name);
3033 info->culture = g_strdup (aname->culture);
3034 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3037 mono_assembly_binding_lock ();
3038 info2 = search_binding_loaded (aname);
3040 /* This binding was added by another thread
3042 mono_assembly_binding_info_free (info);
3047 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3049 mono_assembly_binding_unlock ();
3051 if (!info->is_valid || !check_policy_versions (info, aname))
3054 mono_assembly_bind_version (info, aname, dest_name);
3059 * mono_assembly_load_from_gac
3061 * @aname: The assembly name object
3063 static MonoAssembly*
3064 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3066 MonoAssembly *result = NULL;
3067 gchar *name, *version, *culture, *fullpath, *subpath;
3072 if (aname->public_key_token [0] == 0) {
3076 if (strstr (aname->name, ".dll")) {
3077 len = strlen (filename) - 4;
3078 name = (gchar *)g_malloc (len + 1);
3079 strncpy (name, aname->name, len);
3082 name = g_strdup (aname->name);
3085 if (aname->culture) {
3086 culture = g_utf8_strdown (aname->culture, -1);
3088 culture = g_strdup ("");
3091 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3092 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3093 aname->minor, aname->build, aname->revision,
3097 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3102 if (extra_gac_paths) {
3103 paths = extra_gac_paths;
3104 while (!result && *paths) {
3105 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3106 result = mono_assembly_open_full (fullpath, status, refonly);
3113 result->in_gac = TRUE;
3118 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3119 "mono", "gac", subpath, NULL);
3120 result = mono_assembly_open_full (fullpath, status, refonly);
3124 result->in_gac = TRUE;
3132 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3135 MonoAssemblyName *aname;
3138 /* g_print ("corlib already loaded\n"); */
3142 // In native client, Corlib is embedded in the executable as static variable corlibData
3143 #if defined(__native_client__)
3144 if (corlibData != NULL && corlibSize != 0) {
3146 /* First "FALSE" instructs mono not to make a copy. */
3147 /* Second "FALSE" says this is not just a ref. */
3148 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3149 if (image == NULL || status != 0)
3150 g_print("mono_image_open_from_data_full failed: %d\n", status);
3151 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3152 if (corlib == NULL || status != 0)
3153 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3159 // A nonstandard preload hook may provide a special mscorlib assembly
3160 aname = mono_assembly_name_new ("mscorlib.dll");
3161 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3162 mono_assembly_name_free (aname);
3165 goto return_corlib_and_facades;
3167 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3168 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3169 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3171 goto return_corlib_and_facades;
3174 /* Normal case: Load corlib from mono/<version> */
3175 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3176 if (assemblies_path) { // Custom assemblies path
3177 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3179 g_free (corlib_file);
3180 goto return_corlib_and_facades;
3183 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3184 g_free (corlib_file);
3186 return_corlib_and_facades:
3187 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3188 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3194 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3195 const char *basedir,
3196 MonoImageOpenStatus *status,
3199 MonoAssembly *result;
3200 char *fullpath, *filename;
3201 MonoAssemblyName maped_aname;
3202 MonoAssemblyName maped_name_pp;
3207 aname = mono_assembly_remap_version (aname, &maped_aname);
3209 /* Reflection only assemblies don't get assembly binding */
3211 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3213 result = mono_assembly_loaded_full (aname, refonly);
3217 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3219 result->in_gac = FALSE;
3223 /* Currently we retrieve the loaded corlib for reflection
3224 * only requests, like a common reflection only assembly
3226 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3227 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3230 len = strlen (aname->name);
3231 for (ext_index = 0; ext_index < 2; ext_index ++) {
3232 ext = ext_index == 0 ? ".dll" : ".exe";
3233 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3234 filename = g_strdup (aname->name);
3235 /* Don't try appending .dll/.exe if it already has one of those extensions */
3238 filename = g_strconcat (aname->name, ext, NULL);
3241 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3248 fullpath = g_build_filename (basedir, filename, NULL);
3249 result = mono_assembly_open_full (fullpath, status, refonly);
3252 result->in_gac = FALSE;
3258 result = load_in_path (filename, default_path, status, refonly);
3260 result->in_gac = FALSE;
3270 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3272 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3275 /* Try a postload search hook */
3276 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3281 * mono_assembly_load_full:
3282 * @aname: A MonoAssemblyName with the assembly name to load.
3283 * @basedir: A directory to look up the assembly at.
3284 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3285 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3287 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3288 * attempts to load the assembly from that directory before probing the standard locations.
3290 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3291 * assembly binding takes place.
3293 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3294 * value pointed by status is updated with an error code.
3297 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3299 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3303 * mono_assembly_load:
3304 * @aname: A MonoAssemblyName with the assembly name to load.
3305 * @basedir: A directory to look up the assembly at.
3306 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3308 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3309 * attempts to load the assembly from that directory before probing the standard locations.
3311 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3312 * value pointed by status is updated with an error code.
3315 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3317 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3321 * mono_assembly_loaded_full:
3322 * @aname: an assembly to look for.
3323 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3325 * This is used to determine if the specified assembly has been loaded
3326 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3327 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3330 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3333 MonoAssemblyName maped_aname;
3335 aname = mono_assembly_remap_version (aname, &maped_aname);
3337 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3343 * mono_assembly_loaded:
3344 * @aname: an assembly to look for.
3346 * This is used to determine if the specified assembly has been loaded
3348 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3349 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3352 mono_assembly_loaded (MonoAssemblyName *aname)
3354 return mono_assembly_loaded_full (aname, FALSE);
3358 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3360 if (assembly == NULL || assembly == REFERENCE_MISSING)
3363 if (assembly_is_dynamic (assembly)) {
3365 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3366 for (i = 0; i < dynimg->image.module_count; ++i)
3367 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3368 mono_dynamic_image_release_gc_roots (dynimg);
3373 * Returns whether mono_assembly_close_finish() must be called as
3374 * well. See comment for mono_image_close_except_pools() for why we
3375 * unload in two steps.
3378 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3381 g_return_val_if_fail (assembly != NULL, FALSE);
3383 if (assembly == REFERENCE_MISSING)
3386 /* Might be 0 already */
3387 if (InterlockedDecrement (&assembly->ref_count) > 0)
3390 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3392 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3394 mono_debug_close_image (assembly->image);
3396 mono_assemblies_lock ();
3397 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3398 mono_assemblies_unlock ();
3400 assembly->image->assembly = NULL;
3402 if (!mono_image_close_except_pools (assembly->image))
3403 assembly->image = NULL;
3405 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3406 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3407 mono_assembly_name_free (fname);
3410 g_slist_free (assembly->friend_assembly_names);
3411 g_free (assembly->basedir);
3413 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3419 mono_assembly_close_finish (MonoAssembly *assembly)
3421 g_assert (assembly && assembly != REFERENCE_MISSING);
3423 if (assembly->image)
3424 mono_image_close_finish (assembly->image);
3426 if (assembly_is_dynamic (assembly)) {
3427 g_free ((char*)assembly->aname.culture);
3434 * mono_assembly_close:
3435 * @assembly: the assembly to release.
3437 * This method releases a reference to the @assembly. The assembly is
3438 * only released when all the outstanding references to it are released.
3441 mono_assembly_close (MonoAssembly *assembly)
3443 if (mono_assembly_close_except_image_pools (assembly))
3444 mono_assembly_close_finish (assembly);
3448 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3450 return mono_image_load_file_for_image (assembly->image, idx);
3454 * mono_assembly_foreach:
3455 * @func: function to invoke for each assembly loaded
3456 * @user_data: data passed to the callback
3458 * Invokes the provided @func callback for each assembly loaded into
3459 * the runtime. The first parameter passed to the callback is the
3460 * `MonoAssembly*`, and the second parameter is the @user_data.
3462 * This is done for all assemblies loaded in the runtime, not just
3463 * those loaded in the current application domain.
3466 mono_assembly_foreach (GFunc func, gpointer user_data)
3471 * We make a copy of the list to avoid calling the callback inside the
3472 * lock, which could lead to deadlocks.
3474 mono_assemblies_lock ();
3475 copy = g_list_copy (loaded_assemblies);
3476 mono_assemblies_unlock ();
3478 g_list_foreach (loaded_assemblies, func, user_data);
3484 * mono_assemblies_cleanup:
3486 * Free all resources used by this module.
3489 mono_assemblies_cleanup (void)
3493 mono_os_mutex_destroy (&assemblies_mutex);
3494 mono_os_mutex_destroy (&assembly_binding_mutex);
3496 for (l = loaded_assembly_bindings; l; l = l->next) {
3497 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3499 mono_assembly_binding_info_free (info);
3502 g_slist_free (loaded_assembly_bindings);
3504 free_assembly_load_hooks ();
3505 free_assembly_search_hooks ();
3506 free_assembly_preload_hooks ();
3509 /*LOCKING takes the assembly_binding lock*/
3511 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3515 mono_assembly_binding_lock ();
3516 iter = &loaded_assembly_bindings;
3519 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3521 if (info->domain_id == domain_id) {
3523 mono_assembly_binding_info_free (info);
3530 mono_assembly_binding_unlock ();
3534 * Holds the assembly of the application, for
3535 * System.Diagnostics.Process::MainModule
3537 static MonoAssembly *main_assembly=NULL;
3540 mono_assembly_set_main (MonoAssembly *assembly)
3542 main_assembly = assembly;
3546 * mono_assembly_get_main:
3548 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3551 mono_assembly_get_main (void)
3553 return (main_assembly);
3557 * mono_assembly_get_image:
3558 * @assembly: The assembly to retrieve the image from
3560 * Returns: the MonoImage associated with this assembly.
3563 mono_assembly_get_image (MonoAssembly *assembly)
3565 return assembly->image;
3569 * mono_assembly_get_name:
3570 * @assembly: The assembly to retrieve the name from
3572 * The returned name's lifetime is the same as @assembly's.
3574 * Returns: the MonoAssemblyName associated with this assembly.
3577 mono_assembly_get_name (MonoAssembly *assembly)
3579 return &assembly->aname;
3583 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3585 bundles = assemblies;
3588 #define MONO_DECLSEC_FORMAT_10 0x3C
3589 #define MONO_DECLSEC_FORMAT_20 0x2E
3590 #define MONO_DECLSEC_FIELD 0x53
3591 #define MONO_DECLSEC_PROPERTY 0x54
3593 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3594 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3595 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3596 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3597 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3600 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3604 case MONO_DECLSEC_PROPERTY:
3606 case MONO_DECLSEC_FIELD:
3608 *abort_decoding = TRUE;
3613 if (*p++ != MONO_TYPE_BOOLEAN) {
3614 *abort_decoding = TRUE;
3618 /* property name length */
3619 len = mono_metadata_decode_value (p, &p);
3621 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3632 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3634 int i, j, num, len, params_len;
3636 if (*p == MONO_DECLSEC_FORMAT_10) {
3637 gsize read, written;
3638 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3640 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3646 if (*p++ != MONO_DECLSEC_FORMAT_20)
3649 /* number of encoded permission attributes */
3650 num = mono_metadata_decode_value (p, &p);
3651 for (i = 0; i < num; ++i) {
3652 gboolean is_valid = FALSE;
3653 gboolean abort_decoding = FALSE;
3655 /* attribute name length */
3656 len = mono_metadata_decode_value (p, &p);
3658 /* We don't really need to fully decode the type. Comparing the name is enough */
3659 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3663 /*size of the params table*/
3664 params_len = mono_metadata_decode_value (p, &p);
3666 const char *params_end = p + params_len;
3668 /* number of parameters */
3669 len = mono_metadata_decode_value (p, &p);
3671 for (j = 0; j < len; ++j) {
3672 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3688 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3691 guint32 cols [MONO_DECL_SECURITY_SIZE];
3695 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3696 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3698 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3700 for (i = 0; i < t->rows; ++i) {
3701 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3702 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3704 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3707 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3708 len = mono_metadata_decode_blob_size (blob, &blob);
3712 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3713 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3718 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);