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];
564 * @assembly_dir: the base directory for assemblies
565 * @config_dir: the base directory for configuration files
567 * This routine is used internally and by developers embedding
568 * the runtime into their own applications.
570 * There are a number of cases to consider: Mono as a system-installed
571 * package that is available on the location preconfigured or Mono in
572 * a relocated location.
574 * If you are using a system-installed Mono, you can pass NULL
575 * to both parameters. If you are not, you should compute both
576 * directory values and call this routine.
578 * The values for a given PREFIX are:
580 * assembly_dir: PREFIX/lib
581 * config_dir: PREFIX/etc
583 * Notice that embedders that use Mono in a relocated way must
584 * compute the location at runtime, as they will be in control
585 * of where Mono is installed.
588 mono_set_dirs (const char *assembly_dir, const char *config_dir)
590 if (assembly_dir == NULL)
591 assembly_dir = mono_config_get_assemblies_dir ();
592 if (config_dir == NULL)
593 config_dir = mono_config_get_cfg_dir ();
594 mono_assembly_setrootdir (assembly_dir);
595 mono_set_config_dir (config_dir);
601 compute_base (char *path)
603 char *p = strrchr (path, '/');
607 /* Not a well known Mono executable, we are embedded, cant guess the base */
608 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
612 p = strrchr (path, '/');
616 if (strcmp (p, "/bin") != 0)
625 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
628 static G_GNUC_UNUSED void
632 char *config, *lib, *mono;
637 * Only /usr prefix is treated specially
639 bindir = mono_config_get_bin_dir ();
641 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
646 config = g_build_filename (base, "etc", NULL);
647 lib = g_build_filename (base, "lib", NULL);
648 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
649 if (stat (mono, &buf) == -1)
652 mono_set_dirs (lib, config);
660 #endif /* HOST_WIN32 */
665 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
666 * this auto-detects the prefix where Mono was installed.
669 mono_set_rootdir (void)
671 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
672 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
675 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
679 * _NSGetExecutablePath may return -1 to indicate buf is not large
680 * enough, but we ignore that case to avoid having to do extra dynamic
681 * allocation for the path and hope that 4096 is enough - this is
682 * ok in the Linux/Solaris case below at least...
686 guint buf_size = sizeof (buf);
689 if (_NSGetExecutablePath (buf, &buf_size) == 0)
690 name = g_strdup (buf);
699 resolvedname = mono_path_resolve_symlinks (name);
701 bindir = g_path_get_dirname (resolvedname);
702 installdir = g_path_get_dirname (bindir);
703 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
705 config = g_build_filename (root, "..", "etc", NULL);
707 mono_set_dirs (root, config);
709 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
710 mono_set_dirs (root, config);
720 g_free (resolvedname);
721 #elif defined(DISABLE_MONO_AUTODETECTION)
729 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
737 /* Solaris 10 style */
738 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
739 s = readlink (str, buf, sizeof (buf)-1);
751 * mono_assemblies_init:
753 * Initialize global variables used by this module.
756 mono_assemblies_init (void)
759 * Initialize our internal paths if we have not been initialized yet.
760 * This happens when embedders use Mono.
762 if (mono_assembly_getrootdir () == NULL)
766 check_extra_gac_path_env ();
768 mono_os_mutex_init_recursive (&assemblies_mutex);
769 mono_os_mutex_init (&assembly_binding_mutex);
773 mono_assembly_binding_lock (void)
775 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
779 mono_assembly_binding_unlock (void)
781 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
785 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
787 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
788 guint32 cols [MONO_ASSEMBLY_SIZE];
789 gint32 machine, flags;
794 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
797 aname->hash_value = NULL;
798 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
799 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
800 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
801 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
802 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
803 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
804 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
805 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
806 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
807 guchar* token = (guchar *)g_malloc (8);
812 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
813 len = mono_metadata_decode_blob_size (pkey, &pkey);
814 aname->public_key = (guchar*)pkey;
816 mono_digest_get_public_token (token, aname->public_key, len);
817 encoded = encode_public_tok (token, 8);
818 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
824 aname->public_key = NULL;
825 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
828 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
829 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
832 aname->public_key = 0;
834 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
835 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
837 case COFF_MACHINE_I386:
838 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
839 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
840 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
841 else if ((flags & 0x70) == 0x70)
842 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
844 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
846 case COFF_MACHINE_IA64:
847 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
849 case COFF_MACHINE_AMD64:
850 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
852 case COFF_MACHINE_ARM:
853 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
863 * mono_stringify_assembly_name:
864 * @aname: the assembly name.
866 * Convert @aname into its string format. The returned string is dynamically
867 * allocated and should be freed by the caller.
869 * Returns: a newly allocated string with a string representation of
873 mono_stringify_assembly_name (MonoAssemblyName *aname)
875 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
877 return g_strdup_printf (
878 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
879 quote, aname->name, quote,
880 aname->major, aname->minor, aname->build, aname->revision,
881 aname->culture && *aname->culture? aname->culture: "neutral",
882 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
883 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
887 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
889 const gchar *public_tok;
892 public_tok = mono_metadata_blob_heap (image, key_index);
893 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
895 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
897 mono_digest_get_public_token (token, (guchar*)public_tok, len);
898 return encode_public_tok (token, 8);
901 return encode_public_tok ((guchar*)public_tok, len);
905 * mono_assembly_addref:
906 * @assemnly: the assembly to reference
908 * This routine increments the reference count on a MonoAssembly.
909 * The reference count is reduced every time the method mono_assembly_close() is
913 mono_assembly_addref (MonoAssembly *assembly)
915 InterlockedIncrement (&assembly->ref_count);
919 * CAUTION: This table must be kept in sync with
920 * ivkm/reflect/Fusion.cs
923 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
924 #define WINFX_KEY "31bf3856ad364e35"
925 #define ECMA_KEY "b77a5c561934e089"
926 #define MSFINAL_KEY "b03f5f7f11d50a3a"
927 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
935 static KeyRemapEntry key_remap_table[] = {
936 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
937 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
938 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
939 { "System", SILVERLIGHT_KEY, ECMA_KEY },
940 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
941 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
942 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
943 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
944 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
945 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
946 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
947 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
948 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
949 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
950 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
951 { "System.Numerics", WINFX_KEY, ECMA_KEY },
952 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
953 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
954 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
955 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
956 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
957 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
958 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
959 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
960 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
961 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
962 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
963 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
964 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
968 remap_keys (MonoAssemblyName *aname)
971 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
972 const KeyRemapEntry *entry = &key_remap_table [i];
974 if (strcmp (aname->name, entry->name) ||
975 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
978 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
980 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
981 "Remapped public key token of retargetable assembly %s from %s to %s",
982 aname->name, entry->from, entry->to);
987 static MonoAssemblyName *
988 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
990 const MonoRuntimeInfo *current_runtime;
991 int pos, first, last;
993 if (aname->name == NULL) return aname;
995 current_runtime = mono_get_runtime_info ();
997 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
998 const AssemblyVersionSet* vset;
1000 /* Remap to current runtime */
1001 vset = ¤t_runtime->version_sets [0];
1003 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1004 dest_aname->major = vset->major;
1005 dest_aname->minor = vset->minor;
1006 dest_aname->build = vset->build;
1007 dest_aname->revision = vset->revision;
1008 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1010 /* Remap assembly name */
1011 if (!strcmp (aname->name, "System.Net"))
1012 dest_aname->name = g_strdup ("System");
1014 remap_keys (dest_aname);
1016 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1017 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1019 aname->major, aname->minor, aname->build, aname->revision,
1021 vset->major, vset->minor, vset->build, vset->revision
1027 #ifndef DISABLE_ASSEMBLY_REMAPPING
1029 last = G_N_ELEMENTS (framework_assemblies) - 1;
1031 while (first <= last) {
1033 pos = first + (last - first) / 2;
1034 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1036 const AssemblyVersionSet* vset;
1037 int index = framework_assemblies[pos].version_set_index;
1038 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1039 vset = ¤t_runtime->version_sets [index];
1041 if (aname->major == vset->major && aname->minor == vset->minor &&
1042 aname->build == vset->build && aname->revision == vset->revision)
1045 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1048 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1049 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1050 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1052 aname->major, aname->minor, aname->build, aname->revision,
1053 vset->major, vset->minor, vset->build, vset->revision
1056 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1057 dest_aname->major = vset->major;
1058 dest_aname->minor = vset->minor;
1059 dest_aname->build = vset->build;
1060 dest_aname->revision = vset->revision;
1061 if (framework_assemblies[pos].new_assembly_name != NULL) {
1062 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1063 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1064 "The assembly name %s was remapped to %s",
1069 } else if (res < 0) {
1081 * mono_assembly_get_assemblyref:
1082 * @image: pointer to the MonoImage to extract the information from.
1083 * @index: index to the assembly reference in the image.
1084 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1086 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1089 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1092 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1095 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1097 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1099 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1100 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1101 aname->hash_value = hash;
1102 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1103 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1104 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1105 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1106 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1107 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1108 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1110 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1111 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1112 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1115 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1120 mono_assembly_load_reference (MonoImage *image, int index)
1122 MonoAssembly *reference;
1123 MonoAssemblyName aname;
1124 MonoImageOpenStatus status;
1127 * image->references is shared between threads, so we need to access
1128 * it inside a critical section.
1130 mono_assemblies_lock ();
1131 if (!image->references) {
1132 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1134 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1135 image->nreferences = t->rows;
1137 reference = image->references [index];
1138 mono_assemblies_unlock ();
1142 mono_assembly_get_assemblyref (image, index, &aname);
1144 if (image->assembly && image->assembly->ref_only) {
1145 /* We use the loaded corlib */
1146 if (!strcmp (aname.name, "mscorlib"))
1147 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1149 reference = mono_assembly_loaded_full (&aname, TRUE);
1151 /* Try a postload search hook */
1152 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1156 * Here we must advice that the error was due to
1157 * a non loaded reference using the ReflectionOnly api
1160 reference = (MonoAssembly *)REFERENCE_MISSING;
1162 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1163 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1164 * accordingly, it would fail on the MS runtime before).
1165 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1166 * example bug-349190.2.cs and who knows how much more code in the wild.
1168 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1169 if (!reference && image->assembly)
1170 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1173 if (reference == NULL){
1176 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1177 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 : "" );
1178 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1179 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1180 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1181 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1182 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1183 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1185 extra_msg = g_strdup ("");
1188 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1189 " Assembly: %s (assemblyref_index=%d)\n"
1190 " Version: %d.%d.%d.%d\n"
1191 " Public Key: %s\n%s",
1192 image->name, aname.name, index,
1193 aname.major, aname.minor, aname.build, aname.revision,
1194 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1197 } else if (!image->assembly->ref_only) {
1199 if (mono_assembly_get_reference_assembly_attribute (reference, &error)) {
1200 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following reference assembly assembly referenced from %s was not loaded. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context:\n"
1201 " Assembly: %s (assemblyref_index=%d)\n"
1202 " Version: %d.%d.%d.%d\n"
1203 " Public Key: %s\n",
1204 image->name, aname.name, index,
1205 aname.major, aname.minor, aname.build, aname.revision,
1206 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token);
1207 reference = NULL; /* don't load reference assemblies for execution */
1209 if (!is_ok (&error)) {
1211 mono_error_cleanup (&error);
1215 mono_assemblies_lock ();
1216 if (reference == NULL) {
1217 /* Flag as not found */
1218 reference = (MonoAssembly *)REFERENCE_MISSING;
1221 if (!image->references [index]) {
1222 if (reference != REFERENCE_MISSING){
1223 mono_assembly_addref (reference);
1224 if (image->assembly)
1225 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1226 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1228 if (image->assembly)
1229 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1230 image->assembly->aname.name, image->assembly);
1233 image->references [index] = reference;
1235 mono_assemblies_unlock ();
1237 if (image->references [index] != reference) {
1238 /* Somebody loaded it before us */
1239 mono_assembly_close (reference);
1244 * mono_assembly_load_references:
1247 * @deprecated: There is no reason to use this method anymore, it does nothing
1249 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1252 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1254 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1255 *status = MONO_IMAGE_OK;
1258 typedef struct AssemblyLoadHook AssemblyLoadHook;
1259 struct AssemblyLoadHook {
1260 AssemblyLoadHook *next;
1261 MonoAssemblyLoadFunc func;
1265 AssemblyLoadHook *assembly_load_hook = NULL;
1268 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1270 AssemblyLoadHook *hook;
1272 for (hook = assembly_load_hook; hook; hook = hook->next) {
1273 hook->func (ass, hook->user_data);
1278 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1280 AssemblyLoadHook *hook;
1282 g_return_if_fail (func != NULL);
1284 hook = g_new0 (AssemblyLoadHook, 1);
1286 hook->user_data = user_data;
1287 hook->next = assembly_load_hook;
1288 assembly_load_hook = hook;
1292 free_assembly_load_hooks (void)
1294 AssemblyLoadHook *hook, *next;
1296 for (hook = assembly_load_hook; hook; hook = next) {
1302 typedef struct AssemblySearchHook AssemblySearchHook;
1303 struct AssemblySearchHook {
1304 AssemblySearchHook *next;
1305 MonoAssemblySearchFunc func;
1311 AssemblySearchHook *assembly_search_hook = NULL;
1313 static MonoAssembly*
1314 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1316 AssemblySearchHook *hook;
1318 for (hook = assembly_search_hook; hook; hook = hook->next) {
1319 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1322 * A little explanation is in order here.
1324 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1325 * The embedding API exposes a search hook that doesn't take such argument.
1327 * The original fix would call the default search hook before all the registered ones and pass
1328 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1329 * rely on. Which is the ordering between user hooks and the default runtime hook.
1331 * Registering the hook after mono_jit_init would let your hook run before the default one and
1332 * when using it to handle non standard app layouts this could save your app from a massive amount
1333 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1334 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1336 * So what's the fix? We register the default hook using regular means and special case it when iterating
1337 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1340 if (hook->func == (void*)mono_domain_assembly_postload_search)
1341 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1343 ass = hook->func (aname, hook->user_data);
1353 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1355 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1359 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1361 AssemblySearchHook *hook;
1363 g_return_if_fail (func != NULL);
1365 hook = g_new0 (AssemblySearchHook, 1);
1367 hook->user_data = user_data;
1368 hook->refonly = refonly;
1369 hook->postload = postload;
1370 hook->next = assembly_search_hook;
1371 assembly_search_hook = hook;
1375 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1377 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1381 free_assembly_search_hooks (void)
1383 AssemblySearchHook *hook, *next;
1385 for (hook = assembly_search_hook; hook; hook = next) {
1392 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1394 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1398 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1400 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1404 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1406 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1409 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1410 struct AssemblyPreLoadHook {
1411 AssemblyPreLoadHook *next;
1412 MonoAssemblyPreLoadFunc func;
1416 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1417 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1419 static MonoAssembly *
1420 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1422 AssemblyPreLoadHook *hook;
1423 MonoAssembly *assembly;
1425 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1426 assembly = hook->func (aname, assemblies_path, hook->user_data);
1427 if (assembly != NULL)
1434 static MonoAssembly *
1435 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1437 AssemblyPreLoadHook *hook;
1438 MonoAssembly *assembly;
1440 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1441 assembly = hook->func (aname, assemblies_path, hook->user_data);
1442 if (assembly != NULL)
1450 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1452 AssemblyPreLoadHook *hook;
1454 g_return_if_fail (func != NULL);
1456 hook = g_new0 (AssemblyPreLoadHook, 1);
1458 hook->user_data = user_data;
1459 hook->next = assembly_preload_hook;
1460 assembly_preload_hook = hook;
1464 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1466 AssemblyPreLoadHook *hook;
1468 g_return_if_fail (func != NULL);
1470 hook = g_new0 (AssemblyPreLoadHook, 1);
1472 hook->user_data = user_data;
1473 hook->next = assembly_refonly_preload_hook;
1474 assembly_refonly_preload_hook = hook;
1478 free_assembly_preload_hooks (void)
1480 AssemblyPreLoadHook *hook, *next;
1482 for (hook = assembly_preload_hook; hook; hook = next) {
1487 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1494 absolute_dir (const gchar *filename)
1505 if (g_path_is_absolute (filename)) {
1506 part = g_path_get_dirname (filename);
1507 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1512 cwd = g_get_current_dir ();
1513 mixed = g_build_filename (cwd, filename, NULL);
1514 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1519 for (i = 0; (part = parts [i]) != NULL; i++) {
1520 if (!strcmp (part, "."))
1523 if (!strcmp (part, "..")) {
1524 if (list && list->next) /* Don't remove root */
1525 list = g_list_delete_link (list, list);
1527 list = g_list_prepend (list, part);
1531 result = g_string_new ("");
1532 list = g_list_reverse (list);
1534 /* Ignores last data pointer, which should be the filename */
1535 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1537 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1542 g_string_free (result, FALSE);
1547 return g_strdup (".");
1554 * mono_assembly_open_from_bundle:
1555 * @filename: Filename requested
1556 * @status: return status code
1558 * This routine tries to open the assembly specified by `filename' from the
1559 * defined bundles, if found, returns the MonoImage for it, if not found
1563 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1567 MonoImage *image = NULL;
1570 * we do a very simple search for bundled assemblies: it's not a general
1571 * purpose assembly loading mechanism.
1577 name = g_path_get_basename (filename);
1579 mono_assemblies_lock ();
1580 for (i = 0; !image && bundles [i]; ++i) {
1581 if (strcmp (bundles [i]->name, name) == 0) {
1582 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1586 mono_assemblies_unlock ();
1588 mono_image_addref (image);
1589 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
1598 * mono_assemblies_open_full:
1599 * @filename: the file to load
1600 * @status: return status code
1601 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1603 * This loads an assembly from the specified @filename. The @filename allows
1604 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1605 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1606 * is treated as a local path.
1608 * First, an attempt is made to load the assembly from the bundled executable (for those
1609 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1610 * assembly has been registered as an embedded assembly). If this is not the case, then
1611 * the assembly is loaded from disk using `api:mono_image_open_full`.
1613 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1614 * the assembly is made.
1616 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1617 * the `System.Reflection` API.
1619 * Returns: NULL on error, with the @status set to an error code, or a pointer
1623 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1627 MonoImageOpenStatus def_status;
1630 gboolean loaded_from_bundle;
1632 g_return_val_if_fail (filename != NULL, NULL);
1635 status = &def_status;
1636 *status = MONO_IMAGE_OK;
1638 if (strncmp (filename, "file://", 7) == 0) {
1639 GError *error = NULL;
1640 gchar *uri = (gchar *) filename;
1644 * MS allows file://c:/... and fails on file://localhost/c:/...
1645 * They also throw an IndexOutOfRangeException if "file://"
1648 uri = g_strdup_printf ("file:///%s", uri + 7);
1651 uri = mono_escape_uri_string (tmpuri);
1652 fname = g_filename_from_uri (uri, NULL, &error);
1655 if (tmpuri != filename)
1658 if (error != NULL) {
1659 g_warning ("%s\n", error->message);
1660 g_error_free (error);
1661 fname = g_strdup (filename);
1664 fname = g_strdup (filename);
1667 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1668 "Assembly Loader probing location: '%s'.", fname);
1671 if (!mono_assembly_is_in_gac (fname)) {
1673 new_fname = mono_make_shadow_copy (fname, &error);
1674 if (!is_ok (&error)) {
1675 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1676 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1677 mono_error_cleanup (&error);
1678 *status = MONO_IMAGE_IMAGE_INVALID;
1683 if (new_fname && new_fname != fname) {
1686 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1687 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1692 // If VM built with mkbundle
1693 loaded_from_bundle = FALSE;
1694 if (bundles != NULL) {
1695 image = mono_assembly_open_from_bundle (fname, status, refonly);
1696 loaded_from_bundle = image != NULL;
1700 image = mono_image_open_full (fname, status, refonly);
1703 if (*status == MONO_IMAGE_OK)
1704 *status = MONO_IMAGE_ERROR_ERRNO;
1709 if (image->assembly) {
1710 /* Already loaded by another appdomain */
1711 mono_assembly_invoke_load_hook (image->assembly);
1712 mono_image_close (image);
1714 return image->assembly;
1717 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1720 if (!loaded_from_bundle)
1721 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1722 "Assembly Loader loaded assembly from location: '%s'.", filename);
1724 mono_config_for_assembly (ass->image);
1727 /* Clear the reference added by mono_image_open */
1728 mono_image_close (image);
1736 free_item (gpointer val, gpointer user_data)
1742 * mono_assembly_load_friends:
1745 * Load the list of friend assemblies that are allowed to access
1746 * the assembly's internal types and members. They are stored as assembly
1747 * names in custom attributes.
1749 * This is an internal method, we need this because when we load mscorlib
1750 * we do not have the internals visible cattr loaded yet,
1751 * so we need to load these after we initialize the runtime.
1753 * LOCKING: Acquires the assemblies lock plus the loader lock.
1756 mono_assembly_load_friends (MonoAssembly* ass)
1760 MonoCustomAttrInfo* attrs;
1763 if (ass->friend_assembly_names_inited)
1766 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1767 mono_error_assert_ok (&error);
1769 mono_assemblies_lock ();
1770 ass->friend_assembly_names_inited = TRUE;
1771 mono_assemblies_unlock ();
1775 mono_assemblies_lock ();
1776 if (ass->friend_assembly_names_inited) {
1777 mono_assemblies_unlock ();
1780 mono_assemblies_unlock ();
1784 * We build the list outside the assemblies lock, the worse that can happen
1785 * is that we'll need to free the allocated list.
1787 for (i = 0; i < attrs->num_attrs; ++i) {
1788 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1789 MonoAssemblyName *aname;
1791 /* Do some sanity checking */
1792 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1794 if (attr->data_size < 4)
1796 data = (const char*)attr->data;
1797 /* 0xFF means null string, see custom attr format */
1798 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1800 mono_metadata_decode_value (data + 2, &data);
1801 aname = g_new0 (MonoAssemblyName, 1);
1802 /*g_print ("friend ass: %s\n", data);*/
1803 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1804 list = g_slist_prepend (list, aname);
1809 mono_custom_attrs_free (attrs);
1811 mono_assemblies_lock ();
1812 if (ass->friend_assembly_names_inited) {
1813 mono_assemblies_unlock ();
1814 g_slist_foreach (list, free_item, NULL);
1815 g_slist_free (list);
1818 ass->friend_assembly_names = list;
1820 /* Because of the double checked locking pattern above */
1821 mono_memory_barrier ();
1822 ass->friend_assembly_names_inited = TRUE;
1823 mono_assemblies_unlock ();
1828 * mono_assembly_get_reference_assembly_attribute:
1829 * @assembly: a MonoAssembly
1830 * @error: set on error.
1832 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1833 * On error returns FALSE and sets @error.
1836 mono_assembly_get_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1838 mono_error_init (error);
1840 MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
1841 return_val_if_nok (error, FALSE);
1844 MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
1845 gboolean result = FALSE;
1846 for (int i = 0; i < attrs->num_attrs; ++i) {
1847 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1848 if (attr->ctor && attr->ctor->klass && attr->ctor->klass == ref_asm_class) {
1853 mono_custom_attrs_free (attrs);
1858 * mono_assembly_open:
1859 * @filename: Opens the assembly pointed out by this name
1860 * @status: return status code
1862 * This loads an assembly from the specified @filename. The @filename allows
1863 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1864 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1865 * is treated as a local path.
1867 * First, an attempt is made to load the assembly from the bundled executable (for those
1868 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1869 * assembly has been registered as an embedded assembly). If this is not the case, then
1870 * the assembly is loaded from disk using `api:mono_image_open_full`.
1872 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1873 * the assembly is made.
1875 * Return: a pointer to the MonoAssembly if @filename contains a valid
1876 * assembly or NULL on error. Details about the error are stored in the
1880 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1882 return mono_assembly_open_full (filename, status, FALSE);
1886 * mono_assembly_load_from_full:
1887 * @image: Image to load the assembly from
1888 * @fname: assembly name to associate with the assembly
1889 * @status: returns the status condition
1890 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1892 * If the provided @image has an assembly reference, it will process the given
1893 * image as an assembly with the given name.
1895 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1897 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1898 * set to #MONO_IMAGE_OK; or NULL on error.
1900 * If there is an error loading the assembly the @status will indicate the
1901 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1902 * image did not contain an assembly reference table.
1905 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1906 MonoImageOpenStatus *status, gboolean refonly)
1908 MonoAssembly *ass, *ass2;
1911 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1912 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1913 *status = MONO_IMAGE_IMAGE_INVALID;
1917 #if defined (HOST_WIN32)
1922 tmp_fn = g_strdup (fname);
1923 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1924 if (tmp_fn [i] == '/')
1928 base_dir = absolute_dir (tmp_fn);
1932 base_dir = absolute_dir (fname);
1936 * Create assembly struct, and enter it into the assembly cache
1938 ass = g_new0 (MonoAssembly, 1);
1939 ass->basedir = base_dir;
1940 ass->ref_only = refonly;
1943 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1945 mono_assembly_fill_assembly_name (image, &ass->aname);
1947 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1948 // MS.NET doesn't support loading other mscorlibs
1951 mono_image_addref (mono_defaults.corlib);
1952 *status = MONO_IMAGE_OK;
1953 return mono_defaults.corlib->assembly;
1956 /* Add a non-temporary reference because of ass->image */
1957 mono_image_addref (image);
1959 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);
1962 * The load hooks might take locks so we can't call them while holding the
1965 if (ass->aname.name) {
1966 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1970 mono_image_close (image);
1971 *status = MONO_IMAGE_OK;
1976 mono_assemblies_lock ();
1978 if (image->assembly) {
1980 * This means another thread has already loaded the assembly, but not yet
1981 * called the load hooks so the search hook can't find the assembly.
1983 mono_assemblies_unlock ();
1984 ass2 = image->assembly;
1987 mono_image_close (image);
1988 *status = MONO_IMAGE_OK;
1992 image->assembly = ass;
1994 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1995 mono_assemblies_unlock ();
1998 if (image->is_module_handle)
1999 mono_image_fixup_vtable (image);
2002 mono_assembly_invoke_load_hook (ass);
2004 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2010 * mono_assembly_load_from:
2011 * @image: Image to load the assembly from
2012 * @fname: assembly name to associate with the assembly
2013 * @status: return status code
2015 * If the provided @image has an assembly reference, it will process the given
2016 * image as an assembly with the given name.
2018 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2020 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2021 * @refonly parameter set to FALSE.
2022 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2023 * set to #MONO_IMAGE_OK; or NULL on error.
2025 * If there is an error loading the assembly the @status will indicate the
2026 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2027 * image did not contain an assembly reference table.
2031 mono_assembly_load_from (MonoImage *image, const char *fname,
2032 MonoImageOpenStatus *status)
2034 return mono_assembly_load_from_full (image, fname, status, FALSE);
2038 * mono_assembly_name_free:
2039 * @aname: assembly name to free
2041 * Frees the provided assembly name object.
2042 * (it does not frees the object itself, only the name members).
2045 mono_assembly_name_free (MonoAssemblyName *aname)
2050 g_free ((void *) aname->name);
2051 g_free ((void *) aname->culture);
2052 g_free ((void *) aname->hash_value);
2053 g_free ((guint8*) aname->public_key);
2057 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2060 gchar header [16], val, *arr;
2061 gint i, j, offset, bitlen, keylen, pkeylen;
2063 keylen = strlen (key) >> 1;
2067 /* allow the ECMA standard key */
2068 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2070 *pubkey = g_strdup (key);
2076 val = g_ascii_xdigit_value (key [0]) << 4;
2077 val |= g_ascii_xdigit_value (key [1]);
2082 val = g_ascii_xdigit_value (key [24]);
2083 val |= g_ascii_xdigit_value (key [25]);
2095 /* We need the first 16 bytes
2096 * to check whether this key is valid or not */
2097 pkeylen = strlen (pkey) >> 1;
2101 for (i = 0, j = 0; i < 16; i++) {
2102 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2103 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2106 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2107 header [1] != 0x02 || /* Version (0x02) */
2108 header [2] != 0x00 || /* Reserved (word) */
2109 header [3] != 0x00 ||
2110 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2113 /* Based on this length, we _should_ be able to know if the length is right */
2114 bitlen = read32 (header + 12) >> 3;
2115 if ((bitlen + 16 + 4) != pkeylen)
2118 /* parsing is OK and the public key itself is not requested back */
2122 /* Encode the size of the blob */
2124 if (keylen <= 127) {
2125 arr = (gchar *)g_malloc (keylen + 1);
2126 arr [offset++] = keylen;
2128 arr = (gchar *)g_malloc (keylen + 2);
2129 arr [offset++] = 0x80; /* 10bs */
2130 arr [offset++] = keylen;
2133 for (i = offset, j = 0; i < keylen + offset; i++) {
2134 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2135 arr [i] |= g_ascii_xdigit_value (key [j++]);
2144 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)
2146 gint major, minor, build, revision;
2149 gchar *pkey, *pkeyptr, *encoded, tok [8];
2151 memset (aname, 0, sizeof (MonoAssemblyName));
2154 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2155 if (version_parts < 2 || version_parts > 4)
2158 /* FIXME: we should set build & revision to -1 (instead of 0)
2159 if these are not set in the version string. That way, later on,
2160 we can still determine if these were specified. */
2161 aname->major = major;
2162 aname->minor = minor;
2163 if (version_parts >= 3)
2164 aname->build = build;
2167 if (version_parts == 4)
2168 aname->revision = revision;
2170 aname->revision = 0;
2173 aname->flags = flags;
2175 aname->name = g_strdup (name);
2178 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2179 aname->culture = g_strdup ("");
2181 aname->culture = g_strdup (culture);
2184 if (token && strncmp (token, "null", 4) != 0) {
2187 /* the constant includes the ending NULL, hence the -1 */
2188 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2189 mono_assembly_name_free (aname);
2192 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2193 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2199 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2200 mono_assembly_name_free (aname);
2205 if (save_public_key)
2206 aname->public_key = (guint8*)pkey;
2209 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2213 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2214 // We also need to generate the key token
2215 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2216 encoded = encode_public_tok ((guchar*) tok, 8);
2217 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2220 if (save_public_key)
2221 aname->public_key = (guint8*) pkey;
2230 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2235 parts = g_strsplit (dirname, "_", 3);
2236 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2241 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2247 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2249 char *eqsign = strchr (pair, '=');
2257 *key = (gchar*)pair;
2258 *keylen = eqsign - *key;
2259 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2261 *value = g_strstrip (eqsign + 1);
2266 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2270 gchar *version = NULL;
2272 gchar *culture = NULL;
2274 gchar *token = NULL;
2278 gchar *retargetable = NULL;
2279 gchar *retargetable_uq;
2283 gchar *value, *part_name;
2284 guint32 part_name_len;
2287 gboolean version_defined;
2288 gboolean token_defined;
2290 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2292 if (!is_version_defined)
2293 is_version_defined = &version_defined;
2294 *is_version_defined = FALSE;
2295 if (!is_token_defined)
2296 is_token_defined = &token_defined;
2297 *is_token_defined = FALSE;
2299 parts = tmp = g_strsplit (name, ",", 6);
2300 if (!tmp || !*tmp) {
2305 dllname = g_strstrip (*tmp);
2310 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2311 goto cleanup_and_fail;
2313 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2314 *is_version_defined = TRUE;
2316 if (strlen (version) == 0) {
2317 goto cleanup_and_fail;
2323 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2325 if (strlen (culture) == 0) {
2326 goto cleanup_and_fail;
2332 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2333 *is_token_defined = TRUE;
2335 if (strlen (token) == 0) {
2336 goto cleanup_and_fail;
2342 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2344 if (strlen (key) == 0) {
2345 goto cleanup_and_fail;
2351 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2352 retargetable = value;
2353 retargetable_uq = unquote (retargetable);
2354 if (retargetable_uq != NULL)
2355 retargetable = retargetable_uq;
2357 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2358 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2359 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2360 g_free (retargetable_uq);
2361 goto cleanup_and_fail;
2364 g_free (retargetable_uq);
2369 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2371 procarch_uq = unquote (procarch);
2372 if (procarch_uq != NULL)
2373 procarch = procarch_uq;
2375 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2376 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2377 else if (!g_ascii_strcasecmp (procarch, "X86"))
2378 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2379 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2380 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2381 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2382 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2384 g_free (procarch_uq);
2385 goto cleanup_and_fail;
2388 g_free (procarch_uq);
2397 /* if retargetable flag is set, then we must have a fully qualified name */
2398 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2399 goto cleanup_and_fail;
2402 dllname_uq = unquote (dllname);
2403 version_uq = unquote (version);
2404 culture_uq = unquote (culture);
2405 token_uq = unquote (token);
2406 key_uq = unquote (key);
2408 res = build_assembly_name (
2409 dllname_uq == NULL ? dllname : dllname_uq,
2410 version_uq == NULL ? version : version_uq,
2411 culture_uq == NULL ? culture : culture_uq,
2412 token_uq == NULL ? token : token_uq,
2413 key_uq == NULL ? key : key_uq,
2414 flags, arch, aname, save_public_key);
2416 g_free (dllname_uq);
2417 g_free (version_uq);
2418 g_free (culture_uq);
2431 unquote (const char *str)
2439 slen = strlen (str);
2443 if (*str != '\'' && *str != '\"')
2446 end = str + slen - 1;
2450 return g_strndup (str + 1, slen - 2);
2454 * mono_assembly_name_parse:
2455 * @name: name to parse
2456 * @aname: the destination assembly name
2458 * Parses an assembly qualified type name and assigns the name,
2459 * version, culture and token to the provided assembly name object.
2461 * Returns: TRUE if the name could be parsed.
2464 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2466 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2470 * mono_assembly_name_new:
2471 * @name: name to parse
2473 * Allocate a new MonoAssemblyName and fill its values from the
2476 * Returns: a newly allocated structure or NULL if there was any failure.
2479 mono_assembly_name_new (const char *name)
2481 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2482 if (mono_assembly_name_parse (name, aname))
2489 mono_assembly_name_get_name (MonoAssemblyName *aname)
2495 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2497 return aname->culture;
2501 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2503 if (aname->public_key_token [0])
2504 return aname->public_key_token;
2509 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2512 *minor = aname->minor;
2514 *build = aname->build;
2516 *revision = aname->revision;
2517 return aname->major;
2520 static MonoAssembly*
2521 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2523 gchar *fullpath = NULL;
2525 const char* direntry;
2526 MonoAssemblyName gac_aname;
2527 gint major=-1, minor=0, build=0, revision=0;
2528 gboolean exact_version;
2530 dirhandle = g_dir_open (basepath, 0, NULL);
2534 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2536 while ((direntry = g_dir_read_name (dirhandle))) {
2537 gboolean match = TRUE;
2539 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2542 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2545 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2546 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2550 if (exact_version) {
2551 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2552 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2554 else if (gac_aname.major < major)
2556 else if (gac_aname.major == major) {
2557 if (gac_aname.minor < minor)
2559 else if (gac_aname.minor == minor) {
2560 if (gac_aname.build < build)
2562 else if (gac_aname.build == build && gac_aname.revision <= revision)
2569 major = gac_aname.major;
2570 minor = gac_aname.minor;
2571 build = gac_aname.build;
2572 revision = gac_aname.revision;
2574 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2577 mono_assembly_name_free (&gac_aname);
2580 g_dir_close (dirhandle);
2582 if (fullpath == NULL)
2585 MonoAssembly *res = mono_assembly_open (fullpath, status);
2592 * mono_assembly_load_with_partial_name:
2593 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2594 * @status: return status code
2596 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2597 * so it might contain a qualified type name, version, culture and token.
2599 * This will load the assembly from the file whose name is derived from the assembly name
2600 * by appending the .dll extension.
2602 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2603 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2604 * if that fails from the GAC.
2606 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2609 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2613 MonoAssemblyName *aname, base_name;
2614 MonoAssemblyName mapped_aname;
2615 gchar *fullname, *gacpath;
2618 memset (&base_name, 0, sizeof (MonoAssemblyName));
2621 if (!mono_assembly_name_parse (name, aname))
2625 * If no specific version has been requested, make sure we load the
2626 * correct version for system assemblies.
2628 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2629 aname = mono_assembly_remap_version (aname, &mapped_aname);
2631 res = mono_assembly_loaded (aname);
2633 mono_assembly_name_free (aname);
2637 res = invoke_assembly_preload_hook (aname, assemblies_path);
2639 res->in_gac = FALSE;
2640 mono_assembly_name_free (aname);
2644 fullname = g_strdup_printf ("%s.dll", aname->name);
2646 if (extra_gac_paths) {
2647 paths = extra_gac_paths;
2648 while (!res && *paths) {
2649 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2650 res = probe_for_partial_name (gacpath, fullname, aname, status);
2659 mono_assembly_name_free (aname);
2663 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2664 res = probe_for_partial_name (gacpath, fullname, aname, status);
2670 MonoDomain *domain = mono_domain_get ();
2671 MonoReflectionAssembly *refasm;
2673 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2674 if (!is_ok (&error)) {
2676 mono_assembly_name_free (aname);
2677 mono_error_cleanup (&error);
2678 if (*status == MONO_IMAGE_OK)
2679 *status = MONO_IMAGE_IMAGE_INVALID;
2683 res = refasm->assembly;
2687 mono_assembly_name_free (aname);
2693 mono_assembly_is_in_gac (const gchar *filename)
2695 const gchar *rootdir;
2699 if (filename == NULL)
2702 for (paths = extra_gac_paths; paths && *paths; paths++) {
2703 if (strstr (*paths, filename) != *paths)
2706 gp = (gchar *) (filename + strlen (*paths));
2707 if (*gp != G_DIR_SEPARATOR)
2710 if (strncmp (gp, "lib", 3))
2713 if (*gp != G_DIR_SEPARATOR)
2716 if (strncmp (gp, "mono", 4))
2719 if (*gp != G_DIR_SEPARATOR)
2722 if (strncmp (gp, "gac", 3))
2725 if (*gp != G_DIR_SEPARATOR)
2731 rootdir = mono_assembly_getrootdir ();
2732 if (strstr (filename, rootdir) != filename)
2735 gp = (gchar *) (filename + strlen (rootdir));
2736 if (*gp != G_DIR_SEPARATOR)
2739 if (strncmp (gp, "mono", 4))
2742 if (*gp != G_DIR_SEPARATOR)
2745 if (strncmp (gp, "gac", 3))
2748 if (*gp != G_DIR_SEPARATOR)
2754 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2757 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2761 if (strstr (aname->name, ".dll")) {
2762 len = strlen (aname->name) - 4;
2763 name = (gchar *)g_malloc (len + 1);
2764 strncpy (name, aname->name, len);
2767 name = g_strdup (aname->name);
2770 culture = g_utf8_strdown (aname->culture, -1);
2772 culture = g_strdup ("");
2774 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2775 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2779 filename = g_strconcat (pname, ".dll", NULL);
2780 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2786 if (extra_gac_paths) {
2787 paths = extra_gac_paths;
2788 while (!image && *paths) {
2789 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2790 "lib", "mono", "gac", subpath, NULL);
2791 image = mono_image_open (fullpath, NULL);
2802 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2803 "mono", "gac", subpath, NULL);
2804 image = mono_image_open (fullpath, NULL);
2811 static MonoAssemblyName*
2812 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2814 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2815 dest_name->major = info->new_version.major;
2816 dest_name->minor = info->new_version.minor;
2817 dest_name->build = info->new_version.build;
2818 dest_name->revision = info->new_version.revision;
2823 /* LOCKING: assembly_binding lock must be held */
2824 static MonoAssemblyBindingInfo*
2825 search_binding_loaded (MonoAssemblyName *aname)
2829 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2830 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2831 if (assembly_binding_maps_name (info, aname))
2838 static inline gboolean
2839 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2841 if (left->major != right->major || left->minor != right->minor ||
2842 left->build != right->build || left->revision != right->revision)
2848 static inline gboolean
2849 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2851 if (left->has_old_version_bottom != right->has_old_version_bottom)
2854 if (left->has_old_version_top != right->has_old_version_top)
2857 if (left->has_new_version != right->has_new_version)
2860 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2863 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2866 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2872 /* LOCKING: assumes all the necessary locks are held */
2874 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2876 MonoAssemblyBindingInfo *info_copy;
2878 MonoAssemblyBindingInfo *info_tmp;
2879 MonoDomain *domain = (MonoDomain*)user_data;
2884 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2885 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2886 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2890 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2891 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2893 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2895 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2897 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2901 get_version_number (int major, int minor)
2903 return major * 256 + minor;
2906 static inline gboolean
2907 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2909 int aname_version_number = get_version_number (aname->major, aname->minor);
2910 if (!info->has_old_version_bottom)
2913 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2916 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2919 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2920 info->major = aname->major;
2921 info->minor = aname->minor;
2926 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2927 static MonoAssemblyBindingInfo*
2928 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2930 MonoAssemblyBindingInfo *info;
2933 if (!domain->assembly_bindings)
2937 for (list = domain->assembly_bindings; list; list = list->next) {
2938 info = (MonoAssemblyBindingInfo *)list->data;
2939 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2945 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2946 info->has_new_version && assembly_binding_maps_name (info, aname))
2947 info->is_valid = TRUE;
2949 info->is_valid = FALSE;
2955 static MonoAssemblyName*
2956 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2959 MonoAssemblyBindingInfo *info, *info2;
2963 if (aname->public_key_token [0] == 0)
2966 domain = mono_domain_get ();
2968 mono_assembly_binding_lock ();
2969 info = search_binding_loaded (aname);
2970 mono_assembly_binding_unlock ();
2973 mono_domain_lock (domain);
2974 info = get_per_domain_assembly_binding_info (domain, aname);
2975 mono_domain_unlock (domain);
2979 if (!check_policy_versions (info, aname))
2982 mono_assembly_bind_version (info, aname, dest_name);
2986 if (domain && domain->setup && domain->setup->configuration_file) {
2987 mono_domain_lock (domain);
2988 if (!domain->assembly_bindings_parsed) {
2989 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2990 /* expect this to succeed because mono_domain_set_options_from_config () did
2991 * the same thing when the domain was created. */
2992 mono_error_assert_ok (&error);
2994 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2996 if (!domain_config_file_path)
2997 domain_config_file_path = domain_config_file_name;
2999 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3000 domain->assembly_bindings_parsed = TRUE;
3001 if (domain_config_file_name != domain_config_file_path)
3002 g_free (domain_config_file_name);
3003 g_free (domain_config_file_path);
3006 info2 = get_per_domain_assembly_binding_info (domain, aname);
3009 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3010 info->name = g_strdup (info2->name);
3011 info->culture = g_strdup (info2->culture);
3012 info->domain_id = domain->domain_id;
3015 mono_domain_unlock (domain);
3019 info = g_new0 (MonoAssemblyBindingInfo, 1);
3020 info->major = aname->major;
3021 info->minor = aname->minor;
3024 if (!info->is_valid) {
3025 ppimage = mono_assembly_load_publisher_policy (aname);
3027 get_publisher_policy_info (ppimage, aname, info);
3028 mono_image_close (ppimage);
3032 /* Define default error value if needed */
3033 if (!info->is_valid) {
3034 info->name = g_strdup (aname->name);
3035 info->culture = g_strdup (aname->culture);
3036 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3039 mono_assembly_binding_lock ();
3040 info2 = search_binding_loaded (aname);
3042 /* This binding was added by another thread
3044 mono_assembly_binding_info_free (info);
3049 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3051 mono_assembly_binding_unlock ();
3053 if (!info->is_valid || !check_policy_versions (info, aname))
3056 mono_assembly_bind_version (info, aname, dest_name);
3061 * mono_assembly_load_from_gac
3063 * @aname: The assembly name object
3065 static MonoAssembly*
3066 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3068 MonoAssembly *result = NULL;
3069 gchar *name, *version, *culture, *fullpath, *subpath;
3074 if (aname->public_key_token [0] == 0) {
3078 if (strstr (aname->name, ".dll")) {
3079 len = strlen (filename) - 4;
3080 name = (gchar *)g_malloc (len + 1);
3081 strncpy (name, aname->name, len);
3084 name = g_strdup (aname->name);
3087 if (aname->culture) {
3088 culture = g_utf8_strdown (aname->culture, -1);
3090 culture = g_strdup ("");
3093 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3094 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3095 aname->minor, aname->build, aname->revision,
3099 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3104 if (extra_gac_paths) {
3105 paths = extra_gac_paths;
3106 while (!result && *paths) {
3107 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3108 result = mono_assembly_open_full (fullpath, status, refonly);
3115 result->in_gac = TRUE;
3120 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3121 "mono", "gac", subpath, NULL);
3122 result = mono_assembly_open_full (fullpath, status, refonly);
3126 result->in_gac = TRUE;
3134 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3137 MonoAssemblyName *aname;
3140 /* g_print ("corlib already loaded\n"); */
3144 // In native client, Corlib is embedded in the executable as static variable corlibData
3145 #if defined(__native_client__)
3146 if (corlibData != NULL && corlibSize != 0) {
3148 /* First "FALSE" instructs mono not to make a copy. */
3149 /* Second "FALSE" says this is not just a ref. */
3150 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3151 if (image == NULL || status != 0)
3152 g_print("mono_image_open_from_data_full failed: %d\n", status);
3153 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3154 if (corlib == NULL || status != 0)
3155 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3161 // A nonstandard preload hook may provide a special mscorlib assembly
3162 aname = mono_assembly_name_new ("mscorlib.dll");
3163 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3164 mono_assembly_name_free (aname);
3167 goto return_corlib_and_facades;
3169 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3170 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3171 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3173 goto return_corlib_and_facades;
3176 /* Normal case: Load corlib from mono/<version> */
3177 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3178 if (assemblies_path) { // Custom assemblies path
3179 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3181 g_free (corlib_file);
3182 goto return_corlib_and_facades;
3185 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3186 g_free (corlib_file);
3188 return_corlib_and_facades:
3189 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3190 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3196 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3197 const char *basedir,
3198 MonoImageOpenStatus *status,
3201 MonoAssembly *result;
3202 char *fullpath, *filename;
3203 MonoAssemblyName maped_aname;
3204 MonoAssemblyName maped_name_pp;
3209 aname = mono_assembly_remap_version (aname, &maped_aname);
3211 /* Reflection only assemblies don't get assembly binding */
3213 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3215 result = mono_assembly_loaded_full (aname, refonly);
3219 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3221 result->in_gac = FALSE;
3225 /* Currently we retrieve the loaded corlib for reflection
3226 * only requests, like a common reflection only assembly
3228 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3229 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3232 len = strlen (aname->name);
3233 for (ext_index = 0; ext_index < 2; ext_index ++) {
3234 ext = ext_index == 0 ? ".dll" : ".exe";
3235 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3236 filename = g_strdup (aname->name);
3237 /* Don't try appending .dll/.exe if it already has one of those extensions */
3240 filename = g_strconcat (aname->name, ext, NULL);
3243 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3250 fullpath = g_build_filename (basedir, filename, NULL);
3251 result = mono_assembly_open_full (fullpath, status, refonly);
3254 result->in_gac = FALSE;
3260 result = load_in_path (filename, default_path, status, refonly);
3262 result->in_gac = FALSE;
3272 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3274 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3277 /* Try a postload search hook */
3278 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3283 * mono_assembly_load_full:
3284 * @aname: A MonoAssemblyName with the assembly name to load.
3285 * @basedir: A directory to look up the assembly at.
3286 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3287 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3289 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3290 * attempts to load the assembly from that directory before probing the standard locations.
3292 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3293 * assembly binding takes place.
3295 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3296 * value pointed by status is updated with an error code.
3299 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3301 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3305 * mono_assembly_load:
3306 * @aname: A MonoAssemblyName with the assembly name to load.
3307 * @basedir: A directory to look up the assembly at.
3308 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3310 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3311 * attempts to load the assembly from that directory before probing the standard locations.
3313 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3314 * value pointed by status is updated with an error code.
3317 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3319 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3323 * mono_assembly_loaded_full:
3324 * @aname: an assembly to look for.
3325 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3327 * This is used to determine if the specified assembly has been loaded
3328 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3329 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3332 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3335 MonoAssemblyName maped_aname;
3337 aname = mono_assembly_remap_version (aname, &maped_aname);
3339 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3345 * mono_assembly_loaded:
3346 * @aname: an assembly to look for.
3348 * This is used to determine if the specified assembly has been loaded
3350 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3351 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3354 mono_assembly_loaded (MonoAssemblyName *aname)
3356 return mono_assembly_loaded_full (aname, FALSE);
3360 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3362 if (assembly == NULL || assembly == REFERENCE_MISSING)
3365 if (assembly_is_dynamic (assembly)) {
3367 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3368 for (i = 0; i < dynimg->image.module_count; ++i)
3369 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3370 mono_dynamic_image_release_gc_roots (dynimg);
3375 * Returns whether mono_assembly_close_finish() must be called as
3376 * well. See comment for mono_image_close_except_pools() for why we
3377 * unload in two steps.
3380 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3383 g_return_val_if_fail (assembly != NULL, FALSE);
3385 if (assembly == REFERENCE_MISSING)
3388 /* Might be 0 already */
3389 if (InterlockedDecrement (&assembly->ref_count) > 0)
3392 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3394 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3396 mono_debug_close_image (assembly->image);
3398 mono_assemblies_lock ();
3399 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3400 mono_assemblies_unlock ();
3402 assembly->image->assembly = NULL;
3404 if (!mono_image_close_except_pools (assembly->image))
3405 assembly->image = NULL;
3407 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3408 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3409 mono_assembly_name_free (fname);
3412 g_slist_free (assembly->friend_assembly_names);
3413 g_free (assembly->basedir);
3415 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3421 mono_assembly_close_finish (MonoAssembly *assembly)
3423 g_assert (assembly && assembly != REFERENCE_MISSING);
3425 if (assembly->image)
3426 mono_image_close_finish (assembly->image);
3428 if (assembly_is_dynamic (assembly)) {
3429 g_free ((char*)assembly->aname.culture);
3436 * mono_assembly_close:
3437 * @assembly: the assembly to release.
3439 * This method releases a reference to the @assembly. The assembly is
3440 * only released when all the outstanding references to it are released.
3443 mono_assembly_close (MonoAssembly *assembly)
3445 if (mono_assembly_close_except_image_pools (assembly))
3446 mono_assembly_close_finish (assembly);
3450 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3452 return mono_image_load_file_for_image (assembly->image, idx);
3456 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3458 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3463 * mono_assembly_foreach:
3464 * @func: function to invoke for each assembly loaded
3465 * @user_data: data passed to the callback
3467 * Invokes the provided @func callback for each assembly loaded into
3468 * the runtime. The first parameter passed to the callback is the
3469 * `MonoAssembly*`, and the second parameter is the @user_data.
3471 * This is done for all assemblies loaded in the runtime, not just
3472 * those loaded in the current application domain.
3475 mono_assembly_foreach (GFunc func, gpointer user_data)
3480 * We make a copy of the list to avoid calling the callback inside the
3481 * lock, which could lead to deadlocks.
3483 mono_assemblies_lock ();
3484 copy = g_list_copy (loaded_assemblies);
3485 mono_assemblies_unlock ();
3487 g_list_foreach (loaded_assemblies, func, user_data);
3493 * mono_assemblies_cleanup:
3495 * Free all resources used by this module.
3498 mono_assemblies_cleanup (void)
3502 mono_os_mutex_destroy (&assemblies_mutex);
3503 mono_os_mutex_destroy (&assembly_binding_mutex);
3505 for (l = loaded_assembly_bindings; l; l = l->next) {
3506 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3508 mono_assembly_binding_info_free (info);
3511 g_slist_free (loaded_assembly_bindings);
3513 free_assembly_load_hooks ();
3514 free_assembly_search_hooks ();
3515 free_assembly_preload_hooks ();
3518 /*LOCKING takes the assembly_binding lock*/
3520 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3524 mono_assembly_binding_lock ();
3525 iter = &loaded_assembly_bindings;
3528 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3530 if (info->domain_id == domain_id) {
3532 mono_assembly_binding_info_free (info);
3539 mono_assembly_binding_unlock ();
3543 * Holds the assembly of the application, for
3544 * System.Diagnostics.Process::MainModule
3546 static MonoAssembly *main_assembly=NULL;
3549 mono_assembly_set_main (MonoAssembly *assembly)
3551 main_assembly = assembly;
3555 * mono_assembly_get_main:
3557 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3560 mono_assembly_get_main (void)
3562 return (main_assembly);
3566 * mono_assembly_get_image:
3567 * @assembly: The assembly to retrieve the image from
3569 * Returns: the MonoImage associated with this assembly.
3572 mono_assembly_get_image (MonoAssembly *assembly)
3574 return assembly->image;
3578 * mono_assembly_get_name:
3579 * @assembly: The assembly to retrieve the name from
3581 * The returned name's lifetime is the same as @assembly's.
3583 * Returns: the MonoAssemblyName associated with this assembly.
3586 mono_assembly_get_name (MonoAssembly *assembly)
3588 return &assembly->aname;
3592 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3594 bundles = assemblies;
3597 #define MONO_DECLSEC_FORMAT_10 0x3C
3598 #define MONO_DECLSEC_FORMAT_20 0x2E
3599 #define MONO_DECLSEC_FIELD 0x53
3600 #define MONO_DECLSEC_PROPERTY 0x54
3602 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3603 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3604 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3605 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3606 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3609 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3613 case MONO_DECLSEC_PROPERTY:
3615 case MONO_DECLSEC_FIELD:
3617 *abort_decoding = TRUE;
3622 if (*p++ != MONO_TYPE_BOOLEAN) {
3623 *abort_decoding = TRUE;
3627 /* property name length */
3628 len = mono_metadata_decode_value (p, &p);
3630 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3641 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3643 int i, j, num, len, params_len;
3645 if (*p == MONO_DECLSEC_FORMAT_10) {
3646 gsize read, written;
3647 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3649 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3655 if (*p++ != MONO_DECLSEC_FORMAT_20)
3658 /* number of encoded permission attributes */
3659 num = mono_metadata_decode_value (p, &p);
3660 for (i = 0; i < num; ++i) {
3661 gboolean is_valid = FALSE;
3662 gboolean abort_decoding = FALSE;
3664 /* attribute name length */
3665 len = mono_metadata_decode_value (p, &p);
3667 /* We don't really need to fully decode the type. Comparing the name is enough */
3668 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3672 /*size of the params table*/
3673 params_len = mono_metadata_decode_value (p, &p);
3675 const char *params_end = p + params_len;
3677 /* number of parameters */
3678 len = mono_metadata_decode_value (p, &p);
3680 for (j = 0; j < len; ++j) {
3681 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3697 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3700 guint32 cols [MONO_DECL_SECURITY_SIZE];
3704 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3705 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3707 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3709 for (i = 0; i < t->rows; ++i) {
3710 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3711 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3713 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3716 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3717 len = mono_metadata_decode_blob_size (blob, &blob);
3721 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3722 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3727 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);