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)
208 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
210 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
212 mono_assembly_is_in_gac (const gchar *filanem);
215 encode_public_tok (const guchar *token, gint32 len)
217 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
221 res = (gchar *)g_malloc (len * 2 + 1);
222 for (i = 0; i < len; i++) {
223 res [i * 2] = allowed [token [i] >> 4];
224 res [i * 2 + 1] = allowed [token [i] & 0xF];
231 * mono_public_tokens_are_equal:
232 * @pubt1: first public key token
233 * @pubt2: second public key token
235 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
239 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
241 return memcmp (pubt1, pubt2, 16) == 0;
245 * mono_set_assemblies_path:
246 * @path: list of paths that contain directories where Mono will look for assemblies
248 * Use this method to override the standard assembly lookup system and
249 * override any assemblies coming from the GAC. This is the method
250 * that supports the MONO_PATH variable.
252 * Notice that MONO_PATH and this method are really a very bad idea as
253 * it prevents the GAC from working and it prevents the standard
254 * resolution mechanisms from working. Nonetheless, for some debugging
255 * situations and bootstrapping setups, this is useful to have.
258 mono_set_assemblies_path (const char* path)
260 char **splitted, **dest;
262 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
264 g_strfreev (assemblies_path);
265 assemblies_path = dest = splitted;
267 char *tmp = *splitted;
269 *dest++ = mono_path_canonicalize (tmp);
275 if (g_getenv ("MONO_DEBUG") == NULL)
278 splitted = assemblies_path;
280 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
281 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
287 /* Native Client can't get this info from an environment variable so */
288 /* it's passed in to the runtime, or set manually by embedding code. */
289 #ifdef __native_client__
290 char* nacl_mono_path = NULL;
294 check_path_env (void)
297 path = g_getenv ("MONO_PATH");
298 #ifdef __native_client__
300 path = nacl_mono_path;
302 if (!path || assemblies_path != NULL)
305 mono_set_assemblies_path(path);
309 check_extra_gac_path_env (void) {
311 char **splitted, **dest;
313 path = g_getenv ("MONO_GAC_PREFIX");
317 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
319 g_strfreev (extra_gac_paths);
320 extra_gac_paths = dest = splitted;
328 if (g_getenv ("MONO_DEBUG") == NULL)
332 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
333 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
340 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
342 if (!info || !info->name)
345 if (strcmp (info->name, aname->name))
348 if (info->major != aname->major || info->minor != aname->minor)
351 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
354 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
357 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
364 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
370 g_free (info->culture);
374 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
377 guint32 cols [MONO_MANIFEST_SIZE];
378 const gchar *filename;
379 gchar *subpath, *fullpath;
381 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
382 /* MS Impl. accepts policy assemblies with more than
383 * one manifest resource, and only takes the first one */
385 binding_info->is_valid = FALSE;
389 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
390 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
391 binding_info->is_valid = FALSE;
395 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
396 g_assert (filename != NULL);
398 subpath = g_path_get_dirname (image->name);
399 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
400 mono_config_parse_publisher_policy (fullpath, binding_info);
404 /* Define the optional elements/attributes before checking */
405 if (!binding_info->culture)
406 binding_info->culture = g_strdup ("");
408 /* Check that the most important elements/attributes exist */
409 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
410 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
411 mono_assembly_binding_info_free (binding_info);
412 binding_info->is_valid = FALSE;
416 binding_info->is_valid = TRUE;
420 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
422 if (v->major > aname->major)
424 else if (v->major < aname->major)
427 if (v->minor > aname->minor)
429 else if (v->minor < aname->minor)
432 if (v->build > aname->build)
434 else if (v->build < aname->build)
437 if (v->revision > aname->revision)
439 else if (v->revision < aname->revision)
446 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
451 /* If has_old_version_top doesn't exist, we don't have an interval */
452 if (!info->has_old_version_top) {
453 if (compare_versions (&info->old_version_bottom, name) == 0)
459 /* Check that the version defined by name is valid for the interval */
460 if (compare_versions (&info->old_version_top, name) < 0)
463 /* We should be greater or equal than the small version */
464 if (compare_versions (&info->old_version_bottom, name) > 0)
471 * mono_assembly_names_equal:
473 * @r: second assembly.
475 * Compares two MonoAssemblyNames and returns whether they are equal.
477 * This compares the names, the cultures, the release version and their
480 * Returns: TRUE if both assembly names are equal.
483 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
485 if (!l->name || !r->name)
488 if (strcmp (l->name, r->name))
491 if (l->culture && r->culture && strcmp (l->culture, r->culture))
494 if (l->major != r->major || l->minor != r->minor ||
495 l->build != r->build || l->revision != r->revision)
496 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)))
499 if (!l->public_key_token [0] || !r->public_key_token [0])
502 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
508 static MonoAssembly *
509 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
513 MonoAssembly *result;
515 for (i = 0; search_path [i]; ++i) {
516 fullpath = g_build_filename (search_path [i], basename, NULL);
517 result = mono_assembly_open_full (fullpath, status, refonly);
526 * mono_assembly_setrootdir:
527 * @root_dir: The pathname of the root directory where we will locate assemblies
529 * This routine sets the internal default root directory for looking up
532 * This is used by Windows installations to compute dynamically the
533 * place where the Mono assemblies are located.
537 mono_assembly_setrootdir (const char *root_dir)
540 * Override the MONO_ASSEMBLIES directory configured at compile time.
542 /* Leak if called more than once */
543 default_path [0] = g_strdup (root_dir);
547 * mono_assembly_getrootdir:
549 * Obtains the root directory used for looking up assemblies.
551 * Returns: a string with the directory, this string should not be freed.
553 G_CONST_RETURN gchar *
554 mono_assembly_getrootdir (void)
556 return default_path [0];
561 * @assembly_dir: the base directory for assemblies
562 * @config_dir: the base directory for configuration files
564 * This routine is used internally and by developers embedding
565 * the runtime into their own applications.
567 * There are a number of cases to consider: Mono as a system-installed
568 * package that is available on the location preconfigured or Mono in
569 * a relocated location.
571 * If you are using a system-installed Mono, you can pass NULL
572 * to both parameters. If you are not, you should compute both
573 * directory values and call this routine.
575 * The values for a given PREFIX are:
577 * assembly_dir: PREFIX/lib
578 * config_dir: PREFIX/etc
580 * Notice that embedders that use Mono in a relocated way must
581 * compute the location at runtime, as they will be in control
582 * of where Mono is installed.
585 mono_set_dirs (const char *assembly_dir, const char *config_dir)
587 if (assembly_dir == NULL)
588 assembly_dir = mono_config_get_assemblies_dir ();
589 if (config_dir == NULL)
590 config_dir = mono_config_get_cfg_dir ();
591 mono_assembly_setrootdir (assembly_dir);
592 mono_set_config_dir (config_dir);
598 compute_base (char *path)
600 char *p = strrchr (path, '/');
604 /* Not a well known Mono executable, we are embedded, cant guess the base */
605 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
609 p = strrchr (path, '/');
613 if (strcmp (p, "/bin") != 0)
622 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
625 static G_GNUC_UNUSED void
629 char *config, *lib, *mono;
634 * Only /usr prefix is treated specially
636 bindir = mono_config_get_bin_dir ();
638 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
643 config = g_build_filename (base, "etc", NULL);
644 lib = g_build_filename (base, "lib", NULL);
645 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
646 if (stat (mono, &buf) == -1)
649 mono_set_dirs (lib, config);
657 #endif /* HOST_WIN32 */
662 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
663 * this auto-detects the prefix where Mono was installed.
666 mono_set_rootdir (void)
668 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
669 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
672 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
676 * _NSGetExecutablePath may return -1 to indicate buf is not large
677 * enough, but we ignore that case to avoid having to do extra dynamic
678 * allocation for the path and hope that 4096 is enough - this is
679 * ok in the Linux/Solaris case below at least...
683 guint buf_size = sizeof (buf);
686 if (_NSGetExecutablePath (buf, &buf_size) == 0)
687 name = g_strdup (buf);
696 resolvedname = mono_path_resolve_symlinks (name);
698 bindir = g_path_get_dirname (resolvedname);
699 installdir = g_path_get_dirname (bindir);
700 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
702 config = g_build_filename (root, "..", "etc", NULL);
704 mono_set_dirs (root, config);
706 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
707 mono_set_dirs (root, config);
717 g_free (resolvedname);
718 #elif defined(DISABLE_MONO_AUTODETECTION)
726 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
734 /* Solaris 10 style */
735 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
736 s = readlink (str, buf, sizeof (buf)-1);
748 * mono_assemblies_init:
750 * Initialize global variables used by this module.
753 mono_assemblies_init (void)
756 * Initialize our internal paths if we have not been initialized yet.
757 * This happens when embedders use Mono.
759 if (mono_assembly_getrootdir () == NULL)
763 check_extra_gac_path_env ();
765 mono_os_mutex_init_recursive (&assemblies_mutex);
766 mono_os_mutex_init (&assembly_binding_mutex);
770 mono_assembly_binding_lock (void)
772 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
776 mono_assembly_binding_unlock (void)
778 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
782 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
784 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
785 guint32 cols [MONO_ASSEMBLY_SIZE];
786 gint32 machine, flags;
791 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
794 aname->hash_value = NULL;
795 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
796 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
797 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
798 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
799 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
800 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
801 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
802 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
803 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
804 guchar* token = (guchar *)g_malloc (8);
809 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
810 len = mono_metadata_decode_blob_size (pkey, &pkey);
811 aname->public_key = (guchar*)pkey;
813 mono_digest_get_public_token (token, aname->public_key, len);
814 encoded = encode_public_tok (token, 8);
815 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
821 aname->public_key = NULL;
822 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
825 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
826 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
829 aname->public_key = 0;
831 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
832 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
834 case COFF_MACHINE_I386:
835 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
836 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
837 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
838 else if ((flags & 0x70) == 0x70)
839 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
841 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
843 case COFF_MACHINE_IA64:
844 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
846 case COFF_MACHINE_AMD64:
847 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
849 case COFF_MACHINE_ARM:
850 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
860 * mono_stringify_assembly_name:
861 * @aname: the assembly name.
863 * Convert @aname into its string format. The returned string is dynamically
864 * allocated and should be freed by the caller.
866 * Returns: a newly allocated string with a string representation of
870 mono_stringify_assembly_name (MonoAssemblyName *aname)
872 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
874 return g_strdup_printf (
875 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
876 quote, aname->name, quote,
877 aname->major, aname->minor, aname->build, aname->revision,
878 aname->culture && *aname->culture? aname->culture: "neutral",
879 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
880 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
884 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
886 const gchar *public_tok;
889 public_tok = mono_metadata_blob_heap (image, key_index);
890 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
892 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
894 mono_digest_get_public_token (token, (guchar*)public_tok, len);
895 return encode_public_tok (token, 8);
898 return encode_public_tok ((guchar*)public_tok, len);
902 * mono_assembly_addref:
903 * @assemnly: the assembly to reference
905 * This routine increments the reference count on a MonoAssembly.
906 * The reference count is reduced every time the method mono_assembly_close() is
910 mono_assembly_addref (MonoAssembly *assembly)
912 InterlockedIncrement (&assembly->ref_count);
916 * CAUTION: This table must be kept in sync with
917 * ivkm/reflect/Fusion.cs
920 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
921 #define WINFX_KEY "31bf3856ad364e35"
922 #define ECMA_KEY "b77a5c561934e089"
923 #define MSFINAL_KEY "b03f5f7f11d50a3a"
931 static KeyRemapEntry key_remap_table[] = {
932 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
933 { "System", SILVERLIGHT_KEY, ECMA_KEY },
934 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
935 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
936 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
937 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
938 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
939 { "System.Numerics", WINFX_KEY, ECMA_KEY },
940 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
941 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
942 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
943 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
944 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
945 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
946 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
950 remap_keys (MonoAssemblyName *aname)
953 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
954 const KeyRemapEntry *entry = &key_remap_table [i];
956 if (strcmp (aname->name, entry->name) ||
957 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
960 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
962 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
963 "Remapped public key token of retargetable assembly %s from %s to %s",
964 aname->name, entry->from, entry->to);
969 static MonoAssemblyName *
970 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
972 const MonoRuntimeInfo *current_runtime;
973 int pos, first, last;
975 if (aname->name == NULL) return aname;
977 current_runtime = mono_get_runtime_info ();
979 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
980 const AssemblyVersionSet* vset;
982 /* Remap to current runtime */
983 vset = ¤t_runtime->version_sets [0];
985 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
986 dest_aname->major = vset->major;
987 dest_aname->minor = vset->minor;
988 dest_aname->build = vset->build;
989 dest_aname->revision = vset->revision;
990 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
992 /* Remap assembly name */
993 if (!strcmp (aname->name, "System.Net"))
994 dest_aname->name = g_strdup ("System");
996 remap_keys (dest_aname);
998 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
999 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1001 aname->major, aname->minor, aname->build, aname->revision,
1003 vset->major, vset->minor, vset->build, vset->revision
1009 #ifndef DISABLE_ASSEMBLY_REMAPPING
1011 last = G_N_ELEMENTS (framework_assemblies) - 1;
1013 while (first <= last) {
1015 pos = first + (last - first) / 2;
1016 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1018 const AssemblyVersionSet* vset;
1019 int index = framework_assemblies[pos].version_set_index;
1020 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1021 vset = ¤t_runtime->version_sets [index];
1023 if (aname->major == vset->major && aname->minor == vset->minor &&
1024 aname->build == vset->build && aname->revision == vset->revision)
1027 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1030 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1031 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1032 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1034 aname->major, aname->minor, aname->build, aname->revision,
1035 vset->major, vset->minor, vset->build, vset->revision
1038 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1039 dest_aname->major = vset->major;
1040 dest_aname->minor = vset->minor;
1041 dest_aname->build = vset->build;
1042 dest_aname->revision = vset->revision;
1043 if (framework_assemblies[pos].new_assembly_name != NULL) {
1044 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1045 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1046 "The assembly name %s was remapped to %s",
1051 } else if (res < 0) {
1063 * mono_assembly_get_assemblyref:
1064 * @image: pointer to the MonoImage to extract the information from.
1065 * @index: index to the assembly reference in the image.
1066 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1068 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1071 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1074 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1077 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1079 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1081 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1082 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1083 aname->hash_value = hash;
1084 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1085 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1086 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1087 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1088 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1089 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1090 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1092 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1093 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1094 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1097 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1102 mono_assembly_load_reference (MonoImage *image, int index)
1104 MonoAssembly *reference;
1105 MonoAssemblyName aname;
1106 MonoImageOpenStatus status;
1109 * image->references is shared between threads, so we need to access
1110 * it inside a critical section.
1112 mono_assemblies_lock ();
1113 if (!image->references) {
1114 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1116 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1117 image->nreferences = t->rows;
1119 reference = image->references [index];
1120 mono_assemblies_unlock ();
1124 mono_assembly_get_assemblyref (image, index, &aname);
1126 if (image->assembly && image->assembly->ref_only) {
1127 /* We use the loaded corlib */
1128 if (!strcmp (aname.name, "mscorlib"))
1129 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1131 reference = mono_assembly_loaded_full (&aname, TRUE);
1133 /* Try a postload search hook */
1134 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1138 * Here we must advice that the error was due to
1139 * a non loaded reference using the ReflectionOnly api
1142 reference = (MonoAssembly *)REFERENCE_MISSING;
1144 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1145 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1146 * accordingly, it would fail on the MS runtime before).
1147 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1148 * example bug-349190.2.cs and who knows how much more code in the wild.
1150 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1151 if (!reference && image->assembly)
1152 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1155 if (reference == NULL){
1158 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1159 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 : "" );
1160 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1161 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1162 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1163 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1164 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1165 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1167 extra_msg = g_strdup ("");
1170 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1171 " Assembly: %s (assemblyref_index=%d)\n"
1172 " Version: %d.%d.%d.%d\n"
1173 " Public Key: %s\n%s",
1174 image->name, aname.name, index,
1175 aname.major, aname.minor, aname.build, aname.revision,
1176 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1180 mono_assemblies_lock ();
1181 if (reference == NULL) {
1182 /* Flag as not found */
1183 reference = (MonoAssembly *)REFERENCE_MISSING;
1186 if (!image->references [index]) {
1187 if (reference != REFERENCE_MISSING){
1188 mono_assembly_addref (reference);
1189 if (image->assembly)
1190 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1191 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1193 if (image->assembly)
1194 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1195 image->assembly->aname.name, image->assembly);
1198 image->references [index] = reference;
1200 mono_assemblies_unlock ();
1202 if (image->references [index] != reference) {
1203 /* Somebody loaded it before us */
1204 mono_assembly_close (reference);
1209 * mono_assembly_load_references:
1212 * @deprecated: There is no reason to use this method anymore, it does nothing
1214 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1217 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1219 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1220 *status = MONO_IMAGE_OK;
1223 typedef struct AssemblyLoadHook AssemblyLoadHook;
1224 struct AssemblyLoadHook {
1225 AssemblyLoadHook *next;
1226 MonoAssemblyLoadFunc func;
1230 AssemblyLoadHook *assembly_load_hook = NULL;
1233 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1235 AssemblyLoadHook *hook;
1237 for (hook = assembly_load_hook; hook; hook = hook->next) {
1238 hook->func (ass, hook->user_data);
1243 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1245 AssemblyLoadHook *hook;
1247 g_return_if_fail (func != NULL);
1249 hook = g_new0 (AssemblyLoadHook, 1);
1251 hook->user_data = user_data;
1252 hook->next = assembly_load_hook;
1253 assembly_load_hook = hook;
1257 free_assembly_load_hooks (void)
1259 AssemblyLoadHook *hook, *next;
1261 for (hook = assembly_load_hook; hook; hook = next) {
1267 typedef struct AssemblySearchHook AssemblySearchHook;
1268 struct AssemblySearchHook {
1269 AssemblySearchHook *next;
1270 MonoAssemblySearchFunc func;
1276 AssemblySearchHook *assembly_search_hook = NULL;
1278 static MonoAssembly*
1279 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1281 AssemblySearchHook *hook;
1283 for (hook = assembly_search_hook; hook; hook = hook->next) {
1284 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1287 * A little explanation is in order here.
1289 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1290 * The embedding API exposes a search hook that doesn't take such argument.
1292 * The original fix would call the default search hook before all the registered ones and pass
1293 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1294 * rely on. Which is the ordering between user hooks and the default runtime hook.
1296 * Registering the hook after mono_jit_init would let your hook run before the default one and
1297 * when using it to handle non standard app layouts this could save your app from a massive amount
1298 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1299 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1301 * So what's the fix? We register the default hook using regular means and special case it when iterating
1302 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1305 if (hook->func == (void*)mono_domain_assembly_postload_search)
1306 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1308 ass = hook->func (aname, hook->user_data);
1318 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1320 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1324 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1326 AssemblySearchHook *hook;
1328 g_return_if_fail (func != NULL);
1330 hook = g_new0 (AssemblySearchHook, 1);
1332 hook->user_data = user_data;
1333 hook->refonly = refonly;
1334 hook->postload = postload;
1335 hook->next = assembly_search_hook;
1336 assembly_search_hook = hook;
1340 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1342 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1346 free_assembly_search_hooks (void)
1348 AssemblySearchHook *hook, *next;
1350 for (hook = assembly_search_hook; hook; hook = next) {
1357 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1359 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1363 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1365 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1369 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1371 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1374 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1375 struct AssemblyPreLoadHook {
1376 AssemblyPreLoadHook *next;
1377 MonoAssemblyPreLoadFunc func;
1381 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1382 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1384 static MonoAssembly *
1385 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1387 AssemblyPreLoadHook *hook;
1388 MonoAssembly *assembly;
1390 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1391 assembly = hook->func (aname, assemblies_path, hook->user_data);
1392 if (assembly != NULL)
1399 static MonoAssembly *
1400 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1402 AssemblyPreLoadHook *hook;
1403 MonoAssembly *assembly;
1405 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1406 assembly = hook->func (aname, assemblies_path, hook->user_data);
1407 if (assembly != NULL)
1415 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1417 AssemblyPreLoadHook *hook;
1419 g_return_if_fail (func != NULL);
1421 hook = g_new0 (AssemblyPreLoadHook, 1);
1423 hook->user_data = user_data;
1424 hook->next = assembly_preload_hook;
1425 assembly_preload_hook = hook;
1429 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1431 AssemblyPreLoadHook *hook;
1433 g_return_if_fail (func != NULL);
1435 hook = g_new0 (AssemblyPreLoadHook, 1);
1437 hook->user_data = user_data;
1438 hook->next = assembly_refonly_preload_hook;
1439 assembly_refonly_preload_hook = hook;
1443 free_assembly_preload_hooks (void)
1445 AssemblyPreLoadHook *hook, *next;
1447 for (hook = assembly_preload_hook; hook; hook = next) {
1452 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1459 absolute_dir (const gchar *filename)
1470 if (g_path_is_absolute (filename)) {
1471 part = g_path_get_dirname (filename);
1472 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1477 cwd = g_get_current_dir ();
1478 mixed = g_build_filename (cwd, filename, NULL);
1479 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1484 for (i = 0; (part = parts [i]) != NULL; i++) {
1485 if (!strcmp (part, "."))
1488 if (!strcmp (part, "..")) {
1489 if (list && list->next) /* Don't remove root */
1490 list = g_list_delete_link (list, list);
1492 list = g_list_prepend (list, part);
1496 result = g_string_new ("");
1497 list = g_list_reverse (list);
1499 /* Ignores last data pointer, which should be the filename */
1500 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1502 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1507 g_string_free (result, FALSE);
1512 return g_strdup (".");
1519 * mono_assembly_open_from_bundle:
1520 * @filename: Filename requested
1521 * @status: return status code
1523 * This routine tries to open the assembly specified by `filename' from the
1524 * defined bundles, if found, returns the MonoImage for it, if not found
1528 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1532 MonoImage *image = NULL;
1535 * we do a very simple search for bundled assemblies: it's not a general
1536 * purpose assembly loading mechanism.
1542 name = g_path_get_basename (filename);
1544 mono_assemblies_lock ();
1545 for (i = 0; !image && bundles [i]; ++i) {
1546 if (strcmp (bundles [i]->name, name) == 0) {
1547 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1551 mono_assemblies_unlock ();
1553 mono_image_addref (image);
1554 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
1563 * mono_assemblies_open_full:
1564 * @filename: the file to load
1565 * @status: return status code
1566 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1568 * This loads an assembly from the specified @filename. The @filename allows
1569 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1570 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1571 * is treated as a local path.
1573 * First, an attempt is made to load the assembly from the bundled executable (for those
1574 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1575 * assembly has been registered as an embedded assembly). If this is not the case, then
1576 * the assembly is loaded from disk using `api:mono_image_open_full`.
1578 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1579 * the assembly is made.
1581 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1582 * the `System.Reflection` API.
1584 * Returns: NULL on error, with the @status set to an error code, or a pointer
1588 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1592 MonoImageOpenStatus def_status;
1595 gboolean loaded_from_bundle;
1597 g_return_val_if_fail (filename != NULL, NULL);
1600 status = &def_status;
1601 *status = MONO_IMAGE_OK;
1603 if (strncmp (filename, "file://", 7) == 0) {
1604 GError *error = NULL;
1605 gchar *uri = (gchar *) filename;
1609 * MS allows file://c:/... and fails on file://localhost/c:/...
1610 * They also throw an IndexOutOfRangeException if "file://"
1613 uri = g_strdup_printf ("file:///%s", uri + 7);
1616 uri = mono_escape_uri_string (tmpuri);
1617 fname = g_filename_from_uri (uri, NULL, &error);
1620 if (tmpuri != filename)
1623 if (error != NULL) {
1624 g_warning ("%s\n", error->message);
1625 g_error_free (error);
1626 fname = g_strdup (filename);
1629 fname = g_strdup (filename);
1632 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1633 "Assembly Loader probing location: '%s'.", fname);
1636 if (!mono_assembly_is_in_gac (fname)) {
1638 new_fname = mono_make_shadow_copy (fname, &error);
1639 mono_error_raise_exception (&error); /* FIXME don't raise here */
1641 if (new_fname && new_fname != fname) {
1644 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1645 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1650 // If VM built with mkbundle
1651 loaded_from_bundle = FALSE;
1652 if (bundles != NULL) {
1653 image = mono_assembly_open_from_bundle (fname, status, refonly);
1654 loaded_from_bundle = image != NULL;
1658 image = mono_image_open_full (fname, status, refonly);
1661 if (*status == MONO_IMAGE_OK)
1662 *status = MONO_IMAGE_ERROR_ERRNO;
1667 if (image->assembly) {
1668 /* Already loaded by another appdomain */
1669 mono_assembly_invoke_load_hook (image->assembly);
1670 mono_image_close (image);
1672 return image->assembly;
1675 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1678 if (!loaded_from_bundle)
1679 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1680 "Assembly Loader loaded assembly from location: '%s'.", filename);
1682 mono_config_for_assembly (ass->image);
1685 /* Clear the reference added by mono_image_open */
1686 mono_image_close (image);
1694 free_item (gpointer val, gpointer user_data)
1700 * mono_assembly_load_friends:
1703 * Load the list of friend assemblies that are allowed to access
1704 * the assembly's internal types and members. They are stored as assembly
1705 * names in custom attributes.
1707 * This is an internal method, we need this because when we load mscorlib
1708 * we do not have the internals visible cattr loaded yet,
1709 * so we need to load these after we initialize the runtime.
1711 * LOCKING: Acquires the assemblies lock plus the loader lock.
1714 mono_assembly_load_friends (MonoAssembly* ass)
1718 MonoCustomAttrInfo* attrs;
1721 if (ass->friend_assembly_names_inited)
1724 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1725 mono_error_assert_ok (&error);
1727 mono_assemblies_lock ();
1728 ass->friend_assembly_names_inited = TRUE;
1729 mono_assemblies_unlock ();
1733 mono_assemblies_lock ();
1734 if (ass->friend_assembly_names_inited) {
1735 mono_assemblies_unlock ();
1738 mono_assemblies_unlock ();
1742 * We build the list outside the assemblies lock, the worse that can happen
1743 * is that we'll need to free the allocated list.
1745 for (i = 0; i < attrs->num_attrs; ++i) {
1746 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1747 MonoAssemblyName *aname;
1749 /* Do some sanity checking */
1750 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1752 if (attr->data_size < 4)
1754 data = (const char*)attr->data;
1755 /* 0xFF means null string, see custom attr format */
1756 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1758 mono_metadata_decode_value (data + 2, &data);
1759 aname = g_new0 (MonoAssemblyName, 1);
1760 /*g_print ("friend ass: %s\n", data);*/
1761 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1762 list = g_slist_prepend (list, aname);
1767 mono_custom_attrs_free (attrs);
1769 mono_assemblies_lock ();
1770 if (ass->friend_assembly_names_inited) {
1771 mono_assemblies_unlock ();
1772 g_slist_foreach (list, free_item, NULL);
1773 g_slist_free (list);
1776 ass->friend_assembly_names = list;
1778 /* Because of the double checked locking pattern above */
1779 mono_memory_barrier ();
1780 ass->friend_assembly_names_inited = TRUE;
1781 mono_assemblies_unlock ();
1785 * mono_assembly_open:
1786 * @filename: Opens the assembly pointed out by this name
1787 * @status: return status code
1789 * This loads an assembly from the specified @filename. The @filename allows
1790 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1791 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1792 * is treated as a local path.
1794 * First, an attempt is made to load the assembly from the bundled executable (for those
1795 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1796 * assembly has been registered as an embedded assembly). If this is not the case, then
1797 * the assembly is loaded from disk using `api:mono_image_open_full`.
1799 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1800 * the assembly is made.
1802 * Return: a pointer to the MonoAssembly if @filename contains a valid
1803 * assembly or NULL on error. Details about the error are stored in the
1807 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1809 return mono_assembly_open_full (filename, status, FALSE);
1813 * mono_assembly_load_from_full:
1814 * @image: Image to load the assembly from
1815 * @fname: assembly name to associate with the assembly
1816 * @status: returns the status condition
1817 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1819 * If the provided @image has an assembly reference, it will process the given
1820 * image as an assembly with the given name.
1822 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1824 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1825 * set to #MONO_IMAGE_OK; or NULL on error.
1827 * If there is an error loading the assembly the @status will indicate the
1828 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1829 * image did not contain an assembly reference table.
1832 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1833 MonoImageOpenStatus *status, gboolean refonly)
1835 MonoAssembly *ass, *ass2;
1838 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1839 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1840 *status = MONO_IMAGE_IMAGE_INVALID;
1844 #if defined (HOST_WIN32)
1849 tmp_fn = g_strdup (fname);
1850 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1851 if (tmp_fn [i] == '/')
1855 base_dir = absolute_dir (tmp_fn);
1859 base_dir = absolute_dir (fname);
1863 * Create assembly struct, and enter it into the assembly cache
1865 ass = g_new0 (MonoAssembly, 1);
1866 ass->basedir = base_dir;
1867 ass->ref_only = refonly;
1870 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1872 mono_assembly_fill_assembly_name (image, &ass->aname);
1874 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1875 // MS.NET doesn't support loading other mscorlibs
1878 mono_image_addref (mono_defaults.corlib);
1879 *status = MONO_IMAGE_OK;
1880 return mono_defaults.corlib->assembly;
1883 /* Add a non-temporary reference because of ass->image */
1884 mono_image_addref (image);
1886 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);
1889 * The load hooks might take locks so we can't call them while holding the
1892 if (ass->aname.name) {
1893 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1897 mono_image_close (image);
1898 *status = MONO_IMAGE_OK;
1903 mono_assemblies_lock ();
1905 if (image->assembly) {
1907 * This means another thread has already loaded the assembly, but not yet
1908 * called the load hooks so the search hook can't find the assembly.
1910 mono_assemblies_unlock ();
1911 ass2 = image->assembly;
1914 mono_image_close (image);
1915 *status = MONO_IMAGE_OK;
1919 image->assembly = ass;
1921 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1922 mono_assemblies_unlock ();
1925 if (image->is_module_handle)
1926 mono_image_fixup_vtable (image);
1929 mono_assembly_invoke_load_hook (ass);
1931 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1937 * mono_assembly_load_from:
1938 * @image: Image to load the assembly from
1939 * @fname: assembly name to associate with the assembly
1940 * @status: return status code
1942 * If the provided @image has an assembly reference, it will process the given
1943 * image as an assembly with the given name.
1945 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1947 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
1948 * @refonly parameter set to FALSE.
1949 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1950 * set to #MONO_IMAGE_OK; or NULL on error.
1952 * If there is an error loading the assembly the @status will indicate the
1953 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1954 * image did not contain an assembly reference table.
1958 mono_assembly_load_from (MonoImage *image, const char *fname,
1959 MonoImageOpenStatus *status)
1961 return mono_assembly_load_from_full (image, fname, status, FALSE);
1965 * mono_assembly_name_free:
1966 * @aname: assembly name to free
1968 * Frees the provided assembly name object.
1969 * (it does not frees the object itself, only the name members).
1972 mono_assembly_name_free (MonoAssemblyName *aname)
1977 g_free ((void *) aname->name);
1978 g_free ((void *) aname->culture);
1979 g_free ((void *) aname->hash_value);
1983 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
1986 gchar header [16], val, *arr;
1987 gint i, j, offset, bitlen, keylen, pkeylen;
1989 keylen = strlen (key) >> 1;
1993 /* allow the ECMA standard key */
1994 if (strcmp (key, "00000000000000000400000000000000") == 0) {
1996 *pubkey = g_strdup (key);
2002 val = g_ascii_xdigit_value (key [0]) << 4;
2003 val |= g_ascii_xdigit_value (key [1]);
2008 val = g_ascii_xdigit_value (key [24]);
2009 val |= g_ascii_xdigit_value (key [25]);
2021 /* We need the first 16 bytes
2022 * to check whether this key is valid or not */
2023 pkeylen = strlen (pkey) >> 1;
2027 for (i = 0, j = 0; i < 16; i++) {
2028 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2029 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2032 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2033 header [1] != 0x02 || /* Version (0x02) */
2034 header [2] != 0x00 || /* Reserved (word) */
2035 header [3] != 0x00 ||
2036 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2039 /* Based on this length, we _should_ be able to know if the length is right */
2040 bitlen = read32 (header + 12) >> 3;
2041 if ((bitlen + 16 + 4) != pkeylen)
2044 /* parsing is OK and the public key itself is not requested back */
2048 /* Encode the size of the blob */
2050 if (keylen <= 127) {
2051 arr = (gchar *)g_malloc (keylen + 1);
2052 arr [offset++] = keylen;
2054 arr = (gchar *)g_malloc (keylen + 2);
2055 arr [offset++] = 0x80; /* 10bs */
2056 arr [offset++] = keylen;
2059 for (i = offset, j = 0; i < keylen + offset; i++) {
2060 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2061 arr [i] |= g_ascii_xdigit_value (key [j++]);
2070 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)
2072 gint major, minor, build, revision;
2075 gchar *pkey, *pkeyptr, *encoded, tok [8];
2077 memset (aname, 0, sizeof (MonoAssemblyName));
2080 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2081 if (version_parts < 2 || version_parts > 4)
2084 /* FIXME: we should set build & revision to -1 (instead of 0)
2085 if these are not set in the version string. That way, later on,
2086 we can still determine if these were specified. */
2087 aname->major = major;
2088 aname->minor = minor;
2089 if (version_parts >= 3)
2090 aname->build = build;
2093 if (version_parts == 4)
2094 aname->revision = revision;
2096 aname->revision = 0;
2099 aname->flags = flags;
2101 aname->name = g_strdup (name);
2104 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2105 aname->culture = g_strdup ("");
2107 aname->culture = g_strdup (culture);
2110 if (token && strncmp (token, "null", 4) != 0) {
2113 /* the constant includes the ending NULL, hence the -1 */
2114 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2115 mono_assembly_name_free (aname);
2118 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2119 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2125 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2126 mono_assembly_name_free (aname);
2131 if (save_public_key)
2132 aname->public_key = (guint8*)pkey;
2135 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2139 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2140 // We also need to generate the key token
2141 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2142 encoded = encode_public_tok ((guchar*) tok, 8);
2143 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2146 if (save_public_key)
2147 aname->public_key = (guint8*) pkey;
2156 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2161 parts = g_strsplit (dirname, "_", 3);
2162 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2167 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2173 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2175 char *eqsign = strchr (pair, '=');
2183 *key = (gchar*)pair;
2184 *keylen = eqsign - *key;
2185 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2187 *value = g_strstrip (eqsign + 1);
2192 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2196 gchar *version = NULL;
2198 gchar *culture = NULL;
2200 gchar *token = NULL;
2204 gchar *retargetable = NULL;
2205 gchar *retargetable_uq;
2209 gchar *value, *part_name;
2210 guint32 part_name_len;
2213 gboolean version_defined;
2214 gboolean token_defined;
2216 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2218 if (!is_version_defined)
2219 is_version_defined = &version_defined;
2220 *is_version_defined = FALSE;
2221 if (!is_token_defined)
2222 is_token_defined = &token_defined;
2223 *is_token_defined = FALSE;
2225 parts = tmp = g_strsplit (name, ",", 6);
2226 if (!tmp || !*tmp) {
2231 dllname = g_strstrip (*tmp);
2236 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2237 goto cleanup_and_fail;
2239 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2240 *is_version_defined = TRUE;
2242 if (strlen (version) == 0) {
2243 goto cleanup_and_fail;
2249 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2251 if (strlen (culture) == 0) {
2252 goto cleanup_and_fail;
2258 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2259 *is_token_defined = TRUE;
2261 if (strlen (token) == 0) {
2262 goto cleanup_and_fail;
2268 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2270 if (strlen (key) == 0) {
2271 goto cleanup_and_fail;
2277 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2278 retargetable = value;
2279 retargetable_uq = unquote (retargetable);
2280 if (retargetable_uq != NULL)
2281 retargetable = retargetable_uq;
2283 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2284 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2285 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2286 free (retargetable_uq);
2287 goto cleanup_and_fail;
2290 free (retargetable_uq);
2295 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2297 procarch_uq = unquote (procarch);
2298 if (procarch_uq != NULL)
2299 procarch = procarch_uq;
2301 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2302 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2303 else if (!g_ascii_strcasecmp (procarch, "X86"))
2304 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2305 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2306 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2307 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2308 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2311 goto cleanup_and_fail;
2323 /* if retargetable flag is set, then we must have a fully qualified name */
2324 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2325 goto cleanup_and_fail;
2328 dllname_uq = unquote (dllname);
2329 version_uq = unquote (version);
2330 culture_uq = unquote (culture);
2331 token_uq = unquote (token);
2332 key_uq = unquote (key);
2334 res = build_assembly_name (
2335 dllname_uq == NULL ? dllname : dllname_uq,
2336 version_uq == NULL ? version : version_uq,
2337 culture_uq == NULL ? culture : culture_uq,
2338 token_uq == NULL ? token : token_uq,
2339 key_uq == NULL ? key : key_uq,
2340 flags, arch, aname, save_public_key);
2357 unquote (const char *str)
2365 slen = strlen (str);
2369 if (*str != '\'' && *str != '\"')
2372 end = str + slen - 1;
2376 return g_strndup (str + 1, slen - 2);
2380 * mono_assembly_name_parse:
2381 * @name: name to parse
2382 * @aname: the destination assembly name
2384 * Parses an assembly qualified type name and assigns the name,
2385 * version, culture and token to the provided assembly name object.
2387 * Returns: TRUE if the name could be parsed.
2390 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2392 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2396 * mono_assembly_name_new:
2397 * @name: name to parse
2399 * Allocate a new MonoAssemblyName and fill its values from the
2402 * Returns: a newly allocated structure or NULL if there was any failure.
2405 mono_assembly_name_new (const char *name)
2407 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2408 if (mono_assembly_name_parse (name, aname))
2415 mono_assembly_name_get_name (MonoAssemblyName *aname)
2421 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2423 return aname->culture;
2427 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2429 if (aname->public_key_token [0])
2430 return aname->public_key_token;
2435 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2438 *minor = aname->minor;
2440 *build = aname->build;
2442 *revision = aname->revision;
2443 return aname->major;
2446 static MonoAssembly*
2447 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2449 gchar *fullpath = NULL;
2451 const char* direntry;
2452 MonoAssemblyName gac_aname;
2453 gint major=-1, minor=0, build=0, revision=0;
2454 gboolean exact_version;
2456 dirhandle = g_dir_open (basepath, 0, NULL);
2460 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2462 while ((direntry = g_dir_read_name (dirhandle))) {
2463 gboolean match = TRUE;
2465 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2468 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2471 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2472 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2476 if (exact_version) {
2477 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2478 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2480 else if (gac_aname.major < major)
2482 else if (gac_aname.major == major) {
2483 if (gac_aname.minor < minor)
2485 else if (gac_aname.minor == minor) {
2486 if (gac_aname.build < build)
2488 else if (gac_aname.build == build && gac_aname.revision <= revision)
2495 major = gac_aname.major;
2496 minor = gac_aname.minor;
2497 build = gac_aname.build;
2498 revision = gac_aname.revision;
2500 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2503 mono_assembly_name_free (&gac_aname);
2506 g_dir_close (dirhandle);
2508 if (fullpath == NULL)
2511 MonoAssembly *res = mono_assembly_open (fullpath, status);
2518 * mono_assembly_load_with_partial_name:
2519 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2520 * @status: return status code
2522 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2523 * so it might contain a qualified type name, version, culture and token.
2525 * This will load the assembly from the file whose name is derived from the assembly name
2526 * by appending the .dll extension.
2528 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2529 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2530 * if that fails from the GAC.
2532 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2535 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2539 MonoAssemblyName *aname, base_name;
2540 MonoAssemblyName mapped_aname;
2541 gchar *fullname, *gacpath;
2544 memset (&base_name, 0, sizeof (MonoAssemblyName));
2547 if (!mono_assembly_name_parse (name, aname))
2551 * If no specific version has been requested, make sure we load the
2552 * correct version for system assemblies.
2554 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2555 aname = mono_assembly_remap_version (aname, &mapped_aname);
2557 res = mono_assembly_loaded (aname);
2559 mono_assembly_name_free (aname);
2563 res = invoke_assembly_preload_hook (aname, assemblies_path);
2565 res->in_gac = FALSE;
2566 mono_assembly_name_free (aname);
2570 fullname = g_strdup_printf ("%s.dll", aname->name);
2572 if (extra_gac_paths) {
2573 paths = extra_gac_paths;
2574 while (!res && *paths) {
2575 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2576 res = probe_for_partial_name (gacpath, fullname, aname, status);
2585 mono_assembly_name_free (aname);
2589 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2590 res = probe_for_partial_name (gacpath, fullname, aname, status);
2596 MonoDomain *domain = mono_domain_get ();
2597 MonoReflectionAssembly *refasm;
2599 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2600 if (!mono_error_ok (&error)) {
2602 mono_assembly_name_free (aname);
2603 mono_error_raise_exception (&error); /* FIXME don't raise here */
2607 res = refasm->assembly;
2611 mono_assembly_name_free (aname);
2617 mono_assembly_is_in_gac (const gchar *filename)
2619 const gchar *rootdir;
2623 if (filename == NULL)
2626 for (paths = extra_gac_paths; paths && *paths; paths++) {
2627 if (strstr (*paths, filename) != *paths)
2630 gp = (gchar *) (filename + strlen (*paths));
2631 if (*gp != G_DIR_SEPARATOR)
2634 if (strncmp (gp, "lib", 3))
2637 if (*gp != G_DIR_SEPARATOR)
2640 if (strncmp (gp, "mono", 4))
2643 if (*gp != G_DIR_SEPARATOR)
2646 if (strncmp (gp, "gac", 3))
2649 if (*gp != G_DIR_SEPARATOR)
2655 rootdir = mono_assembly_getrootdir ();
2656 if (strstr (filename, rootdir) != filename)
2659 gp = (gchar *) (filename + strlen (rootdir));
2660 if (*gp != G_DIR_SEPARATOR)
2663 if (strncmp (gp, "mono", 4))
2666 if (*gp != G_DIR_SEPARATOR)
2669 if (strncmp (gp, "gac", 3))
2672 if (*gp != G_DIR_SEPARATOR)
2678 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2681 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2685 if (strstr (aname->name, ".dll")) {
2686 len = strlen (aname->name) - 4;
2687 name = (gchar *)g_malloc (len + 1);
2688 strncpy (name, aname->name, len);
2691 name = g_strdup (aname->name);
2694 culture = g_utf8_strdown (aname->culture, -1);
2696 culture = g_strdup ("");
2698 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2699 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2703 filename = g_strconcat (pname, ".dll", NULL);
2704 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2710 if (extra_gac_paths) {
2711 paths = extra_gac_paths;
2712 while (!image && *paths) {
2713 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2714 "lib", "mono", "gac", subpath, NULL);
2715 image = mono_image_open (fullpath, NULL);
2726 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2727 "mono", "gac", subpath, NULL);
2728 image = mono_image_open (fullpath, NULL);
2735 static MonoAssemblyName*
2736 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2738 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2739 dest_name->major = info->new_version.major;
2740 dest_name->minor = info->new_version.minor;
2741 dest_name->build = info->new_version.build;
2742 dest_name->revision = info->new_version.revision;
2747 /* LOCKING: assembly_binding lock must be held */
2748 static MonoAssemblyBindingInfo*
2749 search_binding_loaded (MonoAssemblyName *aname)
2753 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2754 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2755 if (assembly_binding_maps_name (info, aname))
2762 static inline gboolean
2763 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2765 if (left->major != right->major || left->minor != right->minor ||
2766 left->build != right->build || left->revision != right->revision)
2772 static inline gboolean
2773 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2775 if (left->has_old_version_bottom != right->has_old_version_bottom)
2778 if (left->has_old_version_top != right->has_old_version_top)
2781 if (left->has_new_version != right->has_new_version)
2784 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2787 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2790 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2796 /* LOCKING: assumes all the necessary locks are held */
2798 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2800 MonoAssemblyBindingInfo *info_copy;
2802 MonoAssemblyBindingInfo *info_tmp;
2803 MonoDomain *domain = (MonoDomain*)user_data;
2808 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2809 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2810 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2814 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2815 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2817 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2819 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2821 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2825 get_version_number (int major, int minor)
2827 return major * 256 + minor;
2830 static inline gboolean
2831 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2833 int aname_version_number = get_version_number (aname->major, aname->minor);
2834 if (!info->has_old_version_bottom)
2837 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2840 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2843 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2844 info->major = aname->major;
2845 info->minor = aname->minor;
2850 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2851 static MonoAssemblyBindingInfo*
2852 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2854 MonoAssemblyBindingInfo *info;
2857 if (!domain->assembly_bindings)
2861 for (list = domain->assembly_bindings; list; list = list->next) {
2862 info = (MonoAssemblyBindingInfo *)list->data;
2863 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2869 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2870 info->has_new_version && assembly_binding_maps_name (info, aname))
2871 info->is_valid = TRUE;
2873 info->is_valid = FALSE;
2879 static MonoAssemblyName*
2880 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2882 MonoAssemblyBindingInfo *info, *info2;
2886 if (aname->public_key_token [0] == 0)
2889 domain = mono_domain_get ();
2891 mono_assembly_binding_lock ();
2892 info = search_binding_loaded (aname);
2893 mono_assembly_binding_unlock ();
2896 mono_domain_lock (domain);
2897 info = get_per_domain_assembly_binding_info (domain, aname);
2898 mono_domain_unlock (domain);
2902 if (!check_policy_versions (info, aname))
2905 mono_assembly_bind_version (info, aname, dest_name);
2909 if (domain && domain->setup && domain->setup->configuration_file) {
2910 mono_domain_lock (domain);
2911 if (!domain->assembly_bindings_parsed) {
2912 gchar *domain_config_file_name = mono_string_to_utf8 (domain->setup->configuration_file);
2913 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2915 if (!domain_config_file_path)
2916 domain_config_file_path = domain_config_file_name;
2918 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2919 domain->assembly_bindings_parsed = TRUE;
2920 if (domain_config_file_name != domain_config_file_path)
2921 g_free (domain_config_file_name);
2922 g_free (domain_config_file_path);
2925 info2 = get_per_domain_assembly_binding_info (domain, aname);
2928 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2929 info->name = g_strdup (info2->name);
2930 info->culture = g_strdup (info2->culture);
2931 info->domain_id = domain->domain_id;
2934 mono_domain_unlock (domain);
2938 info = g_new0 (MonoAssemblyBindingInfo, 1);
2939 info->major = aname->major;
2940 info->minor = aname->minor;
2943 if (!info->is_valid) {
2944 ppimage = mono_assembly_load_publisher_policy (aname);
2946 get_publisher_policy_info (ppimage, aname, info);
2947 mono_image_close (ppimage);
2951 /* Define default error value if needed */
2952 if (!info->is_valid) {
2953 info->name = g_strdup (aname->name);
2954 info->culture = g_strdup (aname->culture);
2955 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2958 mono_assembly_binding_lock ();
2959 info2 = search_binding_loaded (aname);
2961 /* This binding was added by another thread
2963 mono_assembly_binding_info_free (info);
2968 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2970 mono_assembly_binding_unlock ();
2972 if (!info->is_valid || !check_policy_versions (info, aname))
2975 mono_assembly_bind_version (info, aname, dest_name);
2980 * mono_assembly_load_from_gac
2982 * @aname: The assembly name object
2984 static MonoAssembly*
2985 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
2987 MonoAssembly *result = NULL;
2988 gchar *name, *version, *culture, *fullpath, *subpath;
2993 if (aname->public_key_token [0] == 0) {
2997 if (strstr (aname->name, ".dll")) {
2998 len = strlen (filename) - 4;
2999 name = (gchar *)g_malloc (len + 1);
3000 strncpy (name, aname->name, len);
3003 name = g_strdup (aname->name);
3006 if (aname->culture) {
3007 culture = g_utf8_strdown (aname->culture, -1);
3009 culture = g_strdup ("");
3012 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3013 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3014 aname->minor, aname->build, aname->revision,
3018 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3023 if (extra_gac_paths) {
3024 paths = extra_gac_paths;
3025 while (!result && *paths) {
3026 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3027 result = mono_assembly_open_full (fullpath, status, refonly);
3034 result->in_gac = TRUE;
3039 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3040 "mono", "gac", subpath, NULL);
3041 result = mono_assembly_open_full (fullpath, status, refonly);
3045 result->in_gac = TRUE;
3053 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3056 MonoAssemblyName *aname;
3059 /* g_print ("corlib already loaded\n"); */
3063 // In native client, Corlib is embedded in the executable as static variable corlibData
3064 #if defined(__native_client__)
3065 if (corlibData != NULL && corlibSize != 0) {
3067 /* First "FALSE" instructs mono not to make a copy. */
3068 /* Second "FALSE" says this is not just a ref. */
3069 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3070 if (image == NULL || status != 0)
3071 g_print("mono_image_open_from_data_full failed: %d\n", status);
3072 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3073 if (corlib == NULL || status != 0)
3074 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3080 // A nonstandard preload hook may provide a special mscorlib assembly
3081 aname = mono_assembly_name_new ("mscorlib.dll");
3082 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3083 mono_assembly_name_free (aname);
3086 goto return_corlib_and_facades;
3088 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3089 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3090 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3092 goto return_corlib_and_facades;
3095 /* Normal case: Load corlib from mono/<version> */
3096 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3097 if (assemblies_path) { // Custom assemblies path
3098 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3100 g_free (corlib_file);
3101 goto return_corlib_and_facades;
3104 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3105 g_free (corlib_file);
3107 return_corlib_and_facades:
3108 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3109 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3115 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3116 const char *basedir,
3117 MonoImageOpenStatus *status,
3120 MonoAssembly *result;
3121 char *fullpath, *filename;
3122 MonoAssemblyName maped_aname;
3123 MonoAssemblyName maped_name_pp;
3128 aname = mono_assembly_remap_version (aname, &maped_aname);
3130 /* Reflection only assemblies don't get assembly binding */
3132 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3134 result = mono_assembly_loaded_full (aname, refonly);
3138 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3140 result->in_gac = FALSE;
3144 /* Currently we retrieve the loaded corlib for reflection
3145 * only requests, like a common reflection only assembly
3147 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3148 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3151 len = strlen (aname->name);
3152 for (ext_index = 0; ext_index < 2; ext_index ++) {
3153 ext = ext_index == 0 ? ".dll" : ".exe";
3154 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3155 filename = g_strdup (aname->name);
3156 /* Don't try appending .dll/.exe if it already has one of those extensions */
3159 filename = g_strconcat (aname->name, ext, NULL);
3162 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3169 fullpath = g_build_filename (basedir, filename, NULL);
3170 result = mono_assembly_open_full (fullpath, status, refonly);
3173 result->in_gac = FALSE;
3179 result = load_in_path (filename, default_path, status, refonly);
3181 result->in_gac = FALSE;
3191 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3193 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3196 /* Try a postload search hook */
3197 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3202 * mono_assembly_load_full:
3203 * @aname: A MonoAssemblyName with the assembly name to load.
3204 * @basedir: A directory to look up the assembly at.
3205 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3206 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3208 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3209 * attempts to load the assembly from that directory before probing the standard locations.
3211 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3212 * assembly binding takes place.
3214 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3215 * value pointed by status is updated with an error code.
3218 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3220 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3224 * mono_assembly_load:
3225 * @aname: A MonoAssemblyName with the assembly name to load.
3226 * @basedir: A directory to look up the assembly at.
3227 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3229 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3230 * attempts to load the assembly from that directory before probing the standard locations.
3232 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3233 * value pointed by status is updated with an error code.
3236 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3238 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3242 * mono_assembly_loaded_full:
3243 * @aname: an assembly to look for.
3244 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3246 * This is used to determine if the specified assembly has been loaded
3247 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3248 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3251 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3254 MonoAssemblyName maped_aname;
3256 aname = mono_assembly_remap_version (aname, &maped_aname);
3258 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3264 * mono_assembly_loaded:
3265 * @aname: an assembly to look for.
3267 * This is used to determine if the specified assembly has been loaded
3269 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3270 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3273 mono_assembly_loaded (MonoAssemblyName *aname)
3275 return mono_assembly_loaded_full (aname, FALSE);
3279 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3281 if (assembly == NULL || assembly == REFERENCE_MISSING)
3284 if (assembly_is_dynamic (assembly)) {
3286 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3287 for (i = 0; i < dynimg->image.module_count; ++i)
3288 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3289 mono_dynamic_image_release_gc_roots (dynimg);
3294 * Returns whether mono_assembly_close_finish() must be called as
3295 * well. See comment for mono_image_close_except_pools() for why we
3296 * unload in two steps.
3299 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3302 g_return_val_if_fail (assembly != NULL, FALSE);
3304 if (assembly == REFERENCE_MISSING)
3307 /* Might be 0 already */
3308 if (InterlockedDecrement (&assembly->ref_count) > 0)
3311 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3313 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3315 mono_debug_close_image (assembly->image);
3317 mono_assemblies_lock ();
3318 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3319 mono_assemblies_unlock ();
3321 assembly->image->assembly = NULL;
3323 if (!mono_image_close_except_pools (assembly->image))
3324 assembly->image = NULL;
3326 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3327 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3328 mono_assembly_name_free (fname);
3331 g_slist_free (assembly->friend_assembly_names);
3332 g_free (assembly->basedir);
3334 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3340 mono_assembly_close_finish (MonoAssembly *assembly)
3342 g_assert (assembly && assembly != REFERENCE_MISSING);
3344 if (assembly->image)
3345 mono_image_close_finish (assembly->image);
3347 if (assembly_is_dynamic (assembly)) {
3348 g_free ((char*)assembly->aname.culture);
3355 * mono_assembly_close:
3356 * @assembly: the assembly to release.
3358 * This method releases a reference to the @assembly. The assembly is
3359 * only released when all the outstanding references to it are released.
3362 mono_assembly_close (MonoAssembly *assembly)
3364 if (mono_assembly_close_except_image_pools (assembly))
3365 mono_assembly_close_finish (assembly);
3369 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3371 return mono_image_load_file_for_image (assembly->image, idx);
3375 * mono_assembly_foreach:
3376 * @func: function to invoke for each assembly loaded
3377 * @user_data: data passed to the callback
3379 * Invokes the provided @func callback for each assembly loaded into
3380 * the runtime. The first parameter passed to the callback is the
3381 * `MonoAssembly*`, and the second parameter is the @user_data.
3383 * This is done for all assemblies loaded in the runtime, not just
3384 * those loaded in the current application domain.
3387 mono_assembly_foreach (GFunc func, gpointer user_data)
3392 * We make a copy of the list to avoid calling the callback inside the
3393 * lock, which could lead to deadlocks.
3395 mono_assemblies_lock ();
3396 copy = g_list_copy (loaded_assemblies);
3397 mono_assemblies_unlock ();
3399 g_list_foreach (loaded_assemblies, func, user_data);
3405 * mono_assemblies_cleanup:
3407 * Free all resources used by this module.
3410 mono_assemblies_cleanup (void)
3414 mono_os_mutex_destroy (&assemblies_mutex);
3415 mono_os_mutex_destroy (&assembly_binding_mutex);
3417 for (l = loaded_assembly_bindings; l; l = l->next) {
3418 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3420 mono_assembly_binding_info_free (info);
3423 g_slist_free (loaded_assembly_bindings);
3425 free_assembly_load_hooks ();
3426 free_assembly_search_hooks ();
3427 free_assembly_preload_hooks ();
3430 /*LOCKING takes the assembly_binding lock*/
3432 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3436 mono_assembly_binding_lock ();
3437 iter = &loaded_assembly_bindings;
3440 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3442 if (info->domain_id == domain_id) {
3444 mono_assembly_binding_info_free (info);
3451 mono_assembly_binding_unlock ();
3455 * Holds the assembly of the application, for
3456 * System.Diagnostics.Process::MainModule
3458 static MonoAssembly *main_assembly=NULL;
3461 mono_assembly_set_main (MonoAssembly *assembly)
3463 main_assembly = assembly;
3467 * mono_assembly_get_main:
3469 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3472 mono_assembly_get_main (void)
3474 return (main_assembly);
3478 * mono_assembly_get_image:
3479 * @assembly: The assembly to retrieve the image from
3481 * Returns: the MonoImage associated with this assembly.
3484 mono_assembly_get_image (MonoAssembly *assembly)
3486 return assembly->image;
3490 * mono_assembly_get_name:
3491 * @assembly: The assembly to retrieve the name from
3493 * The returned name's lifetime is the same as @assembly's.
3495 * Returns: the MonoAssemblyName associated with this assembly.
3498 mono_assembly_get_name (MonoAssembly *assembly)
3500 return &assembly->aname;
3504 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3506 bundles = assemblies;
3509 #define MONO_DECLSEC_FORMAT_10 0x3C
3510 #define MONO_DECLSEC_FORMAT_20 0x2E
3511 #define MONO_DECLSEC_FIELD 0x53
3512 #define MONO_DECLSEC_PROPERTY 0x54
3514 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3515 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3516 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3517 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3518 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3521 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3525 case MONO_DECLSEC_PROPERTY:
3527 case MONO_DECLSEC_FIELD:
3529 *abort_decoding = TRUE;
3534 if (*p++ != MONO_TYPE_BOOLEAN) {
3535 *abort_decoding = TRUE;
3539 /* property name length */
3540 len = mono_metadata_decode_value (p, &p);
3542 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3553 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3555 int i, j, num, len, params_len;
3557 if (*p == MONO_DECLSEC_FORMAT_10) {
3558 gsize read, written;
3559 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3561 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3567 if (*p++ != MONO_DECLSEC_FORMAT_20)
3570 /* number of encoded permission attributes */
3571 num = mono_metadata_decode_value (p, &p);
3572 for (i = 0; i < num; ++i) {
3573 gboolean is_valid = FALSE;
3574 gboolean abort_decoding = FALSE;
3576 /* attribute name length */
3577 len = mono_metadata_decode_value (p, &p);
3579 /* We don't really need to fully decode the type. Comparing the name is enough */
3580 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3584 /*size of the params table*/
3585 params_len = mono_metadata_decode_value (p, &p);
3587 const char *params_end = p + params_len;
3589 /* number of parameters */
3590 len = mono_metadata_decode_value (p, &p);
3592 for (j = 0; j < len; ++j) {
3593 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3609 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3612 guint32 cols [MONO_DECL_SECURITY_SIZE];
3616 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3617 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3619 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3621 for (i = 0; i < t->rows; ++i) {
3622 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3623 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3625 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3628 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3629 len = mono_metadata_decode_blob_size (blob, &blob);
3633 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3634 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3639 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);