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 MonoImage *image = NULL;
1551 * we do a very simple search for bundled assemblies: it's not a general
1552 * purpose assembly loading mechanism.
1558 name = g_path_get_basename (filename);
1560 mono_assemblies_lock ();
1561 for (i = 0; !image && bundles [i]; ++i) {
1562 if (strcmp (bundles [i]->name, name) == 0) {
1563 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1567 mono_assemblies_unlock ();
1569 mono_image_addref (image);
1570 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
1579 * mono_assemblies_open_full:
1580 * @filename: the file to load
1581 * @status: return status code
1582 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1584 * This loads an assembly from the specified @filename. The @filename allows
1585 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1586 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1587 * is treated as a local path.
1589 * First, an attempt is made to load the assembly from the bundled executable (for those
1590 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1591 * assembly has been registered as an embedded assembly). If this is not the case, then
1592 * the assembly is loaded from disk using `api:mono_image_open_full`.
1594 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1595 * the assembly is made.
1597 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1598 * the `System.Reflection` API.
1600 * Returns: NULL on error, with the @status set to an error code, or a pointer
1604 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1608 MonoImageOpenStatus def_status;
1611 gboolean loaded_from_bundle;
1613 g_return_val_if_fail (filename != NULL, NULL);
1616 status = &def_status;
1617 *status = MONO_IMAGE_OK;
1619 if (strncmp (filename, "file://", 7) == 0) {
1620 GError *error = NULL;
1621 gchar *uri = (gchar *) filename;
1625 * MS allows file://c:/... and fails on file://localhost/c:/...
1626 * They also throw an IndexOutOfRangeException if "file://"
1629 uri = g_strdup_printf ("file:///%s", uri + 7);
1632 uri = mono_escape_uri_string (tmpuri);
1633 fname = g_filename_from_uri (uri, NULL, &error);
1636 if (tmpuri != filename)
1639 if (error != NULL) {
1640 g_warning ("%s\n", error->message);
1641 g_error_free (error);
1642 fname = g_strdup (filename);
1645 fname = g_strdup (filename);
1648 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1649 "Assembly Loader probing location: '%s'.", fname);
1652 if (!mono_assembly_is_in_gac (fname)) {
1654 new_fname = mono_make_shadow_copy (fname, &error);
1655 if (!is_ok (&error)) {
1656 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1657 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1658 mono_error_cleanup (&error);
1659 *status = MONO_IMAGE_IMAGE_INVALID;
1664 if (new_fname && new_fname != fname) {
1667 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1668 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1673 // If VM built with mkbundle
1674 loaded_from_bundle = FALSE;
1675 if (bundles != NULL) {
1676 image = mono_assembly_open_from_bundle (fname, status, refonly);
1677 loaded_from_bundle = image != NULL;
1681 image = mono_image_open_full (fname, status, refonly);
1684 if (*status == MONO_IMAGE_OK)
1685 *status = MONO_IMAGE_ERROR_ERRNO;
1690 if (image->assembly) {
1691 /* Already loaded by another appdomain */
1692 mono_assembly_invoke_load_hook (image->assembly);
1693 mono_image_close (image);
1695 return image->assembly;
1698 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1701 if (!loaded_from_bundle)
1702 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1703 "Assembly Loader loaded assembly from location: '%s'.", filename);
1705 mono_config_for_assembly (ass->image);
1708 /* Clear the reference added by mono_image_open */
1709 mono_image_close (image);
1717 free_item (gpointer val, gpointer user_data)
1723 * mono_assembly_load_friends:
1726 * Load the list of friend assemblies that are allowed to access
1727 * the assembly's internal types and members. They are stored as assembly
1728 * names in custom attributes.
1730 * This is an internal method, we need this because when we load mscorlib
1731 * we do not have the internals visible cattr loaded yet,
1732 * so we need to load these after we initialize the runtime.
1734 * LOCKING: Acquires the assemblies lock plus the loader lock.
1737 mono_assembly_load_friends (MonoAssembly* ass)
1741 MonoCustomAttrInfo* attrs;
1744 if (ass->friend_assembly_names_inited)
1747 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1748 mono_error_assert_ok (&error);
1750 mono_assemblies_lock ();
1751 ass->friend_assembly_names_inited = TRUE;
1752 mono_assemblies_unlock ();
1756 mono_assemblies_lock ();
1757 if (ass->friend_assembly_names_inited) {
1758 mono_assemblies_unlock ();
1761 mono_assemblies_unlock ();
1765 * We build the list outside the assemblies lock, the worse that can happen
1766 * is that we'll need to free the allocated list.
1768 for (i = 0; i < attrs->num_attrs; ++i) {
1769 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1770 MonoAssemblyName *aname;
1772 /* Do some sanity checking */
1773 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1775 if (attr->data_size < 4)
1777 data = (const char*)attr->data;
1778 /* 0xFF means null string, see custom attr format */
1779 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1781 mono_metadata_decode_value (data + 2, &data);
1782 aname = g_new0 (MonoAssemblyName, 1);
1783 /*g_print ("friend ass: %s\n", data);*/
1784 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1785 list = g_slist_prepend (list, aname);
1790 mono_custom_attrs_free (attrs);
1792 mono_assemblies_lock ();
1793 if (ass->friend_assembly_names_inited) {
1794 mono_assemblies_unlock ();
1795 g_slist_foreach (list, free_item, NULL);
1796 g_slist_free (list);
1799 ass->friend_assembly_names = list;
1801 /* Because of the double checked locking pattern above */
1802 mono_memory_barrier ();
1803 ass->friend_assembly_names_inited = TRUE;
1804 mono_assemblies_unlock ();
1809 * mono_assembly_get_reference_assembly_attribute:
1810 * @assembly: a MonoAssembly
1811 * @error: set on error.
1813 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1814 * On error returns FALSE and sets @error.
1817 mono_assembly_get_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1819 mono_error_init (error);
1821 MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
1822 return_val_if_nok (error, FALSE);
1825 MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
1826 gboolean result = FALSE;
1827 for (int i = 0; i < attrs->num_attrs; ++i) {
1828 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1829 if (attr->ctor && attr->ctor->klass && attr->ctor->klass == ref_asm_class) {
1834 mono_custom_attrs_free (attrs);
1839 * mono_assembly_open:
1840 * @filename: Opens the assembly pointed out by this name
1841 * @status: return status code
1843 * This loads an assembly from the specified @filename. The @filename allows
1844 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1845 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1846 * is treated as a local path.
1848 * First, an attempt is made to load the assembly from the bundled executable (for those
1849 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1850 * assembly has been registered as an embedded assembly). If this is not the case, then
1851 * the assembly is loaded from disk using `api:mono_image_open_full`.
1853 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1854 * the assembly is made.
1856 * Return: a pointer to the MonoAssembly if @filename contains a valid
1857 * assembly or NULL on error. Details about the error are stored in the
1861 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1863 return mono_assembly_open_full (filename, status, FALSE);
1867 * mono_assembly_load_from_full:
1868 * @image: Image to load the assembly from
1869 * @fname: assembly name to associate with the assembly
1870 * @status: returns the status condition
1871 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1873 * If the provided @image has an assembly reference, it will process the given
1874 * image as an assembly with the given name.
1876 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1878 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1879 * set to #MONO_IMAGE_OK; or NULL on error.
1881 * If there is an error loading the assembly the @status will indicate the
1882 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1883 * image did not contain an assembly reference table.
1886 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1887 MonoImageOpenStatus *status, gboolean refonly)
1889 MonoAssembly *ass, *ass2;
1892 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1893 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1894 *status = MONO_IMAGE_IMAGE_INVALID;
1898 #if defined (HOST_WIN32)
1903 tmp_fn = g_strdup (fname);
1904 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1905 if (tmp_fn [i] == '/')
1909 base_dir = absolute_dir (tmp_fn);
1913 base_dir = absolute_dir (fname);
1917 * Create assembly struct, and enter it into the assembly cache
1919 ass = g_new0 (MonoAssembly, 1);
1920 ass->basedir = base_dir;
1921 ass->ref_only = refonly;
1924 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1926 mono_assembly_fill_assembly_name (image, &ass->aname);
1928 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1929 // MS.NET doesn't support loading other mscorlibs
1932 mono_image_addref (mono_defaults.corlib);
1933 *status = MONO_IMAGE_OK;
1934 return mono_defaults.corlib->assembly;
1937 /* Add a non-temporary reference because of ass->image */
1938 mono_image_addref (image);
1940 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);
1943 * The load hooks might take locks so we can't call them while holding the
1946 if (ass->aname.name) {
1947 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1951 mono_image_close (image);
1952 *status = MONO_IMAGE_OK;
1957 mono_assemblies_lock ();
1959 if (image->assembly) {
1961 * This means another thread has already loaded the assembly, but not yet
1962 * called the load hooks so the search hook can't find the assembly.
1964 mono_assemblies_unlock ();
1965 ass2 = image->assembly;
1968 mono_image_close (image);
1969 *status = MONO_IMAGE_OK;
1973 image->assembly = ass;
1975 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1976 mono_assemblies_unlock ();
1979 if (image->is_module_handle)
1980 mono_image_fixup_vtable (image);
1983 mono_assembly_invoke_load_hook (ass);
1985 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1991 * mono_assembly_load_from:
1992 * @image: Image to load the assembly from
1993 * @fname: assembly name to associate with the assembly
1994 * @status: return status code
1996 * If the provided @image has an assembly reference, it will process the given
1997 * image as an assembly with the given name.
1999 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2001 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2002 * @refonly parameter set to FALSE.
2003 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2004 * set to #MONO_IMAGE_OK; or NULL on error.
2006 * If there is an error loading the assembly the @status will indicate the
2007 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2008 * image did not contain an assembly reference table.
2012 mono_assembly_load_from (MonoImage *image, const char *fname,
2013 MonoImageOpenStatus *status)
2015 return mono_assembly_load_from_full (image, fname, status, FALSE);
2019 * mono_assembly_name_free:
2020 * @aname: assembly name to free
2022 * Frees the provided assembly name object.
2023 * (it does not frees the object itself, only the name members).
2026 mono_assembly_name_free (MonoAssemblyName *aname)
2031 g_free ((void *) aname->name);
2032 g_free ((void *) aname->culture);
2033 g_free ((void *) aname->hash_value);
2034 g_free ((guint8*) aname->public_key);
2038 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2041 gchar header [16], val, *arr;
2042 gint i, j, offset, bitlen, keylen, pkeylen;
2044 keylen = strlen (key) >> 1;
2048 /* allow the ECMA standard key */
2049 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2051 *pubkey = g_strdup (key);
2057 val = g_ascii_xdigit_value (key [0]) << 4;
2058 val |= g_ascii_xdigit_value (key [1]);
2063 val = g_ascii_xdigit_value (key [24]);
2064 val |= g_ascii_xdigit_value (key [25]);
2076 /* We need the first 16 bytes
2077 * to check whether this key is valid or not */
2078 pkeylen = strlen (pkey) >> 1;
2082 for (i = 0, j = 0; i < 16; i++) {
2083 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2084 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2087 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2088 header [1] != 0x02 || /* Version (0x02) */
2089 header [2] != 0x00 || /* Reserved (word) */
2090 header [3] != 0x00 ||
2091 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2094 /* Based on this length, we _should_ be able to know if the length is right */
2095 bitlen = read32 (header + 12) >> 3;
2096 if ((bitlen + 16 + 4) != pkeylen)
2099 /* parsing is OK and the public key itself is not requested back */
2103 /* Encode the size of the blob */
2105 if (keylen <= 127) {
2106 arr = (gchar *)g_malloc (keylen + 1);
2107 arr [offset++] = keylen;
2109 arr = (gchar *)g_malloc (keylen + 2);
2110 arr [offset++] = 0x80; /* 10bs */
2111 arr [offset++] = keylen;
2114 for (i = offset, j = 0; i < keylen + offset; i++) {
2115 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2116 arr [i] |= g_ascii_xdigit_value (key [j++]);
2125 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)
2127 gint major, minor, build, revision;
2130 gchar *pkey, *pkeyptr, *encoded, tok [8];
2132 memset (aname, 0, sizeof (MonoAssemblyName));
2135 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2136 if (version_parts < 2 || version_parts > 4)
2139 /* FIXME: we should set build & revision to -1 (instead of 0)
2140 if these are not set in the version string. That way, later on,
2141 we can still determine if these were specified. */
2142 aname->major = major;
2143 aname->minor = minor;
2144 if (version_parts >= 3)
2145 aname->build = build;
2148 if (version_parts == 4)
2149 aname->revision = revision;
2151 aname->revision = 0;
2154 aname->flags = flags;
2156 aname->name = g_strdup (name);
2159 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2160 aname->culture = g_strdup ("");
2162 aname->culture = g_strdup (culture);
2165 if (token && strncmp (token, "null", 4) != 0) {
2168 /* the constant includes the ending NULL, hence the -1 */
2169 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2170 mono_assembly_name_free (aname);
2173 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2174 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2180 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2181 mono_assembly_name_free (aname);
2186 if (save_public_key)
2187 aname->public_key = (guint8*)pkey;
2190 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2194 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2195 // We also need to generate the key token
2196 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2197 encoded = encode_public_tok ((guchar*) tok, 8);
2198 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2201 if (save_public_key)
2202 aname->public_key = (guint8*) pkey;
2211 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2216 parts = g_strsplit (dirname, "_", 3);
2217 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2222 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2228 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2230 char *eqsign = strchr (pair, '=');
2238 *key = (gchar*)pair;
2239 *keylen = eqsign - *key;
2240 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2242 *value = g_strstrip (eqsign + 1);
2247 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2251 gchar *version = NULL;
2253 gchar *culture = NULL;
2255 gchar *token = NULL;
2259 gchar *retargetable = NULL;
2260 gchar *retargetable_uq;
2264 gchar *value, *part_name;
2265 guint32 part_name_len;
2268 gboolean version_defined;
2269 gboolean token_defined;
2271 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2273 if (!is_version_defined)
2274 is_version_defined = &version_defined;
2275 *is_version_defined = FALSE;
2276 if (!is_token_defined)
2277 is_token_defined = &token_defined;
2278 *is_token_defined = FALSE;
2280 parts = tmp = g_strsplit (name, ",", 6);
2281 if (!tmp || !*tmp) {
2286 dllname = g_strstrip (*tmp);
2291 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2292 goto cleanup_and_fail;
2294 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2295 *is_version_defined = TRUE;
2297 if (strlen (version) == 0) {
2298 goto cleanup_and_fail;
2304 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2306 if (strlen (culture) == 0) {
2307 goto cleanup_and_fail;
2313 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2314 *is_token_defined = TRUE;
2316 if (strlen (token) == 0) {
2317 goto cleanup_and_fail;
2323 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2325 if (strlen (key) == 0) {
2326 goto cleanup_and_fail;
2332 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2333 retargetable = value;
2334 retargetable_uq = unquote (retargetable);
2335 if (retargetable_uq != NULL)
2336 retargetable = retargetable_uq;
2338 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2339 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2340 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2341 g_free (retargetable_uq);
2342 goto cleanup_and_fail;
2345 g_free (retargetable_uq);
2350 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2352 procarch_uq = unquote (procarch);
2353 if (procarch_uq != NULL)
2354 procarch = procarch_uq;
2356 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2357 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2358 else if (!g_ascii_strcasecmp (procarch, "X86"))
2359 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2360 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2361 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2362 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2363 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2365 g_free (procarch_uq);
2366 goto cleanup_and_fail;
2369 g_free (procarch_uq);
2378 /* if retargetable flag is set, then we must have a fully qualified name */
2379 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2380 goto cleanup_and_fail;
2383 dllname_uq = unquote (dllname);
2384 version_uq = unquote (version);
2385 culture_uq = unquote (culture);
2386 token_uq = unquote (token);
2387 key_uq = unquote (key);
2389 res = build_assembly_name (
2390 dllname_uq == NULL ? dllname : dllname_uq,
2391 version_uq == NULL ? version : version_uq,
2392 culture_uq == NULL ? culture : culture_uq,
2393 token_uq == NULL ? token : token_uq,
2394 key_uq == NULL ? key : key_uq,
2395 flags, arch, aname, save_public_key);
2397 g_free (dllname_uq);
2398 g_free (version_uq);
2399 g_free (culture_uq);
2412 unquote (const char *str)
2420 slen = strlen (str);
2424 if (*str != '\'' && *str != '\"')
2427 end = str + slen - 1;
2431 return g_strndup (str + 1, slen - 2);
2435 * mono_assembly_name_parse:
2436 * @name: name to parse
2437 * @aname: the destination assembly name
2439 * Parses an assembly qualified type name and assigns the name,
2440 * version, culture and token to the provided assembly name object.
2442 * Returns: TRUE if the name could be parsed.
2445 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2447 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2451 * mono_assembly_name_new:
2452 * @name: name to parse
2454 * Allocate a new MonoAssemblyName and fill its values from the
2457 * Returns: a newly allocated structure or NULL if there was any failure.
2460 mono_assembly_name_new (const char *name)
2462 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2463 if (mono_assembly_name_parse (name, aname))
2470 mono_assembly_name_get_name (MonoAssemblyName *aname)
2476 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2478 return aname->culture;
2482 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2484 if (aname->public_key_token [0])
2485 return aname->public_key_token;
2490 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2493 *minor = aname->minor;
2495 *build = aname->build;
2497 *revision = aname->revision;
2498 return aname->major;
2501 static MonoAssembly*
2502 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2504 gchar *fullpath = NULL;
2506 const char* direntry;
2507 MonoAssemblyName gac_aname;
2508 gint major=-1, minor=0, build=0, revision=0;
2509 gboolean exact_version;
2511 dirhandle = g_dir_open (basepath, 0, NULL);
2515 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2517 while ((direntry = g_dir_read_name (dirhandle))) {
2518 gboolean match = TRUE;
2520 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2523 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2526 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2527 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2531 if (exact_version) {
2532 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2533 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2535 else if (gac_aname.major < major)
2537 else if (gac_aname.major == major) {
2538 if (gac_aname.minor < minor)
2540 else if (gac_aname.minor == minor) {
2541 if (gac_aname.build < build)
2543 else if (gac_aname.build == build && gac_aname.revision <= revision)
2550 major = gac_aname.major;
2551 minor = gac_aname.minor;
2552 build = gac_aname.build;
2553 revision = gac_aname.revision;
2555 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2558 mono_assembly_name_free (&gac_aname);
2561 g_dir_close (dirhandle);
2563 if (fullpath == NULL)
2566 MonoAssembly *res = mono_assembly_open (fullpath, status);
2573 * mono_assembly_load_with_partial_name:
2574 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2575 * @status: return status code
2577 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2578 * so it might contain a qualified type name, version, culture and token.
2580 * This will load the assembly from the file whose name is derived from the assembly name
2581 * by appending the .dll extension.
2583 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2584 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2585 * if that fails from the GAC.
2587 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2590 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2594 MonoAssemblyName *aname, base_name;
2595 MonoAssemblyName mapped_aname;
2596 gchar *fullname, *gacpath;
2599 memset (&base_name, 0, sizeof (MonoAssemblyName));
2602 if (!mono_assembly_name_parse (name, aname))
2606 * If no specific version has been requested, make sure we load the
2607 * correct version for system assemblies.
2609 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2610 aname = mono_assembly_remap_version (aname, &mapped_aname);
2612 res = mono_assembly_loaded (aname);
2614 mono_assembly_name_free (aname);
2618 res = invoke_assembly_preload_hook (aname, assemblies_path);
2620 res->in_gac = FALSE;
2621 mono_assembly_name_free (aname);
2625 fullname = g_strdup_printf ("%s.dll", aname->name);
2627 if (extra_gac_paths) {
2628 paths = extra_gac_paths;
2629 while (!res && *paths) {
2630 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2631 res = probe_for_partial_name (gacpath, fullname, aname, status);
2640 mono_assembly_name_free (aname);
2644 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2645 res = probe_for_partial_name (gacpath, fullname, aname, status);
2651 MonoDomain *domain = mono_domain_get ();
2652 MonoReflectionAssembly *refasm;
2654 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2655 if (!is_ok (&error)) {
2657 mono_assembly_name_free (aname);
2658 mono_error_cleanup (&error);
2659 if (*status == MONO_IMAGE_OK)
2660 *status = MONO_IMAGE_IMAGE_INVALID;
2664 res = refasm->assembly;
2668 mono_assembly_name_free (aname);
2674 mono_assembly_is_in_gac (const gchar *filename)
2676 const gchar *rootdir;
2680 if (filename == NULL)
2683 for (paths = extra_gac_paths; paths && *paths; paths++) {
2684 if (strstr (*paths, filename) != *paths)
2687 gp = (gchar *) (filename + strlen (*paths));
2688 if (*gp != G_DIR_SEPARATOR)
2691 if (strncmp (gp, "lib", 3))
2694 if (*gp != G_DIR_SEPARATOR)
2697 if (strncmp (gp, "mono", 4))
2700 if (*gp != G_DIR_SEPARATOR)
2703 if (strncmp (gp, "gac", 3))
2706 if (*gp != G_DIR_SEPARATOR)
2712 rootdir = mono_assembly_getrootdir ();
2713 if (strstr (filename, rootdir) != filename)
2716 gp = (gchar *) (filename + strlen (rootdir));
2717 if (*gp != G_DIR_SEPARATOR)
2720 if (strncmp (gp, "mono", 4))
2723 if (*gp != G_DIR_SEPARATOR)
2726 if (strncmp (gp, "gac", 3))
2729 if (*gp != G_DIR_SEPARATOR)
2735 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2738 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2742 if (strstr (aname->name, ".dll")) {
2743 len = strlen (aname->name) - 4;
2744 name = (gchar *)g_malloc (len + 1);
2745 strncpy (name, aname->name, len);
2748 name = g_strdup (aname->name);
2751 culture = g_utf8_strdown (aname->culture, -1);
2753 culture = g_strdup ("");
2755 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2756 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2760 filename = g_strconcat (pname, ".dll", NULL);
2761 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2767 if (extra_gac_paths) {
2768 paths = extra_gac_paths;
2769 while (!image && *paths) {
2770 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2771 "lib", "mono", "gac", subpath, NULL);
2772 image = mono_image_open (fullpath, NULL);
2783 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2784 "mono", "gac", subpath, NULL);
2785 image = mono_image_open (fullpath, NULL);
2792 static MonoAssemblyName*
2793 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2795 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2796 dest_name->major = info->new_version.major;
2797 dest_name->minor = info->new_version.minor;
2798 dest_name->build = info->new_version.build;
2799 dest_name->revision = info->new_version.revision;
2804 /* LOCKING: assembly_binding lock must be held */
2805 static MonoAssemblyBindingInfo*
2806 search_binding_loaded (MonoAssemblyName *aname)
2810 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2811 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2812 if (assembly_binding_maps_name (info, aname))
2819 static inline gboolean
2820 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2822 if (left->major != right->major || left->minor != right->minor ||
2823 left->build != right->build || left->revision != right->revision)
2829 static inline gboolean
2830 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2832 if (left->has_old_version_bottom != right->has_old_version_bottom)
2835 if (left->has_old_version_top != right->has_old_version_top)
2838 if (left->has_new_version != right->has_new_version)
2841 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2844 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2847 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2853 /* LOCKING: assumes all the necessary locks are held */
2855 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2857 MonoAssemblyBindingInfo *info_copy;
2859 MonoAssemblyBindingInfo *info_tmp;
2860 MonoDomain *domain = (MonoDomain*)user_data;
2865 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2866 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2867 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2871 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2872 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2874 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2876 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2878 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2882 get_version_number (int major, int minor)
2884 return major * 256 + minor;
2887 static inline gboolean
2888 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2890 int aname_version_number = get_version_number (aname->major, aname->minor);
2891 if (!info->has_old_version_bottom)
2894 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2897 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2900 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2901 info->major = aname->major;
2902 info->minor = aname->minor;
2907 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2908 static MonoAssemblyBindingInfo*
2909 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2911 MonoAssemblyBindingInfo *info;
2914 if (!domain->assembly_bindings)
2918 for (list = domain->assembly_bindings; list; list = list->next) {
2919 info = (MonoAssemblyBindingInfo *)list->data;
2920 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2926 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2927 info->has_new_version && assembly_binding_maps_name (info, aname))
2928 info->is_valid = TRUE;
2930 info->is_valid = FALSE;
2936 static MonoAssemblyName*
2937 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2940 MonoAssemblyBindingInfo *info, *info2;
2944 if (aname->public_key_token [0] == 0)
2947 domain = mono_domain_get ();
2949 mono_assembly_binding_lock ();
2950 info = search_binding_loaded (aname);
2951 mono_assembly_binding_unlock ();
2954 mono_domain_lock (domain);
2955 info = get_per_domain_assembly_binding_info (domain, aname);
2956 mono_domain_unlock (domain);
2960 if (!check_policy_versions (info, aname))
2963 mono_assembly_bind_version (info, aname, dest_name);
2967 if (domain && domain->setup && domain->setup->configuration_file) {
2968 mono_domain_lock (domain);
2969 if (!domain->assembly_bindings_parsed) {
2970 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2971 /* expect this to succeed because mono_domain_set_options_from_config () did
2972 * the same thing when the domain was created. */
2973 mono_error_assert_ok (&error);
2975 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2977 if (!domain_config_file_path)
2978 domain_config_file_path = domain_config_file_name;
2980 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2981 domain->assembly_bindings_parsed = TRUE;
2982 if (domain_config_file_name != domain_config_file_path)
2983 g_free (domain_config_file_name);
2984 g_free (domain_config_file_path);
2987 info2 = get_per_domain_assembly_binding_info (domain, aname);
2990 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2991 info->name = g_strdup (info2->name);
2992 info->culture = g_strdup (info2->culture);
2993 info->domain_id = domain->domain_id;
2996 mono_domain_unlock (domain);
3000 info = g_new0 (MonoAssemblyBindingInfo, 1);
3001 info->major = aname->major;
3002 info->minor = aname->minor;
3005 if (!info->is_valid) {
3006 ppimage = mono_assembly_load_publisher_policy (aname);
3008 get_publisher_policy_info (ppimage, aname, info);
3009 mono_image_close (ppimage);
3013 /* Define default error value if needed */
3014 if (!info->is_valid) {
3015 info->name = g_strdup (aname->name);
3016 info->culture = g_strdup (aname->culture);
3017 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3020 mono_assembly_binding_lock ();
3021 info2 = search_binding_loaded (aname);
3023 /* This binding was added by another thread
3025 mono_assembly_binding_info_free (info);
3030 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3032 mono_assembly_binding_unlock ();
3034 if (!info->is_valid || !check_policy_versions (info, aname))
3037 mono_assembly_bind_version (info, aname, dest_name);
3042 * mono_assembly_load_from_gac
3044 * @aname: The assembly name object
3046 static MonoAssembly*
3047 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3049 MonoAssembly *result = NULL;
3050 gchar *name, *version, *culture, *fullpath, *subpath;
3055 if (aname->public_key_token [0] == 0) {
3059 if (strstr (aname->name, ".dll")) {
3060 len = strlen (filename) - 4;
3061 name = (gchar *)g_malloc (len + 1);
3062 strncpy (name, aname->name, len);
3065 name = g_strdup (aname->name);
3068 if (aname->culture) {
3069 culture = g_utf8_strdown (aname->culture, -1);
3071 culture = g_strdup ("");
3074 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3075 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3076 aname->minor, aname->build, aname->revision,
3080 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3085 if (extra_gac_paths) {
3086 paths = extra_gac_paths;
3087 while (!result && *paths) {
3088 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3089 result = mono_assembly_open_full (fullpath, status, refonly);
3096 result->in_gac = TRUE;
3101 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3102 "mono", "gac", subpath, NULL);
3103 result = mono_assembly_open_full (fullpath, status, refonly);
3107 result->in_gac = TRUE;
3115 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3118 MonoAssemblyName *aname;
3121 /* g_print ("corlib already loaded\n"); */
3125 // In native client, Corlib is embedded in the executable as static variable corlibData
3126 #if defined(__native_client__)
3127 if (corlibData != NULL && corlibSize != 0) {
3129 /* First "FALSE" instructs mono not to make a copy. */
3130 /* Second "FALSE" says this is not just a ref. */
3131 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3132 if (image == NULL || status != 0)
3133 g_print("mono_image_open_from_data_full failed: %d\n", status);
3134 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3135 if (corlib == NULL || status != 0)
3136 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3142 // A nonstandard preload hook may provide a special mscorlib assembly
3143 aname = mono_assembly_name_new ("mscorlib.dll");
3144 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3145 mono_assembly_name_free (aname);
3148 goto return_corlib_and_facades;
3150 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3151 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3152 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3154 goto return_corlib_and_facades;
3157 /* Normal case: Load corlib from mono/<version> */
3158 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3159 if (assemblies_path) { // Custom assemblies path
3160 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3162 g_free (corlib_file);
3163 goto return_corlib_and_facades;
3166 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3167 g_free (corlib_file);
3169 return_corlib_and_facades:
3170 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3171 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3177 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3178 const char *basedir,
3179 MonoImageOpenStatus *status,
3182 MonoAssembly *result;
3183 char *fullpath, *filename;
3184 MonoAssemblyName maped_aname;
3185 MonoAssemblyName maped_name_pp;
3190 aname = mono_assembly_remap_version (aname, &maped_aname);
3192 /* Reflection only assemblies don't get assembly binding */
3194 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3196 result = mono_assembly_loaded_full (aname, refonly);
3200 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3202 result->in_gac = FALSE;
3206 /* Currently we retrieve the loaded corlib for reflection
3207 * only requests, like a common reflection only assembly
3209 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3210 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3213 len = strlen (aname->name);
3214 for (ext_index = 0; ext_index < 2; ext_index ++) {
3215 ext = ext_index == 0 ? ".dll" : ".exe";
3216 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3217 filename = g_strdup (aname->name);
3218 /* Don't try appending .dll/.exe if it already has one of those extensions */
3221 filename = g_strconcat (aname->name, ext, NULL);
3224 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3231 fullpath = g_build_filename (basedir, filename, NULL);
3232 result = mono_assembly_open_full (fullpath, status, refonly);
3235 result->in_gac = FALSE;
3241 result = load_in_path (filename, default_path, status, refonly);
3243 result->in_gac = FALSE;
3253 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3255 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3258 /* Try a postload search hook */
3259 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3264 * mono_assembly_load_full:
3265 * @aname: A MonoAssemblyName with the assembly name to load.
3266 * @basedir: A directory to look up the assembly at.
3267 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3268 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3270 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3271 * attempts to load the assembly from that directory before probing the standard locations.
3273 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3274 * assembly binding takes place.
3276 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3277 * value pointed by status is updated with an error code.
3280 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3282 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3286 * mono_assembly_load:
3287 * @aname: A MonoAssemblyName with the assembly name to load.
3288 * @basedir: A directory to look up the assembly at.
3289 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3291 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3292 * attempts to load the assembly from that directory before probing the standard locations.
3294 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3295 * value pointed by status is updated with an error code.
3298 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3300 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3304 * mono_assembly_loaded_full:
3305 * @aname: an assembly to look for.
3306 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3308 * This is used to determine if the specified assembly has been loaded
3309 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3310 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3313 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3316 MonoAssemblyName maped_aname;
3318 aname = mono_assembly_remap_version (aname, &maped_aname);
3320 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3326 * mono_assembly_loaded:
3327 * @aname: an assembly to look for.
3329 * This is used to determine if the specified assembly has been loaded
3331 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3332 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3335 mono_assembly_loaded (MonoAssemblyName *aname)
3337 return mono_assembly_loaded_full (aname, FALSE);
3341 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3343 if (assembly == NULL || assembly == REFERENCE_MISSING)
3346 if (assembly_is_dynamic (assembly)) {
3348 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3349 for (i = 0; i < dynimg->image.module_count; ++i)
3350 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3351 mono_dynamic_image_release_gc_roots (dynimg);
3356 * Returns whether mono_assembly_close_finish() must be called as
3357 * well. See comment for mono_image_close_except_pools() for why we
3358 * unload in two steps.
3361 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3364 g_return_val_if_fail (assembly != NULL, FALSE);
3366 if (assembly == REFERENCE_MISSING)
3369 /* Might be 0 already */
3370 if (InterlockedDecrement (&assembly->ref_count) > 0)
3373 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3375 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3377 mono_debug_close_image (assembly->image);
3379 mono_assemblies_lock ();
3380 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3381 mono_assemblies_unlock ();
3383 assembly->image->assembly = NULL;
3385 if (!mono_image_close_except_pools (assembly->image))
3386 assembly->image = NULL;
3388 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3389 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3390 mono_assembly_name_free (fname);
3393 g_slist_free (assembly->friend_assembly_names);
3394 g_free (assembly->basedir);
3396 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3402 mono_assembly_close_finish (MonoAssembly *assembly)
3404 g_assert (assembly && assembly != REFERENCE_MISSING);
3406 if (assembly->image)
3407 mono_image_close_finish (assembly->image);
3409 if (assembly_is_dynamic (assembly)) {
3410 g_free ((char*)assembly->aname.culture);
3417 * mono_assembly_close:
3418 * @assembly: the assembly to release.
3420 * This method releases a reference to the @assembly. The assembly is
3421 * only released when all the outstanding references to it are released.
3424 mono_assembly_close (MonoAssembly *assembly)
3426 if (mono_assembly_close_except_image_pools (assembly))
3427 mono_assembly_close_finish (assembly);
3431 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3433 return mono_image_load_file_for_image (assembly->image, idx);
3437 * mono_assembly_foreach:
3438 * @func: function to invoke for each assembly loaded
3439 * @user_data: data passed to the callback
3441 * Invokes the provided @func callback for each assembly loaded into
3442 * the runtime. The first parameter passed to the callback is the
3443 * `MonoAssembly*`, and the second parameter is the @user_data.
3445 * This is done for all assemblies loaded in the runtime, not just
3446 * those loaded in the current application domain.
3449 mono_assembly_foreach (GFunc func, gpointer user_data)
3454 * We make a copy of the list to avoid calling the callback inside the
3455 * lock, which could lead to deadlocks.
3457 mono_assemblies_lock ();
3458 copy = g_list_copy (loaded_assemblies);
3459 mono_assemblies_unlock ();
3461 g_list_foreach (loaded_assemblies, func, user_data);
3467 * mono_assemblies_cleanup:
3469 * Free all resources used by this module.
3472 mono_assemblies_cleanup (void)
3476 mono_os_mutex_destroy (&assemblies_mutex);
3477 mono_os_mutex_destroy (&assembly_binding_mutex);
3479 for (l = loaded_assembly_bindings; l; l = l->next) {
3480 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3482 mono_assembly_binding_info_free (info);
3485 g_slist_free (loaded_assembly_bindings);
3487 free_assembly_load_hooks ();
3488 free_assembly_search_hooks ();
3489 free_assembly_preload_hooks ();
3492 /*LOCKING takes the assembly_binding lock*/
3494 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3498 mono_assembly_binding_lock ();
3499 iter = &loaded_assembly_bindings;
3502 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3504 if (info->domain_id == domain_id) {
3506 mono_assembly_binding_info_free (info);
3513 mono_assembly_binding_unlock ();
3517 * Holds the assembly of the application, for
3518 * System.Diagnostics.Process::MainModule
3520 static MonoAssembly *main_assembly=NULL;
3523 mono_assembly_set_main (MonoAssembly *assembly)
3525 main_assembly = assembly;
3529 * mono_assembly_get_main:
3531 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3534 mono_assembly_get_main (void)
3536 return (main_assembly);
3540 * mono_assembly_get_image:
3541 * @assembly: The assembly to retrieve the image from
3543 * Returns: the MonoImage associated with this assembly.
3546 mono_assembly_get_image (MonoAssembly *assembly)
3548 return assembly->image;
3552 * mono_assembly_get_name:
3553 * @assembly: The assembly to retrieve the name from
3555 * The returned name's lifetime is the same as @assembly's.
3557 * Returns: the MonoAssemblyName associated with this assembly.
3560 mono_assembly_get_name (MonoAssembly *assembly)
3562 return &assembly->aname;
3566 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3568 bundles = assemblies;
3571 #define MONO_DECLSEC_FORMAT_10 0x3C
3572 #define MONO_DECLSEC_FORMAT_20 0x2E
3573 #define MONO_DECLSEC_FIELD 0x53
3574 #define MONO_DECLSEC_PROPERTY 0x54
3576 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3577 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3578 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3579 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3580 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3583 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3587 case MONO_DECLSEC_PROPERTY:
3589 case MONO_DECLSEC_FIELD:
3591 *abort_decoding = TRUE;
3596 if (*p++ != MONO_TYPE_BOOLEAN) {
3597 *abort_decoding = TRUE;
3601 /* property name length */
3602 len = mono_metadata_decode_value (p, &p);
3604 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3615 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3617 int i, j, num, len, params_len;
3619 if (*p == MONO_DECLSEC_FORMAT_10) {
3620 gsize read, written;
3621 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3623 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3629 if (*p++ != MONO_DECLSEC_FORMAT_20)
3632 /* number of encoded permission attributes */
3633 num = mono_metadata_decode_value (p, &p);
3634 for (i = 0; i < num; ++i) {
3635 gboolean is_valid = FALSE;
3636 gboolean abort_decoding = FALSE;
3638 /* attribute name length */
3639 len = mono_metadata_decode_value (p, &p);
3641 /* We don't really need to fully decode the type. Comparing the name is enough */
3642 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3646 /*size of the params table*/
3647 params_len = mono_metadata_decode_value (p, &p);
3649 const char *params_end = p + params_len;
3651 /* number of parameters */
3652 len = mono_metadata_decode_value (p, &p);
3654 for (j = 0; j < len; ++j) {
3655 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3671 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3674 guint32 cols [MONO_DECL_SECURITY_SIZE];
3678 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3679 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3681 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3683 for (i = 0; i < t->rows; ++i) {
3684 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3685 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3687 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3690 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3691 len = mono_metadata_decode_blob_size (blob, &blob);
3695 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3696 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3701 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);