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.
19 #include "assembly-internals.h"
21 #include "image-internals.h"
22 #include "object-internals.h"
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/metadata-internals.h>
26 #include <mono/metadata/profiler-private.h>
27 #include <mono/metadata/class-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include <mono/metadata/reflection-internals.h>
30 #include <mono/metadata/mono-endian.h>
31 #include <mono/metadata/mono-debug.h>
32 #include <mono/io-layer/io-layer.h>
33 #include <mono/utils/mono-uri.h>
34 #include <mono/metadata/mono-config.h>
35 #include <mono/metadata/mono-config-dirs.h>
36 #include <mono/utils/mono-digest.h>
37 #include <mono/utils/mono-logger-internals.h>
38 #include <mono/utils/mono-path.h>
39 #include <mono/metadata/reflection.h>
40 #include <mono/metadata/coree.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/utils/mono-io-portability.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-os-mutex.h>
47 #include <sys/types.h>
52 #ifdef PLATFORM_MACOSX
53 #include <mach-o/dyld.h>
56 /* 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 */
58 const char* assembly_name;
59 guint8 version_set_index;
60 const char* new_assembly_name;
61 gboolean only_lower_versions;
64 /* the default search path is empty, the first slot is replaced with the computed value */
72 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
73 static char **assemblies_path = NULL;
75 /* Contains the list of directories that point to auxiliary GACs */
76 static char **extra_gac_paths = NULL;
78 #ifndef DISABLE_ASSEMBLY_REMAPPING
79 /* The list of system assemblies what will be remapped to the running
80 * runtime version. WARNING: this list must be sorted.
81 * The integer number is an index in the MonoRuntimeInfo structure, whose
82 * values can be found in domain.c - supported_runtimes. Look there
83 * to understand what remapping will be made.
85 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
88 static const AssemblyVersionMap framework_assemblies [] = {
90 {"Commons.Xml.Relaxng", 0},
97 {"Microsoft.Build.Engine", 2, NULL, TRUE},
98 {"Microsoft.Build.Framework", 2, NULL, TRUE},
99 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
100 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
101 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
102 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
103 {"Microsoft.VisualBasic", 1},
104 {"Microsoft.VisualC", 1},
106 {"Mono.CompilerServices.SymbolWriter", 0},
108 {"Mono.Data.SybaseClient", 0},
109 {"Mono.Data.Tds", 0},
110 {"Mono.Data.TdsClient", 0},
111 {"Mono.GetOptions", 0},
114 {"Mono.Security", 0},
115 {"Mono.Security.Win32", 0},
117 {"Novell.Directory.Ldap", 0},
120 {"System.ComponentModel.Composition", 2},
121 {"System.ComponentModel.DataAnnotations", 2},
122 {"System.Configuration", 0},
123 {"System.Configuration.Install", 0},
126 {"System.Data.Linq", 2},
127 {"System.Data.OracleClient", 0},
128 {"System.Data.Services", 2},
129 {"System.Data.Services.Client", 2},
130 {"System.Data.SqlXml", 0},
131 {"System.Design", 0},
132 {"System.DirectoryServices", 0},
133 {"System.Drawing", 0},
134 {"System.Drawing.Design", 0},
135 {"System.EnterpriseServices", 0},
136 {"System.IdentityModel", 3},
137 {"System.IdentityModel.Selectors", 3},
138 {"System.Management", 0},
139 {"System.Messaging", 0},
141 {"System.Runtime.Remoting", 0},
142 {"System.Runtime.Serialization", 3},
143 {"System.Runtime.Serialization.Formatters.Soap", 0},
144 {"System.Security", 0},
145 {"System.ServiceModel", 3},
146 {"System.ServiceModel.Web", 2},
147 {"System.ServiceProcess", 0},
148 {"System.Transactions", 0},
150 {"System.Web.Abstractions", 2},
151 {"System.Web.DynamicData", 2},
152 {"System.Web.Extensions", 2},
153 {"System.Web.Mobile", 0},
154 {"System.Web.Routing", 2},
155 {"System.Web.Services", 0},
156 {"System.Windows.Forms", 0},
158 {"System.Xml.Linq", 2},
165 * keeps track of loaded assemblies
167 static GList *loaded_assemblies = NULL;
168 static MonoAssembly *corlib;
170 #if defined(__native_client__)
172 /* On Native Client, allow mscorlib to be loaded from memory */
173 /* instead of loaded off disk. If these are not set, default */
174 /* mscorlib loading will take place */
176 /* NOTE: If mscorlib data is passed to mono in this way then */
177 /* it needs to remain allocated during the use of mono. */
179 static void *corlibData = NULL;
180 static size_t corlibSize = 0;
183 mono_set_corlib_data (void *data, size_t size)
191 static char* unquote (const char *str);
193 /* This protects loaded_assemblies and image->references */
194 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
195 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
196 static mono_mutex_t assemblies_mutex;
198 /* If defined, points to the bundled assembly information */
199 const MonoBundledAssembly **bundles;
201 static mono_mutex_t assembly_binding_mutex;
203 /* Loaded assembly binding info */
204 static GSList *loaded_assembly_bindings = NULL;
206 /* Class lazy loading functions */
207 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
208 static GENERATE_TRY_GET_CLASS_WITH_CACHE (reference_assembly, System.Runtime.CompilerServices, ReferenceAssemblyAttribute)
211 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
213 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
215 mono_assembly_is_in_gac (const gchar *filanem);
218 encode_public_tok (const guchar *token, gint32 len)
220 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
224 res = (gchar *)g_malloc (len * 2 + 1);
225 for (i = 0; i < len; i++) {
226 res [i * 2] = allowed [token [i] >> 4];
227 res [i * 2 + 1] = allowed [token [i] & 0xF];
234 * mono_public_tokens_are_equal:
235 * @pubt1: first public key token
236 * @pubt2: second public key token
238 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
242 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
244 return memcmp (pubt1, pubt2, 16) == 0;
248 * mono_set_assemblies_path:
249 * @path: list of paths that contain directories where Mono will look for assemblies
251 * Use this method to override the standard assembly lookup system and
252 * override any assemblies coming from the GAC. This is the method
253 * that supports the MONO_PATH variable.
255 * Notice that MONO_PATH and this method are really a very bad idea as
256 * it prevents the GAC from working and it prevents the standard
257 * resolution mechanisms from working. Nonetheless, for some debugging
258 * situations and bootstrapping setups, this is useful to have.
261 mono_set_assemblies_path (const char* path)
263 char **splitted, **dest;
265 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
267 g_strfreev (assemblies_path);
268 assemblies_path = dest = splitted;
270 char *tmp = *splitted;
272 *dest++ = mono_path_canonicalize (tmp);
278 if (g_getenv ("MONO_DEBUG") == NULL)
281 splitted = assemblies_path;
283 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
284 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
290 /* Native Client can't get this info from an environment variable so */
291 /* it's passed in to the runtime, or set manually by embedding code. */
292 #ifdef __native_client__
293 char* nacl_mono_path = NULL;
297 check_path_env (void)
300 path = g_getenv ("MONO_PATH");
301 #ifdef __native_client__
303 path = nacl_mono_path;
305 if (!path || assemblies_path != NULL)
308 mono_set_assemblies_path(path);
312 check_extra_gac_path_env (void) {
314 char **splitted, **dest;
316 path = g_getenv ("MONO_GAC_PREFIX");
320 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
322 g_strfreev (extra_gac_paths);
323 extra_gac_paths = dest = splitted;
331 if (g_getenv ("MONO_DEBUG") == NULL)
335 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
336 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
343 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
345 if (!info || !info->name)
348 if (strcmp (info->name, aname->name))
351 if (info->major != aname->major || info->minor != aname->minor)
354 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
357 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
360 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
367 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
373 g_free (info->culture);
377 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
380 guint32 cols [MONO_MANIFEST_SIZE];
381 const gchar *filename;
382 gchar *subpath, *fullpath;
384 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
385 /* MS Impl. accepts policy assemblies with more than
386 * one manifest resource, and only takes the first one */
388 binding_info->is_valid = FALSE;
392 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
393 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
394 binding_info->is_valid = FALSE;
398 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
399 g_assert (filename != NULL);
401 subpath = g_path_get_dirname (image->name);
402 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
403 mono_config_parse_publisher_policy (fullpath, binding_info);
407 /* Define the optional elements/attributes before checking */
408 if (!binding_info->culture)
409 binding_info->culture = g_strdup ("");
411 /* Check that the most important elements/attributes exist */
412 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
413 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
414 mono_assembly_binding_info_free (binding_info);
415 binding_info->is_valid = FALSE;
419 binding_info->is_valid = TRUE;
423 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
425 if (v->major > aname->major)
427 else if (v->major < aname->major)
430 if (v->minor > aname->minor)
432 else if (v->minor < aname->minor)
435 if (v->build > aname->build)
437 else if (v->build < aname->build)
440 if (v->revision > aname->revision)
442 else if (v->revision < aname->revision)
449 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
454 /* If has_old_version_top doesn't exist, we don't have an interval */
455 if (!info->has_old_version_top) {
456 if (compare_versions (&info->old_version_bottom, name) == 0)
462 /* Check that the version defined by name is valid for the interval */
463 if (compare_versions (&info->old_version_top, name) < 0)
466 /* We should be greater or equal than the small version */
467 if (compare_versions (&info->old_version_bottom, name) > 0)
474 * mono_assembly_names_equal:
476 * @r: second assembly.
478 * Compares two MonoAssemblyNames and returns whether they are equal.
480 * This compares the names, the cultures, the release version and their
483 * Returns: TRUE if both assembly names are equal.
486 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
488 if (!l->name || !r->name)
491 if (strcmp (l->name, r->name))
494 if (l->culture && r->culture && strcmp (l->culture, r->culture))
497 if (l->major != r->major || l->minor != r->minor ||
498 l->build != r->build || l->revision != r->revision)
499 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)))
502 if (!l->public_key_token [0] || !r->public_key_token [0])
505 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
511 static MonoAssembly *
512 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
516 MonoAssembly *result;
518 for (i = 0; search_path [i]; ++i) {
519 fullpath = g_build_filename (search_path [i], basename, NULL);
520 result = mono_assembly_open_full (fullpath, status, refonly);
529 * mono_assembly_setrootdir:
530 * @root_dir: The pathname of the root directory where we will locate assemblies
532 * This routine sets the internal default root directory for looking up
535 * This is used by Windows installations to compute dynamically the
536 * place where the Mono assemblies are located.
540 mono_assembly_setrootdir (const char *root_dir)
543 * Override the MONO_ASSEMBLIES directory configured at compile time.
545 /* Leak if called more than once */
546 default_path [0] = g_strdup (root_dir);
550 * mono_assembly_getrootdir:
552 * Obtains the root directory used for looking up assemblies.
554 * Returns: a string with the directory, this string should not be freed.
556 G_CONST_RETURN gchar *
557 mono_assembly_getrootdir (void)
559 return default_path [0];
563 * mono_native_getrootdir:
565 * Obtains the root directory used for looking up native libs (.so, .dylib).
567 * Returns: a string with the directory, this string should be freed by
570 G_CONST_RETURN gchar *
571 mono_native_getrootdir (void)
573 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
579 * @assembly_dir: the base directory for assemblies
580 * @config_dir: the base directory for configuration files
582 * This routine is used internally and by developers embedding
583 * the runtime into their own applications.
585 * There are a number of cases to consider: Mono as a system-installed
586 * package that is available on the location preconfigured or Mono in
587 * a relocated location.
589 * If you are using a system-installed Mono, you can pass NULL
590 * to both parameters. If you are not, you should compute both
591 * directory values and call this routine.
593 * The values for a given PREFIX are:
595 * assembly_dir: PREFIX/lib
596 * config_dir: PREFIX/etc
598 * Notice that embedders that use Mono in a relocated way must
599 * compute the location at runtime, as they will be in control
600 * of where Mono is installed.
603 mono_set_dirs (const char *assembly_dir, const char *config_dir)
605 if (assembly_dir == NULL)
606 assembly_dir = mono_config_get_assemblies_dir ();
607 if (config_dir == NULL)
608 config_dir = mono_config_get_cfg_dir ();
609 mono_assembly_setrootdir (assembly_dir);
610 mono_set_config_dir (config_dir);
616 compute_base (char *path)
618 char *p = strrchr (path, '/');
622 /* Not a well known Mono executable, we are embedded, cant guess the base */
623 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
627 p = strrchr (path, '/');
631 if (strcmp (p, "/bin") != 0)
640 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
643 static G_GNUC_UNUSED void
647 char *config, *lib, *mono;
652 * Only /usr prefix is treated specially
654 bindir = mono_config_get_bin_dir ();
656 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
661 config = g_build_filename (base, "etc", NULL);
662 lib = g_build_filename (base, "lib", NULL);
663 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
664 if (stat (mono, &buf) == -1)
667 mono_set_dirs (lib, config);
675 #endif /* HOST_WIN32 */
680 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
681 * this auto-detects the prefix where Mono was installed.
684 mono_set_rootdir (void)
686 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
687 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
690 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
694 * _NSGetExecutablePath may return -1 to indicate buf is not large
695 * enough, but we ignore that case to avoid having to do extra dynamic
696 * allocation for the path and hope that 4096 is enough - this is
697 * ok in the Linux/Solaris case below at least...
701 guint buf_size = sizeof (buf);
704 if (_NSGetExecutablePath (buf, &buf_size) == 0)
705 name = g_strdup (buf);
714 resolvedname = mono_path_resolve_symlinks (name);
716 bindir = g_path_get_dirname (resolvedname);
717 installdir = g_path_get_dirname (bindir);
718 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
720 config = g_build_filename (root, "..", "etc", NULL);
722 mono_set_dirs (root, config);
724 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
725 mono_set_dirs (root, config);
735 g_free (resolvedname);
736 #elif defined(DISABLE_MONO_AUTODETECTION)
744 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
752 /* Solaris 10 style */
753 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
754 s = readlink (str, buf, sizeof (buf)-1);
766 * mono_assemblies_init:
768 * Initialize global variables used by this module.
771 mono_assemblies_init (void)
774 * Initialize our internal paths if we have not been initialized yet.
775 * This happens when embedders use Mono.
777 if (mono_assembly_getrootdir () == NULL)
781 check_extra_gac_path_env ();
783 mono_os_mutex_init_recursive (&assemblies_mutex);
784 mono_os_mutex_init (&assembly_binding_mutex);
788 mono_assembly_binding_lock (void)
790 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
794 mono_assembly_binding_unlock (void)
796 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
800 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
802 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
803 guint32 cols [MONO_ASSEMBLY_SIZE];
804 gint32 machine, flags;
809 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
812 aname->hash_value = NULL;
813 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
814 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
815 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
816 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
817 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
818 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
819 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
820 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
821 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
822 guchar* token = (guchar *)g_malloc (8);
827 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
828 len = mono_metadata_decode_blob_size (pkey, &pkey);
829 aname->public_key = (guchar*)pkey;
831 mono_digest_get_public_token (token, aname->public_key, len);
832 encoded = encode_public_tok (token, 8);
833 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
839 aname->public_key = NULL;
840 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
843 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
844 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
847 aname->public_key = 0;
849 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
850 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
852 case COFF_MACHINE_I386:
853 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
854 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
855 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
856 else if ((flags & 0x70) == 0x70)
857 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
859 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
861 case COFF_MACHINE_IA64:
862 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
864 case COFF_MACHINE_AMD64:
865 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
867 case COFF_MACHINE_ARM:
868 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
878 * mono_stringify_assembly_name:
879 * @aname: the assembly name.
881 * Convert @aname into its string format. The returned string is dynamically
882 * allocated and should be freed by the caller.
884 * Returns: a newly allocated string with a string representation of
888 mono_stringify_assembly_name (MonoAssemblyName *aname)
890 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
892 return g_strdup_printf (
893 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
894 quote, aname->name, quote,
895 aname->major, aname->minor, aname->build, aname->revision,
896 aname->culture && *aname->culture? aname->culture: "neutral",
897 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
898 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
902 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
904 const gchar *public_tok;
907 public_tok = mono_metadata_blob_heap (image, key_index);
908 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
910 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
912 mono_digest_get_public_token (token, (guchar*)public_tok, len);
913 return encode_public_tok (token, 8);
916 return encode_public_tok ((guchar*)public_tok, len);
920 * mono_assembly_addref:
921 * @assemnly: the assembly to reference
923 * This routine increments the reference count on a MonoAssembly.
924 * The reference count is reduced every time the method mono_assembly_close() is
928 mono_assembly_addref (MonoAssembly *assembly)
930 InterlockedIncrement (&assembly->ref_count);
934 * CAUTION: This table must be kept in sync with
935 * ivkm/reflect/Fusion.cs
938 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
939 #define WINFX_KEY "31bf3856ad364e35"
940 #define ECMA_KEY "b77a5c561934e089"
941 #define MSFINAL_KEY "b03f5f7f11d50a3a"
942 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
950 static KeyRemapEntry key_remap_table[] = {
951 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
952 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
953 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
954 { "System", SILVERLIGHT_KEY, ECMA_KEY },
955 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
956 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
957 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
958 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
959 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
960 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
961 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
962 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
963 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
964 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
965 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
966 { "System.Numerics", WINFX_KEY, ECMA_KEY },
967 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
968 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
969 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
970 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
971 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
972 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
973 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
974 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
975 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
976 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
977 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
978 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
979 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
983 remap_keys (MonoAssemblyName *aname)
986 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
987 const KeyRemapEntry *entry = &key_remap_table [i];
989 if (strcmp (aname->name, entry->name) ||
990 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
993 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
995 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
996 "Remapped public key token of retargetable assembly %s from %s to %s",
997 aname->name, entry->from, entry->to);
1002 static MonoAssemblyName *
1003 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1005 const MonoRuntimeInfo *current_runtime;
1006 int pos, first, last;
1008 if (aname->name == NULL) return aname;
1010 current_runtime = mono_get_runtime_info ();
1012 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1013 const AssemblyVersionSet* vset;
1015 /* Remap to current runtime */
1016 vset = ¤t_runtime->version_sets [0];
1018 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1019 dest_aname->major = vset->major;
1020 dest_aname->minor = vset->minor;
1021 dest_aname->build = vset->build;
1022 dest_aname->revision = vset->revision;
1023 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1025 /* Remap assembly name */
1026 if (!strcmp (aname->name, "System.Net"))
1027 dest_aname->name = g_strdup ("System");
1029 remap_keys (dest_aname);
1031 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1032 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1034 aname->major, aname->minor, aname->build, aname->revision,
1036 vset->major, vset->minor, vset->build, vset->revision
1042 #ifndef DISABLE_ASSEMBLY_REMAPPING
1044 last = G_N_ELEMENTS (framework_assemblies) - 1;
1046 while (first <= last) {
1048 pos = first + (last - first) / 2;
1049 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1051 const AssemblyVersionSet* vset;
1052 int index = framework_assemblies[pos].version_set_index;
1053 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1054 vset = ¤t_runtime->version_sets [index];
1056 if (aname->major == vset->major && aname->minor == vset->minor &&
1057 aname->build == vset->build && aname->revision == vset->revision)
1060 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1063 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1064 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1065 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1067 aname->major, aname->minor, aname->build, aname->revision,
1068 vset->major, vset->minor, vset->build, vset->revision
1071 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1072 dest_aname->major = vset->major;
1073 dest_aname->minor = vset->minor;
1074 dest_aname->build = vset->build;
1075 dest_aname->revision = vset->revision;
1076 if (framework_assemblies[pos].new_assembly_name != NULL) {
1077 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1078 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1079 "The assembly name %s was remapped to %s",
1084 } else if (res < 0) {
1096 * mono_assembly_get_assemblyref:
1097 * @image: pointer to the MonoImage to extract the information from.
1098 * @index: index to the assembly reference in the image.
1099 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1101 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1104 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1107 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1110 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1112 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1114 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1115 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1116 aname->hash_value = hash;
1117 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1118 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1119 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1120 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1121 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1122 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1123 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1125 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1126 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1127 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1130 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1135 mono_assembly_load_reference (MonoImage *image, int index)
1137 MonoAssembly *reference;
1138 MonoAssemblyName aname;
1139 MonoImageOpenStatus status;
1142 * image->references is shared between threads, so we need to access
1143 * it inside a critical section.
1145 mono_assemblies_lock ();
1146 if (!image->references) {
1147 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1149 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1150 image->nreferences = t->rows;
1152 reference = image->references [index];
1153 mono_assemblies_unlock ();
1157 mono_assembly_get_assemblyref (image, index, &aname);
1159 if (image->assembly && image->assembly->ref_only) {
1160 /* We use the loaded corlib */
1161 if (!strcmp (aname.name, "mscorlib"))
1162 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1164 reference = mono_assembly_loaded_full (&aname, TRUE);
1166 /* Try a postload search hook */
1167 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1171 * Here we must advice that the error was due to
1172 * a non loaded reference using the ReflectionOnly api
1175 reference = (MonoAssembly *)REFERENCE_MISSING;
1177 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1178 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1179 * accordingly, it would fail on the MS runtime before).
1180 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1181 * example bug-349190.2.cs and who knows how much more code in the wild.
1183 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1184 if (!reference && image->assembly)
1185 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1188 if (reference == NULL){
1191 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1192 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 : "" );
1193 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1194 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1195 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1196 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1197 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1198 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1200 extra_msg = g_strdup ("");
1203 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1204 " Assembly: %s (assemblyref_index=%d)\n"
1205 " Version: %d.%d.%d.%d\n"
1206 " Public Key: %s\n%s",
1207 image->name, aname.name, index,
1208 aname.major, aname.minor, aname.build, aname.revision,
1209 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1213 mono_assemblies_lock ();
1214 if (reference == NULL) {
1215 /* Flag as not found */
1216 reference = (MonoAssembly *)REFERENCE_MISSING;
1219 if (!image->references [index]) {
1220 if (reference != REFERENCE_MISSING){
1221 mono_assembly_addref (reference);
1222 if (image->assembly)
1223 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1224 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1226 if (image->assembly)
1227 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1228 image->assembly->aname.name, image->assembly);
1231 image->references [index] = reference;
1233 mono_assemblies_unlock ();
1235 if (image->references [index] != reference) {
1236 /* Somebody loaded it before us */
1237 mono_assembly_close (reference);
1242 * mono_assembly_load_references:
1245 * @deprecated: There is no reason to use this method anymore, it does nothing
1247 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1250 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1252 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1253 *status = MONO_IMAGE_OK;
1256 typedef struct AssemblyLoadHook AssemblyLoadHook;
1257 struct AssemblyLoadHook {
1258 AssemblyLoadHook *next;
1259 MonoAssemblyLoadFunc func;
1263 AssemblyLoadHook *assembly_load_hook = NULL;
1266 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1268 AssemblyLoadHook *hook;
1270 for (hook = assembly_load_hook; hook; hook = hook->next) {
1271 hook->func (ass, hook->user_data);
1276 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1278 AssemblyLoadHook *hook;
1280 g_return_if_fail (func != NULL);
1282 hook = g_new0 (AssemblyLoadHook, 1);
1284 hook->user_data = user_data;
1285 hook->next = assembly_load_hook;
1286 assembly_load_hook = hook;
1290 free_assembly_load_hooks (void)
1292 AssemblyLoadHook *hook, *next;
1294 for (hook = assembly_load_hook; hook; hook = next) {
1300 typedef struct AssemblySearchHook AssemblySearchHook;
1301 struct AssemblySearchHook {
1302 AssemblySearchHook *next;
1303 MonoAssemblySearchFunc func;
1309 AssemblySearchHook *assembly_search_hook = NULL;
1311 static MonoAssembly*
1312 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1314 AssemblySearchHook *hook;
1316 for (hook = assembly_search_hook; hook; hook = hook->next) {
1317 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1320 * A little explanation is in order here.
1322 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1323 * The embedding API exposes a search hook that doesn't take such argument.
1325 * The original fix would call the default search hook before all the registered ones and pass
1326 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1327 * rely on. Which is the ordering between user hooks and the default runtime hook.
1329 * Registering the hook after mono_jit_init would let your hook run before the default one and
1330 * when using it to handle non standard app layouts this could save your app from a massive amount
1331 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1332 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1334 * So what's the fix? We register the default hook using regular means and special case it when iterating
1335 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1338 if (hook->func == (void*)mono_domain_assembly_postload_search)
1339 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1341 ass = hook->func (aname, hook->user_data);
1351 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1353 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1357 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1359 AssemblySearchHook *hook;
1361 g_return_if_fail (func != NULL);
1363 hook = g_new0 (AssemblySearchHook, 1);
1365 hook->user_data = user_data;
1366 hook->refonly = refonly;
1367 hook->postload = postload;
1368 hook->next = assembly_search_hook;
1369 assembly_search_hook = hook;
1373 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1375 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1379 free_assembly_search_hooks (void)
1381 AssemblySearchHook *hook, *next;
1383 for (hook = assembly_search_hook; hook; hook = next) {
1390 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1392 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1396 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1398 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1402 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1404 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1407 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1408 struct AssemblyPreLoadHook {
1409 AssemblyPreLoadHook *next;
1410 MonoAssemblyPreLoadFunc func;
1414 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1415 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1417 static MonoAssembly *
1418 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1420 AssemblyPreLoadHook *hook;
1421 MonoAssembly *assembly;
1423 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1424 assembly = hook->func (aname, assemblies_path, hook->user_data);
1425 if (assembly != NULL)
1432 static MonoAssembly *
1433 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1435 AssemblyPreLoadHook *hook;
1436 MonoAssembly *assembly;
1438 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1439 assembly = hook->func (aname, assemblies_path, hook->user_data);
1440 if (assembly != NULL)
1448 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1450 AssemblyPreLoadHook *hook;
1452 g_return_if_fail (func != NULL);
1454 hook = g_new0 (AssemblyPreLoadHook, 1);
1456 hook->user_data = user_data;
1457 hook->next = assembly_preload_hook;
1458 assembly_preload_hook = hook;
1462 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1464 AssemblyPreLoadHook *hook;
1466 g_return_if_fail (func != NULL);
1468 hook = g_new0 (AssemblyPreLoadHook, 1);
1470 hook->user_data = user_data;
1471 hook->next = assembly_refonly_preload_hook;
1472 assembly_refonly_preload_hook = hook;
1476 free_assembly_preload_hooks (void)
1478 AssemblyPreLoadHook *hook, *next;
1480 for (hook = assembly_preload_hook; hook; hook = next) {
1485 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1492 absolute_dir (const gchar *filename)
1503 if (g_path_is_absolute (filename)) {
1504 part = g_path_get_dirname (filename);
1505 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1510 cwd = g_get_current_dir ();
1511 mixed = g_build_filename (cwd, filename, NULL);
1512 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1517 for (i = 0; (part = parts [i]) != NULL; i++) {
1518 if (!strcmp (part, "."))
1521 if (!strcmp (part, "..")) {
1522 if (list && list->next) /* Don't remove root */
1523 list = g_list_delete_link (list, list);
1525 list = g_list_prepend (list, part);
1529 result = g_string_new ("");
1530 list = g_list_reverse (list);
1532 /* Ignores last data pointer, which should be the filename */
1533 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1535 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1540 g_string_free (result, FALSE);
1545 return g_strdup (".");
1552 * mono_assembly_open_from_bundle:
1553 * @filename: Filename requested
1554 * @status: return status code
1556 * This routine tries to open the assembly specified by `filename' from the
1557 * defined bundles, if found, returns the MonoImage for it, if not found
1561 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1565 gchar *lowercase_filename;
1566 MonoImage *image = NULL;
1567 gboolean is_satellite = FALSE;
1569 * we do a very simple search for bundled assemblies: it's not a general
1570 * purpose assembly loading mechanism.
1576 lowercase_filename = g_utf8_strdown (filename, -1);
1577 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1578 g_free (lowercase_filename);
1579 name = g_path_get_basename (filename);
1580 mono_assemblies_lock ();
1581 for (i = 0; !image && bundles [i]; ++i) {
1582 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1583 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1587 mono_assemblies_unlock ();
1589 mono_image_addref (image);
1590 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1599 * mono_assemblies_open_full:
1600 * @filename: the file to load
1601 * @status: return status code
1602 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1604 * This loads an assembly from the specified @filename. The @filename allows
1605 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1606 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1607 * is treated as a local path.
1609 * First, an attempt is made to load the assembly from the bundled executable (for those
1610 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1611 * assembly has been registered as an embedded assembly). If this is not the case, then
1612 * the assembly is loaded from disk using `api:mono_image_open_full`.
1614 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1615 * the assembly is made.
1617 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1618 * the `System.Reflection` API.
1620 * Returns: NULL on error, with the @status set to an error code, or a pointer
1624 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1628 MonoImageOpenStatus def_status;
1631 gboolean loaded_from_bundle;
1633 g_return_val_if_fail (filename != NULL, NULL);
1636 status = &def_status;
1637 *status = MONO_IMAGE_OK;
1639 if (strncmp (filename, "file://", 7) == 0) {
1640 GError *error = NULL;
1641 gchar *uri = (gchar *) filename;
1645 * MS allows file://c:/... and fails on file://localhost/c:/...
1646 * They also throw an IndexOutOfRangeException if "file://"
1649 uri = g_strdup_printf ("file:///%s", uri + 7);
1652 uri = mono_escape_uri_string (tmpuri);
1653 fname = g_filename_from_uri (uri, NULL, &error);
1656 if (tmpuri != filename)
1659 if (error != NULL) {
1660 g_warning ("%s\n", error->message);
1661 g_error_free (error);
1662 fname = g_strdup (filename);
1665 fname = g_strdup (filename);
1668 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1669 "Assembly Loader probing location: '%s'.", fname);
1672 if (!mono_assembly_is_in_gac (fname)) {
1674 new_fname = mono_make_shadow_copy (fname, &error);
1675 if (!is_ok (&error)) {
1676 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1677 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1678 mono_error_cleanup (&error);
1679 *status = MONO_IMAGE_IMAGE_INVALID;
1684 if (new_fname && new_fname != fname) {
1687 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1688 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1693 // If VM built with mkbundle
1694 loaded_from_bundle = FALSE;
1695 if (bundles != NULL) {
1696 image = mono_assembly_open_from_bundle (fname, status, refonly);
1697 loaded_from_bundle = image != NULL;
1701 image = mono_image_open_full (fname, status, refonly);
1704 if (*status == MONO_IMAGE_OK)
1705 *status = MONO_IMAGE_ERROR_ERRNO;
1710 if (image->assembly) {
1711 /* Already loaded by another appdomain */
1712 mono_assembly_invoke_load_hook (image->assembly);
1713 mono_image_close (image);
1715 return image->assembly;
1718 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1721 if (!loaded_from_bundle)
1722 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1723 "Assembly Loader loaded assembly from location: '%s'.", filename);
1725 mono_config_for_assembly (ass->image);
1728 /* Clear the reference added by mono_image_open */
1729 mono_image_close (image);
1737 free_item (gpointer val, gpointer user_data)
1743 * mono_assembly_load_friends:
1746 * Load the list of friend assemblies that are allowed to access
1747 * the assembly's internal types and members. They are stored as assembly
1748 * names in custom attributes.
1750 * This is an internal method, we need this because when we load mscorlib
1751 * we do not have the internals visible cattr loaded yet,
1752 * so we need to load these after we initialize the runtime.
1754 * LOCKING: Acquires the assemblies lock plus the loader lock.
1757 mono_assembly_load_friends (MonoAssembly* ass)
1761 MonoCustomAttrInfo* attrs;
1764 if (ass->friend_assembly_names_inited)
1767 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1768 mono_error_assert_ok (&error);
1770 mono_assemblies_lock ();
1771 ass->friend_assembly_names_inited = TRUE;
1772 mono_assemblies_unlock ();
1776 mono_assemblies_lock ();
1777 if (ass->friend_assembly_names_inited) {
1778 mono_assemblies_unlock ();
1781 mono_assemblies_unlock ();
1785 * We build the list outside the assemblies lock, the worse that can happen
1786 * is that we'll need to free the allocated list.
1788 for (i = 0; i < attrs->num_attrs; ++i) {
1789 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1790 MonoAssemblyName *aname;
1792 /* Do some sanity checking */
1793 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1795 if (attr->data_size < 4)
1797 data = (const char*)attr->data;
1798 /* 0xFF means null string, see custom attr format */
1799 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1801 mono_metadata_decode_value (data + 2, &data);
1802 aname = g_new0 (MonoAssemblyName, 1);
1803 /*g_print ("friend ass: %s\n", data);*/
1804 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1805 list = g_slist_prepend (list, aname);
1810 mono_custom_attrs_free (attrs);
1812 mono_assemblies_lock ();
1813 if (ass->friend_assembly_names_inited) {
1814 mono_assemblies_unlock ();
1815 g_slist_foreach (list, free_item, NULL);
1816 g_slist_free (list);
1819 ass->friend_assembly_names = list;
1821 /* Because of the double checked locking pattern above */
1822 mono_memory_barrier ();
1823 ass->friend_assembly_names_inited = TRUE;
1824 mono_assemblies_unlock ();
1829 * mono_assembly_get_reference_assembly_attribute:
1830 * @assembly: a MonoAssembly
1831 * @error: set on error.
1833 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1834 * On error returns FALSE and sets @error.
1837 mono_assembly_get_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1839 mono_error_init (error);
1841 MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
1842 return_val_if_nok (error, FALSE);
1845 MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
1846 gboolean result = FALSE;
1847 for (int i = 0; i < attrs->num_attrs; ++i) {
1848 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1849 if (attr->ctor && attr->ctor->klass && attr->ctor->klass == ref_asm_class) {
1854 mono_custom_attrs_free (attrs);
1859 * mono_assembly_open:
1860 * @filename: Opens the assembly pointed out by this name
1861 * @status: return status code
1863 * This loads an assembly from the specified @filename. The @filename allows
1864 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1865 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1866 * is treated as a local path.
1868 * First, an attempt is made to load the assembly from the bundled executable (for those
1869 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1870 * assembly has been registered as an embedded assembly). If this is not the case, then
1871 * the assembly is loaded from disk using `api:mono_image_open_full`.
1873 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1874 * the assembly is made.
1876 * Return: a pointer to the MonoAssembly if @filename contains a valid
1877 * assembly or NULL on error. Details about the error are stored in the
1881 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1883 return mono_assembly_open_full (filename, status, FALSE);
1887 * mono_assembly_load_from_full:
1888 * @image: Image to load the assembly from
1889 * @fname: assembly name to associate with the assembly
1890 * @status: returns the status condition
1891 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1893 * If the provided @image has an assembly reference, it will process the given
1894 * image as an assembly with the given name.
1896 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1898 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1899 * set to #MONO_IMAGE_OK; or NULL on error.
1901 * If there is an error loading the assembly the @status will indicate the
1902 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1903 * image did not contain an assembly reference table.
1906 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1907 MonoImageOpenStatus *status, gboolean refonly)
1909 MonoAssembly *ass, *ass2;
1912 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1913 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1914 *status = MONO_IMAGE_IMAGE_INVALID;
1918 #if defined (HOST_WIN32)
1923 tmp_fn = g_strdup (fname);
1924 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1925 if (tmp_fn [i] == '/')
1929 base_dir = absolute_dir (tmp_fn);
1933 base_dir = absolute_dir (fname);
1937 * Create assembly struct, and enter it into the assembly cache
1939 ass = g_new0 (MonoAssembly, 1);
1940 ass->basedir = base_dir;
1941 ass->ref_only = refonly;
1944 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1946 mono_assembly_fill_assembly_name (image, &ass->aname);
1948 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1949 // MS.NET doesn't support loading other mscorlibs
1952 mono_image_addref (mono_defaults.corlib);
1953 *status = MONO_IMAGE_OK;
1954 return mono_defaults.corlib->assembly;
1957 /* Add a non-temporary reference because of ass->image */
1958 mono_image_addref (image);
1960 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);
1963 * The load hooks might take locks so we can't call them while holding the
1966 if (ass->aname.name) {
1967 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1971 mono_image_close (image);
1972 *status = MONO_IMAGE_OK;
1977 mono_assemblies_lock ();
1979 if (image->assembly) {
1981 * This means another thread has already loaded the assembly, but not yet
1982 * called the load hooks so the search hook can't find the assembly.
1984 mono_assemblies_unlock ();
1985 ass2 = image->assembly;
1988 mono_image_close (image);
1989 *status = MONO_IMAGE_OK;
1993 image->assembly = ass;
1995 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1996 mono_assemblies_unlock ();
1999 if (image->is_module_handle)
2000 mono_image_fixup_vtable (image);
2003 mono_assembly_invoke_load_hook (ass);
2005 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2011 * mono_assembly_load_from:
2012 * @image: Image to load the assembly from
2013 * @fname: assembly name to associate with the assembly
2014 * @status: return status code
2016 * If the provided @image has an assembly reference, it will process the given
2017 * image as an assembly with the given name.
2019 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2021 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2022 * @refonly parameter set to FALSE.
2023 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2024 * set to #MONO_IMAGE_OK; or NULL on error.
2026 * If there is an error loading the assembly the @status will indicate the
2027 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2028 * image did not contain an assembly reference table.
2032 mono_assembly_load_from (MonoImage *image, const char *fname,
2033 MonoImageOpenStatus *status)
2035 return mono_assembly_load_from_full (image, fname, status, FALSE);
2039 * mono_assembly_name_free:
2040 * @aname: assembly name to free
2042 * Frees the provided assembly name object.
2043 * (it does not frees the object itself, only the name members).
2046 mono_assembly_name_free (MonoAssemblyName *aname)
2051 g_free ((void *) aname->name);
2052 g_free ((void *) aname->culture);
2053 g_free ((void *) aname->hash_value);
2054 g_free ((guint8*) aname->public_key);
2058 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2061 gchar header [16], val, *arr;
2062 gint i, j, offset, bitlen, keylen, pkeylen;
2064 keylen = strlen (key) >> 1;
2068 /* allow the ECMA standard key */
2069 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2071 *pubkey = g_strdup (key);
2077 val = g_ascii_xdigit_value (key [0]) << 4;
2078 val |= g_ascii_xdigit_value (key [1]);
2083 val = g_ascii_xdigit_value (key [24]);
2084 val |= g_ascii_xdigit_value (key [25]);
2096 /* We need the first 16 bytes
2097 * to check whether this key is valid or not */
2098 pkeylen = strlen (pkey) >> 1;
2102 for (i = 0, j = 0; i < 16; i++) {
2103 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2104 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2107 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2108 header [1] != 0x02 || /* Version (0x02) */
2109 header [2] != 0x00 || /* Reserved (word) */
2110 header [3] != 0x00 ||
2111 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2114 /* Based on this length, we _should_ be able to know if the length is right */
2115 bitlen = read32 (header + 12) >> 3;
2116 if ((bitlen + 16 + 4) != pkeylen)
2119 /* parsing is OK and the public key itself is not requested back */
2123 /* Encode the size of the blob */
2125 if (keylen <= 127) {
2126 arr = (gchar *)g_malloc (keylen + 1);
2127 arr [offset++] = keylen;
2129 arr = (gchar *)g_malloc (keylen + 2);
2130 arr [offset++] = 0x80; /* 10bs */
2131 arr [offset++] = keylen;
2134 for (i = offset, j = 0; i < keylen + offset; i++) {
2135 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2136 arr [i] |= g_ascii_xdigit_value (key [j++]);
2145 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)
2147 gint major, minor, build, revision;
2150 gchar *pkey, *pkeyptr, *encoded, tok [8];
2152 memset (aname, 0, sizeof (MonoAssemblyName));
2155 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2156 if (version_parts < 2 || version_parts > 4)
2159 /* FIXME: we should set build & revision to -1 (instead of 0)
2160 if these are not set in the version string. That way, later on,
2161 we can still determine if these were specified. */
2162 aname->major = major;
2163 aname->minor = minor;
2164 if (version_parts >= 3)
2165 aname->build = build;
2168 if (version_parts == 4)
2169 aname->revision = revision;
2171 aname->revision = 0;
2174 aname->flags = flags;
2176 aname->name = g_strdup (name);
2179 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2180 aname->culture = g_strdup ("");
2182 aname->culture = g_strdup (culture);
2185 if (token && strncmp (token, "null", 4) != 0) {
2188 /* the constant includes the ending NULL, hence the -1 */
2189 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2190 mono_assembly_name_free (aname);
2193 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2194 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2200 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2201 mono_assembly_name_free (aname);
2206 if (save_public_key)
2207 aname->public_key = (guint8*)pkey;
2210 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2214 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2215 // We also need to generate the key token
2216 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2217 encoded = encode_public_tok ((guchar*) tok, 8);
2218 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2221 if (save_public_key)
2222 aname->public_key = (guint8*) pkey;
2231 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2236 parts = g_strsplit (dirname, "_", 3);
2237 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2242 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2248 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2250 char *eqsign = strchr (pair, '=');
2258 *key = (gchar*)pair;
2259 *keylen = eqsign - *key;
2260 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2262 *value = g_strstrip (eqsign + 1);
2267 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2271 gchar *version = NULL;
2273 gchar *culture = NULL;
2275 gchar *token = NULL;
2279 gchar *retargetable = NULL;
2280 gchar *retargetable_uq;
2284 gchar *value, *part_name;
2285 guint32 part_name_len;
2288 gboolean version_defined;
2289 gboolean token_defined;
2291 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2293 if (!is_version_defined)
2294 is_version_defined = &version_defined;
2295 *is_version_defined = FALSE;
2296 if (!is_token_defined)
2297 is_token_defined = &token_defined;
2298 *is_token_defined = FALSE;
2300 parts = tmp = g_strsplit (name, ",", 6);
2301 if (!tmp || !*tmp) {
2306 dllname = g_strstrip (*tmp);
2311 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2312 goto cleanup_and_fail;
2314 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2315 *is_version_defined = TRUE;
2317 if (strlen (version) == 0) {
2318 goto cleanup_and_fail;
2324 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2326 if (strlen (culture) == 0) {
2327 goto cleanup_and_fail;
2333 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2334 *is_token_defined = TRUE;
2336 if (strlen (token) == 0) {
2337 goto cleanup_and_fail;
2343 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2345 if (strlen (key) == 0) {
2346 goto cleanup_and_fail;
2352 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2353 retargetable = value;
2354 retargetable_uq = unquote (retargetable);
2355 if (retargetable_uq != NULL)
2356 retargetable = retargetable_uq;
2358 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2359 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2360 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2361 g_free (retargetable_uq);
2362 goto cleanup_and_fail;
2365 g_free (retargetable_uq);
2370 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2372 procarch_uq = unquote (procarch);
2373 if (procarch_uq != NULL)
2374 procarch = procarch_uq;
2376 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2377 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2378 else if (!g_ascii_strcasecmp (procarch, "X86"))
2379 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2380 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2381 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2382 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2383 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2385 g_free (procarch_uq);
2386 goto cleanup_and_fail;
2389 g_free (procarch_uq);
2398 /* if retargetable flag is set, then we must have a fully qualified name */
2399 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2400 goto cleanup_and_fail;
2403 dllname_uq = unquote (dllname);
2404 version_uq = unquote (version);
2405 culture_uq = unquote (culture);
2406 token_uq = unquote (token);
2407 key_uq = unquote (key);
2409 res = build_assembly_name (
2410 dllname_uq == NULL ? dllname : dllname_uq,
2411 version_uq == NULL ? version : version_uq,
2412 culture_uq == NULL ? culture : culture_uq,
2413 token_uq == NULL ? token : token_uq,
2414 key_uq == NULL ? key : key_uq,
2415 flags, arch, aname, save_public_key);
2417 g_free (dllname_uq);
2418 g_free (version_uq);
2419 g_free (culture_uq);
2432 unquote (const char *str)
2440 slen = strlen (str);
2444 if (*str != '\'' && *str != '\"')
2447 end = str + slen - 1;
2451 return g_strndup (str + 1, slen - 2);
2455 * mono_assembly_name_parse:
2456 * @name: name to parse
2457 * @aname: the destination assembly name
2459 * Parses an assembly qualified type name and assigns the name,
2460 * version, culture and token to the provided assembly name object.
2462 * Returns: TRUE if the name could be parsed.
2465 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2467 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2471 * mono_assembly_name_new:
2472 * @name: name to parse
2474 * Allocate a new MonoAssemblyName and fill its values from the
2477 * Returns: a newly allocated structure or NULL if there was any failure.
2480 mono_assembly_name_new (const char *name)
2482 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2483 if (mono_assembly_name_parse (name, aname))
2490 mono_assembly_name_get_name (MonoAssemblyName *aname)
2496 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2498 return aname->culture;
2502 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2504 if (aname->public_key_token [0])
2505 return aname->public_key_token;
2510 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2513 *minor = aname->minor;
2515 *build = aname->build;
2517 *revision = aname->revision;
2518 return aname->major;
2521 static MonoAssembly*
2522 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2524 gchar *fullpath = NULL;
2526 const char* direntry;
2527 MonoAssemblyName gac_aname;
2528 gint major=-1, minor=0, build=0, revision=0;
2529 gboolean exact_version;
2531 dirhandle = g_dir_open (basepath, 0, NULL);
2535 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2537 while ((direntry = g_dir_read_name (dirhandle))) {
2538 gboolean match = TRUE;
2540 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2543 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2546 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2547 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2551 if (exact_version) {
2552 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2553 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2555 else if (gac_aname.major < major)
2557 else if (gac_aname.major == major) {
2558 if (gac_aname.minor < minor)
2560 else if (gac_aname.minor == minor) {
2561 if (gac_aname.build < build)
2563 else if (gac_aname.build == build && gac_aname.revision <= revision)
2570 major = gac_aname.major;
2571 minor = gac_aname.minor;
2572 build = gac_aname.build;
2573 revision = gac_aname.revision;
2575 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2578 mono_assembly_name_free (&gac_aname);
2581 g_dir_close (dirhandle);
2583 if (fullpath == NULL)
2586 MonoAssembly *res = mono_assembly_open (fullpath, status);
2593 * mono_assembly_load_with_partial_name:
2594 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2595 * @status: return status code
2597 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2598 * so it might contain a qualified type name, version, culture and token.
2600 * This will load the assembly from the file whose name is derived from the assembly name
2601 * by appending the .dll extension.
2603 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2604 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2605 * if that fails from the GAC.
2607 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2610 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2614 MonoAssemblyName *aname, base_name;
2615 MonoAssemblyName mapped_aname;
2616 gchar *fullname, *gacpath;
2619 memset (&base_name, 0, sizeof (MonoAssemblyName));
2622 if (!mono_assembly_name_parse (name, aname))
2626 * If no specific version has been requested, make sure we load the
2627 * correct version for system assemblies.
2629 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2630 aname = mono_assembly_remap_version (aname, &mapped_aname);
2632 res = mono_assembly_loaded (aname);
2634 mono_assembly_name_free (aname);
2638 res = invoke_assembly_preload_hook (aname, assemblies_path);
2640 res->in_gac = FALSE;
2641 mono_assembly_name_free (aname);
2645 fullname = g_strdup_printf ("%s.dll", aname->name);
2647 if (extra_gac_paths) {
2648 paths = extra_gac_paths;
2649 while (!res && *paths) {
2650 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2651 res = probe_for_partial_name (gacpath, fullname, aname, status);
2660 mono_assembly_name_free (aname);
2664 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2665 res = probe_for_partial_name (gacpath, fullname, aname, status);
2671 MonoDomain *domain = mono_domain_get ();
2672 MonoReflectionAssembly *refasm;
2674 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2675 if (!is_ok (&error)) {
2677 mono_assembly_name_free (aname);
2678 mono_error_cleanup (&error);
2679 if (*status == MONO_IMAGE_OK)
2680 *status = MONO_IMAGE_IMAGE_INVALID;
2684 res = refasm->assembly;
2688 mono_assembly_name_free (aname);
2694 mono_assembly_is_in_gac (const gchar *filename)
2696 const gchar *rootdir;
2700 if (filename == NULL)
2703 for (paths = extra_gac_paths; paths && *paths; paths++) {
2704 if (strstr (*paths, filename) != *paths)
2707 gp = (gchar *) (filename + strlen (*paths));
2708 if (*gp != G_DIR_SEPARATOR)
2711 if (strncmp (gp, "lib", 3))
2714 if (*gp != G_DIR_SEPARATOR)
2717 if (strncmp (gp, "mono", 4))
2720 if (*gp != G_DIR_SEPARATOR)
2723 if (strncmp (gp, "gac", 3))
2726 if (*gp != G_DIR_SEPARATOR)
2732 rootdir = mono_assembly_getrootdir ();
2733 if (strstr (filename, rootdir) != filename)
2736 gp = (gchar *) (filename + strlen (rootdir));
2737 if (*gp != G_DIR_SEPARATOR)
2740 if (strncmp (gp, "mono", 4))
2743 if (*gp != G_DIR_SEPARATOR)
2746 if (strncmp (gp, "gac", 3))
2749 if (*gp != G_DIR_SEPARATOR)
2755 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2758 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2762 if (strstr (aname->name, ".dll")) {
2763 len = strlen (aname->name) - 4;
2764 name = (gchar *)g_malloc (len + 1);
2765 strncpy (name, aname->name, len);
2768 name = g_strdup (aname->name);
2771 culture = g_utf8_strdown (aname->culture, -1);
2773 culture = g_strdup ("");
2775 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2776 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2780 filename = g_strconcat (pname, ".dll", NULL);
2781 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2787 if (extra_gac_paths) {
2788 paths = extra_gac_paths;
2789 while (!image && *paths) {
2790 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2791 "lib", "mono", "gac", subpath, NULL);
2792 image = mono_image_open (fullpath, NULL);
2803 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2804 "mono", "gac", subpath, NULL);
2805 image = mono_image_open (fullpath, NULL);
2812 static MonoAssemblyName*
2813 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2815 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2816 dest_name->major = info->new_version.major;
2817 dest_name->minor = info->new_version.minor;
2818 dest_name->build = info->new_version.build;
2819 dest_name->revision = info->new_version.revision;
2824 /* LOCKING: assembly_binding lock must be held */
2825 static MonoAssemblyBindingInfo*
2826 search_binding_loaded (MonoAssemblyName *aname)
2830 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2831 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2832 if (assembly_binding_maps_name (info, aname))
2839 static inline gboolean
2840 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2842 if (left->major != right->major || left->minor != right->minor ||
2843 left->build != right->build || left->revision != right->revision)
2849 static inline gboolean
2850 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2852 if (left->has_old_version_bottom != right->has_old_version_bottom)
2855 if (left->has_old_version_top != right->has_old_version_top)
2858 if (left->has_new_version != right->has_new_version)
2861 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2864 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2867 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2873 /* LOCKING: assumes all the necessary locks are held */
2875 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2877 MonoAssemblyBindingInfo *info_copy;
2879 MonoAssemblyBindingInfo *info_tmp;
2880 MonoDomain *domain = (MonoDomain*)user_data;
2885 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2886 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2887 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2891 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2892 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2894 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2896 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2898 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2902 get_version_number (int major, int minor)
2904 return major * 256 + minor;
2907 static inline gboolean
2908 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2910 int aname_version_number = get_version_number (aname->major, aname->minor);
2911 if (!info->has_old_version_bottom)
2914 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2917 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2920 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2921 info->major = aname->major;
2922 info->minor = aname->minor;
2927 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2928 static MonoAssemblyBindingInfo*
2929 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2931 MonoAssemblyBindingInfo *info;
2934 if (!domain->assembly_bindings)
2938 for (list = domain->assembly_bindings; list; list = list->next) {
2939 info = (MonoAssemblyBindingInfo *)list->data;
2940 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2946 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2947 info->has_new_version && assembly_binding_maps_name (info, aname))
2948 info->is_valid = TRUE;
2950 info->is_valid = FALSE;
2956 static MonoAssemblyName*
2957 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2960 MonoAssemblyBindingInfo *info, *info2;
2964 if (aname->public_key_token [0] == 0)
2967 domain = mono_domain_get ();
2969 mono_assembly_binding_lock ();
2970 info = search_binding_loaded (aname);
2971 mono_assembly_binding_unlock ();
2974 mono_domain_lock (domain);
2975 info = get_per_domain_assembly_binding_info (domain, aname);
2976 mono_domain_unlock (domain);
2980 if (!check_policy_versions (info, aname))
2983 mono_assembly_bind_version (info, aname, dest_name);
2987 if (domain && domain->setup && domain->setup->configuration_file) {
2988 mono_domain_lock (domain);
2989 if (!domain->assembly_bindings_parsed) {
2990 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2991 /* expect this to succeed because mono_domain_set_options_from_config () did
2992 * the same thing when the domain was created. */
2993 mono_error_assert_ok (&error);
2995 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2997 if (!domain_config_file_path)
2998 domain_config_file_path = domain_config_file_name;
3000 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3001 domain->assembly_bindings_parsed = TRUE;
3002 if (domain_config_file_name != domain_config_file_path)
3003 g_free (domain_config_file_name);
3004 g_free (domain_config_file_path);
3007 info2 = get_per_domain_assembly_binding_info (domain, aname);
3010 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3011 info->name = g_strdup (info2->name);
3012 info->culture = g_strdup (info2->culture);
3013 info->domain_id = domain->domain_id;
3016 mono_domain_unlock (domain);
3020 info = g_new0 (MonoAssemblyBindingInfo, 1);
3021 info->major = aname->major;
3022 info->minor = aname->minor;
3025 if (!info->is_valid) {
3026 ppimage = mono_assembly_load_publisher_policy (aname);
3028 get_publisher_policy_info (ppimage, aname, info);
3029 mono_image_close (ppimage);
3033 /* Define default error value if needed */
3034 if (!info->is_valid) {
3035 info->name = g_strdup (aname->name);
3036 info->culture = g_strdup (aname->culture);
3037 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3040 mono_assembly_binding_lock ();
3041 info2 = search_binding_loaded (aname);
3043 /* This binding was added by another thread
3045 mono_assembly_binding_info_free (info);
3050 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3052 mono_assembly_binding_unlock ();
3054 if (!info->is_valid || !check_policy_versions (info, aname))
3057 mono_assembly_bind_version (info, aname, dest_name);
3062 * mono_assembly_load_from_gac
3064 * @aname: The assembly name object
3066 static MonoAssembly*
3067 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3069 MonoAssembly *result = NULL;
3070 gchar *name, *version, *culture, *fullpath, *subpath;
3075 if (aname->public_key_token [0] == 0) {
3079 if (strstr (aname->name, ".dll")) {
3080 len = strlen (filename) - 4;
3081 name = (gchar *)g_malloc (len + 1);
3082 strncpy (name, aname->name, len);
3085 name = g_strdup (aname->name);
3088 if (aname->culture) {
3089 culture = g_utf8_strdown (aname->culture, -1);
3091 culture = g_strdup ("");
3094 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3095 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3096 aname->minor, aname->build, aname->revision,
3100 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3105 if (extra_gac_paths) {
3106 paths = extra_gac_paths;
3107 while (!result && *paths) {
3108 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3109 result = mono_assembly_open_full (fullpath, status, refonly);
3116 result->in_gac = TRUE;
3121 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3122 "mono", "gac", subpath, NULL);
3123 result = mono_assembly_open_full (fullpath, status, refonly);
3127 result->in_gac = TRUE;
3135 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3138 MonoAssemblyName *aname;
3141 /* g_print ("corlib already loaded\n"); */
3145 // In native client, Corlib is embedded in the executable as static variable corlibData
3146 #if defined(__native_client__)
3147 if (corlibData != NULL && corlibSize != 0) {
3149 /* First "FALSE" instructs mono not to make a copy. */
3150 /* Second "FALSE" says this is not just a ref. */
3151 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3152 if (image == NULL || status != 0)
3153 g_print("mono_image_open_from_data_full failed: %d\n", status);
3154 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3155 if (corlib == NULL || status != 0)
3156 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3162 // A nonstandard preload hook may provide a special mscorlib assembly
3163 aname = mono_assembly_name_new ("mscorlib.dll");
3164 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3165 mono_assembly_name_free (aname);
3168 goto return_corlib_and_facades;
3170 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3171 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3172 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3174 goto return_corlib_and_facades;
3177 /* Normal case: Load corlib from mono/<version> */
3178 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3179 if (assemblies_path) { // Custom assemblies path
3180 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3182 g_free (corlib_file);
3183 goto return_corlib_and_facades;
3186 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3187 g_free (corlib_file);
3189 return_corlib_and_facades:
3190 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3191 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3197 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3198 const char *basedir,
3199 MonoImageOpenStatus *status,
3202 MonoAssembly *result;
3203 char *fullpath, *filename;
3204 MonoAssemblyName maped_aname;
3205 MonoAssemblyName maped_name_pp;
3210 aname = mono_assembly_remap_version (aname, &maped_aname);
3212 /* Reflection only assemblies don't get assembly binding */
3214 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3216 result = mono_assembly_loaded_full (aname, refonly);
3220 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3222 result->in_gac = FALSE;
3226 /* Currently we retrieve the loaded corlib for reflection
3227 * only requests, like a common reflection only assembly
3229 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3230 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3233 len = strlen (aname->name);
3234 for (ext_index = 0; ext_index < 2; ext_index ++) {
3235 ext = ext_index == 0 ? ".dll" : ".exe";
3236 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3237 filename = g_strdup (aname->name);
3238 /* Don't try appending .dll/.exe if it already has one of those extensions */
3241 filename = g_strconcat (aname->name, ext, NULL);
3244 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3251 fullpath = g_build_filename (basedir, filename, NULL);
3252 result = mono_assembly_open_full (fullpath, status, refonly);
3255 result->in_gac = FALSE;
3261 result = load_in_path (filename, default_path, status, refonly);
3263 result->in_gac = FALSE;
3273 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3275 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3278 /* Try a postload search hook */
3279 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3284 * mono_assembly_load_full:
3285 * @aname: A MonoAssemblyName with the assembly name to load.
3286 * @basedir: A directory to look up the assembly at.
3287 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3288 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3290 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3291 * attempts to load the assembly from that directory before probing the standard locations.
3293 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3294 * assembly binding takes place.
3296 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3297 * value pointed by status is updated with an error code.
3300 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3302 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3306 * mono_assembly_load:
3307 * @aname: A MonoAssemblyName with the assembly name to load.
3308 * @basedir: A directory to look up the assembly at.
3309 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3311 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3312 * attempts to load the assembly from that directory before probing the standard locations.
3314 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3315 * value pointed by status is updated with an error code.
3318 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3320 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3324 * mono_assembly_loaded_full:
3325 * @aname: an assembly to look for.
3326 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3328 * This is used to determine if the specified assembly has been loaded
3329 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3330 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3333 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3336 MonoAssemblyName maped_aname;
3338 aname = mono_assembly_remap_version (aname, &maped_aname);
3340 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3346 * mono_assembly_loaded:
3347 * @aname: an assembly to look for.
3349 * This is used to determine if the specified assembly has been loaded
3351 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3352 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3355 mono_assembly_loaded (MonoAssemblyName *aname)
3357 return mono_assembly_loaded_full (aname, FALSE);
3361 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3363 if (assembly == NULL || assembly == REFERENCE_MISSING)
3366 if (assembly_is_dynamic (assembly)) {
3368 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3369 for (i = 0; i < dynimg->image.module_count; ++i)
3370 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3371 mono_dynamic_image_release_gc_roots (dynimg);
3376 * Returns whether mono_assembly_close_finish() must be called as
3377 * well. See comment for mono_image_close_except_pools() for why we
3378 * unload in two steps.
3381 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3384 g_return_val_if_fail (assembly != NULL, FALSE);
3386 if (assembly == REFERENCE_MISSING)
3389 /* Might be 0 already */
3390 if (InterlockedDecrement (&assembly->ref_count) > 0)
3393 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3395 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3397 mono_debug_close_image (assembly->image);
3399 mono_assemblies_lock ();
3400 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3401 mono_assemblies_unlock ();
3403 assembly->image->assembly = NULL;
3405 if (!mono_image_close_except_pools (assembly->image))
3406 assembly->image = NULL;
3408 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3409 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3410 mono_assembly_name_free (fname);
3413 g_slist_free (assembly->friend_assembly_names);
3414 g_free (assembly->basedir);
3416 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3422 mono_assembly_close_finish (MonoAssembly *assembly)
3424 g_assert (assembly && assembly != REFERENCE_MISSING);
3426 if (assembly->image)
3427 mono_image_close_finish (assembly->image);
3429 if (assembly_is_dynamic (assembly)) {
3430 g_free ((char*)assembly->aname.culture);
3437 * mono_assembly_close:
3438 * @assembly: the assembly to release.
3440 * This method releases a reference to the @assembly. The assembly is
3441 * only released when all the outstanding references to it are released.
3444 mono_assembly_close (MonoAssembly *assembly)
3446 if (mono_assembly_close_except_image_pools (assembly))
3447 mono_assembly_close_finish (assembly);
3451 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3454 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3455 mono_error_assert_ok (&error);
3460 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3462 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3467 * mono_assembly_foreach:
3468 * @func: function to invoke for each assembly loaded
3469 * @user_data: data passed to the callback
3471 * Invokes the provided @func callback for each assembly loaded into
3472 * the runtime. The first parameter passed to the callback is the
3473 * `MonoAssembly*`, and the second parameter is the @user_data.
3475 * This is done for all assemblies loaded in the runtime, not just
3476 * those loaded in the current application domain.
3479 mono_assembly_foreach (GFunc func, gpointer user_data)
3484 * We make a copy of the list to avoid calling the callback inside the
3485 * lock, which could lead to deadlocks.
3487 mono_assemblies_lock ();
3488 copy = g_list_copy (loaded_assemblies);
3489 mono_assemblies_unlock ();
3491 g_list_foreach (loaded_assemblies, func, user_data);
3497 * mono_assemblies_cleanup:
3499 * Free all resources used by this module.
3502 mono_assemblies_cleanup (void)
3506 mono_os_mutex_destroy (&assemblies_mutex);
3507 mono_os_mutex_destroy (&assembly_binding_mutex);
3509 for (l = loaded_assembly_bindings; l; l = l->next) {
3510 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3512 mono_assembly_binding_info_free (info);
3515 g_slist_free (loaded_assembly_bindings);
3517 free_assembly_load_hooks ();
3518 free_assembly_search_hooks ();
3519 free_assembly_preload_hooks ();
3522 /*LOCKING takes the assembly_binding lock*/
3524 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3528 mono_assembly_binding_lock ();
3529 iter = &loaded_assembly_bindings;
3532 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3534 if (info->domain_id == domain_id) {
3536 mono_assembly_binding_info_free (info);
3543 mono_assembly_binding_unlock ();
3547 * Holds the assembly of the application, for
3548 * System.Diagnostics.Process::MainModule
3550 static MonoAssembly *main_assembly=NULL;
3553 mono_assembly_set_main (MonoAssembly *assembly)
3555 main_assembly = assembly;
3559 * mono_assembly_get_main:
3561 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3564 mono_assembly_get_main (void)
3566 return (main_assembly);
3570 * mono_assembly_get_image:
3571 * @assembly: The assembly to retrieve the image from
3573 * Returns: the MonoImage associated with this assembly.
3576 mono_assembly_get_image (MonoAssembly *assembly)
3578 return assembly->image;
3582 * mono_assembly_get_name:
3583 * @assembly: The assembly to retrieve the name from
3585 * The returned name's lifetime is the same as @assembly's.
3587 * Returns: the MonoAssemblyName associated with this assembly.
3590 mono_assembly_get_name (MonoAssembly *assembly)
3592 return &assembly->aname;
3596 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3598 bundles = assemblies;
3601 #define MONO_DECLSEC_FORMAT_10 0x3C
3602 #define MONO_DECLSEC_FORMAT_20 0x2E
3603 #define MONO_DECLSEC_FIELD 0x53
3604 #define MONO_DECLSEC_PROPERTY 0x54
3606 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3607 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3608 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3609 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3610 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3613 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3617 case MONO_DECLSEC_PROPERTY:
3619 case MONO_DECLSEC_FIELD:
3621 *abort_decoding = TRUE;
3626 if (*p++ != MONO_TYPE_BOOLEAN) {
3627 *abort_decoding = TRUE;
3631 /* property name length */
3632 len = mono_metadata_decode_value (p, &p);
3634 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3645 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3647 int i, j, num, len, params_len;
3649 if (*p == MONO_DECLSEC_FORMAT_10) {
3650 gsize read, written;
3651 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3653 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3659 if (*p++ != MONO_DECLSEC_FORMAT_20)
3662 /* number of encoded permission attributes */
3663 num = mono_metadata_decode_value (p, &p);
3664 for (i = 0; i < num; ++i) {
3665 gboolean is_valid = FALSE;
3666 gboolean abort_decoding = FALSE;
3668 /* attribute name length */
3669 len = mono_metadata_decode_value (p, &p);
3671 /* We don't really need to fully decode the type. Comparing the name is enough */
3672 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3676 /*size of the params table*/
3677 params_len = mono_metadata_decode_value (p, &p);
3679 const char *params_end = p + params_len;
3681 /* number of parameters */
3682 len = mono_metadata_decode_value (p, &p);
3684 for (j = 0; j < len; ++j) {
3685 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3701 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3704 guint32 cols [MONO_DECL_SECURITY_SIZE];
3708 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3709 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3711 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3713 for (i = 0; i < t->rows; ++i) {
3714 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3715 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3717 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3720 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3721 len = mono_metadata_decode_blob_size (blob, &blob);
3725 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3726 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3731 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);