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 if (!is_ok (&error)) {
1640 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1641 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1642 mono_error_cleanup (&error);
1643 *status = MONO_IMAGE_IMAGE_INVALID;
1648 if (new_fname && new_fname != fname) {
1651 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1652 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1657 // If VM built with mkbundle
1658 loaded_from_bundle = FALSE;
1659 if (bundles != NULL) {
1660 image = mono_assembly_open_from_bundle (fname, status, refonly);
1661 loaded_from_bundle = image != NULL;
1665 image = mono_image_open_full (fname, status, refonly);
1668 if (*status == MONO_IMAGE_OK)
1669 *status = MONO_IMAGE_ERROR_ERRNO;
1674 if (image->assembly) {
1675 /* Already loaded by another appdomain */
1676 mono_assembly_invoke_load_hook (image->assembly);
1677 mono_image_close (image);
1679 return image->assembly;
1682 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1685 if (!loaded_from_bundle)
1686 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1687 "Assembly Loader loaded assembly from location: '%s'.", filename);
1689 mono_config_for_assembly (ass->image);
1692 /* Clear the reference added by mono_image_open */
1693 mono_image_close (image);
1701 free_item (gpointer val, gpointer user_data)
1707 * mono_assembly_load_friends:
1710 * Load the list of friend assemblies that are allowed to access
1711 * the assembly's internal types and members. They are stored as assembly
1712 * names in custom attributes.
1714 * This is an internal method, we need this because when we load mscorlib
1715 * we do not have the internals visible cattr loaded yet,
1716 * so we need to load these after we initialize the runtime.
1718 * LOCKING: Acquires the assemblies lock plus the loader lock.
1721 mono_assembly_load_friends (MonoAssembly* ass)
1725 MonoCustomAttrInfo* attrs;
1728 if (ass->friend_assembly_names_inited)
1731 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1732 mono_error_assert_ok (&error);
1734 mono_assemblies_lock ();
1735 ass->friend_assembly_names_inited = TRUE;
1736 mono_assemblies_unlock ();
1740 mono_assemblies_lock ();
1741 if (ass->friend_assembly_names_inited) {
1742 mono_assemblies_unlock ();
1745 mono_assemblies_unlock ();
1749 * We build the list outside the assemblies lock, the worse that can happen
1750 * is that we'll need to free the allocated list.
1752 for (i = 0; i < attrs->num_attrs; ++i) {
1753 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1754 MonoAssemblyName *aname;
1756 /* Do some sanity checking */
1757 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1759 if (attr->data_size < 4)
1761 data = (const char*)attr->data;
1762 /* 0xFF means null string, see custom attr format */
1763 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1765 mono_metadata_decode_value (data + 2, &data);
1766 aname = g_new0 (MonoAssemblyName, 1);
1767 /*g_print ("friend ass: %s\n", data);*/
1768 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1769 list = g_slist_prepend (list, aname);
1774 mono_custom_attrs_free (attrs);
1776 mono_assemblies_lock ();
1777 if (ass->friend_assembly_names_inited) {
1778 mono_assemblies_unlock ();
1779 g_slist_foreach (list, free_item, NULL);
1780 g_slist_free (list);
1783 ass->friend_assembly_names = list;
1785 /* Because of the double checked locking pattern above */
1786 mono_memory_barrier ();
1787 ass->friend_assembly_names_inited = TRUE;
1788 mono_assemblies_unlock ();
1792 * mono_assembly_open:
1793 * @filename: Opens the assembly pointed out by this name
1794 * @status: return status code
1796 * This loads an assembly from the specified @filename. The @filename allows
1797 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1798 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1799 * is treated as a local path.
1801 * First, an attempt is made to load the assembly from the bundled executable (for those
1802 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1803 * assembly has been registered as an embedded assembly). If this is not the case, then
1804 * the assembly is loaded from disk using `api:mono_image_open_full`.
1806 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1807 * the assembly is made.
1809 * Return: a pointer to the MonoAssembly if @filename contains a valid
1810 * assembly or NULL on error. Details about the error are stored in the
1814 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1816 return mono_assembly_open_full (filename, status, FALSE);
1820 * mono_assembly_load_from_full:
1821 * @image: Image to load the assembly from
1822 * @fname: assembly name to associate with the assembly
1823 * @status: returns the status condition
1824 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1826 * If the provided @image has an assembly reference, it will process the given
1827 * image as an assembly with the given name.
1829 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1831 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1832 * set to #MONO_IMAGE_OK; or NULL on error.
1834 * If there is an error loading the assembly the @status will indicate the
1835 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1836 * image did not contain an assembly reference table.
1839 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1840 MonoImageOpenStatus *status, gboolean refonly)
1842 MonoAssembly *ass, *ass2;
1845 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1846 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1847 *status = MONO_IMAGE_IMAGE_INVALID;
1851 #if defined (HOST_WIN32)
1856 tmp_fn = g_strdup (fname);
1857 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1858 if (tmp_fn [i] == '/')
1862 base_dir = absolute_dir (tmp_fn);
1866 base_dir = absolute_dir (fname);
1870 * Create assembly struct, and enter it into the assembly cache
1872 ass = g_new0 (MonoAssembly, 1);
1873 ass->basedir = base_dir;
1874 ass->ref_only = refonly;
1877 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1879 mono_assembly_fill_assembly_name (image, &ass->aname);
1881 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1882 // MS.NET doesn't support loading other mscorlibs
1885 mono_image_addref (mono_defaults.corlib);
1886 *status = MONO_IMAGE_OK;
1887 return mono_defaults.corlib->assembly;
1890 /* Add a non-temporary reference because of ass->image */
1891 mono_image_addref (image);
1893 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);
1896 * The load hooks might take locks so we can't call them while holding the
1899 if (ass->aname.name) {
1900 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1904 mono_image_close (image);
1905 *status = MONO_IMAGE_OK;
1910 mono_assemblies_lock ();
1912 if (image->assembly) {
1914 * This means another thread has already loaded the assembly, but not yet
1915 * called the load hooks so the search hook can't find the assembly.
1917 mono_assemblies_unlock ();
1918 ass2 = image->assembly;
1921 mono_image_close (image);
1922 *status = MONO_IMAGE_OK;
1926 image->assembly = ass;
1928 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1929 mono_assemblies_unlock ();
1932 if (image->is_module_handle)
1933 mono_image_fixup_vtable (image);
1936 mono_assembly_invoke_load_hook (ass);
1938 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1944 * mono_assembly_load_from:
1945 * @image: Image to load the assembly from
1946 * @fname: assembly name to associate with the assembly
1947 * @status: return status code
1949 * If the provided @image has an assembly reference, it will process the given
1950 * image as an assembly with the given name.
1952 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1954 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
1955 * @refonly parameter set to FALSE.
1956 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1957 * set to #MONO_IMAGE_OK; or NULL on error.
1959 * If there is an error loading the assembly the @status will indicate the
1960 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1961 * image did not contain an assembly reference table.
1965 mono_assembly_load_from (MonoImage *image, const char *fname,
1966 MonoImageOpenStatus *status)
1968 return mono_assembly_load_from_full (image, fname, status, FALSE);
1972 * mono_assembly_name_free:
1973 * @aname: assembly name to free
1975 * Frees the provided assembly name object.
1976 * (it does not frees the object itself, only the name members).
1979 mono_assembly_name_free (MonoAssemblyName *aname)
1984 g_free ((void *) aname->name);
1985 g_free ((void *) aname->culture);
1986 g_free ((void *) aname->hash_value);
1990 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
1993 gchar header [16], val, *arr;
1994 gint i, j, offset, bitlen, keylen, pkeylen;
1996 keylen = strlen (key) >> 1;
2000 /* allow the ECMA standard key */
2001 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2003 *pubkey = g_strdup (key);
2009 val = g_ascii_xdigit_value (key [0]) << 4;
2010 val |= g_ascii_xdigit_value (key [1]);
2015 val = g_ascii_xdigit_value (key [24]);
2016 val |= g_ascii_xdigit_value (key [25]);
2028 /* We need the first 16 bytes
2029 * to check whether this key is valid or not */
2030 pkeylen = strlen (pkey) >> 1;
2034 for (i = 0, j = 0; i < 16; i++) {
2035 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2036 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2039 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2040 header [1] != 0x02 || /* Version (0x02) */
2041 header [2] != 0x00 || /* Reserved (word) */
2042 header [3] != 0x00 ||
2043 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2046 /* Based on this length, we _should_ be able to know if the length is right */
2047 bitlen = read32 (header + 12) >> 3;
2048 if ((bitlen + 16 + 4) != pkeylen)
2051 /* parsing is OK and the public key itself is not requested back */
2055 /* Encode the size of the blob */
2057 if (keylen <= 127) {
2058 arr = (gchar *)g_malloc (keylen + 1);
2059 arr [offset++] = keylen;
2061 arr = (gchar *)g_malloc (keylen + 2);
2062 arr [offset++] = 0x80; /* 10bs */
2063 arr [offset++] = keylen;
2066 for (i = offset, j = 0; i < keylen + offset; i++) {
2067 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2068 arr [i] |= g_ascii_xdigit_value (key [j++]);
2077 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)
2079 gint major, minor, build, revision;
2082 gchar *pkey, *pkeyptr, *encoded, tok [8];
2084 memset (aname, 0, sizeof (MonoAssemblyName));
2087 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2088 if (version_parts < 2 || version_parts > 4)
2091 /* FIXME: we should set build & revision to -1 (instead of 0)
2092 if these are not set in the version string. That way, later on,
2093 we can still determine if these were specified. */
2094 aname->major = major;
2095 aname->minor = minor;
2096 if (version_parts >= 3)
2097 aname->build = build;
2100 if (version_parts == 4)
2101 aname->revision = revision;
2103 aname->revision = 0;
2106 aname->flags = flags;
2108 aname->name = g_strdup (name);
2111 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2112 aname->culture = g_strdup ("");
2114 aname->culture = g_strdup (culture);
2117 if (token && strncmp (token, "null", 4) != 0) {
2120 /* the constant includes the ending NULL, hence the -1 */
2121 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2122 mono_assembly_name_free (aname);
2125 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2126 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2132 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2133 mono_assembly_name_free (aname);
2138 if (save_public_key)
2139 aname->public_key = (guint8*)pkey;
2142 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2146 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2147 // We also need to generate the key token
2148 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2149 encoded = encode_public_tok ((guchar*) tok, 8);
2150 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2153 if (save_public_key)
2154 aname->public_key = (guint8*) pkey;
2163 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2168 parts = g_strsplit (dirname, "_", 3);
2169 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2174 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2180 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2182 char *eqsign = strchr (pair, '=');
2190 *key = (gchar*)pair;
2191 *keylen = eqsign - *key;
2192 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2194 *value = g_strstrip (eqsign + 1);
2199 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2203 gchar *version = NULL;
2205 gchar *culture = NULL;
2207 gchar *token = NULL;
2211 gchar *retargetable = NULL;
2212 gchar *retargetable_uq;
2216 gchar *value, *part_name;
2217 guint32 part_name_len;
2220 gboolean version_defined;
2221 gboolean token_defined;
2223 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2225 if (!is_version_defined)
2226 is_version_defined = &version_defined;
2227 *is_version_defined = FALSE;
2228 if (!is_token_defined)
2229 is_token_defined = &token_defined;
2230 *is_token_defined = FALSE;
2232 parts = tmp = g_strsplit (name, ",", 6);
2233 if (!tmp || !*tmp) {
2238 dllname = g_strstrip (*tmp);
2243 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2244 goto cleanup_and_fail;
2246 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2247 *is_version_defined = TRUE;
2249 if (strlen (version) == 0) {
2250 goto cleanup_and_fail;
2256 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2258 if (strlen (culture) == 0) {
2259 goto cleanup_and_fail;
2265 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2266 *is_token_defined = TRUE;
2268 if (strlen (token) == 0) {
2269 goto cleanup_and_fail;
2275 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2277 if (strlen (key) == 0) {
2278 goto cleanup_and_fail;
2284 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2285 retargetable = value;
2286 retargetable_uq = unquote (retargetable);
2287 if (retargetable_uq != NULL)
2288 retargetable = retargetable_uq;
2290 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2291 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2292 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2293 free (retargetable_uq);
2294 goto cleanup_and_fail;
2297 free (retargetable_uq);
2302 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2304 procarch_uq = unquote (procarch);
2305 if (procarch_uq != NULL)
2306 procarch = procarch_uq;
2308 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2309 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2310 else if (!g_ascii_strcasecmp (procarch, "X86"))
2311 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2312 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2313 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2314 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2315 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2318 goto cleanup_and_fail;
2330 /* if retargetable flag is set, then we must have a fully qualified name */
2331 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2332 goto cleanup_and_fail;
2335 dllname_uq = unquote (dllname);
2336 version_uq = unquote (version);
2337 culture_uq = unquote (culture);
2338 token_uq = unquote (token);
2339 key_uq = unquote (key);
2341 res = build_assembly_name (
2342 dllname_uq == NULL ? dllname : dllname_uq,
2343 version_uq == NULL ? version : version_uq,
2344 culture_uq == NULL ? culture : culture_uq,
2345 token_uq == NULL ? token : token_uq,
2346 key_uq == NULL ? key : key_uq,
2347 flags, arch, aname, save_public_key);
2364 unquote (const char *str)
2372 slen = strlen (str);
2376 if (*str != '\'' && *str != '\"')
2379 end = str + slen - 1;
2383 return g_strndup (str + 1, slen - 2);
2387 * mono_assembly_name_parse:
2388 * @name: name to parse
2389 * @aname: the destination assembly name
2391 * Parses an assembly qualified type name and assigns the name,
2392 * version, culture and token to the provided assembly name object.
2394 * Returns: TRUE if the name could be parsed.
2397 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2399 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2403 * mono_assembly_name_new:
2404 * @name: name to parse
2406 * Allocate a new MonoAssemblyName and fill its values from the
2409 * Returns: a newly allocated structure or NULL if there was any failure.
2412 mono_assembly_name_new (const char *name)
2414 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2415 if (mono_assembly_name_parse (name, aname))
2422 mono_assembly_name_get_name (MonoAssemblyName *aname)
2428 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2430 return aname->culture;
2434 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2436 if (aname->public_key_token [0])
2437 return aname->public_key_token;
2442 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2445 *minor = aname->minor;
2447 *build = aname->build;
2449 *revision = aname->revision;
2450 return aname->major;
2453 static MonoAssembly*
2454 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2456 gchar *fullpath = NULL;
2458 const char* direntry;
2459 MonoAssemblyName gac_aname;
2460 gint major=-1, minor=0, build=0, revision=0;
2461 gboolean exact_version;
2463 dirhandle = g_dir_open (basepath, 0, NULL);
2467 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2469 while ((direntry = g_dir_read_name (dirhandle))) {
2470 gboolean match = TRUE;
2472 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2475 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2478 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2479 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2483 if (exact_version) {
2484 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2485 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2487 else if (gac_aname.major < major)
2489 else if (gac_aname.major == major) {
2490 if (gac_aname.minor < minor)
2492 else if (gac_aname.minor == minor) {
2493 if (gac_aname.build < build)
2495 else if (gac_aname.build == build && gac_aname.revision <= revision)
2502 major = gac_aname.major;
2503 minor = gac_aname.minor;
2504 build = gac_aname.build;
2505 revision = gac_aname.revision;
2507 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2510 mono_assembly_name_free (&gac_aname);
2513 g_dir_close (dirhandle);
2515 if (fullpath == NULL)
2518 MonoAssembly *res = mono_assembly_open (fullpath, status);
2525 * mono_assembly_load_with_partial_name:
2526 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2527 * @status: return status code
2529 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2530 * so it might contain a qualified type name, version, culture and token.
2532 * This will load the assembly from the file whose name is derived from the assembly name
2533 * by appending the .dll extension.
2535 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2536 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2537 * if that fails from the GAC.
2539 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2542 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2546 MonoAssemblyName *aname, base_name;
2547 MonoAssemblyName mapped_aname;
2548 gchar *fullname, *gacpath;
2551 memset (&base_name, 0, sizeof (MonoAssemblyName));
2554 if (!mono_assembly_name_parse (name, aname))
2558 * If no specific version has been requested, make sure we load the
2559 * correct version for system assemblies.
2561 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2562 aname = mono_assembly_remap_version (aname, &mapped_aname);
2564 res = mono_assembly_loaded (aname);
2566 mono_assembly_name_free (aname);
2570 res = invoke_assembly_preload_hook (aname, assemblies_path);
2572 res->in_gac = FALSE;
2573 mono_assembly_name_free (aname);
2577 fullname = g_strdup_printf ("%s.dll", aname->name);
2579 if (extra_gac_paths) {
2580 paths = extra_gac_paths;
2581 while (!res && *paths) {
2582 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2583 res = probe_for_partial_name (gacpath, fullname, aname, status);
2592 mono_assembly_name_free (aname);
2596 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2597 res = probe_for_partial_name (gacpath, fullname, aname, status);
2603 MonoDomain *domain = mono_domain_get ();
2604 MonoReflectionAssembly *refasm;
2606 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2607 if (!is_ok (&error)) {
2609 mono_assembly_name_free (aname);
2610 mono_error_cleanup (&error);
2611 if (*status == MONO_IMAGE_OK)
2612 *status = MONO_IMAGE_IMAGE_INVALID;
2616 res = refasm->assembly;
2620 mono_assembly_name_free (aname);
2626 mono_assembly_is_in_gac (const gchar *filename)
2628 const gchar *rootdir;
2632 if (filename == NULL)
2635 for (paths = extra_gac_paths; paths && *paths; paths++) {
2636 if (strstr (*paths, filename) != *paths)
2639 gp = (gchar *) (filename + strlen (*paths));
2640 if (*gp != G_DIR_SEPARATOR)
2643 if (strncmp (gp, "lib", 3))
2646 if (*gp != G_DIR_SEPARATOR)
2649 if (strncmp (gp, "mono", 4))
2652 if (*gp != G_DIR_SEPARATOR)
2655 if (strncmp (gp, "gac", 3))
2658 if (*gp != G_DIR_SEPARATOR)
2664 rootdir = mono_assembly_getrootdir ();
2665 if (strstr (filename, rootdir) != filename)
2668 gp = (gchar *) (filename + strlen (rootdir));
2669 if (*gp != G_DIR_SEPARATOR)
2672 if (strncmp (gp, "mono", 4))
2675 if (*gp != G_DIR_SEPARATOR)
2678 if (strncmp (gp, "gac", 3))
2681 if (*gp != G_DIR_SEPARATOR)
2687 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2690 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2694 if (strstr (aname->name, ".dll")) {
2695 len = strlen (aname->name) - 4;
2696 name = (gchar *)g_malloc (len + 1);
2697 strncpy (name, aname->name, len);
2700 name = g_strdup (aname->name);
2703 culture = g_utf8_strdown (aname->culture, -1);
2705 culture = g_strdup ("");
2707 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2708 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2712 filename = g_strconcat (pname, ".dll", NULL);
2713 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2719 if (extra_gac_paths) {
2720 paths = extra_gac_paths;
2721 while (!image && *paths) {
2722 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2723 "lib", "mono", "gac", subpath, NULL);
2724 image = mono_image_open (fullpath, NULL);
2735 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2736 "mono", "gac", subpath, NULL);
2737 image = mono_image_open (fullpath, NULL);
2744 static MonoAssemblyName*
2745 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2747 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2748 dest_name->major = info->new_version.major;
2749 dest_name->minor = info->new_version.minor;
2750 dest_name->build = info->new_version.build;
2751 dest_name->revision = info->new_version.revision;
2756 /* LOCKING: assembly_binding lock must be held */
2757 static MonoAssemblyBindingInfo*
2758 search_binding_loaded (MonoAssemblyName *aname)
2762 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2763 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2764 if (assembly_binding_maps_name (info, aname))
2771 static inline gboolean
2772 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2774 if (left->major != right->major || left->minor != right->minor ||
2775 left->build != right->build || left->revision != right->revision)
2781 static inline gboolean
2782 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2784 if (left->has_old_version_bottom != right->has_old_version_bottom)
2787 if (left->has_old_version_top != right->has_old_version_top)
2790 if (left->has_new_version != right->has_new_version)
2793 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2796 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2799 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2805 /* LOCKING: assumes all the necessary locks are held */
2807 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2809 MonoAssemblyBindingInfo *info_copy;
2811 MonoAssemblyBindingInfo *info_tmp;
2812 MonoDomain *domain = (MonoDomain*)user_data;
2817 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2818 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2819 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2823 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2824 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2826 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2828 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2830 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2834 get_version_number (int major, int minor)
2836 return major * 256 + minor;
2839 static inline gboolean
2840 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2842 int aname_version_number = get_version_number (aname->major, aname->minor);
2843 if (!info->has_old_version_bottom)
2846 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2849 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2852 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2853 info->major = aname->major;
2854 info->minor = aname->minor;
2859 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2860 static MonoAssemblyBindingInfo*
2861 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2863 MonoAssemblyBindingInfo *info;
2866 if (!domain->assembly_bindings)
2870 for (list = domain->assembly_bindings; list; list = list->next) {
2871 info = (MonoAssemblyBindingInfo *)list->data;
2872 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2878 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2879 info->has_new_version && assembly_binding_maps_name (info, aname))
2880 info->is_valid = TRUE;
2882 info->is_valid = FALSE;
2888 static MonoAssemblyName*
2889 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2891 MonoAssemblyBindingInfo *info, *info2;
2895 if (aname->public_key_token [0] == 0)
2898 domain = mono_domain_get ();
2900 mono_assembly_binding_lock ();
2901 info = search_binding_loaded (aname);
2902 mono_assembly_binding_unlock ();
2905 mono_domain_lock (domain);
2906 info = get_per_domain_assembly_binding_info (domain, aname);
2907 mono_domain_unlock (domain);
2911 if (!check_policy_versions (info, aname))
2914 mono_assembly_bind_version (info, aname, dest_name);
2918 if (domain && domain->setup && domain->setup->configuration_file) {
2919 mono_domain_lock (domain);
2920 if (!domain->assembly_bindings_parsed) {
2921 gchar *domain_config_file_name = mono_string_to_utf8 (domain->setup->configuration_file);
2922 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2924 if (!domain_config_file_path)
2925 domain_config_file_path = domain_config_file_name;
2927 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2928 domain->assembly_bindings_parsed = TRUE;
2929 if (domain_config_file_name != domain_config_file_path)
2930 g_free (domain_config_file_name);
2931 g_free (domain_config_file_path);
2934 info2 = get_per_domain_assembly_binding_info (domain, aname);
2937 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2938 info->name = g_strdup (info2->name);
2939 info->culture = g_strdup (info2->culture);
2940 info->domain_id = domain->domain_id;
2943 mono_domain_unlock (domain);
2947 info = g_new0 (MonoAssemblyBindingInfo, 1);
2948 info->major = aname->major;
2949 info->minor = aname->minor;
2952 if (!info->is_valid) {
2953 ppimage = mono_assembly_load_publisher_policy (aname);
2955 get_publisher_policy_info (ppimage, aname, info);
2956 mono_image_close (ppimage);
2960 /* Define default error value if needed */
2961 if (!info->is_valid) {
2962 info->name = g_strdup (aname->name);
2963 info->culture = g_strdup (aname->culture);
2964 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2967 mono_assembly_binding_lock ();
2968 info2 = search_binding_loaded (aname);
2970 /* This binding was added by another thread
2972 mono_assembly_binding_info_free (info);
2977 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2979 mono_assembly_binding_unlock ();
2981 if (!info->is_valid || !check_policy_versions (info, aname))
2984 mono_assembly_bind_version (info, aname, dest_name);
2989 * mono_assembly_load_from_gac
2991 * @aname: The assembly name object
2993 static MonoAssembly*
2994 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
2996 MonoAssembly *result = NULL;
2997 gchar *name, *version, *culture, *fullpath, *subpath;
3002 if (aname->public_key_token [0] == 0) {
3006 if (strstr (aname->name, ".dll")) {
3007 len = strlen (filename) - 4;
3008 name = (gchar *)g_malloc (len + 1);
3009 strncpy (name, aname->name, len);
3012 name = g_strdup (aname->name);
3015 if (aname->culture) {
3016 culture = g_utf8_strdown (aname->culture, -1);
3018 culture = g_strdup ("");
3021 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3022 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3023 aname->minor, aname->build, aname->revision,
3027 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3032 if (extra_gac_paths) {
3033 paths = extra_gac_paths;
3034 while (!result && *paths) {
3035 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3036 result = mono_assembly_open_full (fullpath, status, refonly);
3043 result->in_gac = TRUE;
3048 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3049 "mono", "gac", subpath, NULL);
3050 result = mono_assembly_open_full (fullpath, status, refonly);
3054 result->in_gac = TRUE;
3062 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3065 MonoAssemblyName *aname;
3068 /* g_print ("corlib already loaded\n"); */
3072 // In native client, Corlib is embedded in the executable as static variable corlibData
3073 #if defined(__native_client__)
3074 if (corlibData != NULL && corlibSize != 0) {
3076 /* First "FALSE" instructs mono not to make a copy. */
3077 /* Second "FALSE" says this is not just a ref. */
3078 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3079 if (image == NULL || status != 0)
3080 g_print("mono_image_open_from_data_full failed: %d\n", status);
3081 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3082 if (corlib == NULL || status != 0)
3083 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3089 // A nonstandard preload hook may provide a special mscorlib assembly
3090 aname = mono_assembly_name_new ("mscorlib.dll");
3091 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3092 mono_assembly_name_free (aname);
3095 goto return_corlib_and_facades;
3097 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3098 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3099 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3101 goto return_corlib_and_facades;
3104 /* Normal case: Load corlib from mono/<version> */
3105 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3106 if (assemblies_path) { // Custom assemblies path
3107 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3109 g_free (corlib_file);
3110 goto return_corlib_and_facades;
3113 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3114 g_free (corlib_file);
3116 return_corlib_and_facades:
3117 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3118 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3124 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3125 const char *basedir,
3126 MonoImageOpenStatus *status,
3129 MonoAssembly *result;
3130 char *fullpath, *filename;
3131 MonoAssemblyName maped_aname;
3132 MonoAssemblyName maped_name_pp;
3137 aname = mono_assembly_remap_version (aname, &maped_aname);
3139 /* Reflection only assemblies don't get assembly binding */
3141 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3143 result = mono_assembly_loaded_full (aname, refonly);
3147 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3149 result->in_gac = FALSE;
3153 /* Currently we retrieve the loaded corlib for reflection
3154 * only requests, like a common reflection only assembly
3156 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3157 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3160 len = strlen (aname->name);
3161 for (ext_index = 0; ext_index < 2; ext_index ++) {
3162 ext = ext_index == 0 ? ".dll" : ".exe";
3163 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3164 filename = g_strdup (aname->name);
3165 /* Don't try appending .dll/.exe if it already has one of those extensions */
3168 filename = g_strconcat (aname->name, ext, NULL);
3171 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3178 fullpath = g_build_filename (basedir, filename, NULL);
3179 result = mono_assembly_open_full (fullpath, status, refonly);
3182 result->in_gac = FALSE;
3188 result = load_in_path (filename, default_path, status, refonly);
3190 result->in_gac = FALSE;
3200 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3202 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3205 /* Try a postload search hook */
3206 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3211 * mono_assembly_load_full:
3212 * @aname: A MonoAssemblyName with the assembly name to load.
3213 * @basedir: A directory to look up the assembly at.
3214 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3215 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3217 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3218 * attempts to load the assembly from that directory before probing the standard locations.
3220 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3221 * assembly binding takes place.
3223 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3224 * value pointed by status is updated with an error code.
3227 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3229 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3233 * mono_assembly_load:
3234 * @aname: A MonoAssemblyName with the assembly name to load.
3235 * @basedir: A directory to look up the assembly at.
3236 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3238 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3239 * attempts to load the assembly from that directory before probing the standard locations.
3241 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3242 * value pointed by status is updated with an error code.
3245 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3247 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3251 * mono_assembly_loaded_full:
3252 * @aname: an assembly to look for.
3253 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3255 * This is used to determine if the specified assembly has been loaded
3256 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3257 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3260 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3263 MonoAssemblyName maped_aname;
3265 aname = mono_assembly_remap_version (aname, &maped_aname);
3267 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3273 * mono_assembly_loaded:
3274 * @aname: an assembly to look for.
3276 * This is used to determine if the specified assembly has been loaded
3278 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3279 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3282 mono_assembly_loaded (MonoAssemblyName *aname)
3284 return mono_assembly_loaded_full (aname, FALSE);
3288 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3290 if (assembly == NULL || assembly == REFERENCE_MISSING)
3293 if (assembly_is_dynamic (assembly)) {
3295 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3296 for (i = 0; i < dynimg->image.module_count; ++i)
3297 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3298 mono_dynamic_image_release_gc_roots (dynimg);
3303 * Returns whether mono_assembly_close_finish() must be called as
3304 * well. See comment for mono_image_close_except_pools() for why we
3305 * unload in two steps.
3308 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3311 g_return_val_if_fail (assembly != NULL, FALSE);
3313 if (assembly == REFERENCE_MISSING)
3316 /* Might be 0 already */
3317 if (InterlockedDecrement (&assembly->ref_count) > 0)
3320 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3322 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3324 mono_debug_close_image (assembly->image);
3326 mono_assemblies_lock ();
3327 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3328 mono_assemblies_unlock ();
3330 assembly->image->assembly = NULL;
3332 if (!mono_image_close_except_pools (assembly->image))
3333 assembly->image = NULL;
3335 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3336 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3337 mono_assembly_name_free (fname);
3340 g_slist_free (assembly->friend_assembly_names);
3341 g_free (assembly->basedir);
3343 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3349 mono_assembly_close_finish (MonoAssembly *assembly)
3351 g_assert (assembly && assembly != REFERENCE_MISSING);
3353 if (assembly->image)
3354 mono_image_close_finish (assembly->image);
3356 if (assembly_is_dynamic (assembly)) {
3357 g_free ((char*)assembly->aname.culture);
3364 * mono_assembly_close:
3365 * @assembly: the assembly to release.
3367 * This method releases a reference to the @assembly. The assembly is
3368 * only released when all the outstanding references to it are released.
3371 mono_assembly_close (MonoAssembly *assembly)
3373 if (mono_assembly_close_except_image_pools (assembly))
3374 mono_assembly_close_finish (assembly);
3378 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3380 return mono_image_load_file_for_image (assembly->image, idx);
3384 * mono_assembly_foreach:
3385 * @func: function to invoke for each assembly loaded
3386 * @user_data: data passed to the callback
3388 * Invokes the provided @func callback for each assembly loaded into
3389 * the runtime. The first parameter passed to the callback is the
3390 * `MonoAssembly*`, and the second parameter is the @user_data.
3392 * This is done for all assemblies loaded in the runtime, not just
3393 * those loaded in the current application domain.
3396 mono_assembly_foreach (GFunc func, gpointer user_data)
3401 * We make a copy of the list to avoid calling the callback inside the
3402 * lock, which could lead to deadlocks.
3404 mono_assemblies_lock ();
3405 copy = g_list_copy (loaded_assemblies);
3406 mono_assemblies_unlock ();
3408 g_list_foreach (loaded_assemblies, func, user_data);
3414 * mono_assemblies_cleanup:
3416 * Free all resources used by this module.
3419 mono_assemblies_cleanup (void)
3423 mono_os_mutex_destroy (&assemblies_mutex);
3424 mono_os_mutex_destroy (&assembly_binding_mutex);
3426 for (l = loaded_assembly_bindings; l; l = l->next) {
3427 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3429 mono_assembly_binding_info_free (info);
3432 g_slist_free (loaded_assembly_bindings);
3434 free_assembly_load_hooks ();
3435 free_assembly_search_hooks ();
3436 free_assembly_preload_hooks ();
3439 /*LOCKING takes the assembly_binding lock*/
3441 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3445 mono_assembly_binding_lock ();
3446 iter = &loaded_assembly_bindings;
3449 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3451 if (info->domain_id == domain_id) {
3453 mono_assembly_binding_info_free (info);
3460 mono_assembly_binding_unlock ();
3464 * Holds the assembly of the application, for
3465 * System.Diagnostics.Process::MainModule
3467 static MonoAssembly *main_assembly=NULL;
3470 mono_assembly_set_main (MonoAssembly *assembly)
3472 main_assembly = assembly;
3476 * mono_assembly_get_main:
3478 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3481 mono_assembly_get_main (void)
3483 return (main_assembly);
3487 * mono_assembly_get_image:
3488 * @assembly: The assembly to retrieve the image from
3490 * Returns: the MonoImage associated with this assembly.
3493 mono_assembly_get_image (MonoAssembly *assembly)
3495 return assembly->image;
3499 * mono_assembly_get_name:
3500 * @assembly: The assembly to retrieve the name from
3502 * The returned name's lifetime is the same as @assembly's.
3504 * Returns: the MonoAssemblyName associated with this assembly.
3507 mono_assembly_get_name (MonoAssembly *assembly)
3509 return &assembly->aname;
3513 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3515 bundles = assemblies;
3518 #define MONO_DECLSEC_FORMAT_10 0x3C
3519 #define MONO_DECLSEC_FORMAT_20 0x2E
3520 #define MONO_DECLSEC_FIELD 0x53
3521 #define MONO_DECLSEC_PROPERTY 0x54
3523 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3524 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3525 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3526 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3527 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3530 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3534 case MONO_DECLSEC_PROPERTY:
3536 case MONO_DECLSEC_FIELD:
3538 *abort_decoding = TRUE;
3543 if (*p++ != MONO_TYPE_BOOLEAN) {
3544 *abort_decoding = TRUE;
3548 /* property name length */
3549 len = mono_metadata_decode_value (p, &p);
3551 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3562 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3564 int i, j, num, len, params_len;
3566 if (*p == MONO_DECLSEC_FORMAT_10) {
3567 gsize read, written;
3568 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3570 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3576 if (*p++ != MONO_DECLSEC_FORMAT_20)
3579 /* number of encoded permission attributes */
3580 num = mono_metadata_decode_value (p, &p);
3581 for (i = 0; i < num; ++i) {
3582 gboolean is_valid = FALSE;
3583 gboolean abort_decoding = FALSE;
3585 /* attribute name length */
3586 len = mono_metadata_decode_value (p, &p);
3588 /* We don't really need to fully decode the type. Comparing the name is enough */
3589 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3593 /*size of the params table*/
3594 params_len = mono_metadata_decode_value (p, &p);
3596 const char *params_end = p + params_len;
3598 /* number of parameters */
3599 len = mono_metadata_decode_value (p, &p);
3601 for (j = 0; j < len; ++j) {
3602 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3618 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3621 guint32 cols [MONO_DECL_SECURITY_SIZE];
3625 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3626 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3628 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3630 for (i = 0; i < t->rows; ++i) {
3631 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3632 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3634 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3637 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3638 len = mono_metadata_decode_blob_size (blob, &blob);
3642 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3643 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3648 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);