2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "object-internals.h"
21 #include <mono/metadata/loader.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/metadata-internals.h>
24 #include <mono/metadata/profiler-private.h>
25 #include <mono/metadata/class-internals.h>
26 #include <mono/metadata/domain-internals.h>
27 #include <mono/metadata/reflection-internals.h>
28 #include <mono/metadata/mono-endian.h>
29 #include <mono/metadata/mono-debug.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/utils/mono-uri.h>
32 #include <mono/metadata/mono-config.h>
33 #include <mono/metadata/mono-config-dirs.h>
34 #include <mono/utils/mono-digest.h>
35 #include <mono/utils/mono-logger-internals.h>
36 #include <mono/utils/mono-path.h>
37 #include <mono/metadata/reflection.h>
38 #include <mono/metadata/coree.h>
39 #include <mono/metadata/cil-coff.h>
40 #include <mono/utils/mono-io-portability.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-os-mutex.h>
45 #include <sys/types.h>
50 #ifdef PLATFORM_MACOSX
51 #include <mach-o/dyld.h>
54 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
56 const char* assembly_name;
57 guint8 version_set_index;
58 const char* new_assembly_name;
59 gboolean only_lower_versions;
62 /* the default search path is empty, the first slot is replaced with the computed value */
70 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
71 static char **assemblies_path = NULL;
73 /* Contains the list of directories that point to auxiliary GACs */
74 static char **extra_gac_paths = NULL;
76 #ifndef DISABLE_ASSEMBLY_REMAPPING
77 /* The list of system assemblies what will be remapped to the running
78 * runtime version. WARNING: this list must be sorted.
79 * The integer number is an index in the MonoRuntimeInfo structure, whose
80 * values can be found in domain.c - supported_runtimes. Look there
81 * to understand what remapping will be made.
83 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
86 static const AssemblyVersionMap framework_assemblies [] = {
88 {"Commons.Xml.Relaxng", 0},
95 {"Microsoft.Build.Engine", 2, NULL, TRUE},
96 {"Microsoft.Build.Framework", 2, NULL, TRUE},
97 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
98 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
99 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
100 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
101 {"Microsoft.VisualBasic", 1},
102 {"Microsoft.VisualC", 1},
104 {"Mono.CompilerServices.SymbolWriter", 0},
106 {"Mono.Data.SybaseClient", 0},
107 {"Mono.Data.Tds", 0},
108 {"Mono.Data.TdsClient", 0},
109 {"Mono.GetOptions", 0},
112 {"Mono.Security", 0},
113 {"Mono.Security.Win32", 0},
115 {"Novell.Directory.Ldap", 0},
118 {"System.ComponentModel.Composition", 2},
119 {"System.ComponentModel.DataAnnotations", 2},
120 {"System.Configuration", 0},
121 {"System.Configuration.Install", 0},
124 {"System.Data.Linq", 2},
125 {"System.Data.OracleClient", 0},
126 {"System.Data.Services", 2},
127 {"System.Data.Services.Client", 2},
128 {"System.Data.SqlXml", 0},
129 {"System.Design", 0},
130 {"System.DirectoryServices", 0},
131 {"System.Drawing", 0},
132 {"System.Drawing.Design", 0},
133 {"System.EnterpriseServices", 0},
134 {"System.IdentityModel", 3},
135 {"System.IdentityModel.Selectors", 3},
136 {"System.Management", 0},
137 {"System.Messaging", 0},
139 {"System.Runtime.Remoting", 0},
140 {"System.Runtime.Serialization", 3},
141 {"System.Runtime.Serialization.Formatters.Soap", 0},
142 {"System.Security", 0},
143 {"System.ServiceModel", 3},
144 {"System.ServiceModel.Web", 2},
145 {"System.ServiceProcess", 0},
146 {"System.Transactions", 0},
148 {"System.Web.Abstractions", 2},
149 {"System.Web.DynamicData", 2},
150 {"System.Web.Extensions", 2},
151 {"System.Web.Mobile", 0},
152 {"System.Web.Routing", 2},
153 {"System.Web.Services", 0},
154 {"System.Windows.Forms", 0},
156 {"System.Xml.Linq", 2},
163 * keeps track of loaded assemblies
165 static GList *loaded_assemblies = NULL;
166 static MonoAssembly *corlib;
168 #if defined(__native_client__)
170 /* On Native Client, allow mscorlib to be loaded from memory */
171 /* instead of loaded off disk. If these are not set, default */
172 /* mscorlib loading will take place */
174 /* NOTE: If mscorlib data is passed to mono in this way then */
175 /* it needs to remain allocated during the use of mono. */
177 static void *corlibData = NULL;
178 static size_t corlibSize = 0;
181 mono_set_corlib_data (void *data, size_t size)
189 static char* unquote (const char *str);
191 /* This protects loaded_assemblies and image->references */
192 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
193 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
194 static mono_mutex_t assemblies_mutex;
196 /* If defined, points to the bundled assembly information */
197 const MonoBundledAssembly **bundles;
199 static mono_mutex_t assembly_binding_mutex;
201 /* Loaded assembly binding info */
202 static GSList *loaded_assembly_bindings = NULL;
204 /* Class lazy loading functions */
205 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
206 static GENERATE_TRY_GET_CLASS_WITH_CACHE (reference_assembly, System.Runtime.CompilerServices, ReferenceAssemblyAttribute)
209 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
211 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
213 mono_assembly_is_in_gac (const gchar *filanem);
216 encode_public_tok (const guchar *token, gint32 len)
218 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
222 res = (gchar *)g_malloc (len * 2 + 1);
223 for (i = 0; i < len; i++) {
224 res [i * 2] = allowed [token [i] >> 4];
225 res [i * 2 + 1] = allowed [token [i] & 0xF];
232 * mono_public_tokens_are_equal:
233 * @pubt1: first public key token
234 * @pubt2: second public key token
236 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
240 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
242 return memcmp (pubt1, pubt2, 16) == 0;
246 * mono_set_assemblies_path:
247 * @path: list of paths that contain directories where Mono will look for assemblies
249 * Use this method to override the standard assembly lookup system and
250 * override any assemblies coming from the GAC. This is the method
251 * that supports the MONO_PATH variable.
253 * Notice that MONO_PATH and this method are really a very bad idea as
254 * it prevents the GAC from working and it prevents the standard
255 * resolution mechanisms from working. Nonetheless, for some debugging
256 * situations and bootstrapping setups, this is useful to have.
259 mono_set_assemblies_path (const char* path)
261 char **splitted, **dest;
263 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
265 g_strfreev (assemblies_path);
266 assemblies_path = dest = splitted;
268 char *tmp = *splitted;
270 *dest++ = mono_path_canonicalize (tmp);
276 if (g_getenv ("MONO_DEBUG") == NULL)
279 splitted = assemblies_path;
281 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
282 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
288 /* Native Client can't get this info from an environment variable so */
289 /* it's passed in to the runtime, or set manually by embedding code. */
290 #ifdef __native_client__
291 char* nacl_mono_path = NULL;
295 check_path_env (void)
298 path = g_getenv ("MONO_PATH");
299 #ifdef __native_client__
301 path = nacl_mono_path;
303 if (!path || assemblies_path != NULL)
306 mono_set_assemblies_path(path);
310 check_extra_gac_path_env (void) {
312 char **splitted, **dest;
314 path = g_getenv ("MONO_GAC_PREFIX");
318 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
320 g_strfreev (extra_gac_paths);
321 extra_gac_paths = dest = splitted;
329 if (g_getenv ("MONO_DEBUG") == NULL)
333 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
334 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
341 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
343 if (!info || !info->name)
346 if (strcmp (info->name, aname->name))
349 if (info->major != aname->major || info->minor != aname->minor)
352 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
355 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
358 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
365 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
371 g_free (info->culture);
375 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
378 guint32 cols [MONO_MANIFEST_SIZE];
379 const gchar *filename;
380 gchar *subpath, *fullpath;
382 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
383 /* MS Impl. accepts policy assemblies with more than
384 * one manifest resource, and only takes the first one */
386 binding_info->is_valid = FALSE;
390 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
391 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
392 binding_info->is_valid = FALSE;
396 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
397 g_assert (filename != NULL);
399 subpath = g_path_get_dirname (image->name);
400 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
401 mono_config_parse_publisher_policy (fullpath, binding_info);
405 /* Define the optional elements/attributes before checking */
406 if (!binding_info->culture)
407 binding_info->culture = g_strdup ("");
409 /* Check that the most important elements/attributes exist */
410 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
411 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
412 mono_assembly_binding_info_free (binding_info);
413 binding_info->is_valid = FALSE;
417 binding_info->is_valid = TRUE;
421 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
423 if (v->major > aname->major)
425 else if (v->major < aname->major)
428 if (v->minor > aname->minor)
430 else if (v->minor < aname->minor)
433 if (v->build > aname->build)
435 else if (v->build < aname->build)
438 if (v->revision > aname->revision)
440 else if (v->revision < aname->revision)
447 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
452 /* If has_old_version_top doesn't exist, we don't have an interval */
453 if (!info->has_old_version_top) {
454 if (compare_versions (&info->old_version_bottom, name) == 0)
460 /* Check that the version defined by name is valid for the interval */
461 if (compare_versions (&info->old_version_top, name) < 0)
464 /* We should be greater or equal than the small version */
465 if (compare_versions (&info->old_version_bottom, name) > 0)
472 * mono_assembly_names_equal:
474 * @r: second assembly.
476 * Compares two MonoAssemblyNames and returns whether they are equal.
478 * This compares the names, the cultures, the release version and their
481 * Returns: TRUE if both assembly names are equal.
484 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
486 if (!l->name || !r->name)
489 if (strcmp (l->name, r->name))
492 if (l->culture && r->culture && strcmp (l->culture, r->culture))
495 if (l->major != r->major || l->minor != r->minor ||
496 l->build != r->build || l->revision != r->revision)
497 if (! ((l->major == 0 && l->minor == 0 && l->build == 0 && l->revision == 0) || (r->major == 0 && r->minor == 0 && r->build == 0 && r->revision == 0)))
500 if (!l->public_key_token [0] || !r->public_key_token [0])
503 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
509 static MonoAssembly *
510 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
514 MonoAssembly *result;
516 for (i = 0; search_path [i]; ++i) {
517 fullpath = g_build_filename (search_path [i], basename, NULL);
518 result = mono_assembly_open_full (fullpath, status, refonly);
527 * mono_assembly_setrootdir:
528 * @root_dir: The pathname of the root directory where we will locate assemblies
530 * This routine sets the internal default root directory for looking up
533 * This is used by Windows installations to compute dynamically the
534 * place where the Mono assemblies are located.
538 mono_assembly_setrootdir (const char *root_dir)
541 * Override the MONO_ASSEMBLIES directory configured at compile time.
543 /* Leak if called more than once */
544 default_path [0] = g_strdup (root_dir);
548 * mono_assembly_getrootdir:
550 * Obtains the root directory used for looking up assemblies.
552 * Returns: a string with the directory, this string should not be freed.
554 G_CONST_RETURN gchar *
555 mono_assembly_getrootdir (void)
557 return default_path [0];
562 * @assembly_dir: the base directory for assemblies
563 * @config_dir: the base directory for configuration files
565 * This routine is used internally and by developers embedding
566 * the runtime into their own applications.
568 * There are a number of cases to consider: Mono as a system-installed
569 * package that is available on the location preconfigured or Mono in
570 * a relocated location.
572 * If you are using a system-installed Mono, you can pass NULL
573 * to both parameters. If you are not, you should compute both
574 * directory values and call this routine.
576 * The values for a given PREFIX are:
578 * assembly_dir: PREFIX/lib
579 * config_dir: PREFIX/etc
581 * Notice that embedders that use Mono in a relocated way must
582 * compute the location at runtime, as they will be in control
583 * of where Mono is installed.
586 mono_set_dirs (const char *assembly_dir, const char *config_dir)
588 if (assembly_dir == NULL)
589 assembly_dir = mono_config_get_assemblies_dir ();
590 if (config_dir == NULL)
591 config_dir = mono_config_get_cfg_dir ();
592 mono_assembly_setrootdir (assembly_dir);
593 mono_set_config_dir (config_dir);
599 compute_base (char *path)
601 char *p = strrchr (path, '/');
605 /* Not a well known Mono executable, we are embedded, cant guess the base */
606 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
610 p = strrchr (path, '/');
614 if (strcmp (p, "/bin") != 0)
623 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
626 static G_GNUC_UNUSED void
630 char *config, *lib, *mono;
635 * Only /usr prefix is treated specially
637 bindir = mono_config_get_bin_dir ();
639 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
644 config = g_build_filename (base, "etc", NULL);
645 lib = g_build_filename (base, "lib", NULL);
646 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
647 if (stat (mono, &buf) == -1)
650 mono_set_dirs (lib, config);
658 #endif /* HOST_WIN32 */
663 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
664 * this auto-detects the prefix where Mono was installed.
667 mono_set_rootdir (void)
669 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
670 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
673 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
677 * _NSGetExecutablePath may return -1 to indicate buf is not large
678 * enough, but we ignore that case to avoid having to do extra dynamic
679 * allocation for the path and hope that 4096 is enough - this is
680 * ok in the Linux/Solaris case below at least...
684 guint buf_size = sizeof (buf);
687 if (_NSGetExecutablePath (buf, &buf_size) == 0)
688 name = g_strdup (buf);
697 resolvedname = mono_path_resolve_symlinks (name);
699 bindir = g_path_get_dirname (resolvedname);
700 installdir = g_path_get_dirname (bindir);
701 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
703 config = g_build_filename (root, "..", "etc", NULL);
705 mono_set_dirs (root, config);
707 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
708 mono_set_dirs (root, config);
718 g_free (resolvedname);
719 #elif defined(DISABLE_MONO_AUTODETECTION)
727 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
735 /* Solaris 10 style */
736 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
737 s = readlink (str, buf, sizeof (buf)-1);
749 * mono_assemblies_init:
751 * Initialize global variables used by this module.
754 mono_assemblies_init (void)
757 * Initialize our internal paths if we have not been initialized yet.
758 * This happens when embedders use Mono.
760 if (mono_assembly_getrootdir () == NULL)
764 check_extra_gac_path_env ();
766 mono_os_mutex_init_recursive (&assemblies_mutex);
767 mono_os_mutex_init (&assembly_binding_mutex);
771 mono_assembly_binding_lock (void)
773 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
777 mono_assembly_binding_unlock (void)
779 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
783 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
785 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
786 guint32 cols [MONO_ASSEMBLY_SIZE];
787 gint32 machine, flags;
792 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
795 aname->hash_value = NULL;
796 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
797 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
798 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
799 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
800 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
801 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
802 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
803 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
804 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
805 guchar* token = (guchar *)g_malloc (8);
810 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
811 len = mono_metadata_decode_blob_size (pkey, &pkey);
812 aname->public_key = (guchar*)pkey;
814 mono_digest_get_public_token (token, aname->public_key, len);
815 encoded = encode_public_tok (token, 8);
816 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
822 aname->public_key = NULL;
823 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
826 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
827 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
830 aname->public_key = 0;
832 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
833 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
835 case COFF_MACHINE_I386:
836 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
837 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
838 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
839 else if ((flags & 0x70) == 0x70)
840 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
842 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
844 case COFF_MACHINE_IA64:
845 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
847 case COFF_MACHINE_AMD64:
848 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
850 case COFF_MACHINE_ARM:
851 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
861 * mono_stringify_assembly_name:
862 * @aname: the assembly name.
864 * Convert @aname into its string format. The returned string is dynamically
865 * allocated and should be freed by the caller.
867 * Returns: a newly allocated string with a string representation of
871 mono_stringify_assembly_name (MonoAssemblyName *aname)
873 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
875 return g_strdup_printf (
876 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
877 quote, aname->name, quote,
878 aname->major, aname->minor, aname->build, aname->revision,
879 aname->culture && *aname->culture? aname->culture: "neutral",
880 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
881 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
885 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
887 const gchar *public_tok;
890 public_tok = mono_metadata_blob_heap (image, key_index);
891 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
893 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
895 mono_digest_get_public_token (token, (guchar*)public_tok, len);
896 return encode_public_tok (token, 8);
899 return encode_public_tok ((guchar*)public_tok, len);
903 * mono_assembly_addref:
904 * @assemnly: the assembly to reference
906 * This routine increments the reference count on a MonoAssembly.
907 * The reference count is reduced every time the method mono_assembly_close() is
911 mono_assembly_addref (MonoAssembly *assembly)
913 InterlockedIncrement (&assembly->ref_count);
917 * CAUTION: This table must be kept in sync with
918 * ivkm/reflect/Fusion.cs
921 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
922 #define WINFX_KEY "31bf3856ad364e35"
923 #define ECMA_KEY "b77a5c561934e089"
924 #define MSFINAL_KEY "b03f5f7f11d50a3a"
925 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
933 static KeyRemapEntry key_remap_table[] = {
934 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
935 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
936 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
937 { "System", SILVERLIGHT_KEY, ECMA_KEY },
938 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
939 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
940 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
941 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
942 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
943 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
944 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
945 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
946 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
947 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
948 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
949 { "System.Numerics", WINFX_KEY, ECMA_KEY },
950 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
951 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
952 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
953 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
954 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
955 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
956 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
957 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
958 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
959 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
960 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
961 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
962 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
966 remap_keys (MonoAssemblyName *aname)
969 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
970 const KeyRemapEntry *entry = &key_remap_table [i];
972 if (strcmp (aname->name, entry->name) ||
973 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
976 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
978 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
979 "Remapped public key token of retargetable assembly %s from %s to %s",
980 aname->name, entry->from, entry->to);
985 static MonoAssemblyName *
986 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
988 const MonoRuntimeInfo *current_runtime;
989 int pos, first, last;
991 if (aname->name == NULL) return aname;
993 current_runtime = mono_get_runtime_info ();
995 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
996 const AssemblyVersionSet* vset;
998 /* Remap to current runtime */
999 vset = ¤t_runtime->version_sets [0];
1001 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1002 dest_aname->major = vset->major;
1003 dest_aname->minor = vset->minor;
1004 dest_aname->build = vset->build;
1005 dest_aname->revision = vset->revision;
1006 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1008 /* Remap assembly name */
1009 if (!strcmp (aname->name, "System.Net"))
1010 dest_aname->name = g_strdup ("System");
1012 remap_keys (dest_aname);
1014 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1015 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1017 aname->major, aname->minor, aname->build, aname->revision,
1019 vset->major, vset->minor, vset->build, vset->revision
1025 #ifndef DISABLE_ASSEMBLY_REMAPPING
1027 last = G_N_ELEMENTS (framework_assemblies) - 1;
1029 while (first <= last) {
1031 pos = first + (last - first) / 2;
1032 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1034 const AssemblyVersionSet* vset;
1035 int index = framework_assemblies[pos].version_set_index;
1036 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1037 vset = ¤t_runtime->version_sets [index];
1039 if (aname->major == vset->major && aname->minor == vset->minor &&
1040 aname->build == vset->build && aname->revision == vset->revision)
1043 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1046 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1047 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1048 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1050 aname->major, aname->minor, aname->build, aname->revision,
1051 vset->major, vset->minor, vset->build, vset->revision
1054 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1055 dest_aname->major = vset->major;
1056 dest_aname->minor = vset->minor;
1057 dest_aname->build = vset->build;
1058 dest_aname->revision = vset->revision;
1059 if (framework_assemblies[pos].new_assembly_name != NULL) {
1060 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1061 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1062 "The assembly name %s was remapped to %s",
1067 } else if (res < 0) {
1079 * mono_assembly_get_assemblyref:
1080 * @image: pointer to the MonoImage to extract the information from.
1081 * @index: index to the assembly reference in the image.
1082 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1084 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1087 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1090 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1093 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1095 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1097 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1098 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1099 aname->hash_value = hash;
1100 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1101 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1102 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1103 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1104 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1105 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1106 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1108 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1109 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1110 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1113 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1118 mono_assembly_load_reference (MonoImage *image, int index)
1120 MonoAssembly *reference;
1121 MonoAssemblyName aname;
1122 MonoImageOpenStatus status;
1125 * image->references is shared between threads, so we need to access
1126 * it inside a critical section.
1128 mono_assemblies_lock ();
1129 if (!image->references) {
1130 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1132 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1133 image->nreferences = t->rows;
1135 reference = image->references [index];
1136 mono_assemblies_unlock ();
1140 mono_assembly_get_assemblyref (image, index, &aname);
1142 if (image->assembly && image->assembly->ref_only) {
1143 /* We use the loaded corlib */
1144 if (!strcmp (aname.name, "mscorlib"))
1145 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1147 reference = mono_assembly_loaded_full (&aname, TRUE);
1149 /* Try a postload search hook */
1150 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1154 * Here we must advice that the error was due to
1155 * a non loaded reference using the ReflectionOnly api
1158 reference = (MonoAssembly *)REFERENCE_MISSING;
1160 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1161 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1162 * accordingly, it would fail on the MS runtime before).
1163 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1164 * example bug-349190.2.cs and who knows how much more code in the wild.
1166 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1167 if (!reference && image->assembly)
1168 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1171 if (reference == NULL){
1174 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1175 extra_msg = g_strdup_printf ("The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (%s).\n", image->assembly != NULL ? image->assembly->basedir : "" );
1176 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1177 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1178 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1179 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1180 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1181 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1183 extra_msg = g_strdup ("");
1186 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1187 " Assembly: %s (assemblyref_index=%d)\n"
1188 " Version: %d.%d.%d.%d\n"
1189 " Public Key: %s\n%s",
1190 image->name, aname.name, index,
1191 aname.major, aname.minor, aname.build, aname.revision,
1192 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1196 mono_assemblies_lock ();
1197 if (reference == NULL) {
1198 /* Flag as not found */
1199 reference = (MonoAssembly *)REFERENCE_MISSING;
1202 if (!image->references [index]) {
1203 if (reference != REFERENCE_MISSING){
1204 mono_assembly_addref (reference);
1205 if (image->assembly)
1206 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1207 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1209 if (image->assembly)
1210 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1211 image->assembly->aname.name, image->assembly);
1214 image->references [index] = reference;
1216 mono_assemblies_unlock ();
1218 if (image->references [index] != reference) {
1219 /* Somebody loaded it before us */
1220 mono_assembly_close (reference);
1225 * mono_assembly_load_references:
1228 * @deprecated: There is no reason to use this method anymore, it does nothing
1230 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1233 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1235 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1236 *status = MONO_IMAGE_OK;
1239 typedef struct AssemblyLoadHook AssemblyLoadHook;
1240 struct AssemblyLoadHook {
1241 AssemblyLoadHook *next;
1242 MonoAssemblyLoadFunc func;
1246 AssemblyLoadHook *assembly_load_hook = NULL;
1249 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1251 AssemblyLoadHook *hook;
1253 for (hook = assembly_load_hook; hook; hook = hook->next) {
1254 hook->func (ass, hook->user_data);
1259 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1261 AssemblyLoadHook *hook;
1263 g_return_if_fail (func != NULL);
1265 hook = g_new0 (AssemblyLoadHook, 1);
1267 hook->user_data = user_data;
1268 hook->next = assembly_load_hook;
1269 assembly_load_hook = hook;
1273 free_assembly_load_hooks (void)
1275 AssemblyLoadHook *hook, *next;
1277 for (hook = assembly_load_hook; hook; hook = next) {
1283 typedef struct AssemblySearchHook AssemblySearchHook;
1284 struct AssemblySearchHook {
1285 AssemblySearchHook *next;
1286 MonoAssemblySearchFunc func;
1292 AssemblySearchHook *assembly_search_hook = NULL;
1294 static MonoAssembly*
1295 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1297 AssemblySearchHook *hook;
1299 for (hook = assembly_search_hook; hook; hook = hook->next) {
1300 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1303 * A little explanation is in order here.
1305 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1306 * The embedding API exposes a search hook that doesn't take such argument.
1308 * The original fix would call the default search hook before all the registered ones and pass
1309 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1310 * rely on. Which is the ordering between user hooks and the default runtime hook.
1312 * Registering the hook after mono_jit_init would let your hook run before the default one and
1313 * when using it to handle non standard app layouts this could save your app from a massive amount
1314 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1315 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1317 * So what's the fix? We register the default hook using regular means and special case it when iterating
1318 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1321 if (hook->func == (void*)mono_domain_assembly_postload_search)
1322 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1324 ass = hook->func (aname, hook->user_data);
1334 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1336 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1340 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1342 AssemblySearchHook *hook;
1344 g_return_if_fail (func != NULL);
1346 hook = g_new0 (AssemblySearchHook, 1);
1348 hook->user_data = user_data;
1349 hook->refonly = refonly;
1350 hook->postload = postload;
1351 hook->next = assembly_search_hook;
1352 assembly_search_hook = hook;
1356 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1358 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1362 free_assembly_search_hooks (void)
1364 AssemblySearchHook *hook, *next;
1366 for (hook = assembly_search_hook; hook; hook = next) {
1373 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1375 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1379 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1381 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1385 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1387 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1390 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1391 struct AssemblyPreLoadHook {
1392 AssemblyPreLoadHook *next;
1393 MonoAssemblyPreLoadFunc func;
1397 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1398 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1400 static MonoAssembly *
1401 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1403 AssemblyPreLoadHook *hook;
1404 MonoAssembly *assembly;
1406 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1407 assembly = hook->func (aname, assemblies_path, hook->user_data);
1408 if (assembly != NULL)
1415 static MonoAssembly *
1416 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1418 AssemblyPreLoadHook *hook;
1419 MonoAssembly *assembly;
1421 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1422 assembly = hook->func (aname, assemblies_path, hook->user_data);
1423 if (assembly != NULL)
1431 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1433 AssemblyPreLoadHook *hook;
1435 g_return_if_fail (func != NULL);
1437 hook = g_new0 (AssemblyPreLoadHook, 1);
1439 hook->user_data = user_data;
1440 hook->next = assembly_preload_hook;
1441 assembly_preload_hook = hook;
1445 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1447 AssemblyPreLoadHook *hook;
1449 g_return_if_fail (func != NULL);
1451 hook = g_new0 (AssemblyPreLoadHook, 1);
1453 hook->user_data = user_data;
1454 hook->next = assembly_refonly_preload_hook;
1455 assembly_refonly_preload_hook = hook;
1459 free_assembly_preload_hooks (void)
1461 AssemblyPreLoadHook *hook, *next;
1463 for (hook = assembly_preload_hook; hook; hook = next) {
1468 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1475 absolute_dir (const gchar *filename)
1486 if (g_path_is_absolute (filename)) {
1487 part = g_path_get_dirname (filename);
1488 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1493 cwd = g_get_current_dir ();
1494 mixed = g_build_filename (cwd, filename, NULL);
1495 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1500 for (i = 0; (part = parts [i]) != NULL; i++) {
1501 if (!strcmp (part, "."))
1504 if (!strcmp (part, "..")) {
1505 if (list && list->next) /* Don't remove root */
1506 list = g_list_delete_link (list, list);
1508 list = g_list_prepend (list, part);
1512 result = g_string_new ("");
1513 list = g_list_reverse (list);
1515 /* Ignores last data pointer, which should be the filename */
1516 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1518 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1523 g_string_free (result, FALSE);
1528 return g_strdup (".");
1535 * mono_assembly_open_from_bundle:
1536 * @filename: Filename requested
1537 * @status: return status code
1539 * This routine tries to open the assembly specified by `filename' from the
1540 * defined bundles, if found, returns the MonoImage for it, if not found
1544 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1548 gchar *lowercase_filename;
1549 MonoImage *image = NULL;
1550 gboolean is_satellite = FALSE;
1552 * we do a very simple search for bundled assemblies: it's not a general
1553 * purpose assembly loading mechanism.
1559 lowercase_filename = g_utf8_strdown (filename, -1);
1560 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1561 g_free (lowercase_filename);
1562 name = g_path_get_basename (filename);
1563 mono_assemblies_lock ();
1564 for (i = 0; !image && bundles [i]; ++i) {
1565 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1566 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1570 mono_assemblies_unlock ();
1572 mono_image_addref (image);
1573 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1582 * mono_assemblies_open_full:
1583 * @filename: the file to load
1584 * @status: return status code
1585 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1587 * This loads an assembly from the specified @filename. The @filename allows
1588 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1589 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1590 * is treated as a local path.
1592 * First, an attempt is made to load the assembly from the bundled executable (for those
1593 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1594 * assembly has been registered as an embedded assembly). If this is not the case, then
1595 * the assembly is loaded from disk using `api:mono_image_open_full`.
1597 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1598 * the assembly is made.
1600 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1601 * the `System.Reflection` API.
1603 * Returns: NULL on error, with the @status set to an error code, or a pointer
1607 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1611 MonoImageOpenStatus def_status;
1614 gboolean loaded_from_bundle;
1616 g_return_val_if_fail (filename != NULL, NULL);
1619 status = &def_status;
1620 *status = MONO_IMAGE_OK;
1622 if (strncmp (filename, "file://", 7) == 0) {
1623 GError *error = NULL;
1624 gchar *uri = (gchar *) filename;
1628 * MS allows file://c:/... and fails on file://localhost/c:/...
1629 * They also throw an IndexOutOfRangeException if "file://"
1632 uri = g_strdup_printf ("file:///%s", uri + 7);
1635 uri = mono_escape_uri_string (tmpuri);
1636 fname = g_filename_from_uri (uri, NULL, &error);
1639 if (tmpuri != filename)
1642 if (error != NULL) {
1643 g_warning ("%s\n", error->message);
1644 g_error_free (error);
1645 fname = g_strdup (filename);
1648 fname = g_strdup (filename);
1651 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1652 "Assembly Loader probing location: '%s'.", fname);
1655 if (!mono_assembly_is_in_gac (fname)) {
1657 new_fname = mono_make_shadow_copy (fname, &error);
1658 if (!is_ok (&error)) {
1659 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1660 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1661 mono_error_cleanup (&error);
1662 *status = MONO_IMAGE_IMAGE_INVALID;
1667 if (new_fname && new_fname != fname) {
1670 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1671 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1676 // If VM built with mkbundle
1677 loaded_from_bundle = FALSE;
1678 if (bundles != NULL) {
1679 image = mono_assembly_open_from_bundle (fname, status, refonly);
1680 loaded_from_bundle = image != NULL;
1684 image = mono_image_open_full (fname, status, refonly);
1687 if (*status == MONO_IMAGE_OK)
1688 *status = MONO_IMAGE_ERROR_ERRNO;
1693 if (image->assembly) {
1694 /* Already loaded by another appdomain */
1695 mono_assembly_invoke_load_hook (image->assembly);
1696 mono_image_close (image);
1698 return image->assembly;
1701 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1704 if (!loaded_from_bundle)
1705 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1706 "Assembly Loader loaded assembly from location: '%s'.", filename);
1708 mono_config_for_assembly (ass->image);
1711 /* Clear the reference added by mono_image_open */
1712 mono_image_close (image);
1720 free_item (gpointer val, gpointer user_data)
1726 * mono_assembly_load_friends:
1729 * Load the list of friend assemblies that are allowed to access
1730 * the assembly's internal types and members. They are stored as assembly
1731 * names in custom attributes.
1733 * This is an internal method, we need this because when we load mscorlib
1734 * we do not have the internals visible cattr loaded yet,
1735 * so we need to load these after we initialize the runtime.
1737 * LOCKING: Acquires the assemblies lock plus the loader lock.
1740 mono_assembly_load_friends (MonoAssembly* ass)
1744 MonoCustomAttrInfo* attrs;
1747 if (ass->friend_assembly_names_inited)
1750 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1751 mono_error_assert_ok (&error);
1753 mono_assemblies_lock ();
1754 ass->friend_assembly_names_inited = TRUE;
1755 mono_assemblies_unlock ();
1759 mono_assemblies_lock ();
1760 if (ass->friend_assembly_names_inited) {
1761 mono_assemblies_unlock ();
1764 mono_assemblies_unlock ();
1768 * We build the list outside the assemblies lock, the worse that can happen
1769 * is that we'll need to free the allocated list.
1771 for (i = 0; i < attrs->num_attrs; ++i) {
1772 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1773 MonoAssemblyName *aname;
1775 /* Do some sanity checking */
1776 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1778 if (attr->data_size < 4)
1780 data = (const char*)attr->data;
1781 /* 0xFF means null string, see custom attr format */
1782 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1784 mono_metadata_decode_value (data + 2, &data);
1785 aname = g_new0 (MonoAssemblyName, 1);
1786 /*g_print ("friend ass: %s\n", data);*/
1787 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1788 list = g_slist_prepend (list, aname);
1793 mono_custom_attrs_free (attrs);
1795 mono_assemblies_lock ();
1796 if (ass->friend_assembly_names_inited) {
1797 mono_assemblies_unlock ();
1798 g_slist_foreach (list, free_item, NULL);
1799 g_slist_free (list);
1802 ass->friend_assembly_names = list;
1804 /* Because of the double checked locking pattern above */
1805 mono_memory_barrier ();
1806 ass->friend_assembly_names_inited = TRUE;
1807 mono_assemblies_unlock ();
1812 * mono_assembly_get_reference_assembly_attribute:
1813 * @assembly: a MonoAssembly
1814 * @error: set on error.
1816 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1817 * On error returns FALSE and sets @error.
1820 mono_assembly_get_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1822 mono_error_init (error);
1824 MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
1825 return_val_if_nok (error, FALSE);
1828 MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
1829 gboolean result = FALSE;
1830 for (int i = 0; i < attrs->num_attrs; ++i) {
1831 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1832 if (attr->ctor && attr->ctor->klass && attr->ctor->klass == ref_asm_class) {
1837 mono_custom_attrs_free (attrs);
1842 * mono_assembly_open:
1843 * @filename: Opens the assembly pointed out by this name
1844 * @status: return status code
1846 * This loads an assembly from the specified @filename. The @filename allows
1847 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1848 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1849 * is treated as a local path.
1851 * First, an attempt is made to load the assembly from the bundled executable (for those
1852 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1853 * assembly has been registered as an embedded assembly). If this is not the case, then
1854 * the assembly is loaded from disk using `api:mono_image_open_full`.
1856 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1857 * the assembly is made.
1859 * Return: a pointer to the MonoAssembly if @filename contains a valid
1860 * assembly or NULL on error. Details about the error are stored in the
1864 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1866 return mono_assembly_open_full (filename, status, FALSE);
1870 * mono_assembly_load_from_full:
1871 * @image: Image to load the assembly from
1872 * @fname: assembly name to associate with the assembly
1873 * @status: returns the status condition
1874 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1876 * If the provided @image has an assembly reference, it will process the given
1877 * image as an assembly with the given name.
1879 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1881 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1882 * set to #MONO_IMAGE_OK; or NULL on error.
1884 * If there is an error loading the assembly the @status will indicate the
1885 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1886 * image did not contain an assembly reference table.
1889 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1890 MonoImageOpenStatus *status, gboolean refonly)
1892 MonoAssembly *ass, *ass2;
1895 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1896 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1897 *status = MONO_IMAGE_IMAGE_INVALID;
1901 #if defined (HOST_WIN32)
1906 tmp_fn = g_strdup (fname);
1907 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1908 if (tmp_fn [i] == '/')
1912 base_dir = absolute_dir (tmp_fn);
1916 base_dir = absolute_dir (fname);
1920 * Create assembly struct, and enter it into the assembly cache
1922 ass = g_new0 (MonoAssembly, 1);
1923 ass->basedir = base_dir;
1924 ass->ref_only = refonly;
1927 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1929 mono_assembly_fill_assembly_name (image, &ass->aname);
1931 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1932 // MS.NET doesn't support loading other mscorlibs
1935 mono_image_addref (mono_defaults.corlib);
1936 *status = MONO_IMAGE_OK;
1937 return mono_defaults.corlib->assembly;
1940 /* Add a non-temporary reference because of ass->image */
1941 mono_image_addref (image);
1943 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);
1946 * The load hooks might take locks so we can't call them while holding the
1949 if (ass->aname.name) {
1950 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1954 mono_image_close (image);
1955 *status = MONO_IMAGE_OK;
1960 mono_assemblies_lock ();
1962 if (image->assembly) {
1964 * This means another thread has already loaded the assembly, but not yet
1965 * called the load hooks so the search hook can't find the assembly.
1967 mono_assemblies_unlock ();
1968 ass2 = image->assembly;
1971 mono_image_close (image);
1972 *status = MONO_IMAGE_OK;
1976 image->assembly = ass;
1978 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1979 mono_assemblies_unlock ();
1982 if (image->is_module_handle)
1983 mono_image_fixup_vtable (image);
1986 mono_assembly_invoke_load_hook (ass);
1988 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1994 * mono_assembly_load_from:
1995 * @image: Image to load the assembly from
1996 * @fname: assembly name to associate with the assembly
1997 * @status: return status code
1999 * If the provided @image has an assembly reference, it will process the given
2000 * image as an assembly with the given name.
2002 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2004 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2005 * @refonly parameter set to FALSE.
2006 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2007 * set to #MONO_IMAGE_OK; or NULL on error.
2009 * If there is an error loading the assembly the @status will indicate the
2010 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2011 * image did not contain an assembly reference table.
2015 mono_assembly_load_from (MonoImage *image, const char *fname,
2016 MonoImageOpenStatus *status)
2018 return mono_assembly_load_from_full (image, fname, status, FALSE);
2022 * mono_assembly_name_free:
2023 * @aname: assembly name to free
2025 * Frees the provided assembly name object.
2026 * (it does not frees the object itself, only the name members).
2029 mono_assembly_name_free (MonoAssemblyName *aname)
2034 g_free ((void *) aname->name);
2035 g_free ((void *) aname->culture);
2036 g_free ((void *) aname->hash_value);
2037 g_free ((guint8*) aname->public_key);
2041 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2044 gchar header [16], val, *arr;
2045 gint i, j, offset, bitlen, keylen, pkeylen;
2047 keylen = strlen (key) >> 1;
2051 /* allow the ECMA standard key */
2052 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2054 *pubkey = g_strdup (key);
2060 val = g_ascii_xdigit_value (key [0]) << 4;
2061 val |= g_ascii_xdigit_value (key [1]);
2066 val = g_ascii_xdigit_value (key [24]);
2067 val |= g_ascii_xdigit_value (key [25]);
2079 /* We need the first 16 bytes
2080 * to check whether this key is valid or not */
2081 pkeylen = strlen (pkey) >> 1;
2085 for (i = 0, j = 0; i < 16; i++) {
2086 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2087 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2090 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2091 header [1] != 0x02 || /* Version (0x02) */
2092 header [2] != 0x00 || /* Reserved (word) */
2093 header [3] != 0x00 ||
2094 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2097 /* Based on this length, we _should_ be able to know if the length is right */
2098 bitlen = read32 (header + 12) >> 3;
2099 if ((bitlen + 16 + 4) != pkeylen)
2102 /* parsing is OK and the public key itself is not requested back */
2106 /* Encode the size of the blob */
2108 if (keylen <= 127) {
2109 arr = (gchar *)g_malloc (keylen + 1);
2110 arr [offset++] = keylen;
2112 arr = (gchar *)g_malloc (keylen + 2);
2113 arr [offset++] = 0x80; /* 10bs */
2114 arr [offset++] = keylen;
2117 for (i = offset, j = 0; i < keylen + offset; i++) {
2118 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2119 arr [i] |= g_ascii_xdigit_value (key [j++]);
2128 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)
2130 gint major, minor, build, revision;
2133 gchar *pkey, *pkeyptr, *encoded, tok [8];
2135 memset (aname, 0, sizeof (MonoAssemblyName));
2138 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2139 if (version_parts < 2 || version_parts > 4)
2142 /* FIXME: we should set build & revision to -1 (instead of 0)
2143 if these are not set in the version string. That way, later on,
2144 we can still determine if these were specified. */
2145 aname->major = major;
2146 aname->minor = minor;
2147 if (version_parts >= 3)
2148 aname->build = build;
2151 if (version_parts == 4)
2152 aname->revision = revision;
2154 aname->revision = 0;
2157 aname->flags = flags;
2159 aname->name = g_strdup (name);
2162 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2163 aname->culture = g_strdup ("");
2165 aname->culture = g_strdup (culture);
2168 if (token && strncmp (token, "null", 4) != 0) {
2171 /* the constant includes the ending NULL, hence the -1 */
2172 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2173 mono_assembly_name_free (aname);
2176 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2177 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2183 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2184 mono_assembly_name_free (aname);
2189 if (save_public_key)
2190 aname->public_key = (guint8*)pkey;
2193 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2197 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2198 // We also need to generate the key token
2199 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2200 encoded = encode_public_tok ((guchar*) tok, 8);
2201 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2204 if (save_public_key)
2205 aname->public_key = (guint8*) pkey;
2214 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2219 parts = g_strsplit (dirname, "_", 3);
2220 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2225 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2231 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2233 char *eqsign = strchr (pair, '=');
2241 *key = (gchar*)pair;
2242 *keylen = eqsign - *key;
2243 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2245 *value = g_strstrip (eqsign + 1);
2250 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2254 gchar *version = NULL;
2256 gchar *culture = NULL;
2258 gchar *token = NULL;
2262 gchar *retargetable = NULL;
2263 gchar *retargetable_uq;
2267 gchar *value, *part_name;
2268 guint32 part_name_len;
2271 gboolean version_defined;
2272 gboolean token_defined;
2274 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2276 if (!is_version_defined)
2277 is_version_defined = &version_defined;
2278 *is_version_defined = FALSE;
2279 if (!is_token_defined)
2280 is_token_defined = &token_defined;
2281 *is_token_defined = FALSE;
2283 parts = tmp = g_strsplit (name, ",", 6);
2284 if (!tmp || !*tmp) {
2289 dllname = g_strstrip (*tmp);
2294 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2295 goto cleanup_and_fail;
2297 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2298 *is_version_defined = TRUE;
2300 if (strlen (version) == 0) {
2301 goto cleanup_and_fail;
2307 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2309 if (strlen (culture) == 0) {
2310 goto cleanup_and_fail;
2316 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2317 *is_token_defined = TRUE;
2319 if (strlen (token) == 0) {
2320 goto cleanup_and_fail;
2326 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2328 if (strlen (key) == 0) {
2329 goto cleanup_and_fail;
2335 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2336 retargetable = value;
2337 retargetable_uq = unquote (retargetable);
2338 if (retargetable_uq != NULL)
2339 retargetable = retargetable_uq;
2341 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2342 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2343 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2344 g_free (retargetable_uq);
2345 goto cleanup_and_fail;
2348 g_free (retargetable_uq);
2353 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2355 procarch_uq = unquote (procarch);
2356 if (procarch_uq != NULL)
2357 procarch = procarch_uq;
2359 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2360 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2361 else if (!g_ascii_strcasecmp (procarch, "X86"))
2362 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2363 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2364 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2365 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2366 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2368 g_free (procarch_uq);
2369 goto cleanup_and_fail;
2372 g_free (procarch_uq);
2381 /* if retargetable flag is set, then we must have a fully qualified name */
2382 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2383 goto cleanup_and_fail;
2386 dllname_uq = unquote (dllname);
2387 version_uq = unquote (version);
2388 culture_uq = unquote (culture);
2389 token_uq = unquote (token);
2390 key_uq = unquote (key);
2392 res = build_assembly_name (
2393 dllname_uq == NULL ? dllname : dllname_uq,
2394 version_uq == NULL ? version : version_uq,
2395 culture_uq == NULL ? culture : culture_uq,
2396 token_uq == NULL ? token : token_uq,
2397 key_uq == NULL ? key : key_uq,
2398 flags, arch, aname, save_public_key);
2400 g_free (dllname_uq);
2401 g_free (version_uq);
2402 g_free (culture_uq);
2415 unquote (const char *str)
2423 slen = strlen (str);
2427 if (*str != '\'' && *str != '\"')
2430 end = str + slen - 1;
2434 return g_strndup (str + 1, slen - 2);
2438 * mono_assembly_name_parse:
2439 * @name: name to parse
2440 * @aname: the destination assembly name
2442 * Parses an assembly qualified type name and assigns the name,
2443 * version, culture and token to the provided assembly name object.
2445 * Returns: TRUE if the name could be parsed.
2448 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2450 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2454 * mono_assembly_name_new:
2455 * @name: name to parse
2457 * Allocate a new MonoAssemblyName and fill its values from the
2460 * Returns: a newly allocated structure or NULL if there was any failure.
2463 mono_assembly_name_new (const char *name)
2465 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2466 if (mono_assembly_name_parse (name, aname))
2473 mono_assembly_name_get_name (MonoAssemblyName *aname)
2479 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2481 return aname->culture;
2485 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2487 if (aname->public_key_token [0])
2488 return aname->public_key_token;
2493 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2496 *minor = aname->minor;
2498 *build = aname->build;
2500 *revision = aname->revision;
2501 return aname->major;
2504 static MonoAssembly*
2505 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2507 gchar *fullpath = NULL;
2509 const char* direntry;
2510 MonoAssemblyName gac_aname;
2511 gint major=-1, minor=0, build=0, revision=0;
2512 gboolean exact_version;
2514 dirhandle = g_dir_open (basepath, 0, NULL);
2518 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2520 while ((direntry = g_dir_read_name (dirhandle))) {
2521 gboolean match = TRUE;
2523 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2526 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2529 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2530 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2534 if (exact_version) {
2535 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2536 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2538 else if (gac_aname.major < major)
2540 else if (gac_aname.major == major) {
2541 if (gac_aname.minor < minor)
2543 else if (gac_aname.minor == minor) {
2544 if (gac_aname.build < build)
2546 else if (gac_aname.build == build && gac_aname.revision <= revision)
2553 major = gac_aname.major;
2554 minor = gac_aname.minor;
2555 build = gac_aname.build;
2556 revision = gac_aname.revision;
2558 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2561 mono_assembly_name_free (&gac_aname);
2564 g_dir_close (dirhandle);
2566 if (fullpath == NULL)
2569 MonoAssembly *res = mono_assembly_open (fullpath, status);
2576 * mono_assembly_load_with_partial_name:
2577 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2578 * @status: return status code
2580 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2581 * so it might contain a qualified type name, version, culture and token.
2583 * This will load the assembly from the file whose name is derived from the assembly name
2584 * by appending the .dll extension.
2586 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2587 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2588 * if that fails from the GAC.
2590 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2593 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2597 MonoAssemblyName *aname, base_name;
2598 MonoAssemblyName mapped_aname;
2599 gchar *fullname, *gacpath;
2602 memset (&base_name, 0, sizeof (MonoAssemblyName));
2605 if (!mono_assembly_name_parse (name, aname))
2609 * If no specific version has been requested, make sure we load the
2610 * correct version for system assemblies.
2612 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2613 aname = mono_assembly_remap_version (aname, &mapped_aname);
2615 res = mono_assembly_loaded (aname);
2617 mono_assembly_name_free (aname);
2621 res = invoke_assembly_preload_hook (aname, assemblies_path);
2623 res->in_gac = FALSE;
2624 mono_assembly_name_free (aname);
2628 fullname = g_strdup_printf ("%s.dll", aname->name);
2630 if (extra_gac_paths) {
2631 paths = extra_gac_paths;
2632 while (!res && *paths) {
2633 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2634 res = probe_for_partial_name (gacpath, fullname, aname, status);
2643 mono_assembly_name_free (aname);
2647 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2648 res = probe_for_partial_name (gacpath, fullname, aname, status);
2654 MonoDomain *domain = mono_domain_get ();
2655 MonoReflectionAssembly *refasm;
2657 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2658 if (!is_ok (&error)) {
2660 mono_assembly_name_free (aname);
2661 mono_error_cleanup (&error);
2662 if (*status == MONO_IMAGE_OK)
2663 *status = MONO_IMAGE_IMAGE_INVALID;
2667 res = refasm->assembly;
2671 mono_assembly_name_free (aname);
2677 mono_assembly_is_in_gac (const gchar *filename)
2679 const gchar *rootdir;
2683 if (filename == NULL)
2686 for (paths = extra_gac_paths; paths && *paths; paths++) {
2687 if (strstr (*paths, filename) != *paths)
2690 gp = (gchar *) (filename + strlen (*paths));
2691 if (*gp != G_DIR_SEPARATOR)
2694 if (strncmp (gp, "lib", 3))
2697 if (*gp != G_DIR_SEPARATOR)
2700 if (strncmp (gp, "mono", 4))
2703 if (*gp != G_DIR_SEPARATOR)
2706 if (strncmp (gp, "gac", 3))
2709 if (*gp != G_DIR_SEPARATOR)
2715 rootdir = mono_assembly_getrootdir ();
2716 if (strstr (filename, rootdir) != filename)
2719 gp = (gchar *) (filename + strlen (rootdir));
2720 if (*gp != G_DIR_SEPARATOR)
2723 if (strncmp (gp, "mono", 4))
2726 if (*gp != G_DIR_SEPARATOR)
2729 if (strncmp (gp, "gac", 3))
2732 if (*gp != G_DIR_SEPARATOR)
2738 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2741 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2745 if (strstr (aname->name, ".dll")) {
2746 len = strlen (aname->name) - 4;
2747 name = (gchar *)g_malloc (len + 1);
2748 strncpy (name, aname->name, len);
2751 name = g_strdup (aname->name);
2754 culture = g_utf8_strdown (aname->culture, -1);
2756 culture = g_strdup ("");
2758 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2759 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2763 filename = g_strconcat (pname, ".dll", NULL);
2764 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2770 if (extra_gac_paths) {
2771 paths = extra_gac_paths;
2772 while (!image && *paths) {
2773 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2774 "lib", "mono", "gac", subpath, NULL);
2775 image = mono_image_open (fullpath, NULL);
2786 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2787 "mono", "gac", subpath, NULL);
2788 image = mono_image_open (fullpath, NULL);
2795 static MonoAssemblyName*
2796 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2798 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2799 dest_name->major = info->new_version.major;
2800 dest_name->minor = info->new_version.minor;
2801 dest_name->build = info->new_version.build;
2802 dest_name->revision = info->new_version.revision;
2807 /* LOCKING: assembly_binding lock must be held */
2808 static MonoAssemblyBindingInfo*
2809 search_binding_loaded (MonoAssemblyName *aname)
2813 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2814 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2815 if (assembly_binding_maps_name (info, aname))
2822 static inline gboolean
2823 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2825 if (left->major != right->major || left->minor != right->minor ||
2826 left->build != right->build || left->revision != right->revision)
2832 static inline gboolean
2833 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2835 if (left->has_old_version_bottom != right->has_old_version_bottom)
2838 if (left->has_old_version_top != right->has_old_version_top)
2841 if (left->has_new_version != right->has_new_version)
2844 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2847 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2850 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2856 /* LOCKING: assumes all the necessary locks are held */
2858 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2860 MonoAssemblyBindingInfo *info_copy;
2862 MonoAssemblyBindingInfo *info_tmp;
2863 MonoDomain *domain = (MonoDomain*)user_data;
2868 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2869 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2870 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2874 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2875 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2877 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2879 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2881 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2885 get_version_number (int major, int minor)
2887 return major * 256 + minor;
2890 static inline gboolean
2891 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2893 int aname_version_number = get_version_number (aname->major, aname->minor);
2894 if (!info->has_old_version_bottom)
2897 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2900 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2903 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2904 info->major = aname->major;
2905 info->minor = aname->minor;
2910 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2911 static MonoAssemblyBindingInfo*
2912 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2914 MonoAssemblyBindingInfo *info;
2917 if (!domain->assembly_bindings)
2921 for (list = domain->assembly_bindings; list; list = list->next) {
2922 info = (MonoAssemblyBindingInfo *)list->data;
2923 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2929 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2930 info->has_new_version && assembly_binding_maps_name (info, aname))
2931 info->is_valid = TRUE;
2933 info->is_valid = FALSE;
2939 static MonoAssemblyName*
2940 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2943 MonoAssemblyBindingInfo *info, *info2;
2947 if (aname->public_key_token [0] == 0)
2950 domain = mono_domain_get ();
2952 mono_assembly_binding_lock ();
2953 info = search_binding_loaded (aname);
2954 mono_assembly_binding_unlock ();
2957 mono_domain_lock (domain);
2958 info = get_per_domain_assembly_binding_info (domain, aname);
2959 mono_domain_unlock (domain);
2963 if (!check_policy_versions (info, aname))
2966 mono_assembly_bind_version (info, aname, dest_name);
2970 if (domain && domain->setup && domain->setup->configuration_file) {
2971 mono_domain_lock (domain);
2972 if (!domain->assembly_bindings_parsed) {
2973 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2974 /* expect this to succeed because mono_domain_set_options_from_config () did
2975 * the same thing when the domain was created. */
2976 mono_error_assert_ok (&error);
2978 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2980 if (!domain_config_file_path)
2981 domain_config_file_path = domain_config_file_name;
2983 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2984 domain->assembly_bindings_parsed = TRUE;
2985 if (domain_config_file_name != domain_config_file_path)
2986 g_free (domain_config_file_name);
2987 g_free (domain_config_file_path);
2990 info2 = get_per_domain_assembly_binding_info (domain, aname);
2993 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2994 info->name = g_strdup (info2->name);
2995 info->culture = g_strdup (info2->culture);
2996 info->domain_id = domain->domain_id;
2999 mono_domain_unlock (domain);
3003 info = g_new0 (MonoAssemblyBindingInfo, 1);
3004 info->major = aname->major;
3005 info->minor = aname->minor;
3008 if (!info->is_valid) {
3009 ppimage = mono_assembly_load_publisher_policy (aname);
3011 get_publisher_policy_info (ppimage, aname, info);
3012 mono_image_close (ppimage);
3016 /* Define default error value if needed */
3017 if (!info->is_valid) {
3018 info->name = g_strdup (aname->name);
3019 info->culture = g_strdup (aname->culture);
3020 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3023 mono_assembly_binding_lock ();
3024 info2 = search_binding_loaded (aname);
3026 /* This binding was added by another thread
3028 mono_assembly_binding_info_free (info);
3033 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3035 mono_assembly_binding_unlock ();
3037 if (!info->is_valid || !check_policy_versions (info, aname))
3040 mono_assembly_bind_version (info, aname, dest_name);
3045 * mono_assembly_load_from_gac
3047 * @aname: The assembly name object
3049 static MonoAssembly*
3050 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3052 MonoAssembly *result = NULL;
3053 gchar *name, *version, *culture, *fullpath, *subpath;
3058 if (aname->public_key_token [0] == 0) {
3062 if (strstr (aname->name, ".dll")) {
3063 len = strlen (filename) - 4;
3064 name = (gchar *)g_malloc (len + 1);
3065 strncpy (name, aname->name, len);
3068 name = g_strdup (aname->name);
3071 if (aname->culture) {
3072 culture = g_utf8_strdown (aname->culture, -1);
3074 culture = g_strdup ("");
3077 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3078 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3079 aname->minor, aname->build, aname->revision,
3083 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3088 if (extra_gac_paths) {
3089 paths = extra_gac_paths;
3090 while (!result && *paths) {
3091 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3092 result = mono_assembly_open_full (fullpath, status, refonly);
3099 result->in_gac = TRUE;
3104 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3105 "mono", "gac", subpath, NULL);
3106 result = mono_assembly_open_full (fullpath, status, refonly);
3110 result->in_gac = TRUE;
3118 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3121 MonoAssemblyName *aname;
3124 /* g_print ("corlib already loaded\n"); */
3128 // In native client, Corlib is embedded in the executable as static variable corlibData
3129 #if defined(__native_client__)
3130 if (corlibData != NULL && corlibSize != 0) {
3132 /* First "FALSE" instructs mono not to make a copy. */
3133 /* Second "FALSE" says this is not just a ref. */
3134 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3135 if (image == NULL || status != 0)
3136 g_print("mono_image_open_from_data_full failed: %d\n", status);
3137 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3138 if (corlib == NULL || status != 0)
3139 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3145 // A nonstandard preload hook may provide a special mscorlib assembly
3146 aname = mono_assembly_name_new ("mscorlib.dll");
3147 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3148 mono_assembly_name_free (aname);
3151 goto return_corlib_and_facades;
3153 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3154 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3155 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3157 goto return_corlib_and_facades;
3160 /* Normal case: Load corlib from mono/<version> */
3161 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3162 if (assemblies_path) { // Custom assemblies path
3163 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3165 g_free (corlib_file);
3166 goto return_corlib_and_facades;
3169 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3170 g_free (corlib_file);
3172 return_corlib_and_facades:
3173 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3174 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3180 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3181 const char *basedir,
3182 MonoImageOpenStatus *status,
3185 MonoAssembly *result;
3186 char *fullpath, *filename;
3187 MonoAssemblyName maped_aname;
3188 MonoAssemblyName maped_name_pp;
3193 aname = mono_assembly_remap_version (aname, &maped_aname);
3195 /* Reflection only assemblies don't get assembly binding */
3197 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3199 result = mono_assembly_loaded_full (aname, refonly);
3203 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3205 result->in_gac = FALSE;
3209 /* Currently we retrieve the loaded corlib for reflection
3210 * only requests, like a common reflection only assembly
3212 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3213 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3216 len = strlen (aname->name);
3217 for (ext_index = 0; ext_index < 2; ext_index ++) {
3218 ext = ext_index == 0 ? ".dll" : ".exe";
3219 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3220 filename = g_strdup (aname->name);
3221 /* Don't try appending .dll/.exe if it already has one of those extensions */
3224 filename = g_strconcat (aname->name, ext, NULL);
3227 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3234 fullpath = g_build_filename (basedir, filename, NULL);
3235 result = mono_assembly_open_full (fullpath, status, refonly);
3238 result->in_gac = FALSE;
3244 result = load_in_path (filename, default_path, status, refonly);
3246 result->in_gac = FALSE;
3256 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3258 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3261 /* Try a postload search hook */
3262 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3267 * mono_assembly_load_full:
3268 * @aname: A MonoAssemblyName with the assembly name to load.
3269 * @basedir: A directory to look up the assembly at.
3270 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3271 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3273 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3274 * attempts to load the assembly from that directory before probing the standard locations.
3276 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3277 * assembly binding takes place.
3279 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3280 * value pointed by status is updated with an error code.
3283 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3285 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3289 * mono_assembly_load:
3290 * @aname: A MonoAssemblyName with the assembly name to load.
3291 * @basedir: A directory to look up the assembly at.
3292 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3294 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3295 * attempts to load the assembly from that directory before probing the standard locations.
3297 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3298 * value pointed by status is updated with an error code.
3301 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3303 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3307 * mono_assembly_loaded_full:
3308 * @aname: an assembly to look for.
3309 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3311 * This is used to determine if the specified assembly has been loaded
3312 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3313 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3316 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3319 MonoAssemblyName maped_aname;
3321 aname = mono_assembly_remap_version (aname, &maped_aname);
3323 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3329 * mono_assembly_loaded:
3330 * @aname: an assembly to look for.
3332 * This is used to determine if the specified assembly has been loaded
3334 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3335 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3338 mono_assembly_loaded (MonoAssemblyName *aname)
3340 return mono_assembly_loaded_full (aname, FALSE);
3344 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3346 if (assembly == NULL || assembly == REFERENCE_MISSING)
3349 if (assembly_is_dynamic (assembly)) {
3351 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3352 for (i = 0; i < dynimg->image.module_count; ++i)
3353 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3354 mono_dynamic_image_release_gc_roots (dynimg);
3359 * Returns whether mono_assembly_close_finish() must be called as
3360 * well. See comment for mono_image_close_except_pools() for why we
3361 * unload in two steps.
3364 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3367 g_return_val_if_fail (assembly != NULL, FALSE);
3369 if (assembly == REFERENCE_MISSING)
3372 /* Might be 0 already */
3373 if (InterlockedDecrement (&assembly->ref_count) > 0)
3376 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3378 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3380 mono_debug_close_image (assembly->image);
3382 mono_assemblies_lock ();
3383 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3384 mono_assemblies_unlock ();
3386 assembly->image->assembly = NULL;
3388 if (!mono_image_close_except_pools (assembly->image))
3389 assembly->image = NULL;
3391 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3392 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3393 mono_assembly_name_free (fname);
3396 g_slist_free (assembly->friend_assembly_names);
3397 g_free (assembly->basedir);
3399 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3405 mono_assembly_close_finish (MonoAssembly *assembly)
3407 g_assert (assembly && assembly != REFERENCE_MISSING);
3409 if (assembly->image)
3410 mono_image_close_finish (assembly->image);
3412 if (assembly_is_dynamic (assembly)) {
3413 g_free ((char*)assembly->aname.culture);
3420 * mono_assembly_close:
3421 * @assembly: the assembly to release.
3423 * This method releases a reference to the @assembly. The assembly is
3424 * only released when all the outstanding references to it are released.
3427 mono_assembly_close (MonoAssembly *assembly)
3429 if (mono_assembly_close_except_image_pools (assembly))
3430 mono_assembly_close_finish (assembly);
3434 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3436 return mono_image_load_file_for_image (assembly->image, idx);
3440 * mono_assembly_foreach:
3441 * @func: function to invoke for each assembly loaded
3442 * @user_data: data passed to the callback
3444 * Invokes the provided @func callback for each assembly loaded into
3445 * the runtime. The first parameter passed to the callback is the
3446 * `MonoAssembly*`, and the second parameter is the @user_data.
3448 * This is done for all assemblies loaded in the runtime, not just
3449 * those loaded in the current application domain.
3452 mono_assembly_foreach (GFunc func, gpointer user_data)
3457 * We make a copy of the list to avoid calling the callback inside the
3458 * lock, which could lead to deadlocks.
3460 mono_assemblies_lock ();
3461 copy = g_list_copy (loaded_assemblies);
3462 mono_assemblies_unlock ();
3464 g_list_foreach (loaded_assemblies, func, user_data);
3470 * mono_assemblies_cleanup:
3472 * Free all resources used by this module.
3475 mono_assemblies_cleanup (void)
3479 mono_os_mutex_destroy (&assemblies_mutex);
3480 mono_os_mutex_destroy (&assembly_binding_mutex);
3482 for (l = loaded_assembly_bindings; l; l = l->next) {
3483 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3485 mono_assembly_binding_info_free (info);
3488 g_slist_free (loaded_assembly_bindings);
3490 free_assembly_load_hooks ();
3491 free_assembly_search_hooks ();
3492 free_assembly_preload_hooks ();
3495 /*LOCKING takes the assembly_binding lock*/
3497 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3501 mono_assembly_binding_lock ();
3502 iter = &loaded_assembly_bindings;
3505 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3507 if (info->domain_id == domain_id) {
3509 mono_assembly_binding_info_free (info);
3516 mono_assembly_binding_unlock ();
3520 * Holds the assembly of the application, for
3521 * System.Diagnostics.Process::MainModule
3523 static MonoAssembly *main_assembly=NULL;
3526 mono_assembly_set_main (MonoAssembly *assembly)
3528 main_assembly = assembly;
3532 * mono_assembly_get_main:
3534 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3537 mono_assembly_get_main (void)
3539 return (main_assembly);
3543 * mono_assembly_get_image:
3544 * @assembly: The assembly to retrieve the image from
3546 * Returns: the MonoImage associated with this assembly.
3549 mono_assembly_get_image (MonoAssembly *assembly)
3551 return assembly->image;
3555 * mono_assembly_get_name:
3556 * @assembly: The assembly to retrieve the name from
3558 * The returned name's lifetime is the same as @assembly's.
3560 * Returns: the MonoAssemblyName associated with this assembly.
3563 mono_assembly_get_name (MonoAssembly *assembly)
3565 return &assembly->aname;
3569 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3571 bundles = assemblies;
3574 #define MONO_DECLSEC_FORMAT_10 0x3C
3575 #define MONO_DECLSEC_FORMAT_20 0x2E
3576 #define MONO_DECLSEC_FIELD 0x53
3577 #define MONO_DECLSEC_PROPERTY 0x54
3579 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3580 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3581 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3582 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3583 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3586 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3590 case MONO_DECLSEC_PROPERTY:
3592 case MONO_DECLSEC_FIELD:
3594 *abort_decoding = TRUE;
3599 if (*p++ != MONO_TYPE_BOOLEAN) {
3600 *abort_decoding = TRUE;
3604 /* property name length */
3605 len = mono_metadata_decode_value (p, &p);
3607 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3618 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3620 int i, j, num, len, params_len;
3622 if (*p == MONO_DECLSEC_FORMAT_10) {
3623 gsize read, written;
3624 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3626 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3632 if (*p++ != MONO_DECLSEC_FORMAT_20)
3635 /* number of encoded permission attributes */
3636 num = mono_metadata_decode_value (p, &p);
3637 for (i = 0; i < num; ++i) {
3638 gboolean is_valid = FALSE;
3639 gboolean abort_decoding = FALSE;
3641 /* attribute name length */
3642 len = mono_metadata_decode_value (p, &p);
3644 /* We don't really need to fully decode the type. Comparing the name is enough */
3645 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3649 /*size of the params table*/
3650 params_len = mono_metadata_decode_value (p, &p);
3652 const char *params_end = p + params_len;
3654 /* number of parameters */
3655 len = mono_metadata_decode_value (p, &p);
3657 for (j = 0; j < len; ++j) {
3658 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3674 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3677 guint32 cols [MONO_DECL_SECURITY_SIZE];
3681 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3682 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3684 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3686 for (i = 0; i < t->rows; ++i) {
3687 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3688 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3690 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3693 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3694 len = mono_metadata_decode_blob_size (blob, &blob);
3698 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3699 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3704 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);