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)
19 #include "object-internals.h"
20 #include <mono/metadata/loader.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/class-internals.h>
25 #include <mono/metadata/domain-internals.h>
26 #include <mono/metadata/reflection-internals.h>
27 #include <mono/metadata/mono-endian.h>
28 #include <mono/metadata/mono-debug.h>
29 #include <mono/io-layer/io-layer.h>
30 #include <mono/utils/mono-uri.h>
31 #include <mono/metadata/mono-config.h>
32 #include <mono/metadata/mono-config-dirs.h>
33 #include <mono/utils/mono-digest.h>
34 #include <mono/utils/mono-logger-internals.h>
35 #include <mono/utils/mono-path.h>
36 #include <mono/metadata/reflection.h>
37 #include <mono/metadata/coree.h>
38 #include <mono/metadata/cil-coff.h>
39 #include <mono/utils/mono-io-portability.h>
40 #include <mono/utils/atomic.h>
41 #include <mono/utils/mono-os-mutex.h>
44 #include <sys/types.h>
49 #ifdef PLATFORM_MACOSX
50 #include <mach-o/dyld.h>
53 /* 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 */
55 const char* assembly_name;
56 guint8 version_set_index;
57 const char* new_assembly_name;
58 gboolean only_lower_versions;
61 /* the default search path is empty, the first slot is replaced with the computed value */
69 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
70 static char **assemblies_path = NULL;
72 /* Contains the list of directories that point to auxiliary GACs */
73 static char **extra_gac_paths = NULL;
75 #ifndef DISABLE_ASSEMBLY_REMAPPING
76 /* The list of system assemblies what will be remapped to the running
77 * runtime version. WARNING: this list must be sorted.
78 * The integer number is an index in the MonoRuntimeInfo structure, whose
79 * values can be found in domain.c - supported_runtimes. Look there
80 * to understand what remapping will be made.
82 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
85 static const AssemblyVersionMap framework_assemblies [] = {
87 {"Commons.Xml.Relaxng", 0},
94 {"Microsoft.Build.Engine", 2, NULL, TRUE},
95 {"Microsoft.Build.Framework", 2, NULL, TRUE},
96 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
97 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
98 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
99 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
100 {"Microsoft.VisualBasic", 1},
101 {"Microsoft.VisualC", 1},
103 {"Mono.CompilerServices.SymbolWriter", 0},
105 {"Mono.Data.SybaseClient", 0},
106 {"Mono.Data.Tds", 0},
107 {"Mono.Data.TdsClient", 0},
108 {"Mono.GetOptions", 0},
111 {"Mono.Security", 0},
112 {"Mono.Security.Win32", 0},
114 {"Novell.Directory.Ldap", 0},
117 {"System.ComponentModel.Composition", 2},
118 {"System.ComponentModel.DataAnnotations", 2},
119 {"System.Configuration", 0},
120 {"System.Configuration.Install", 0},
123 {"System.Data.Linq", 2},
124 {"System.Data.OracleClient", 0},
125 {"System.Data.Services", 2},
126 {"System.Data.Services.Client", 2},
127 {"System.Data.SqlXml", 0},
128 {"System.Design", 0},
129 {"System.DirectoryServices", 0},
130 {"System.Drawing", 0},
131 {"System.Drawing.Design", 0},
132 {"System.EnterpriseServices", 0},
133 {"System.IdentityModel", 3},
134 {"System.IdentityModel.Selectors", 3},
135 {"System.Management", 0},
136 {"System.Messaging", 0},
138 {"System.Runtime.Remoting", 0},
139 {"System.Runtime.Serialization", 3},
140 {"System.Runtime.Serialization.Formatters.Soap", 0},
141 {"System.Security", 0},
142 {"System.ServiceModel", 3},
143 {"System.ServiceModel.Web", 2},
144 {"System.ServiceProcess", 0},
145 {"System.Transactions", 0},
147 {"System.Web.Abstractions", 2},
148 {"System.Web.DynamicData", 2},
149 {"System.Web.Extensions", 2},
150 {"System.Web.Mobile", 0},
151 {"System.Web.Routing", 2},
152 {"System.Web.Services", 0},
153 {"System.Windows.Forms", 0},
155 {"System.Xml.Linq", 2},
162 * keeps track of loaded assemblies
164 static GList *loaded_assemblies = NULL;
165 static MonoAssembly *corlib;
167 #if defined(__native_client__)
169 /* On Native Client, allow mscorlib to be loaded from memory */
170 /* instead of loaded off disk. If these are not set, default */
171 /* mscorlib loading will take place */
173 /* NOTE: If mscorlib data is passed to mono in this way then */
174 /* it needs to remain allocated during the use of mono. */
176 static void *corlibData = NULL;
177 static size_t corlibSize = 0;
180 mono_set_corlib_data (void *data, size_t size)
188 static char* unquote (const char *str);
190 /* This protects loaded_assemblies and image->references */
191 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
192 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
193 static mono_mutex_t assemblies_mutex;
195 /* If defined, points to the bundled assembly information */
196 const MonoBundledAssembly **bundles;
198 static mono_mutex_t assembly_binding_mutex;
200 /* Loaded assembly binding info */
201 static GSList *loaded_assembly_bindings = NULL;
203 /* Class lazy loading functions */
204 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
207 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
209 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
211 mono_assembly_is_in_gac (const gchar *filanem);
214 encode_public_tok (const guchar *token, gint32 len)
216 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
220 res = (gchar *)g_malloc (len * 2 + 1);
221 for (i = 0; i < len; i++) {
222 res [i * 2] = allowed [token [i] >> 4];
223 res [i * 2 + 1] = allowed [token [i] & 0xF];
230 * mono_public_tokens_are_equal:
231 * @pubt1: first public key token
232 * @pubt2: second public key token
234 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
238 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
240 return memcmp (pubt1, pubt2, 16) == 0;
244 * mono_set_assemblies_path:
245 * @path: list of paths that contain directories where Mono will look for assemblies
247 * Use this method to override the standard assembly lookup system and
248 * override any assemblies coming from the GAC. This is the method
249 * that supports the MONO_PATH variable.
251 * Notice that MONO_PATH and this method are really a very bad idea as
252 * it prevents the GAC from working and it prevents the standard
253 * resolution mechanisms from working. Nonetheless, for some debugging
254 * situations and bootstrapping setups, this is useful to have.
257 mono_set_assemblies_path (const char* path)
259 char **splitted, **dest;
261 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
263 g_strfreev (assemblies_path);
264 assemblies_path = dest = splitted;
266 char *tmp = *splitted;
268 *dest++ = mono_path_canonicalize (tmp);
274 if (g_getenv ("MONO_DEBUG") == NULL)
277 splitted = assemblies_path;
279 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
280 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
286 /* Native Client can't get this info from an environment variable so */
287 /* it's passed in to the runtime, or set manually by embedding code. */
288 #ifdef __native_client__
289 char* nacl_mono_path = NULL;
293 check_path_env (void)
296 path = g_getenv ("MONO_PATH");
297 #ifdef __native_client__
299 path = nacl_mono_path;
301 if (!path || assemblies_path != NULL)
304 mono_set_assemblies_path(path);
308 check_extra_gac_path_env (void) {
310 char **splitted, **dest;
312 path = g_getenv ("MONO_GAC_PREFIX");
316 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
318 g_strfreev (extra_gac_paths);
319 extra_gac_paths = dest = splitted;
327 if (g_getenv ("MONO_DEBUG") == NULL)
331 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
332 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
339 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
341 if (!info || !info->name)
344 if (strcmp (info->name, aname->name))
347 if (info->major != aname->major || info->minor != aname->minor)
350 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
353 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
356 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
363 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
369 g_free (info->culture);
373 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
376 guint32 cols [MONO_MANIFEST_SIZE];
377 const gchar *filename;
378 gchar *subpath, *fullpath;
380 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
381 /* MS Impl. accepts policy assemblies with more than
382 * one manifest resource, and only takes the first one */
384 binding_info->is_valid = FALSE;
388 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
389 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
390 binding_info->is_valid = FALSE;
394 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
395 g_assert (filename != NULL);
397 subpath = g_path_get_dirname (image->name);
398 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
399 mono_config_parse_publisher_policy (fullpath, binding_info);
403 /* Define the optional elements/attributes before checking */
404 if (!binding_info->culture)
405 binding_info->culture = g_strdup ("");
407 /* Check that the most important elements/attributes exist */
408 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
409 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
410 mono_assembly_binding_info_free (binding_info);
411 binding_info->is_valid = FALSE;
415 binding_info->is_valid = TRUE;
419 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
421 if (v->major > aname->major)
423 else if (v->major < aname->major)
426 if (v->minor > aname->minor)
428 else if (v->minor < aname->minor)
431 if (v->build > aname->build)
433 else if (v->build < aname->build)
436 if (v->revision > aname->revision)
438 else if (v->revision < aname->revision)
445 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
450 /* If has_old_version_top doesn't exist, we don't have an interval */
451 if (!info->has_old_version_top) {
452 if (compare_versions (&info->old_version_bottom, name) == 0)
458 /* Check that the version defined by name is valid for the interval */
459 if (compare_versions (&info->old_version_top, name) < 0)
462 /* We should be greater or equal than the small version */
463 if (compare_versions (&info->old_version_bottom, name) > 0)
470 * mono_assembly_names_equal:
472 * @r: second assembly.
474 * Compares two MonoAssemblyNames and returns whether they are equal.
476 * This compares the names, the cultures, the release version and their
479 * Returns: TRUE if both assembly names are equal.
482 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
484 if (!l->name || !r->name)
487 if (strcmp (l->name, r->name))
490 if (l->culture && r->culture && strcmp (l->culture, r->culture))
493 if (l->major != r->major || l->minor != r->minor ||
494 l->build != r->build || l->revision != r->revision)
495 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)))
498 if (!l->public_key_token [0] || !r->public_key_token [0])
501 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
507 static MonoAssembly *
508 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
512 MonoAssembly *result;
514 for (i = 0; search_path [i]; ++i) {
515 fullpath = g_build_filename (search_path [i], basename, NULL);
516 result = mono_assembly_open_full (fullpath, status, refonly);
525 * mono_assembly_setrootdir:
526 * @root_dir: The pathname of the root directory where we will locate assemblies
528 * This routine sets the internal default root directory for looking up
531 * This is used by Windows installations to compute dynamically the
532 * place where the Mono assemblies are located.
536 mono_assembly_setrootdir (const char *root_dir)
539 * Override the MONO_ASSEMBLIES directory configured at compile time.
541 /* Leak if called more than once */
542 default_path [0] = g_strdup (root_dir);
546 * mono_assembly_getrootdir:
548 * Obtains the root directory used for looking up assemblies.
550 * Returns: a string with the directory, this string should not be freed.
552 G_CONST_RETURN gchar *
553 mono_assembly_getrootdir (void)
555 return default_path [0];
560 * @assembly_dir: the base directory for assemblies
561 * @config_dir: the base directory for configuration files
563 * This routine is used internally and by developers embedding
564 * the runtime into their own applications.
566 * There are a number of cases to consider: Mono as a system-installed
567 * package that is available on the location preconfigured or Mono in
568 * a relocated location.
570 * If you are using a system-installed Mono, you can pass NULL
571 * to both parameters. If you are not, you should compute both
572 * directory values and call this routine.
574 * The values for a given PREFIX are:
576 * assembly_dir: PREFIX/lib
577 * config_dir: PREFIX/etc
579 * Notice that embedders that use Mono in a relocated way must
580 * compute the location at runtime, as they will be in control
581 * of where Mono is installed.
584 mono_set_dirs (const char *assembly_dir, const char *config_dir)
586 if (assembly_dir == NULL)
587 assembly_dir = mono_config_get_assemblies_dir ();
588 if (config_dir == NULL)
589 config_dir = mono_config_get_cfg_dir ();
590 mono_assembly_setrootdir (assembly_dir);
591 mono_set_config_dir (config_dir);
597 compute_base (char *path)
599 char *p = strrchr (path, '/');
603 /* Not a well known Mono executable, we are embedded, cant guess the base */
604 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
608 p = strrchr (path, '/');
612 if (strcmp (p, "/bin") != 0)
621 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
624 static G_GNUC_UNUSED void
628 char *config, *lib, *mono;
633 * Only /usr prefix is treated specially
635 bindir = mono_config_get_bin_dir ();
637 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
642 config = g_build_filename (base, "etc", NULL);
643 lib = g_build_filename (base, "lib", NULL);
644 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
645 if (stat (mono, &buf) == -1)
648 mono_set_dirs (lib, config);
656 #endif /* HOST_WIN32 */
661 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
662 * this auto-detects the prefix where Mono was installed.
665 mono_set_rootdir (void)
667 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
668 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
671 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
675 * _NSGetExecutablePath may return -1 to indicate buf is not large
676 * enough, but we ignore that case to avoid having to do extra dynamic
677 * allocation for the path and hope that 4096 is enough - this is
678 * ok in the Linux/Solaris case below at least...
682 guint buf_size = sizeof (buf);
685 if (_NSGetExecutablePath (buf, &buf_size) == 0)
686 name = g_strdup (buf);
695 resolvedname = mono_path_resolve_symlinks (name);
697 bindir = g_path_get_dirname (resolvedname);
698 installdir = g_path_get_dirname (bindir);
699 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
701 config = g_build_filename (root, "..", "etc", NULL);
703 mono_set_dirs (root, config);
705 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
706 mono_set_dirs (root, config);
716 g_free (resolvedname);
717 #elif defined(DISABLE_MONO_AUTODETECTION)
725 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
733 /* Solaris 10 style */
734 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
735 s = readlink (str, buf, sizeof (buf)-1);
747 * mono_assemblies_init:
749 * Initialize global variables used by this module.
752 mono_assemblies_init (void)
755 * Initialize our internal paths if we have not been initialized yet.
756 * This happens when embedders use Mono.
758 if (mono_assembly_getrootdir () == NULL)
762 check_extra_gac_path_env ();
764 mono_os_mutex_init_recursive (&assemblies_mutex);
765 mono_os_mutex_init (&assembly_binding_mutex);
769 mono_assembly_binding_lock (void)
771 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
775 mono_assembly_binding_unlock (void)
777 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
781 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
783 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
784 guint32 cols [MONO_ASSEMBLY_SIZE];
785 gint32 machine, flags;
790 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
793 aname->hash_value = NULL;
794 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
795 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
796 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
797 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
798 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
799 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
800 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
801 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
802 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
803 guchar* token = (guchar *)g_malloc (8);
808 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
809 len = mono_metadata_decode_blob_size (pkey, &pkey);
810 aname->public_key = (guchar*)pkey;
812 mono_digest_get_public_token (token, aname->public_key, len);
813 encoded = encode_public_tok (token, 8);
814 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
820 aname->public_key = NULL;
821 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
824 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
825 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
828 aname->public_key = 0;
830 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
831 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
833 case COFF_MACHINE_I386:
834 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
835 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
836 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
837 else if ((flags & 0x70) == 0x70)
838 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
840 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
842 case COFF_MACHINE_IA64:
843 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
845 case COFF_MACHINE_AMD64:
846 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
848 case COFF_MACHINE_ARM:
849 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
859 * mono_stringify_assembly_name:
860 * @aname: the assembly name.
862 * Convert @aname into its string format. The returned string is dynamically
863 * allocated and should be freed by the caller.
865 * Returns: a newly allocated string with a string representation of
869 mono_stringify_assembly_name (MonoAssemblyName *aname)
871 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
873 return g_strdup_printf (
874 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
875 quote, aname->name, quote,
876 aname->major, aname->minor, aname->build, aname->revision,
877 aname->culture && *aname->culture? aname->culture: "neutral",
878 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
879 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
883 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
885 const gchar *public_tok;
888 public_tok = mono_metadata_blob_heap (image, key_index);
889 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
891 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
893 mono_digest_get_public_token (token, (guchar*)public_tok, len);
894 return encode_public_tok (token, 8);
897 return encode_public_tok ((guchar*)public_tok, len);
901 * mono_assembly_addref:
902 * @assemnly: the assembly to reference
904 * This routine increments the reference count on a MonoAssembly.
905 * The reference count is reduced every time the method mono_assembly_close() is
909 mono_assembly_addref (MonoAssembly *assembly)
911 InterlockedIncrement (&assembly->ref_count);
915 * CAUTION: This table must be kept in sync with
916 * ivkm/reflect/Fusion.cs
919 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
920 #define WINFX_KEY "31bf3856ad364e35"
921 #define ECMA_KEY "b77a5c561934e089"
922 #define MSFINAL_KEY "b03f5f7f11d50a3a"
930 static KeyRemapEntry key_remap_table[] = {
931 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
932 { "System", SILVERLIGHT_KEY, ECMA_KEY },
933 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
934 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
935 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
936 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
937 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
938 { "System.Numerics", WINFX_KEY, ECMA_KEY },
939 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
940 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
941 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
942 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
943 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
944 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
945 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
949 remap_keys (MonoAssemblyName *aname)
952 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
953 const KeyRemapEntry *entry = &key_remap_table [i];
955 if (strcmp (aname->name, entry->name) ||
956 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
959 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
961 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
962 "Remapped public key token of retargetable assembly %s from %s to %s",
963 aname->name, entry->from, entry->to);
968 static MonoAssemblyName *
969 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
971 const MonoRuntimeInfo *current_runtime;
972 int pos, first, last;
974 if (aname->name == NULL) return aname;
976 current_runtime = mono_get_runtime_info ();
978 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
979 const AssemblyVersionSet* vset;
981 /* Remap to current runtime */
982 vset = ¤t_runtime->version_sets [0];
984 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
985 dest_aname->major = vset->major;
986 dest_aname->minor = vset->minor;
987 dest_aname->build = vset->build;
988 dest_aname->revision = vset->revision;
989 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
991 /* Remap assembly name */
992 if (!strcmp (aname->name, "System.Net"))
993 dest_aname->name = g_strdup ("System");
995 remap_keys (dest_aname);
997 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
998 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1000 aname->major, aname->minor, aname->build, aname->revision,
1002 vset->major, vset->minor, vset->build, vset->revision
1008 #ifndef DISABLE_ASSEMBLY_REMAPPING
1010 last = G_N_ELEMENTS (framework_assemblies) - 1;
1012 while (first <= last) {
1014 pos = first + (last - first) / 2;
1015 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1017 const AssemblyVersionSet* vset;
1018 int index = framework_assemblies[pos].version_set_index;
1019 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1020 vset = ¤t_runtime->version_sets [index];
1022 if (aname->major == vset->major && aname->minor == vset->minor &&
1023 aname->build == vset->build && aname->revision == vset->revision)
1026 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1029 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1030 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1031 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1033 aname->major, aname->minor, aname->build, aname->revision,
1034 vset->major, vset->minor, vset->build, vset->revision
1037 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1038 dest_aname->major = vset->major;
1039 dest_aname->minor = vset->minor;
1040 dest_aname->build = vset->build;
1041 dest_aname->revision = vset->revision;
1042 if (framework_assemblies[pos].new_assembly_name != NULL) {
1043 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1044 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1045 "The assembly name %s was remapped to %s",
1050 } else if (res < 0) {
1062 * mono_assembly_get_assemblyref:
1063 * @image: pointer to the MonoImage to extract the information from.
1064 * @index: index to the assembly reference in the image.
1065 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1067 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1070 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1073 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1076 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1078 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1080 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1081 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1082 aname->hash_value = hash;
1083 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1084 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1085 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1086 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1087 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1088 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1089 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1091 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1092 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1093 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1096 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1101 mono_assembly_load_reference (MonoImage *image, int index)
1103 MonoAssembly *reference;
1104 MonoAssemblyName aname;
1105 MonoImageOpenStatus status;
1108 * image->references is shared between threads, so we need to access
1109 * it inside a critical section.
1111 mono_assemblies_lock ();
1112 if (!image->references) {
1113 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1115 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1116 image->nreferences = t->rows;
1118 reference = image->references [index];
1119 mono_assemblies_unlock ();
1123 mono_assembly_get_assemblyref (image, index, &aname);
1125 if (image->assembly && image->assembly->ref_only) {
1126 /* We use the loaded corlib */
1127 if (!strcmp (aname.name, "mscorlib"))
1128 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1130 reference = mono_assembly_loaded_full (&aname, TRUE);
1132 /* Try a postload search hook */
1133 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1137 * Here we must advice that the error was due to
1138 * a non loaded reference using the ReflectionOnly api
1141 reference = (MonoAssembly *)REFERENCE_MISSING;
1143 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1144 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1145 * accordingly, it would fail on the MS runtime before).
1146 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1147 * example bug-349190.2.cs and who knows how much more code in the wild.
1149 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1150 if (!reference && image->assembly)
1151 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1154 if (reference == NULL){
1157 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1158 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 : "" );
1159 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1160 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1161 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1162 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1163 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1164 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1166 extra_msg = g_strdup ("");
1169 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1170 " Assembly: %s (assemblyref_index=%d)\n"
1171 " Version: %d.%d.%d.%d\n"
1172 " Public Key: %s\n%s",
1173 image->name, aname.name, index,
1174 aname.major, aname.minor, aname.build, aname.revision,
1175 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1179 mono_assemblies_lock ();
1180 if (reference == NULL) {
1181 /* Flag as not found */
1182 reference = (MonoAssembly *)REFERENCE_MISSING;
1185 if (!image->references [index]) {
1186 if (reference != REFERENCE_MISSING){
1187 mono_assembly_addref (reference);
1188 if (image->assembly)
1189 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1190 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1192 if (image->assembly)
1193 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1194 image->assembly->aname.name, image->assembly);
1197 image->references [index] = reference;
1199 mono_assemblies_unlock ();
1201 if (image->references [index] != reference) {
1202 /* Somebody loaded it before us */
1203 mono_assembly_close (reference);
1208 * mono_assembly_load_references:
1211 * @deprecated: There is no reason to use this method anymore, it does nothing
1213 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1216 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1218 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1219 *status = MONO_IMAGE_OK;
1222 typedef struct AssemblyLoadHook AssemblyLoadHook;
1223 struct AssemblyLoadHook {
1224 AssemblyLoadHook *next;
1225 MonoAssemblyLoadFunc func;
1229 AssemblyLoadHook *assembly_load_hook = NULL;
1232 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1234 AssemblyLoadHook *hook;
1236 for (hook = assembly_load_hook; hook; hook = hook->next) {
1237 hook->func (ass, hook->user_data);
1242 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1244 AssemblyLoadHook *hook;
1246 g_return_if_fail (func != NULL);
1248 hook = g_new0 (AssemblyLoadHook, 1);
1250 hook->user_data = user_data;
1251 hook->next = assembly_load_hook;
1252 assembly_load_hook = hook;
1256 free_assembly_load_hooks (void)
1258 AssemblyLoadHook *hook, *next;
1260 for (hook = assembly_load_hook; hook; hook = next) {
1266 typedef struct AssemblySearchHook AssemblySearchHook;
1267 struct AssemblySearchHook {
1268 AssemblySearchHook *next;
1269 MonoAssemblySearchFunc func;
1275 AssemblySearchHook *assembly_search_hook = NULL;
1277 static MonoAssembly*
1278 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1280 AssemblySearchHook *hook;
1282 for (hook = assembly_search_hook; hook; hook = hook->next) {
1283 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1286 * A little explanation is in order here.
1288 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1289 * The embedding API exposes a search hook that doesn't take such argument.
1291 * The original fix would call the default search hook before all the registered ones and pass
1292 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1293 * rely on. Which is the ordering between user hooks and the default runtime hook.
1295 * Registering the hook after mono_jit_init would let your hook run before the default one and
1296 * when using it to handle non standard app layouts this could save your app from a massive amount
1297 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1298 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1300 * So what's the fix? We register the default hook using regular means and special case it when iterating
1301 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1304 if (hook->func == (void*)mono_domain_assembly_postload_search)
1305 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1307 ass = hook->func (aname, hook->user_data);
1317 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1319 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1323 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1325 AssemblySearchHook *hook;
1327 g_return_if_fail (func != NULL);
1329 hook = g_new0 (AssemblySearchHook, 1);
1331 hook->user_data = user_data;
1332 hook->refonly = refonly;
1333 hook->postload = postload;
1334 hook->next = assembly_search_hook;
1335 assembly_search_hook = hook;
1339 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1341 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1345 free_assembly_search_hooks (void)
1347 AssemblySearchHook *hook, *next;
1349 for (hook = assembly_search_hook; hook; hook = next) {
1356 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1358 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1362 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1364 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1368 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1370 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1373 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1374 struct AssemblyPreLoadHook {
1375 AssemblyPreLoadHook *next;
1376 MonoAssemblyPreLoadFunc func;
1380 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1381 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1383 static MonoAssembly *
1384 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1386 AssemblyPreLoadHook *hook;
1387 MonoAssembly *assembly;
1389 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1390 assembly = hook->func (aname, assemblies_path, hook->user_data);
1391 if (assembly != NULL)
1398 static MonoAssembly *
1399 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1401 AssemblyPreLoadHook *hook;
1402 MonoAssembly *assembly;
1404 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1405 assembly = hook->func (aname, assemblies_path, hook->user_data);
1406 if (assembly != NULL)
1414 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1416 AssemblyPreLoadHook *hook;
1418 g_return_if_fail (func != NULL);
1420 hook = g_new0 (AssemblyPreLoadHook, 1);
1422 hook->user_data = user_data;
1423 hook->next = assembly_preload_hook;
1424 assembly_preload_hook = hook;
1428 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1430 AssemblyPreLoadHook *hook;
1432 g_return_if_fail (func != NULL);
1434 hook = g_new0 (AssemblyPreLoadHook, 1);
1436 hook->user_data = user_data;
1437 hook->next = assembly_refonly_preload_hook;
1438 assembly_refonly_preload_hook = hook;
1442 free_assembly_preload_hooks (void)
1444 AssemblyPreLoadHook *hook, *next;
1446 for (hook = assembly_preload_hook; hook; hook = next) {
1451 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1458 absolute_dir (const gchar *filename)
1469 if (g_path_is_absolute (filename)) {
1470 part = g_path_get_dirname (filename);
1471 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1476 cwd = g_get_current_dir ();
1477 mixed = g_build_filename (cwd, filename, NULL);
1478 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1483 for (i = 0; (part = parts [i]) != NULL; i++) {
1484 if (!strcmp (part, "."))
1487 if (!strcmp (part, "..")) {
1488 if (list && list->next) /* Don't remove root */
1489 list = g_list_delete_link (list, list);
1491 list = g_list_prepend (list, part);
1495 result = g_string_new ("");
1496 list = g_list_reverse (list);
1498 /* Ignores last data pointer, which should be the filename */
1499 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1501 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1506 g_string_free (result, FALSE);
1511 return g_strdup (".");
1518 * mono_assembly_open_from_bundle:
1519 * @filename: Filename requested
1520 * @status: return status code
1522 * This routine tries to open the assembly specified by `filename' from the
1523 * defined bundles, if found, returns the MonoImage for it, if not found
1527 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1531 MonoImage *image = NULL;
1534 * we do a very simple search for bundled assemblies: it's not a general
1535 * purpose assembly loading mechanism.
1541 name = g_path_get_basename (filename);
1543 mono_assemblies_lock ();
1544 for (i = 0; !image && bundles [i]; ++i) {
1545 if (strcmp (bundles [i]->name, name) == 0) {
1546 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1550 mono_assemblies_unlock ();
1552 mono_image_addref (image);
1553 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
1562 * mono_assemblies_open_full:
1563 * @filename: the file to load
1564 * @status: return status code
1565 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1567 * This loads an assembly from the specified @filename. The @filename allows
1568 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1569 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1570 * is treated as a local path.
1572 * First, an attempt is made to load the assembly from the bundled executable (for those
1573 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1574 * assembly has been registered as an embedded assembly). If this is not the case, then
1575 * the assembly is loaded from disk using `api:mono_image_open_full`.
1577 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1578 * the assembly is made.
1580 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1581 * the `System.Reflection` API.
1583 * Returns: NULL on error, with the @status set to an error code, or a pointer
1587 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1591 MonoImageOpenStatus def_status;
1594 gboolean loaded_from_bundle;
1596 g_return_val_if_fail (filename != NULL, NULL);
1599 status = &def_status;
1600 *status = MONO_IMAGE_OK;
1602 if (strncmp (filename, "file://", 7) == 0) {
1603 GError *error = NULL;
1604 gchar *uri = (gchar *) filename;
1608 * MS allows file://c:/... and fails on file://localhost/c:/...
1609 * They also throw an IndexOutOfRangeException if "file://"
1612 uri = g_strdup_printf ("file:///%s", uri + 7);
1615 uri = mono_escape_uri_string (tmpuri);
1616 fname = g_filename_from_uri (uri, NULL, &error);
1619 if (tmpuri != filename)
1622 if (error != NULL) {
1623 g_warning ("%s\n", error->message);
1624 g_error_free (error);
1625 fname = g_strdup (filename);
1628 fname = g_strdup (filename);
1631 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1632 "Assembly Loader probing location: '%s'.", fname);
1635 if (!mono_assembly_is_in_gac (fname)) {
1637 new_fname = mono_make_shadow_copy (fname, &error);
1638 mono_error_raise_exception (&error); /* FIXME don't raise here */
1640 if (new_fname && new_fname != fname) {
1643 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1644 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1649 // If VM built with mkbundle
1650 loaded_from_bundle = FALSE;
1651 if (bundles != NULL) {
1652 image = mono_assembly_open_from_bundle (fname, status, refonly);
1653 loaded_from_bundle = image != NULL;
1657 image = mono_image_open_full (fname, status, refonly);
1660 if (*status == MONO_IMAGE_OK)
1661 *status = MONO_IMAGE_ERROR_ERRNO;
1666 if (image->assembly) {
1667 /* Already loaded by another appdomain */
1668 mono_assembly_invoke_load_hook (image->assembly);
1669 mono_image_close (image);
1671 return image->assembly;
1674 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1677 if (!loaded_from_bundle)
1678 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1679 "Assembly Loader loaded assembly from location: '%s'.", filename);
1681 mono_config_for_assembly (ass->image);
1684 /* Clear the reference added by mono_image_open */
1685 mono_image_close (image);
1693 free_item (gpointer val, gpointer user_data)
1699 * mono_assembly_load_friends:
1702 * Load the list of friend assemblies that are allowed to access
1703 * the assembly's internal types and members. They are stored as assembly
1704 * names in custom attributes.
1706 * This is an internal method, we need this because when we load mscorlib
1707 * we do not have the internals visible cattr loaded yet,
1708 * so we need to load these after we initialize the runtime.
1710 * LOCKING: Acquires the assemblies lock plus the loader lock.
1713 mono_assembly_load_friends (MonoAssembly* ass)
1717 MonoCustomAttrInfo* attrs;
1720 if (ass->friend_assembly_names_inited)
1723 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1724 mono_error_assert_ok (&error);
1726 mono_assemblies_lock ();
1727 ass->friend_assembly_names_inited = TRUE;
1728 mono_assemblies_unlock ();
1732 mono_assemblies_lock ();
1733 if (ass->friend_assembly_names_inited) {
1734 mono_assemblies_unlock ();
1737 mono_assemblies_unlock ();
1741 * We build the list outside the assemblies lock, the worse that can happen
1742 * is that we'll need to free the allocated list.
1744 for (i = 0; i < attrs->num_attrs; ++i) {
1745 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1746 MonoAssemblyName *aname;
1748 /* Do some sanity checking */
1749 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1751 if (attr->data_size < 4)
1753 data = (const char*)attr->data;
1754 /* 0xFF means null string, see custom attr format */
1755 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1757 mono_metadata_decode_value (data + 2, &data);
1758 aname = g_new0 (MonoAssemblyName, 1);
1759 /*g_print ("friend ass: %s\n", data);*/
1760 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1761 list = g_slist_prepend (list, aname);
1766 mono_custom_attrs_free (attrs);
1768 mono_assemblies_lock ();
1769 if (ass->friend_assembly_names_inited) {
1770 mono_assemblies_unlock ();
1771 g_slist_foreach (list, free_item, NULL);
1772 g_slist_free (list);
1775 ass->friend_assembly_names = list;
1777 /* Because of the double checked locking pattern above */
1778 mono_memory_barrier ();
1779 ass->friend_assembly_names_inited = TRUE;
1780 mono_assemblies_unlock ();
1784 * mono_assembly_open:
1785 * @filename: Opens the assembly pointed out by this name
1786 * @status: return status code
1788 * This loads an assembly from the specified @filename. The @filename allows
1789 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1790 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1791 * is treated as a local path.
1793 * First, an attempt is made to load the assembly from the bundled executable (for those
1794 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1795 * assembly has been registered as an embedded assembly). If this is not the case, then
1796 * the assembly is loaded from disk using `api:mono_image_open_full`.
1798 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1799 * the assembly is made.
1801 * Return: a pointer to the MonoAssembly if @filename contains a valid
1802 * assembly or NULL on error. Details about the error are stored in the
1806 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1808 return mono_assembly_open_full (filename, status, FALSE);
1812 * mono_assembly_load_from_full:
1813 * @image: Image to load the assembly from
1814 * @fname: assembly name to associate with the assembly
1815 * @status: returns the status condition
1816 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1818 * If the provided @image has an assembly reference, it will process the given
1819 * image as an assembly with the given name.
1821 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1823 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1824 * set to #MONO_IMAGE_OK; or NULL on error.
1826 * If there is an error loading the assembly the @status will indicate the
1827 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1828 * image did not contain an assembly reference table.
1831 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1832 MonoImageOpenStatus *status, gboolean refonly)
1834 MonoAssembly *ass, *ass2;
1837 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1838 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1839 *status = MONO_IMAGE_IMAGE_INVALID;
1843 #if defined (HOST_WIN32)
1848 tmp_fn = g_strdup (fname);
1849 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1850 if (tmp_fn [i] == '/')
1854 base_dir = absolute_dir (tmp_fn);
1858 base_dir = absolute_dir (fname);
1862 * Create assembly struct, and enter it into the assembly cache
1864 ass = g_new0 (MonoAssembly, 1);
1865 ass->basedir = base_dir;
1866 ass->ref_only = refonly;
1869 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1871 mono_assembly_fill_assembly_name (image, &ass->aname);
1873 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1874 // MS.NET doesn't support loading other mscorlibs
1877 mono_image_addref (mono_defaults.corlib);
1878 *status = MONO_IMAGE_OK;
1879 return mono_defaults.corlib->assembly;
1882 /* Add a non-temporary reference because of ass->image */
1883 mono_image_addref (image);
1885 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);
1888 * The load hooks might take locks so we can't call them while holding the
1891 if (ass->aname.name) {
1892 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1896 mono_image_close (image);
1897 *status = MONO_IMAGE_OK;
1902 mono_assemblies_lock ();
1904 if (image->assembly) {
1906 * This means another thread has already loaded the assembly, but not yet
1907 * called the load hooks so the search hook can't find the assembly.
1909 mono_assemblies_unlock ();
1910 ass2 = image->assembly;
1913 mono_image_close (image);
1914 *status = MONO_IMAGE_OK;
1918 image->assembly = ass;
1920 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1921 mono_assemblies_unlock ();
1924 if (image->is_module_handle)
1925 mono_image_fixup_vtable (image);
1928 mono_assembly_invoke_load_hook (ass);
1930 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1936 * mono_assembly_load_from:
1937 * @image: Image to load the assembly from
1938 * @fname: assembly name to associate with the assembly
1939 * @status: return status code
1941 * If the provided @image has an assembly reference, it will process the given
1942 * image as an assembly with the given name.
1944 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1946 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
1947 * @refonly parameter set to FALSE.
1948 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1949 * set to #MONO_IMAGE_OK; or NULL on error.
1951 * If there is an error loading the assembly the @status will indicate the
1952 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1953 * image did not contain an assembly reference table.
1957 mono_assembly_load_from (MonoImage *image, const char *fname,
1958 MonoImageOpenStatus *status)
1960 return mono_assembly_load_from_full (image, fname, status, FALSE);
1964 * mono_assembly_name_free:
1965 * @aname: assembly name to free
1967 * Frees the provided assembly name object.
1968 * (it does not frees the object itself, only the name members).
1971 mono_assembly_name_free (MonoAssemblyName *aname)
1976 g_free ((void *) aname->name);
1977 g_free ((void *) aname->culture);
1978 g_free ((void *) aname->hash_value);
1982 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
1985 gchar header [16], val, *arr;
1986 gint i, j, offset, bitlen, keylen, pkeylen;
1988 keylen = strlen (key) >> 1;
1992 /* allow the ECMA standard key */
1993 if (strcmp (key, "00000000000000000400000000000000") == 0) {
1995 *pubkey = g_strdup (key);
2001 val = g_ascii_xdigit_value (key [0]) << 4;
2002 val |= g_ascii_xdigit_value (key [1]);
2007 val = g_ascii_xdigit_value (key [24]);
2008 val |= g_ascii_xdigit_value (key [25]);
2020 /* We need the first 16 bytes
2021 * to check whether this key is valid or not */
2022 pkeylen = strlen (pkey) >> 1;
2026 for (i = 0, j = 0; i < 16; i++) {
2027 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2028 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2031 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2032 header [1] != 0x02 || /* Version (0x02) */
2033 header [2] != 0x00 || /* Reserved (word) */
2034 header [3] != 0x00 ||
2035 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2038 /* Based on this length, we _should_ be able to know if the length is right */
2039 bitlen = read32 (header + 12) >> 3;
2040 if ((bitlen + 16 + 4) != pkeylen)
2043 /* parsing is OK and the public key itself is not requested back */
2047 /* Encode the size of the blob */
2049 if (keylen <= 127) {
2050 arr = (gchar *)g_malloc (keylen + 1);
2051 arr [offset++] = keylen;
2053 arr = (gchar *)g_malloc (keylen + 2);
2054 arr [offset++] = 0x80; /* 10bs */
2055 arr [offset++] = keylen;
2058 for (i = offset, j = 0; i < keylen + offset; i++) {
2059 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2060 arr [i] |= g_ascii_xdigit_value (key [j++]);
2069 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)
2071 gint major, minor, build, revision;
2074 gchar *pkey, *pkeyptr, *encoded, tok [8];
2076 memset (aname, 0, sizeof (MonoAssemblyName));
2079 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2080 if (version_parts < 2 || version_parts > 4)
2083 /* FIXME: we should set build & revision to -1 (instead of 0)
2084 if these are not set in the version string. That way, later on,
2085 we can still determine if these were specified. */
2086 aname->major = major;
2087 aname->minor = minor;
2088 if (version_parts >= 3)
2089 aname->build = build;
2092 if (version_parts == 4)
2093 aname->revision = revision;
2095 aname->revision = 0;
2098 aname->flags = flags;
2100 aname->name = g_strdup (name);
2103 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2104 aname->culture = g_strdup ("");
2106 aname->culture = g_strdup (culture);
2109 if (token && strncmp (token, "null", 4) != 0) {
2112 /* the constant includes the ending NULL, hence the -1 */
2113 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2114 mono_assembly_name_free (aname);
2117 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2118 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2124 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2125 mono_assembly_name_free (aname);
2130 if (save_public_key)
2131 aname->public_key = (guint8*)pkey;
2134 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2138 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2139 // We also need to generate the key token
2140 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2141 encoded = encode_public_tok ((guchar*) tok, 8);
2142 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2145 if (save_public_key)
2146 aname->public_key = (guint8*) pkey;
2155 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2160 parts = g_strsplit (dirname, "_", 3);
2161 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2166 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2172 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2174 char *eqsign = strchr (pair, '=');
2182 *key = (gchar*)pair;
2183 *keylen = eqsign - *key;
2184 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2186 *value = g_strstrip (eqsign + 1);
2191 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2195 gchar *version = NULL;
2197 gchar *culture = NULL;
2199 gchar *token = NULL;
2203 gchar *retargetable = NULL;
2204 gchar *retargetable_uq;
2208 gchar *value, *part_name;
2209 guint32 part_name_len;
2212 gboolean version_defined;
2213 gboolean token_defined;
2215 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2217 if (!is_version_defined)
2218 is_version_defined = &version_defined;
2219 *is_version_defined = FALSE;
2220 if (!is_token_defined)
2221 is_token_defined = &token_defined;
2222 *is_token_defined = FALSE;
2224 parts = tmp = g_strsplit (name, ",", 6);
2225 if (!tmp || !*tmp) {
2230 dllname = g_strstrip (*tmp);
2235 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2236 goto cleanup_and_fail;
2238 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2239 *is_version_defined = TRUE;
2241 if (strlen (version) == 0) {
2242 goto cleanup_and_fail;
2248 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2250 if (strlen (culture) == 0) {
2251 goto cleanup_and_fail;
2257 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2258 *is_token_defined = TRUE;
2260 if (strlen (token) == 0) {
2261 goto cleanup_and_fail;
2267 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2269 if (strlen (key) == 0) {
2270 goto cleanup_and_fail;
2276 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2277 retargetable = value;
2278 retargetable_uq = unquote (retargetable);
2279 if (retargetable_uq != NULL)
2280 retargetable = retargetable_uq;
2282 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2283 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2284 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2285 free (retargetable_uq);
2286 goto cleanup_and_fail;
2289 free (retargetable_uq);
2294 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2296 procarch_uq = unquote (procarch);
2297 if (procarch_uq != NULL)
2298 procarch = procarch_uq;
2300 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2301 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2302 else if (!g_ascii_strcasecmp (procarch, "X86"))
2303 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2304 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2305 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2306 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2307 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2310 goto cleanup_and_fail;
2322 /* if retargetable flag is set, then we must have a fully qualified name */
2323 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2324 goto cleanup_and_fail;
2327 dllname_uq = unquote (dllname);
2328 version_uq = unquote (version);
2329 culture_uq = unquote (culture);
2330 token_uq = unquote (token);
2331 key_uq = unquote (key);
2333 res = build_assembly_name (
2334 dllname_uq == NULL ? dllname : dllname_uq,
2335 version_uq == NULL ? version : version_uq,
2336 culture_uq == NULL ? culture : culture_uq,
2337 token_uq == NULL ? token : token_uq,
2338 key_uq == NULL ? key : key_uq,
2339 flags, arch, aname, save_public_key);
2356 unquote (const char *str)
2364 slen = strlen (str);
2368 if (*str != '\'' && *str != '\"')
2371 end = str + slen - 1;
2375 return g_strndup (str + 1, slen - 2);
2379 * mono_assembly_name_parse:
2380 * @name: name to parse
2381 * @aname: the destination assembly name
2383 * Parses an assembly qualified type name and assigns the name,
2384 * version, culture and token to the provided assembly name object.
2386 * Returns: TRUE if the name could be parsed.
2389 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2391 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2395 * mono_assembly_name_new:
2396 * @name: name to parse
2398 * Allocate a new MonoAssemblyName and fill its values from the
2401 * Returns: a newly allocated structure or NULL if there was any failure.
2404 mono_assembly_name_new (const char *name)
2406 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2407 if (mono_assembly_name_parse (name, aname))
2414 mono_assembly_name_get_name (MonoAssemblyName *aname)
2420 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2422 return aname->culture;
2426 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2428 if (aname->public_key_token [0])
2429 return aname->public_key_token;
2434 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2437 *minor = aname->minor;
2439 *build = aname->build;
2441 *revision = aname->revision;
2442 return aname->major;
2445 static MonoAssembly*
2446 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2448 gchar *fullpath = NULL;
2450 const char* direntry;
2451 MonoAssemblyName gac_aname;
2452 gint major=-1, minor=0, build=0, revision=0;
2453 gboolean exact_version;
2455 dirhandle = g_dir_open (basepath, 0, NULL);
2459 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2461 while ((direntry = g_dir_read_name (dirhandle))) {
2462 gboolean match = TRUE;
2464 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2467 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2470 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2471 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2475 if (exact_version) {
2476 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2477 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2479 else if (gac_aname.major < major)
2481 else if (gac_aname.major == major) {
2482 if (gac_aname.minor < minor)
2484 else if (gac_aname.minor == minor) {
2485 if (gac_aname.build < build)
2487 else if (gac_aname.build == build && gac_aname.revision <= revision)
2494 major = gac_aname.major;
2495 minor = gac_aname.minor;
2496 build = gac_aname.build;
2497 revision = gac_aname.revision;
2499 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2502 mono_assembly_name_free (&gac_aname);
2505 g_dir_close (dirhandle);
2507 if (fullpath == NULL)
2510 MonoAssembly *res = mono_assembly_open (fullpath, status);
2517 * mono_assembly_load_with_partial_name:
2518 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2519 * @status: return status code
2521 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2522 * so it might contain a qualified type name, version, culture and token.
2524 * This will load the assembly from the file whose name is derived from the assembly name
2525 * by appending the .dll extension.
2527 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2528 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2529 * if that fails from the GAC.
2531 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2534 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2538 MonoAssemblyName *aname, base_name;
2539 MonoAssemblyName mapped_aname;
2540 gchar *fullname, *gacpath;
2543 memset (&base_name, 0, sizeof (MonoAssemblyName));
2546 if (!mono_assembly_name_parse (name, aname))
2550 * If no specific version has been requested, make sure we load the
2551 * correct version for system assemblies.
2553 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2554 aname = mono_assembly_remap_version (aname, &mapped_aname);
2556 res = mono_assembly_loaded (aname);
2558 mono_assembly_name_free (aname);
2562 res = invoke_assembly_preload_hook (aname, assemblies_path);
2564 res->in_gac = FALSE;
2565 mono_assembly_name_free (aname);
2569 fullname = g_strdup_printf ("%s.dll", aname->name);
2571 if (extra_gac_paths) {
2572 paths = extra_gac_paths;
2573 while (!res && *paths) {
2574 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2575 res = probe_for_partial_name (gacpath, fullname, aname, status);
2584 mono_assembly_name_free (aname);
2588 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2589 res = probe_for_partial_name (gacpath, fullname, aname, status);
2595 MonoDomain *domain = mono_domain_get ();
2596 MonoReflectionAssembly *refasm;
2598 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2599 if (!mono_error_ok (&error)) {
2601 mono_assembly_name_free (aname);
2602 mono_error_raise_exception (&error); /* FIXME don't raise here */
2606 res = refasm->assembly;
2610 mono_assembly_name_free (aname);
2616 mono_assembly_is_in_gac (const gchar *filename)
2618 const gchar *rootdir;
2622 if (filename == NULL)
2625 for (paths = extra_gac_paths; paths && *paths; paths++) {
2626 if (strstr (*paths, filename) != *paths)
2629 gp = (gchar *) (filename + strlen (*paths));
2630 if (*gp != G_DIR_SEPARATOR)
2633 if (strncmp (gp, "lib", 3))
2636 if (*gp != G_DIR_SEPARATOR)
2639 if (strncmp (gp, "mono", 4))
2642 if (*gp != G_DIR_SEPARATOR)
2645 if (strncmp (gp, "gac", 3))
2648 if (*gp != G_DIR_SEPARATOR)
2654 rootdir = mono_assembly_getrootdir ();
2655 if (strstr (filename, rootdir) != filename)
2658 gp = (gchar *) (filename + strlen (rootdir));
2659 if (*gp != G_DIR_SEPARATOR)
2662 if (strncmp (gp, "mono", 4))
2665 if (*gp != G_DIR_SEPARATOR)
2668 if (strncmp (gp, "gac", 3))
2671 if (*gp != G_DIR_SEPARATOR)
2677 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2680 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2684 if (strstr (aname->name, ".dll")) {
2685 len = strlen (aname->name) - 4;
2686 name = (gchar *)g_malloc (len + 1);
2687 strncpy (name, aname->name, len);
2690 name = g_strdup (aname->name);
2693 culture = g_utf8_strdown (aname->culture, -1);
2695 culture = g_strdup ("");
2697 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2698 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2702 filename = g_strconcat (pname, ".dll", NULL);
2703 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2709 if (extra_gac_paths) {
2710 paths = extra_gac_paths;
2711 while (!image && *paths) {
2712 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2713 "lib", "mono", "gac", subpath, NULL);
2714 image = mono_image_open (fullpath, NULL);
2725 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2726 "mono", "gac", subpath, NULL);
2727 image = mono_image_open (fullpath, NULL);
2734 static MonoAssemblyName*
2735 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2737 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2738 dest_name->major = info->new_version.major;
2739 dest_name->minor = info->new_version.minor;
2740 dest_name->build = info->new_version.build;
2741 dest_name->revision = info->new_version.revision;
2746 /* LOCKING: assembly_binding lock must be held */
2747 static MonoAssemblyBindingInfo*
2748 search_binding_loaded (MonoAssemblyName *aname)
2752 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2753 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2754 if (assembly_binding_maps_name (info, aname))
2761 static inline gboolean
2762 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2764 if (left->major != right->major || left->minor != right->minor ||
2765 left->build != right->build || left->revision != right->revision)
2771 static inline gboolean
2772 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2774 if (left->has_old_version_bottom != right->has_old_version_bottom)
2777 if (left->has_old_version_top != right->has_old_version_top)
2780 if (left->has_new_version != right->has_new_version)
2783 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2786 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2789 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2795 /* LOCKING: assumes all the necessary locks are held */
2797 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2799 MonoAssemblyBindingInfo *info_copy;
2801 MonoAssemblyBindingInfo *info_tmp;
2802 MonoDomain *domain = (MonoDomain*)user_data;
2807 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2808 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2809 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2813 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2814 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2816 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2818 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2820 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2824 get_version_number (int major, int minor)
2826 return major * 256 + minor;
2829 static inline gboolean
2830 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2832 int aname_version_number = get_version_number (aname->major, aname->minor);
2833 if (!info->has_old_version_bottom)
2836 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2839 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2842 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2843 info->major = aname->major;
2844 info->minor = aname->minor;
2849 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2850 static MonoAssemblyBindingInfo*
2851 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2853 MonoAssemblyBindingInfo *info;
2856 if (!domain->assembly_bindings)
2860 for (list = domain->assembly_bindings; list; list = list->next) {
2861 info = (MonoAssemblyBindingInfo *)list->data;
2862 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2868 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2869 info->has_new_version && assembly_binding_maps_name (info, aname))
2870 info->is_valid = TRUE;
2872 info->is_valid = FALSE;
2878 static MonoAssemblyName*
2879 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2881 MonoAssemblyBindingInfo *info, *info2;
2885 if (aname->public_key_token [0] == 0)
2888 domain = mono_domain_get ();
2890 mono_assembly_binding_lock ();
2891 info = search_binding_loaded (aname);
2892 mono_assembly_binding_unlock ();
2895 mono_domain_lock (domain);
2896 info = get_per_domain_assembly_binding_info (domain, aname);
2897 mono_domain_unlock (domain);
2901 if (!check_policy_versions (info, aname))
2904 mono_assembly_bind_version (info, aname, dest_name);
2908 if (domain && domain->setup && domain->setup->configuration_file) {
2909 mono_domain_lock (domain);
2910 if (!domain->assembly_bindings_parsed) {
2911 gchar *domain_config_file_name = mono_string_to_utf8 (domain->setup->configuration_file);
2912 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2914 if (!domain_config_file_path)
2915 domain_config_file_path = domain_config_file_name;
2917 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2918 domain->assembly_bindings_parsed = TRUE;
2919 if (domain_config_file_name != domain_config_file_path)
2920 g_free (domain_config_file_name);
2921 g_free (domain_config_file_path);
2924 info2 = get_per_domain_assembly_binding_info (domain, aname);
2927 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2928 info->name = g_strdup (info2->name);
2929 info->culture = g_strdup (info2->culture);
2930 info->domain_id = domain->domain_id;
2933 mono_domain_unlock (domain);
2937 info = g_new0 (MonoAssemblyBindingInfo, 1);
2938 info->major = aname->major;
2939 info->minor = aname->minor;
2942 if (!info->is_valid) {
2943 ppimage = mono_assembly_load_publisher_policy (aname);
2945 get_publisher_policy_info (ppimage, aname, info);
2946 mono_image_close (ppimage);
2950 /* Define default error value if needed */
2951 if (!info->is_valid) {
2952 info->name = g_strdup (aname->name);
2953 info->culture = g_strdup (aname->culture);
2954 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2957 mono_assembly_binding_lock ();
2958 info2 = search_binding_loaded (aname);
2960 /* This binding was added by another thread
2962 mono_assembly_binding_info_free (info);
2967 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2969 mono_assembly_binding_unlock ();
2971 if (!info->is_valid || !check_policy_versions (info, aname))
2974 mono_assembly_bind_version (info, aname, dest_name);
2979 * mono_assembly_load_from_gac
2981 * @aname: The assembly name object
2983 static MonoAssembly*
2984 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
2986 MonoAssembly *result = NULL;
2987 gchar *name, *version, *culture, *fullpath, *subpath;
2992 if (aname->public_key_token [0] == 0) {
2996 if (strstr (aname->name, ".dll")) {
2997 len = strlen (filename) - 4;
2998 name = (gchar *)g_malloc (len + 1);
2999 strncpy (name, aname->name, len);
3002 name = g_strdup (aname->name);
3005 if (aname->culture) {
3006 culture = g_utf8_strdown (aname->culture, -1);
3008 culture = g_strdup ("");
3011 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3012 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3013 aname->minor, aname->build, aname->revision,
3017 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3022 if (extra_gac_paths) {
3023 paths = extra_gac_paths;
3024 while (!result && *paths) {
3025 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3026 result = mono_assembly_open_full (fullpath, status, refonly);
3033 result->in_gac = TRUE;
3038 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3039 "mono", "gac", subpath, NULL);
3040 result = mono_assembly_open_full (fullpath, status, refonly);
3044 result->in_gac = TRUE;
3052 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3055 MonoAssemblyName *aname;
3058 /* g_print ("corlib already loaded\n"); */
3062 // In native client, Corlib is embedded in the executable as static variable corlibData
3063 #if defined(__native_client__)
3064 if (corlibData != NULL && corlibSize != 0) {
3066 /* First "FALSE" instructs mono not to make a copy. */
3067 /* Second "FALSE" says this is not just a ref. */
3068 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3069 if (image == NULL || status != 0)
3070 g_print("mono_image_open_from_data_full failed: %d\n", status);
3071 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3072 if (corlib == NULL || status != 0)
3073 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3079 // A nonstandard preload hook may provide a special mscorlib assembly
3080 aname = mono_assembly_name_new ("mscorlib.dll");
3081 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3082 mono_assembly_name_free (aname);
3085 goto return_corlib_and_facades;
3087 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3088 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3089 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3091 goto return_corlib_and_facades;
3094 /* Normal case: Load corlib from mono/<version> */
3095 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3096 if (assemblies_path) { // Custom assemblies path
3097 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3099 g_free (corlib_file);
3100 goto return_corlib_and_facades;
3103 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3104 g_free (corlib_file);
3106 return_corlib_and_facades:
3107 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3108 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3114 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3115 const char *basedir,
3116 MonoImageOpenStatus *status,
3119 MonoAssembly *result;
3120 char *fullpath, *filename;
3121 MonoAssemblyName maped_aname;
3122 MonoAssemblyName maped_name_pp;
3127 aname = mono_assembly_remap_version (aname, &maped_aname);
3129 /* Reflection only assemblies don't get assembly binding */
3131 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3133 result = mono_assembly_loaded_full (aname, refonly);
3137 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3139 result->in_gac = FALSE;
3143 /* Currently we retrieve the loaded corlib for reflection
3144 * only requests, like a common reflection only assembly
3146 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3147 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3150 len = strlen (aname->name);
3151 for (ext_index = 0; ext_index < 2; ext_index ++) {
3152 ext = ext_index == 0 ? ".dll" : ".exe";
3153 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3154 filename = g_strdup (aname->name);
3155 /* Don't try appending .dll/.exe if it already has one of those extensions */
3158 filename = g_strconcat (aname->name, ext, NULL);
3161 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3168 fullpath = g_build_filename (basedir, filename, NULL);
3169 result = mono_assembly_open_full (fullpath, status, refonly);
3172 result->in_gac = FALSE;
3178 result = load_in_path (filename, default_path, status, refonly);
3180 result->in_gac = FALSE;
3190 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3192 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3195 /* Try a postload search hook */
3196 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3201 * mono_assembly_load_full:
3202 * @aname: A MonoAssemblyName with the assembly name to load.
3203 * @basedir: A directory to look up the assembly at.
3204 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3205 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3207 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3208 * attempts to load the assembly from that directory before probing the standard locations.
3210 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3211 * assembly binding takes place.
3213 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3214 * value pointed by status is updated with an error code.
3217 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3219 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3223 * mono_assembly_load:
3224 * @aname: A MonoAssemblyName with the assembly name to load.
3225 * @basedir: A directory to look up the assembly at.
3226 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3228 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3229 * attempts to load the assembly from that directory before probing the standard locations.
3231 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3232 * value pointed by status is updated with an error code.
3235 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3237 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3241 * mono_assembly_loaded_full:
3242 * @aname: an assembly to look for.
3243 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3245 * This is used to determine if the specified assembly has been loaded
3246 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3247 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3250 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3253 MonoAssemblyName maped_aname;
3255 aname = mono_assembly_remap_version (aname, &maped_aname);
3257 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3263 * mono_assembly_loaded:
3264 * @aname: an assembly to look for.
3266 * This is used to determine if the specified assembly has been loaded
3268 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3269 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3272 mono_assembly_loaded (MonoAssemblyName *aname)
3274 return mono_assembly_loaded_full (aname, FALSE);
3278 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3280 if (assembly == NULL || assembly == REFERENCE_MISSING)
3283 if (assembly_is_dynamic (assembly)) {
3285 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3286 for (i = 0; i < dynimg->image.module_count; ++i)
3287 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3288 mono_dynamic_image_release_gc_roots (dynimg);
3293 * Returns whether mono_assembly_close_finish() must be called as
3294 * well. See comment for mono_image_close_except_pools() for why we
3295 * unload in two steps.
3298 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3301 g_return_val_if_fail (assembly != NULL, FALSE);
3303 if (assembly == REFERENCE_MISSING)
3306 /* Might be 0 already */
3307 if (InterlockedDecrement (&assembly->ref_count) > 0)
3310 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3312 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3314 mono_debug_close_image (assembly->image);
3316 mono_assemblies_lock ();
3317 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3318 mono_assemblies_unlock ();
3320 assembly->image->assembly = NULL;
3322 if (!mono_image_close_except_pools (assembly->image))
3323 assembly->image = NULL;
3325 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3326 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3327 mono_assembly_name_free (fname);
3330 g_slist_free (assembly->friend_assembly_names);
3331 g_free (assembly->basedir);
3333 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3339 mono_assembly_close_finish (MonoAssembly *assembly)
3341 g_assert (assembly && assembly != REFERENCE_MISSING);
3343 if (assembly->image)
3344 mono_image_close_finish (assembly->image);
3346 if (assembly_is_dynamic (assembly)) {
3347 g_free ((char*)assembly->aname.culture);
3354 * mono_assembly_close:
3355 * @assembly: the assembly to release.
3357 * This method releases a reference to the @assembly. The assembly is
3358 * only released when all the outstanding references to it are released.
3361 mono_assembly_close (MonoAssembly *assembly)
3363 if (mono_assembly_close_except_image_pools (assembly))
3364 mono_assembly_close_finish (assembly);
3368 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3370 return mono_image_load_file_for_image (assembly->image, idx);
3374 * mono_assembly_foreach:
3375 * @func: function to invoke for each assembly loaded
3376 * @user_data: data passed to the callback
3378 * Invokes the provided @func callback for each assembly loaded into
3379 * the runtime. The first parameter passed to the callback is the
3380 * `MonoAssembly*`, and the second parameter is the @user_data.
3382 * This is done for all assemblies loaded in the runtime, not just
3383 * those loaded in the current application domain.
3386 mono_assembly_foreach (GFunc func, gpointer user_data)
3391 * We make a copy of the list to avoid calling the callback inside the
3392 * lock, which could lead to deadlocks.
3394 mono_assemblies_lock ();
3395 copy = g_list_copy (loaded_assemblies);
3396 mono_assemblies_unlock ();
3398 g_list_foreach (loaded_assemblies, func, user_data);
3404 * mono_assemblies_cleanup:
3406 * Free all resources used by this module.
3409 mono_assemblies_cleanup (void)
3413 mono_os_mutex_destroy (&assemblies_mutex);
3414 mono_os_mutex_destroy (&assembly_binding_mutex);
3416 for (l = loaded_assembly_bindings; l; l = l->next) {
3417 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3419 mono_assembly_binding_info_free (info);
3422 g_slist_free (loaded_assembly_bindings);
3424 free_assembly_load_hooks ();
3425 free_assembly_search_hooks ();
3426 free_assembly_preload_hooks ();
3429 /*LOCKING takes the assembly_binding lock*/
3431 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3435 mono_assembly_binding_lock ();
3436 iter = &loaded_assembly_bindings;
3439 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3441 if (info->domain_id == domain_id) {
3443 mono_assembly_binding_info_free (info);
3450 mono_assembly_binding_unlock ();
3454 * Holds the assembly of the application, for
3455 * System.Diagnostics.Process::MainModule
3457 static MonoAssembly *main_assembly=NULL;
3460 mono_assembly_set_main (MonoAssembly *assembly)
3462 main_assembly = assembly;
3466 * mono_assembly_get_main:
3468 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3471 mono_assembly_get_main (void)
3473 return (main_assembly);
3477 * mono_assembly_get_image:
3478 * @assembly: The assembly to retrieve the image from
3480 * Returns: the MonoImage associated with this assembly.
3483 mono_assembly_get_image (MonoAssembly *assembly)
3485 return assembly->image;
3489 * mono_assembly_get_name:
3490 * @assembly: The assembly to retrieve the name from
3492 * The returned name's lifetime is the same as @assembly's.
3494 * Returns: the MonoAssemblyName associated with this assembly.
3497 mono_assembly_get_name (MonoAssembly *assembly)
3499 return &assembly->aname;
3503 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3505 bundles = assemblies;
3508 #define MONO_DECLSEC_FORMAT_10 0x3C
3509 #define MONO_DECLSEC_FORMAT_20 0x2E
3510 #define MONO_DECLSEC_FIELD 0x53
3511 #define MONO_DECLSEC_PROPERTY 0x54
3513 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3514 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3515 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3516 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3517 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3520 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3524 case MONO_DECLSEC_PROPERTY:
3526 case MONO_DECLSEC_FIELD:
3528 *abort_decoding = TRUE;
3533 if (*p++ != MONO_TYPE_BOOLEAN) {
3534 *abort_decoding = TRUE;
3538 /* property name length */
3539 len = mono_metadata_decode_value (p, &p);
3541 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3552 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3554 int i, j, num, len, params_len;
3556 if (*p == MONO_DECLSEC_FORMAT_10) {
3557 gsize read, written;
3558 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3560 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3566 if (*p++ != MONO_DECLSEC_FORMAT_20)
3569 /* number of encoded permission attributes */
3570 num = mono_metadata_decode_value (p, &p);
3571 for (i = 0; i < num; ++i) {
3572 gboolean is_valid = FALSE;
3573 gboolean abort_decoding = FALSE;
3575 /* attribute name length */
3576 len = mono_metadata_decode_value (p, &p);
3578 /* We don't really need to fully decode the type. Comparing the name is enough */
3579 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3583 /*size of the params table*/
3584 params_len = mono_metadata_decode_value (p, &p);
3586 const char *params_end = p + params_len;
3588 /* number of parameters */
3589 len = mono_metadata_decode_value (p, &p);
3591 for (j = 0; j < len; ++j) {
3592 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3608 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3611 guint32 cols [MONO_DECL_SECURITY_SIZE];
3615 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3616 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3618 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3620 for (i = 0; i < t->rows; ++i) {
3621 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3622 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3624 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3627 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3628 len = mono_metadata_decode_blob_size (blob, &blob);
3632 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3633 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3638 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);