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 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
221 encode_public_tok (const guchar *token, gint32 len)
223 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
227 res = (gchar *)g_malloc (len * 2 + 1);
228 for (i = 0; i < len; i++) {
229 res [i * 2] = allowed [token [i] >> 4];
230 res [i * 2 + 1] = allowed [token [i] & 0xF];
237 * mono_public_tokens_are_equal:
238 * @pubt1: first public key token
239 * @pubt2: second public key token
241 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
245 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
247 return memcmp (pubt1, pubt2, 16) == 0;
251 * mono_set_assemblies_path:
252 * @path: list of paths that contain directories where Mono will look for assemblies
254 * Use this method to override the standard assembly lookup system and
255 * override any assemblies coming from the GAC. This is the method
256 * that supports the MONO_PATH variable.
258 * Notice that MONO_PATH and this method are really a very bad idea as
259 * it prevents the GAC from working and it prevents the standard
260 * resolution mechanisms from working. Nonetheless, for some debugging
261 * situations and bootstrapping setups, this is useful to have.
264 mono_set_assemblies_path (const char* path)
266 char **splitted, **dest;
268 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
270 g_strfreev (assemblies_path);
271 assemblies_path = dest = splitted;
273 char *tmp = *splitted;
275 *dest++ = mono_path_canonicalize (tmp);
281 if (g_getenv ("MONO_DEBUG") == NULL)
284 splitted = assemblies_path;
286 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
287 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
293 /* Native Client can't get this info from an environment variable so */
294 /* it's passed in to the runtime, or set manually by embedding code. */
295 #ifdef __native_client__
296 char* nacl_mono_path = NULL;
300 check_path_env (void)
303 path = g_getenv ("MONO_PATH");
304 #ifdef __native_client__
306 path = nacl_mono_path;
308 if (!path || assemblies_path != NULL)
311 mono_set_assemblies_path(path);
315 check_extra_gac_path_env (void) {
317 char **splitted, **dest;
319 path = g_getenv ("MONO_GAC_PREFIX");
323 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
325 g_strfreev (extra_gac_paths);
326 extra_gac_paths = dest = splitted;
334 if (g_getenv ("MONO_DEBUG") == NULL)
338 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
339 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
346 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
348 if (!info || !info->name)
351 if (strcmp (info->name, aname->name))
354 if (info->major != aname->major || info->minor != aname->minor)
357 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
360 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
363 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
370 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
376 g_free (info->culture);
380 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
383 guint32 cols [MONO_MANIFEST_SIZE];
384 const gchar *filename;
385 gchar *subpath, *fullpath;
387 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
388 /* MS Impl. accepts policy assemblies with more than
389 * one manifest resource, and only takes the first one */
391 binding_info->is_valid = FALSE;
395 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
396 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
397 binding_info->is_valid = FALSE;
401 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
402 g_assert (filename != NULL);
404 subpath = g_path_get_dirname (image->name);
405 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
406 mono_config_parse_publisher_policy (fullpath, binding_info);
410 /* Define the optional elements/attributes before checking */
411 if (!binding_info->culture)
412 binding_info->culture = g_strdup ("");
414 /* Check that the most important elements/attributes exist */
415 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
416 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
417 mono_assembly_binding_info_free (binding_info);
418 binding_info->is_valid = FALSE;
422 binding_info->is_valid = TRUE;
426 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
428 if (v->major > aname->major)
430 else if (v->major < aname->major)
433 if (v->minor > aname->minor)
435 else if (v->minor < aname->minor)
438 if (v->build > aname->build)
440 else if (v->build < aname->build)
443 if (v->revision > aname->revision)
445 else if (v->revision < aname->revision)
452 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
457 /* If has_old_version_top doesn't exist, we don't have an interval */
458 if (!info->has_old_version_top) {
459 if (compare_versions (&info->old_version_bottom, name) == 0)
465 /* Check that the version defined by name is valid for the interval */
466 if (compare_versions (&info->old_version_top, name) < 0)
469 /* We should be greater or equal than the small version */
470 if (compare_versions (&info->old_version_bottom, name) > 0)
477 * mono_assembly_names_equal:
479 * @r: second assembly.
481 * Compares two MonoAssemblyNames and returns whether they are equal.
483 * This compares the names, the cultures, the release version and their
486 * Returns: TRUE if both assembly names are equal.
489 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
491 if (!l->name || !r->name)
494 if (strcmp (l->name, r->name))
497 if (l->culture && r->culture && strcmp (l->culture, r->culture))
500 if (l->major != r->major || l->minor != r->minor ||
501 l->build != r->build || l->revision != r->revision)
502 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)))
505 if (!l->public_key_token [0] || !r->public_key_token [0])
508 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
514 static MonoAssembly *
515 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
519 MonoAssembly *result;
521 for (i = 0; search_path [i]; ++i) {
522 fullpath = g_build_filename (search_path [i], basename, NULL);
523 result = mono_assembly_open_full (fullpath, status, refonly);
532 * mono_assembly_setrootdir:
533 * @root_dir: The pathname of the root directory where we will locate assemblies
535 * This routine sets the internal default root directory for looking up
538 * This is used by Windows installations to compute dynamically the
539 * place where the Mono assemblies are located.
543 mono_assembly_setrootdir (const char *root_dir)
546 * Override the MONO_ASSEMBLIES directory configured at compile time.
548 /* Leak if called more than once */
549 default_path [0] = g_strdup (root_dir);
553 * mono_assembly_getrootdir:
555 * Obtains the root directory used for looking up assemblies.
557 * Returns: a string with the directory, this string should not be freed.
559 G_CONST_RETURN gchar *
560 mono_assembly_getrootdir (void)
562 return default_path [0];
566 * mono_native_getrootdir:
568 * Obtains the root directory used for looking up native libs (.so, .dylib).
570 * Returns: a string with the directory, this string should be freed by
573 G_CONST_RETURN gchar *
574 mono_native_getrootdir (void)
576 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
582 * @assembly_dir: the base directory for assemblies
583 * @config_dir: the base directory for configuration files
585 * This routine is used internally and by developers embedding
586 * the runtime into their own applications.
588 * There are a number of cases to consider: Mono as a system-installed
589 * package that is available on the location preconfigured or Mono in
590 * a relocated location.
592 * If you are using a system-installed Mono, you can pass NULL
593 * to both parameters. If you are not, you should compute both
594 * directory values and call this routine.
596 * The values for a given PREFIX are:
598 * assembly_dir: PREFIX/lib
599 * config_dir: PREFIX/etc
601 * Notice that embedders that use Mono in a relocated way must
602 * compute the location at runtime, as they will be in control
603 * of where Mono is installed.
606 mono_set_dirs (const char *assembly_dir, const char *config_dir)
608 if (assembly_dir == NULL)
609 assembly_dir = mono_config_get_assemblies_dir ();
610 if (config_dir == NULL)
611 config_dir = mono_config_get_cfg_dir ();
612 mono_assembly_setrootdir (assembly_dir);
613 mono_set_config_dir (config_dir);
619 compute_base (char *path)
621 char *p = strrchr (path, '/');
625 /* Not a well known Mono executable, we are embedded, cant guess the base */
626 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
630 p = strrchr (path, '/');
634 if (strcmp (p, "/bin") != 0)
643 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
646 static G_GNUC_UNUSED void
650 char *config, *lib, *mono;
655 * Only /usr prefix is treated specially
657 bindir = mono_config_get_bin_dir ();
659 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
664 config = g_build_filename (base, "etc", NULL);
665 lib = g_build_filename (base, "lib", NULL);
666 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
667 if (stat (mono, &buf) == -1)
670 mono_set_dirs (lib, config);
678 #endif /* HOST_WIN32 */
683 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
684 * this auto-detects the prefix where Mono was installed.
687 mono_set_rootdir (void)
689 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
690 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
693 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
697 * _NSGetExecutablePath may return -1 to indicate buf is not large
698 * enough, but we ignore that case to avoid having to do extra dynamic
699 * allocation for the path and hope that 4096 is enough - this is
700 * ok in the Linux/Solaris case below at least...
704 guint buf_size = sizeof (buf);
707 if (_NSGetExecutablePath (buf, &buf_size) == 0)
708 name = g_strdup (buf);
717 resolvedname = mono_path_resolve_symlinks (name);
719 bindir = g_path_get_dirname (resolvedname);
720 installdir = g_path_get_dirname (bindir);
721 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
723 config = g_build_filename (root, "..", "etc", NULL);
725 mono_set_dirs (root, config);
727 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
728 mono_set_dirs (root, config);
738 g_free (resolvedname);
739 #elif defined(DISABLE_MONO_AUTODETECTION)
747 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
755 /* Solaris 10 style */
756 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
757 s = readlink (str, buf, sizeof (buf)-1);
769 * mono_assemblies_init:
771 * Initialize global variables used by this module.
774 mono_assemblies_init (void)
777 * Initialize our internal paths if we have not been initialized yet.
778 * This happens when embedders use Mono.
780 if (mono_assembly_getrootdir () == NULL)
784 check_extra_gac_path_env ();
786 mono_os_mutex_init_recursive (&assemblies_mutex);
787 mono_os_mutex_init (&assembly_binding_mutex);
791 mono_assembly_binding_lock (void)
793 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
797 mono_assembly_binding_unlock (void)
799 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
803 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
805 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
806 guint32 cols [MONO_ASSEMBLY_SIZE];
807 gint32 machine, flags;
812 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
815 aname->hash_value = NULL;
816 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
817 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
818 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
819 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
820 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
821 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
822 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
823 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
824 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
825 guchar* token = (guchar *)g_malloc (8);
830 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
831 len = mono_metadata_decode_blob_size (pkey, &pkey);
832 aname->public_key = (guchar*)pkey;
834 mono_digest_get_public_token (token, aname->public_key, len);
835 encoded = encode_public_tok (token, 8);
836 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
842 aname->public_key = NULL;
843 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
846 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
847 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
850 aname->public_key = 0;
852 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
853 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
855 case COFF_MACHINE_I386:
856 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
857 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
858 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
859 else if ((flags & 0x70) == 0x70)
860 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
862 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
864 case COFF_MACHINE_IA64:
865 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
867 case COFF_MACHINE_AMD64:
868 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
870 case COFF_MACHINE_ARM:
871 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
881 * mono_stringify_assembly_name:
882 * @aname: the assembly name.
884 * Convert @aname into its string format. The returned string is dynamically
885 * allocated and should be freed by the caller.
887 * Returns: a newly allocated string with a string representation of
891 mono_stringify_assembly_name (MonoAssemblyName *aname)
893 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
895 return g_strdup_printf (
896 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
897 quote, aname->name, quote,
898 aname->major, aname->minor, aname->build, aname->revision,
899 aname->culture && *aname->culture? aname->culture: "neutral",
900 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
901 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
905 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
907 const gchar *public_tok;
910 public_tok = mono_metadata_blob_heap (image, key_index);
911 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
913 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
915 mono_digest_get_public_token (token, (guchar*)public_tok, len);
916 return encode_public_tok (token, 8);
919 return encode_public_tok ((guchar*)public_tok, len);
923 * mono_assembly_addref:
924 * @assemnly: the assembly to reference
926 * This routine increments the reference count on a MonoAssembly.
927 * The reference count is reduced every time the method mono_assembly_close() is
931 mono_assembly_addref (MonoAssembly *assembly)
933 InterlockedIncrement (&assembly->ref_count);
937 * CAUTION: This table must be kept in sync with
938 * ivkm/reflect/Fusion.cs
941 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
942 #define WINFX_KEY "31bf3856ad364e35"
943 #define ECMA_KEY "b77a5c561934e089"
944 #define MSFINAL_KEY "b03f5f7f11d50a3a"
945 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
953 static KeyRemapEntry key_remap_table[] = {
954 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
955 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
956 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
957 { "System", SILVERLIGHT_KEY, ECMA_KEY },
958 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
959 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
960 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
961 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
962 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
963 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
964 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
965 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
966 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
967 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
968 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
969 { "System.Numerics", WINFX_KEY, ECMA_KEY },
970 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
971 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
972 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
973 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
974 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
975 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
976 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
977 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
978 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
979 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
980 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
981 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
982 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
986 remap_keys (MonoAssemblyName *aname)
989 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
990 const KeyRemapEntry *entry = &key_remap_table [i];
992 if (strcmp (aname->name, entry->name) ||
993 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
996 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
998 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
999 "Remapped public key token of retargetable assembly %s from %s to %s",
1000 aname->name, entry->from, entry->to);
1005 static MonoAssemblyName *
1006 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1008 const MonoRuntimeInfo *current_runtime;
1009 int pos, first, last;
1011 if (aname->name == NULL) return aname;
1013 current_runtime = mono_get_runtime_info ();
1015 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1016 const AssemblyVersionSet* vset;
1018 /* Remap to current runtime */
1019 vset = ¤t_runtime->version_sets [0];
1021 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1022 dest_aname->major = vset->major;
1023 dest_aname->minor = vset->minor;
1024 dest_aname->build = vset->build;
1025 dest_aname->revision = vset->revision;
1026 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1028 /* Remap assembly name */
1029 if (!strcmp (aname->name, "System.Net"))
1030 dest_aname->name = g_strdup ("System");
1032 remap_keys (dest_aname);
1034 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1035 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1037 aname->major, aname->minor, aname->build, aname->revision,
1039 vset->major, vset->minor, vset->build, vset->revision
1045 #ifndef DISABLE_ASSEMBLY_REMAPPING
1047 last = G_N_ELEMENTS (framework_assemblies) - 1;
1049 while (first <= last) {
1051 pos = first + (last - first) / 2;
1052 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1054 const AssemblyVersionSet* vset;
1055 int index = framework_assemblies[pos].version_set_index;
1056 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1057 vset = ¤t_runtime->version_sets [index];
1059 if (aname->major == vset->major && aname->minor == vset->minor &&
1060 aname->build == vset->build && aname->revision == vset->revision)
1063 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1066 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1067 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1068 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1070 aname->major, aname->minor, aname->build, aname->revision,
1071 vset->major, vset->minor, vset->build, vset->revision
1074 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1075 dest_aname->major = vset->major;
1076 dest_aname->minor = vset->minor;
1077 dest_aname->build = vset->build;
1078 dest_aname->revision = vset->revision;
1079 if (framework_assemblies[pos].new_assembly_name != NULL) {
1080 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1081 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1082 "The assembly name %s was remapped to %s",
1087 } else if (res < 0) {
1099 * mono_assembly_get_assemblyref:
1100 * @image: pointer to the MonoImage to extract the information from.
1101 * @index: index to the assembly reference in the image.
1102 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1104 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1107 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1110 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1113 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1115 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1117 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1118 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1119 aname->hash_value = hash;
1120 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1121 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1122 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1123 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1124 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1125 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1126 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1128 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1129 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1130 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1133 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1138 mono_assembly_load_reference (MonoImage *image, int index)
1140 MonoAssembly *reference;
1141 MonoAssemblyName aname;
1142 MonoImageOpenStatus status;
1145 * image->references is shared between threads, so we need to access
1146 * it inside a critical section.
1148 mono_assemblies_lock ();
1149 if (!image->references) {
1150 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1152 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1153 image->nreferences = t->rows;
1155 reference = image->references [index];
1156 mono_assemblies_unlock ();
1160 mono_assembly_get_assemblyref (image, index, &aname);
1162 if (image->assembly && image->assembly->ref_only) {
1163 /* We use the loaded corlib */
1164 if (!strcmp (aname.name, "mscorlib"))
1165 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1167 reference = mono_assembly_loaded_full (&aname, TRUE);
1169 /* Try a postload search hook */
1170 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1174 * Here we must advice that the error was due to
1175 * a non loaded reference using the ReflectionOnly api
1178 reference = (MonoAssembly *)REFERENCE_MISSING;
1180 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1181 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1182 * accordingly, it would fail on the MS runtime before).
1183 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1184 * example bug-349190.2.cs and who knows how much more code in the wild.
1186 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1187 if (!reference && image->assembly)
1188 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1191 if (reference == NULL){
1194 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1195 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 : "" );
1196 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1197 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1198 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1199 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1200 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1201 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1203 extra_msg = g_strdup ("");
1206 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1207 " Assembly: %s (assemblyref_index=%d)\n"
1208 " Version: %d.%d.%d.%d\n"
1209 " Public Key: %s\n%s",
1210 image->name, aname.name, index,
1211 aname.major, aname.minor, aname.build, aname.revision,
1212 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1217 mono_assemblies_lock ();
1218 if (reference == NULL) {
1219 /* Flag as not found */
1220 reference = (MonoAssembly *)REFERENCE_MISSING;
1223 if (!image->references [index]) {
1224 if (reference != REFERENCE_MISSING){
1225 mono_assembly_addref (reference);
1226 if (image->assembly)
1227 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1228 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1230 if (image->assembly)
1231 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1232 image->assembly->aname.name, image->assembly);
1235 image->references [index] = reference;
1237 mono_assemblies_unlock ();
1239 if (image->references [index] != reference) {
1240 /* Somebody loaded it before us */
1241 mono_assembly_close (reference);
1246 * mono_assembly_load_references:
1249 * @deprecated: There is no reason to use this method anymore, it does nothing
1251 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1254 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1256 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1257 *status = MONO_IMAGE_OK;
1260 typedef struct AssemblyLoadHook AssemblyLoadHook;
1261 struct AssemblyLoadHook {
1262 AssemblyLoadHook *next;
1263 MonoAssemblyLoadFunc func;
1267 AssemblyLoadHook *assembly_load_hook = NULL;
1270 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1272 AssemblyLoadHook *hook;
1274 for (hook = assembly_load_hook; hook; hook = hook->next) {
1275 hook->func (ass, hook->user_data);
1280 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1282 AssemblyLoadHook *hook;
1284 g_return_if_fail (func != NULL);
1286 hook = g_new0 (AssemblyLoadHook, 1);
1288 hook->user_data = user_data;
1289 hook->next = assembly_load_hook;
1290 assembly_load_hook = hook;
1294 free_assembly_load_hooks (void)
1296 AssemblyLoadHook *hook, *next;
1298 for (hook = assembly_load_hook; hook; hook = next) {
1304 typedef struct AssemblySearchHook AssemblySearchHook;
1305 struct AssemblySearchHook {
1306 AssemblySearchHook *next;
1307 MonoAssemblySearchFunc func;
1313 AssemblySearchHook *assembly_search_hook = NULL;
1315 static MonoAssembly*
1316 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1318 AssemblySearchHook *hook;
1320 for (hook = assembly_search_hook; hook; hook = hook->next) {
1321 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1324 * A little explanation is in order here.
1326 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1327 * The embedding API exposes a search hook that doesn't take such argument.
1329 * The original fix would call the default search hook before all the registered ones and pass
1330 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1331 * rely on. Which is the ordering between user hooks and the default runtime hook.
1333 * Registering the hook after mono_jit_init would let your hook run before the default one and
1334 * when using it to handle non standard app layouts this could save your app from a massive amount
1335 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1336 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1338 * So what's the fix? We register the default hook using regular means and special case it when iterating
1339 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1342 if (hook->func == (void*)mono_domain_assembly_postload_search)
1343 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1345 ass = hook->func (aname, hook->user_data);
1355 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1357 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1361 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1363 AssemblySearchHook *hook;
1365 g_return_if_fail (func != NULL);
1367 hook = g_new0 (AssemblySearchHook, 1);
1369 hook->user_data = user_data;
1370 hook->refonly = refonly;
1371 hook->postload = postload;
1372 hook->next = assembly_search_hook;
1373 assembly_search_hook = hook;
1377 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1379 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1383 free_assembly_search_hooks (void)
1385 AssemblySearchHook *hook, *next;
1387 for (hook = assembly_search_hook; hook; hook = next) {
1394 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1396 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1400 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1402 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1406 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1408 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1411 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1412 struct AssemblyPreLoadHook {
1413 AssemblyPreLoadHook *next;
1414 MonoAssemblyPreLoadFunc func;
1418 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1419 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1421 static MonoAssembly *
1422 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1424 AssemblyPreLoadHook *hook;
1425 MonoAssembly *assembly;
1427 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1428 assembly = hook->func (aname, assemblies_path, hook->user_data);
1429 if (assembly != NULL)
1436 static MonoAssembly *
1437 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1439 AssemblyPreLoadHook *hook;
1440 MonoAssembly *assembly;
1442 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1443 assembly = hook->func (aname, assemblies_path, hook->user_data);
1444 if (assembly != NULL)
1452 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1454 AssemblyPreLoadHook *hook;
1456 g_return_if_fail (func != NULL);
1458 hook = g_new0 (AssemblyPreLoadHook, 1);
1460 hook->user_data = user_data;
1461 hook->next = assembly_preload_hook;
1462 assembly_preload_hook = hook;
1466 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1468 AssemblyPreLoadHook *hook;
1470 g_return_if_fail (func != NULL);
1472 hook = g_new0 (AssemblyPreLoadHook, 1);
1474 hook->user_data = user_data;
1475 hook->next = assembly_refonly_preload_hook;
1476 assembly_refonly_preload_hook = hook;
1480 free_assembly_preload_hooks (void)
1482 AssemblyPreLoadHook *hook, *next;
1484 for (hook = assembly_preload_hook; hook; hook = next) {
1489 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1496 absolute_dir (const gchar *filename)
1507 if (g_path_is_absolute (filename)) {
1508 part = g_path_get_dirname (filename);
1509 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1514 cwd = g_get_current_dir ();
1515 mixed = g_build_filename (cwd, filename, NULL);
1516 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1521 for (i = 0; (part = parts [i]) != NULL; i++) {
1522 if (!strcmp (part, "."))
1525 if (!strcmp (part, "..")) {
1526 if (list && list->next) /* Don't remove root */
1527 list = g_list_delete_link (list, list);
1529 list = g_list_prepend (list, part);
1533 result = g_string_new ("");
1534 list = g_list_reverse (list);
1536 /* Ignores last data pointer, which should be the filename */
1537 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1539 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1544 g_string_free (result, FALSE);
1549 return g_strdup (".");
1556 * mono_assembly_open_from_bundle:
1557 * @filename: Filename requested
1558 * @status: return status code
1560 * This routine tries to open the assembly specified by `filename' from the
1561 * defined bundles, if found, returns the MonoImage for it, if not found
1565 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1569 gchar *lowercase_filename;
1570 MonoImage *image = NULL;
1571 gboolean is_satellite = FALSE;
1573 * we do a very simple search for bundled assemblies: it's not a general
1574 * purpose assembly loading mechanism.
1580 lowercase_filename = g_utf8_strdown (filename, -1);
1581 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1582 g_free (lowercase_filename);
1583 name = g_path_get_basename (filename);
1584 mono_assemblies_lock ();
1585 for (i = 0; !image && bundles [i]; ++i) {
1586 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1587 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1591 mono_assemblies_unlock ();
1593 mono_image_addref (image);
1594 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1603 * mono_assemblies_open_full:
1604 * @filename: the file to load
1605 * @status: return status code
1606 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1608 * This loads an assembly from the specified @filename. The @filename allows
1609 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1610 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1611 * is treated as a local path.
1613 * First, an attempt is made to load the assembly from the bundled executable (for those
1614 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1615 * assembly has been registered as an embedded assembly). If this is not the case, then
1616 * the assembly is loaded from disk using `api:mono_image_open_full`.
1618 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1619 * the assembly is made.
1621 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1622 * the `System.Reflection` API.
1624 * Returns: NULL on error, with the @status set to an error code, or a pointer
1628 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1632 MonoImageOpenStatus def_status;
1635 gboolean loaded_from_bundle;
1637 g_return_val_if_fail (filename != NULL, NULL);
1640 status = &def_status;
1641 *status = MONO_IMAGE_OK;
1643 if (strncmp (filename, "file://", 7) == 0) {
1644 GError *error = NULL;
1645 gchar *uri = (gchar *) filename;
1649 * MS allows file://c:/... and fails on file://localhost/c:/...
1650 * They also throw an IndexOutOfRangeException if "file://"
1653 uri = g_strdup_printf ("file:///%s", uri + 7);
1656 uri = mono_escape_uri_string (tmpuri);
1657 fname = g_filename_from_uri (uri, NULL, &error);
1660 if (tmpuri != filename)
1663 if (error != NULL) {
1664 g_warning ("%s\n", error->message);
1665 g_error_free (error);
1666 fname = g_strdup (filename);
1669 fname = g_strdup (filename);
1672 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1673 "Assembly Loader probing location: '%s'.", fname);
1676 if (!mono_assembly_is_in_gac (fname)) {
1678 new_fname = mono_make_shadow_copy (fname, &error);
1679 if (!is_ok (&error)) {
1680 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1681 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1682 mono_error_cleanup (&error);
1683 *status = MONO_IMAGE_IMAGE_INVALID;
1688 if (new_fname && new_fname != fname) {
1691 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1692 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1697 // If VM built with mkbundle
1698 loaded_from_bundle = FALSE;
1699 if (bundles != NULL) {
1700 image = mono_assembly_open_from_bundle (fname, status, refonly);
1701 loaded_from_bundle = image != NULL;
1705 image = mono_image_open_full (fname, status, refonly);
1708 if (*status == MONO_IMAGE_OK)
1709 *status = MONO_IMAGE_ERROR_ERRNO;
1714 if (image->assembly) {
1715 /* Already loaded by another appdomain */
1716 mono_assembly_invoke_load_hook (image->assembly);
1717 mono_image_close (image);
1719 return image->assembly;
1722 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1725 if (!loaded_from_bundle)
1726 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1727 "Assembly Loader loaded assembly from location: '%s'.", filename);
1729 mono_config_for_assembly (ass->image);
1732 /* Clear the reference added by mono_image_open */
1733 mono_image_close (image);
1741 free_item (gpointer val, gpointer user_data)
1747 * mono_assembly_load_friends:
1750 * Load the list of friend assemblies that are allowed to access
1751 * the assembly's internal types and members. They are stored as assembly
1752 * names in custom attributes.
1754 * This is an internal method, we need this because when we load mscorlib
1755 * we do not have the internals visible cattr loaded yet,
1756 * so we need to load these after we initialize the runtime.
1758 * LOCKING: Acquires the assemblies lock plus the loader lock.
1761 mono_assembly_load_friends (MonoAssembly* ass)
1765 MonoCustomAttrInfo* attrs;
1768 if (ass->friend_assembly_names_inited)
1771 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1772 mono_error_assert_ok (&error);
1774 mono_assemblies_lock ();
1775 ass->friend_assembly_names_inited = TRUE;
1776 mono_assemblies_unlock ();
1780 mono_assemblies_lock ();
1781 if (ass->friend_assembly_names_inited) {
1782 mono_assemblies_unlock ();
1785 mono_assemblies_unlock ();
1789 * We build the list outside the assemblies lock, the worse that can happen
1790 * is that we'll need to free the allocated list.
1792 for (i = 0; i < attrs->num_attrs; ++i) {
1793 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1794 MonoAssemblyName *aname;
1796 /* Do some sanity checking */
1797 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1799 if (attr->data_size < 4)
1801 data = (const char*)attr->data;
1802 /* 0xFF means null string, see custom attr format */
1803 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1805 mono_metadata_decode_value (data + 2, &data);
1806 aname = g_new0 (MonoAssemblyName, 1);
1807 /*g_print ("friend ass: %s\n", data);*/
1808 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1809 list = g_slist_prepend (list, aname);
1814 mono_custom_attrs_free (attrs);
1816 mono_assemblies_lock ();
1817 if (ass->friend_assembly_names_inited) {
1818 mono_assemblies_unlock ();
1819 g_slist_foreach (list, free_item, NULL);
1820 g_slist_free (list);
1823 ass->friend_assembly_names = list;
1825 /* Because of the double checked locking pattern above */
1826 mono_memory_barrier ();
1827 ass->friend_assembly_names_inited = TRUE;
1828 mono_assemblies_unlock ();
1833 * mono_assembly_has_reference_assembly_attribute:
1834 * @assembly: a MonoAssembly
1835 * @error: set on error.
1837 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1838 * On error returns FALSE and sets @error.
1841 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1843 mono_error_init (error);
1845 MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
1846 return_val_if_nok (error, FALSE);
1849 MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
1850 g_assert (ref_asm_class != NULL && ref_asm_class != mono_defaults.object_class && !strcmp(ref_asm_class->name, "ReferenceAssemblyAttribute") );
1851 gboolean result = mono_custom_attrs_has_attr (attrs, ref_asm_class);
1852 mono_custom_attrs_free (attrs);
1857 * mono_assembly_open:
1858 * @filename: Opens the assembly pointed out by this name
1859 * @status: return status code
1861 * This loads an assembly from the specified @filename. The @filename allows
1862 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1863 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1864 * is treated as a local path.
1866 * First, an attempt is made to load the assembly from the bundled executable (for those
1867 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1868 * assembly has been registered as an embedded assembly). If this is not the case, then
1869 * the assembly is loaded from disk using `api:mono_image_open_full`.
1871 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1872 * the assembly is made.
1874 * Return: a pointer to the MonoAssembly if @filename contains a valid
1875 * assembly or NULL on error. Details about the error are stored in the
1879 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1881 return mono_assembly_open_full (filename, status, FALSE);
1885 * mono_assembly_load_from_full:
1886 * @image: Image to load the assembly from
1887 * @fname: assembly name to associate with the assembly
1888 * @status: returns the status condition
1889 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1891 * If the provided @image has an assembly reference, it will process the given
1892 * image as an assembly with the given name.
1894 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1896 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1897 * set to #MONO_IMAGE_OK; or NULL on error.
1899 * If there is an error loading the assembly the @status will indicate the
1900 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1901 * image did not contain an assembly reference table.
1904 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1905 MonoImageOpenStatus *status, gboolean refonly)
1907 MonoAssembly *ass, *ass2;
1910 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1911 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1912 *status = MONO_IMAGE_IMAGE_INVALID;
1916 #if defined (HOST_WIN32)
1921 tmp_fn = g_strdup (fname);
1922 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1923 if (tmp_fn [i] == '/')
1927 base_dir = absolute_dir (tmp_fn);
1931 base_dir = absolute_dir (fname);
1935 * Create assembly struct, and enter it into the assembly cache
1937 ass = g_new0 (MonoAssembly, 1);
1938 ass->basedir = base_dir;
1939 ass->ref_only = refonly;
1942 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1944 mono_assembly_fill_assembly_name (image, &ass->aname);
1946 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1947 // MS.NET doesn't support loading other mscorlibs
1950 mono_image_addref (mono_defaults.corlib);
1951 *status = MONO_IMAGE_OK;
1952 return mono_defaults.corlib->assembly;
1955 /* Add a non-temporary reference because of ass->image */
1956 mono_image_addref (image);
1958 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);
1961 * The load hooks might take locks so we can't call them while holding the
1964 if (ass->aname.name) {
1965 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1969 mono_image_close (image);
1970 *status = MONO_IMAGE_OK;
1975 mono_assemblies_lock ();
1977 if (image->assembly) {
1979 * This means another thread has already loaded the assembly, but not yet
1980 * called the load hooks so the search hook can't find the assembly.
1982 mono_assemblies_unlock ();
1983 ass2 = image->assembly;
1986 mono_image_close (image);
1987 *status = MONO_IMAGE_OK;
1991 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
1993 /* We need to check for ReferenceAssmeblyAttribute before we
1994 * mark the assembly as loaded and before we fire the load
1995 * hook. Otherwise mono_domain_fire_assembly_load () in
1996 * appdomain.c will cache a mapping from the assembly name to
1997 * this image and we won't be able to look for a different
2000 if (!refonly && strcmp (ass->aname.name, "mscorlib") != 0) {
2001 /* Don't check for reference assmebly attribute for
2002 * corlib here because if corlib isn't loaded yet,
2003 * it's too early to set up the
2004 * ReferenceAssemblyAttribute class. We check that
2005 * we're not running with a reference corlib in
2006 * mono_init_internal().
2008 MonoError refasm_error;
2009 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2010 mono_assemblies_unlock ();
2011 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2014 mono_image_close (image);
2015 *status = MONO_IMAGE_IMAGE_INVALID;
2018 mono_error_cleanup (&refasm_error);
2021 image->assembly = ass;
2023 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2024 mono_assemblies_unlock ();
2027 if (image->is_module_handle)
2028 mono_image_fixup_vtable (image);
2031 mono_assembly_invoke_load_hook (ass);
2033 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2039 * mono_assembly_load_from:
2040 * @image: Image to load the assembly from
2041 * @fname: assembly name to associate with the assembly
2042 * @status: return status code
2044 * If the provided @image has an assembly reference, it will process the given
2045 * image as an assembly with the given name.
2047 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2049 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2050 * @refonly parameter set to FALSE.
2051 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2052 * set to #MONO_IMAGE_OK; or NULL on error.
2054 * If there is an error loading the assembly the @status will indicate the
2055 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2056 * image did not contain an assembly reference table.
2060 mono_assembly_load_from (MonoImage *image, const char *fname,
2061 MonoImageOpenStatus *status)
2063 return mono_assembly_load_from_full (image, fname, status, FALSE);
2067 * mono_assembly_name_free:
2068 * @aname: assembly name to free
2070 * Frees the provided assembly name object.
2071 * (it does not frees the object itself, only the name members).
2074 mono_assembly_name_free (MonoAssemblyName *aname)
2079 g_free ((void *) aname->name);
2080 g_free ((void *) aname->culture);
2081 g_free ((void *) aname->hash_value);
2082 g_free ((guint8*) aname->public_key);
2086 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2089 gchar header [16], val, *arr;
2090 gint i, j, offset, bitlen, keylen, pkeylen;
2092 keylen = strlen (key) >> 1;
2096 /* allow the ECMA standard key */
2097 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2099 *pubkey = g_strdup (key);
2105 val = g_ascii_xdigit_value (key [0]) << 4;
2106 val |= g_ascii_xdigit_value (key [1]);
2111 val = g_ascii_xdigit_value (key [24]);
2112 val |= g_ascii_xdigit_value (key [25]);
2124 /* We need the first 16 bytes
2125 * to check whether this key is valid or not */
2126 pkeylen = strlen (pkey) >> 1;
2130 for (i = 0, j = 0; i < 16; i++) {
2131 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2132 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2135 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2136 header [1] != 0x02 || /* Version (0x02) */
2137 header [2] != 0x00 || /* Reserved (word) */
2138 header [3] != 0x00 ||
2139 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2142 /* Based on this length, we _should_ be able to know if the length is right */
2143 bitlen = read32 (header + 12) >> 3;
2144 if ((bitlen + 16 + 4) != pkeylen)
2147 /* parsing is OK and the public key itself is not requested back */
2151 /* Encode the size of the blob */
2153 if (keylen <= 127) {
2154 arr = (gchar *)g_malloc (keylen + 1);
2155 arr [offset++] = keylen;
2157 arr = (gchar *)g_malloc (keylen + 2);
2158 arr [offset++] = 0x80; /* 10bs */
2159 arr [offset++] = keylen;
2162 for (i = offset, j = 0; i < keylen + offset; i++) {
2163 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2164 arr [i] |= g_ascii_xdigit_value (key [j++]);
2173 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)
2175 gint major, minor, build, revision;
2178 gchar *pkey, *pkeyptr, *encoded, tok [8];
2180 memset (aname, 0, sizeof (MonoAssemblyName));
2183 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2184 if (version_parts < 2 || version_parts > 4)
2187 /* FIXME: we should set build & revision to -1 (instead of 0)
2188 if these are not set in the version string. That way, later on,
2189 we can still determine if these were specified. */
2190 aname->major = major;
2191 aname->minor = minor;
2192 if (version_parts >= 3)
2193 aname->build = build;
2196 if (version_parts == 4)
2197 aname->revision = revision;
2199 aname->revision = 0;
2202 aname->flags = flags;
2204 aname->name = g_strdup (name);
2207 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2208 aname->culture = g_strdup ("");
2210 aname->culture = g_strdup (culture);
2213 if (token && strncmp (token, "null", 4) != 0) {
2216 /* the constant includes the ending NULL, hence the -1 */
2217 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2218 mono_assembly_name_free (aname);
2221 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2222 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2228 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2229 mono_assembly_name_free (aname);
2234 if (save_public_key)
2235 aname->public_key = (guint8*)pkey;
2238 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2242 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2243 // We also need to generate the key token
2244 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2245 encoded = encode_public_tok ((guchar*) tok, 8);
2246 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2249 if (save_public_key)
2250 aname->public_key = (guint8*) pkey;
2259 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2264 parts = g_strsplit (dirname, "_", 3);
2265 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2270 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2276 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2278 char *eqsign = strchr (pair, '=');
2286 *key = (gchar*)pair;
2287 *keylen = eqsign - *key;
2288 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2290 *value = g_strstrip (eqsign + 1);
2295 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2299 gchar *version = NULL;
2301 gchar *culture = NULL;
2303 gchar *token = NULL;
2307 gchar *retargetable = NULL;
2308 gchar *retargetable_uq;
2312 gchar *value, *part_name;
2313 guint32 part_name_len;
2316 gboolean version_defined;
2317 gboolean token_defined;
2319 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2321 if (!is_version_defined)
2322 is_version_defined = &version_defined;
2323 *is_version_defined = FALSE;
2324 if (!is_token_defined)
2325 is_token_defined = &token_defined;
2326 *is_token_defined = FALSE;
2328 parts = tmp = g_strsplit (name, ",", 6);
2329 if (!tmp || !*tmp) {
2334 dllname = g_strstrip (*tmp);
2339 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2340 goto cleanup_and_fail;
2342 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2343 *is_version_defined = TRUE;
2345 if (strlen (version) == 0) {
2346 goto cleanup_and_fail;
2352 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2354 if (strlen (culture) == 0) {
2355 goto cleanup_and_fail;
2361 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2362 *is_token_defined = TRUE;
2364 if (strlen (token) == 0) {
2365 goto cleanup_and_fail;
2371 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2373 if (strlen (key) == 0) {
2374 goto cleanup_and_fail;
2380 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2381 retargetable = value;
2382 retargetable_uq = unquote (retargetable);
2383 if (retargetable_uq != NULL)
2384 retargetable = retargetable_uq;
2386 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2387 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2388 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2389 g_free (retargetable_uq);
2390 goto cleanup_and_fail;
2393 g_free (retargetable_uq);
2398 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2400 procarch_uq = unquote (procarch);
2401 if (procarch_uq != NULL)
2402 procarch = procarch_uq;
2404 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2405 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2406 else if (!g_ascii_strcasecmp (procarch, "X86"))
2407 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2408 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2409 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2410 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2411 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2413 g_free (procarch_uq);
2414 goto cleanup_and_fail;
2417 g_free (procarch_uq);
2426 /* if retargetable flag is set, then we must have a fully qualified name */
2427 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2428 goto cleanup_and_fail;
2431 dllname_uq = unquote (dllname);
2432 version_uq = unquote (version);
2433 culture_uq = unquote (culture);
2434 token_uq = unquote (token);
2435 key_uq = unquote (key);
2437 res = build_assembly_name (
2438 dllname_uq == NULL ? dllname : dllname_uq,
2439 version_uq == NULL ? version : version_uq,
2440 culture_uq == NULL ? culture : culture_uq,
2441 token_uq == NULL ? token : token_uq,
2442 key_uq == NULL ? key : key_uq,
2443 flags, arch, aname, save_public_key);
2445 g_free (dllname_uq);
2446 g_free (version_uq);
2447 g_free (culture_uq);
2460 unquote (const char *str)
2468 slen = strlen (str);
2472 if (*str != '\'' && *str != '\"')
2475 end = str + slen - 1;
2479 return g_strndup (str + 1, slen - 2);
2483 * mono_assembly_name_parse:
2484 * @name: name to parse
2485 * @aname: the destination assembly name
2487 * Parses an assembly qualified type name and assigns the name,
2488 * version, culture and token to the provided assembly name object.
2490 * Returns: TRUE if the name could be parsed.
2493 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2495 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2499 * mono_assembly_name_new:
2500 * @name: name to parse
2502 * Allocate a new MonoAssemblyName and fill its values from the
2505 * Returns: a newly allocated structure or NULL if there was any failure.
2508 mono_assembly_name_new (const char *name)
2510 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2511 if (mono_assembly_name_parse (name, aname))
2518 mono_assembly_name_get_name (MonoAssemblyName *aname)
2524 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2526 return aname->culture;
2530 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2532 if (aname->public_key_token [0])
2533 return aname->public_key_token;
2538 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2541 *minor = aname->minor;
2543 *build = aname->build;
2545 *revision = aname->revision;
2546 return aname->major;
2549 static MonoAssembly*
2550 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2552 gchar *fullpath = NULL;
2554 const char* direntry;
2555 MonoAssemblyName gac_aname;
2556 gint major=-1, minor=0, build=0, revision=0;
2557 gboolean exact_version;
2559 dirhandle = g_dir_open (basepath, 0, NULL);
2563 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2565 while ((direntry = g_dir_read_name (dirhandle))) {
2566 gboolean match = TRUE;
2568 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2571 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2574 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2575 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2579 if (exact_version) {
2580 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2581 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2583 else if (gac_aname.major < major)
2585 else if (gac_aname.major == major) {
2586 if (gac_aname.minor < minor)
2588 else if (gac_aname.minor == minor) {
2589 if (gac_aname.build < build)
2591 else if (gac_aname.build == build && gac_aname.revision <= revision)
2598 major = gac_aname.major;
2599 minor = gac_aname.minor;
2600 build = gac_aname.build;
2601 revision = gac_aname.revision;
2603 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2606 mono_assembly_name_free (&gac_aname);
2609 g_dir_close (dirhandle);
2611 if (fullpath == NULL)
2614 MonoAssembly *res = mono_assembly_open (fullpath, status);
2621 * mono_assembly_load_with_partial_name:
2622 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2623 * @status: return status code
2625 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2626 * so it might contain a qualified type name, version, culture and token.
2628 * This will load the assembly from the file whose name is derived from the assembly name
2629 * by appending the .dll extension.
2631 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2632 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2633 * if that fails from the GAC.
2635 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2638 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2642 MonoAssemblyName *aname, base_name;
2643 MonoAssemblyName mapped_aname;
2644 gchar *fullname, *gacpath;
2647 memset (&base_name, 0, sizeof (MonoAssemblyName));
2650 if (!mono_assembly_name_parse (name, aname))
2654 * If no specific version has been requested, make sure we load the
2655 * correct version for system assemblies.
2657 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2658 aname = mono_assembly_remap_version (aname, &mapped_aname);
2660 res = mono_assembly_loaded (aname);
2662 mono_assembly_name_free (aname);
2666 res = invoke_assembly_preload_hook (aname, assemblies_path);
2668 res->in_gac = FALSE;
2669 mono_assembly_name_free (aname);
2673 fullname = g_strdup_printf ("%s.dll", aname->name);
2675 if (extra_gac_paths) {
2676 paths = extra_gac_paths;
2677 while (!res && *paths) {
2678 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2679 res = probe_for_partial_name (gacpath, fullname, aname, status);
2688 mono_assembly_name_free (aname);
2692 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2693 res = probe_for_partial_name (gacpath, fullname, aname, status);
2699 MonoDomain *domain = mono_domain_get ();
2700 MonoReflectionAssembly *refasm;
2702 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2703 if (!is_ok (&error)) {
2705 mono_assembly_name_free (aname);
2706 mono_error_cleanup (&error);
2707 if (*status == MONO_IMAGE_OK)
2708 *status = MONO_IMAGE_IMAGE_INVALID;
2712 res = refasm->assembly;
2716 mono_assembly_name_free (aname);
2722 mono_assembly_is_in_gac (const gchar *filename)
2724 const gchar *rootdir;
2728 if (filename == NULL)
2731 for (paths = extra_gac_paths; paths && *paths; paths++) {
2732 if (strstr (*paths, filename) != *paths)
2735 gp = (gchar *) (filename + strlen (*paths));
2736 if (*gp != G_DIR_SEPARATOR)
2739 if (strncmp (gp, "lib", 3))
2742 if (*gp != G_DIR_SEPARATOR)
2745 if (strncmp (gp, "mono", 4))
2748 if (*gp != G_DIR_SEPARATOR)
2751 if (strncmp (gp, "gac", 3))
2754 if (*gp != G_DIR_SEPARATOR)
2760 rootdir = mono_assembly_getrootdir ();
2761 if (strstr (filename, rootdir) != filename)
2764 gp = (gchar *) (filename + strlen (rootdir));
2765 if (*gp != G_DIR_SEPARATOR)
2768 if (strncmp (gp, "mono", 4))
2771 if (*gp != G_DIR_SEPARATOR)
2774 if (strncmp (gp, "gac", 3))
2777 if (*gp != G_DIR_SEPARATOR)
2783 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2786 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2790 if (strstr (aname->name, ".dll")) {
2791 len = strlen (aname->name) - 4;
2792 name = (gchar *)g_malloc (len + 1);
2793 strncpy (name, aname->name, len);
2796 name = g_strdup (aname->name);
2799 culture = g_utf8_strdown (aname->culture, -1);
2801 culture = g_strdup ("");
2803 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2804 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2808 filename = g_strconcat (pname, ".dll", NULL);
2809 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2815 if (extra_gac_paths) {
2816 paths = extra_gac_paths;
2817 while (!image && *paths) {
2818 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2819 "lib", "mono", "gac", subpath, NULL);
2820 image = mono_image_open (fullpath, NULL);
2831 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2832 "mono", "gac", subpath, NULL);
2833 image = mono_image_open (fullpath, NULL);
2840 static MonoAssemblyName*
2841 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2843 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2844 dest_name->major = info->new_version.major;
2845 dest_name->minor = info->new_version.minor;
2846 dest_name->build = info->new_version.build;
2847 dest_name->revision = info->new_version.revision;
2852 /* LOCKING: assembly_binding lock must be held */
2853 static MonoAssemblyBindingInfo*
2854 search_binding_loaded (MonoAssemblyName *aname)
2858 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2859 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2860 if (assembly_binding_maps_name (info, aname))
2867 static inline gboolean
2868 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2870 if (left->major != right->major || left->minor != right->minor ||
2871 left->build != right->build || left->revision != right->revision)
2877 static inline gboolean
2878 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2880 if (left->has_old_version_bottom != right->has_old_version_bottom)
2883 if (left->has_old_version_top != right->has_old_version_top)
2886 if (left->has_new_version != right->has_new_version)
2889 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2892 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2895 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2901 /* LOCKING: assumes all the necessary locks are held */
2903 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2905 MonoAssemblyBindingInfo *info_copy;
2907 MonoAssemblyBindingInfo *info_tmp;
2908 MonoDomain *domain = (MonoDomain*)user_data;
2913 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2914 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2915 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2919 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2920 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2922 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2924 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2926 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2930 get_version_number (int major, int minor)
2932 return major * 256 + minor;
2935 static inline gboolean
2936 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2938 int aname_version_number = get_version_number (aname->major, aname->minor);
2939 if (!info->has_old_version_bottom)
2942 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2945 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2948 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2949 info->major = aname->major;
2950 info->minor = aname->minor;
2955 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2956 static MonoAssemblyBindingInfo*
2957 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2959 MonoAssemblyBindingInfo *info;
2962 if (!domain->assembly_bindings)
2966 for (list = domain->assembly_bindings; list; list = list->next) {
2967 info = (MonoAssemblyBindingInfo *)list->data;
2968 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2974 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2975 info->has_new_version && assembly_binding_maps_name (info, aname))
2976 info->is_valid = TRUE;
2978 info->is_valid = FALSE;
2984 static MonoAssemblyName*
2985 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2988 MonoAssemblyBindingInfo *info, *info2;
2992 if (aname->public_key_token [0] == 0)
2995 domain = mono_domain_get ();
2997 mono_assembly_binding_lock ();
2998 info = search_binding_loaded (aname);
2999 mono_assembly_binding_unlock ();
3002 mono_domain_lock (domain);
3003 info = get_per_domain_assembly_binding_info (domain, aname);
3004 mono_domain_unlock (domain);
3008 if (!check_policy_versions (info, aname))
3011 mono_assembly_bind_version (info, aname, dest_name);
3015 if (domain && domain->setup && domain->setup->configuration_file) {
3016 mono_domain_lock (domain);
3017 if (!domain->assembly_bindings_parsed) {
3018 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3019 /* expect this to succeed because mono_domain_set_options_from_config () did
3020 * the same thing when the domain was created. */
3021 mono_error_assert_ok (&error);
3023 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3025 if (!domain_config_file_path)
3026 domain_config_file_path = domain_config_file_name;
3028 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3029 domain->assembly_bindings_parsed = TRUE;
3030 if (domain_config_file_name != domain_config_file_path)
3031 g_free (domain_config_file_name);
3032 g_free (domain_config_file_path);
3035 info2 = get_per_domain_assembly_binding_info (domain, aname);
3038 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3039 info->name = g_strdup (info2->name);
3040 info->culture = g_strdup (info2->culture);
3041 info->domain_id = domain->domain_id;
3044 mono_domain_unlock (domain);
3048 info = g_new0 (MonoAssemblyBindingInfo, 1);
3049 info->major = aname->major;
3050 info->minor = aname->minor;
3053 if (!info->is_valid) {
3054 ppimage = mono_assembly_load_publisher_policy (aname);
3056 get_publisher_policy_info (ppimage, aname, info);
3057 mono_image_close (ppimage);
3061 /* Define default error value if needed */
3062 if (!info->is_valid) {
3063 info->name = g_strdup (aname->name);
3064 info->culture = g_strdup (aname->culture);
3065 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3068 mono_assembly_binding_lock ();
3069 info2 = search_binding_loaded (aname);
3071 /* This binding was added by another thread
3073 mono_assembly_binding_info_free (info);
3078 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3080 mono_assembly_binding_unlock ();
3082 if (!info->is_valid || !check_policy_versions (info, aname))
3085 mono_assembly_bind_version (info, aname, dest_name);
3090 * mono_assembly_load_from_gac
3092 * @aname: The assembly name object
3094 static MonoAssembly*
3095 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3097 MonoAssembly *result = NULL;
3098 gchar *name, *version, *culture, *fullpath, *subpath;
3103 if (aname->public_key_token [0] == 0) {
3107 if (strstr (aname->name, ".dll")) {
3108 len = strlen (filename) - 4;
3109 name = (gchar *)g_malloc (len + 1);
3110 strncpy (name, aname->name, len);
3113 name = g_strdup (aname->name);
3116 if (aname->culture) {
3117 culture = g_utf8_strdown (aname->culture, -1);
3119 culture = g_strdup ("");
3122 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3123 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3124 aname->minor, aname->build, aname->revision,
3128 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3133 if (extra_gac_paths) {
3134 paths = extra_gac_paths;
3135 while (!result && *paths) {
3136 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3137 result = mono_assembly_open_full (fullpath, status, refonly);
3144 result->in_gac = TRUE;
3149 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3150 "mono", "gac", subpath, NULL);
3151 result = mono_assembly_open_full (fullpath, status, refonly);
3155 result->in_gac = TRUE;
3163 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3166 MonoAssemblyName *aname;
3169 /* g_print ("corlib already loaded\n"); */
3173 // In native client, Corlib is embedded in the executable as static variable corlibData
3174 #if defined(__native_client__)
3175 if (corlibData != NULL && corlibSize != 0) {
3177 /* First "FALSE" instructs mono not to make a copy. */
3178 /* Second "FALSE" says this is not just a ref. */
3179 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3180 if (image == NULL || status != 0)
3181 g_print("mono_image_open_from_data_full failed: %d\n", status);
3182 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3183 if (corlib == NULL || status != 0)
3184 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3190 // A nonstandard preload hook may provide a special mscorlib assembly
3191 aname = mono_assembly_name_new ("mscorlib.dll");
3192 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3193 mono_assembly_name_free (aname);
3196 goto return_corlib_and_facades;
3198 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3199 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3200 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3202 goto return_corlib_and_facades;
3205 /* Normal case: Load corlib from mono/<version> */
3206 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3207 if (assemblies_path) { // Custom assemblies path
3208 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3210 g_free (corlib_file);
3211 goto return_corlib_and_facades;
3214 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3215 g_free (corlib_file);
3217 return_corlib_and_facades:
3218 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3219 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3224 static MonoAssembly*
3225 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3227 MonoError refasm_error;
3228 mono_error_init (&refasm_error);
3229 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3232 mono_error_cleanup (&refasm_error);
3238 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3239 const char *basedir,
3240 MonoImageOpenStatus *status,
3243 MonoAssembly *result;
3244 char *fullpath, *filename;
3245 MonoAssemblyName maped_aname;
3246 MonoAssemblyName maped_name_pp;
3251 aname = mono_assembly_remap_version (aname, &maped_aname);
3253 /* Reflection only assemblies don't get assembly binding */
3255 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3257 result = mono_assembly_loaded_full (aname, refonly);
3261 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3263 result->in_gac = FALSE;
3267 /* Currently we retrieve the loaded corlib for reflection
3268 * only requests, like a common reflection only assembly
3270 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3271 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3274 len = strlen (aname->name);
3275 for (ext_index = 0; ext_index < 2; ext_index ++) {
3276 ext = ext_index == 0 ? ".dll" : ".exe";
3277 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3278 filename = g_strdup (aname->name);
3279 /* Don't try appending .dll/.exe if it already has one of those extensions */
3282 filename = g_strconcat (aname->name, ext, NULL);
3285 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3292 fullpath = g_build_filename (basedir, filename, NULL);
3293 result = mono_assembly_open_full (fullpath, status, refonly);
3296 result->in_gac = FALSE;
3302 result = load_in_path (filename, default_path, status, refonly);
3304 result->in_gac = FALSE;
3314 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3316 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3319 /* Try a postload search hook */
3320 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3321 result = prevent_reference_assembly_from_running (result, refonly);
3327 * mono_assembly_load_full:
3328 * @aname: A MonoAssemblyName with the assembly name to load.
3329 * @basedir: A directory to look up the assembly at.
3330 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3331 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3333 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3334 * attempts to load the assembly from that directory before probing the standard locations.
3336 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3337 * assembly binding takes place.
3339 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3340 * value pointed by status is updated with an error code.
3343 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3345 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3349 * mono_assembly_load:
3350 * @aname: A MonoAssemblyName with the assembly name to load.
3351 * @basedir: A directory to look up the assembly at.
3352 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3354 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3355 * attempts to load the assembly from that directory before probing the standard locations.
3357 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3358 * value pointed by status is updated with an error code.
3361 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3363 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3367 * mono_assembly_loaded_full:
3368 * @aname: an assembly to look for.
3369 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3371 * This is used to determine if the specified assembly has been loaded
3372 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3373 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3376 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3379 MonoAssemblyName maped_aname;
3381 aname = mono_assembly_remap_version (aname, &maped_aname);
3383 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3389 * mono_assembly_loaded:
3390 * @aname: an assembly to look for.
3392 * This is used to determine if the specified assembly has been loaded
3394 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3395 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3398 mono_assembly_loaded (MonoAssemblyName *aname)
3400 return mono_assembly_loaded_full (aname, FALSE);
3404 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3406 if (assembly == NULL || assembly == REFERENCE_MISSING)
3409 if (assembly_is_dynamic (assembly)) {
3411 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3412 for (i = 0; i < dynimg->image.module_count; ++i)
3413 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3414 mono_dynamic_image_release_gc_roots (dynimg);
3419 * Returns whether mono_assembly_close_finish() must be called as
3420 * well. See comment for mono_image_close_except_pools() for why we
3421 * unload in two steps.
3424 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3427 g_return_val_if_fail (assembly != NULL, FALSE);
3429 if (assembly == REFERENCE_MISSING)
3432 /* Might be 0 already */
3433 if (InterlockedDecrement (&assembly->ref_count) > 0)
3436 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3438 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3440 mono_debug_close_image (assembly->image);
3442 mono_assemblies_lock ();
3443 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3444 mono_assemblies_unlock ();
3446 assembly->image->assembly = NULL;
3448 if (!mono_image_close_except_pools (assembly->image))
3449 assembly->image = NULL;
3451 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3452 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3453 mono_assembly_name_free (fname);
3456 g_slist_free (assembly->friend_assembly_names);
3457 g_free (assembly->basedir);
3459 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3465 mono_assembly_close_finish (MonoAssembly *assembly)
3467 g_assert (assembly && assembly != REFERENCE_MISSING);
3469 if (assembly->image)
3470 mono_image_close_finish (assembly->image);
3472 if (assembly_is_dynamic (assembly)) {
3473 g_free ((char*)assembly->aname.culture);
3480 * mono_assembly_close:
3481 * @assembly: the assembly to release.
3483 * This method releases a reference to the @assembly. The assembly is
3484 * only released when all the outstanding references to it are released.
3487 mono_assembly_close (MonoAssembly *assembly)
3489 if (mono_assembly_close_except_image_pools (assembly))
3490 mono_assembly_close_finish (assembly);
3494 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3497 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3498 mono_error_assert_ok (&error);
3503 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3505 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3510 * mono_assembly_foreach:
3511 * @func: function to invoke for each assembly loaded
3512 * @user_data: data passed to the callback
3514 * Invokes the provided @func callback for each assembly loaded into
3515 * the runtime. The first parameter passed to the callback is the
3516 * `MonoAssembly*`, and the second parameter is the @user_data.
3518 * This is done for all assemblies loaded in the runtime, not just
3519 * those loaded in the current application domain.
3522 mono_assembly_foreach (GFunc func, gpointer user_data)
3527 * We make a copy of the list to avoid calling the callback inside the
3528 * lock, which could lead to deadlocks.
3530 mono_assemblies_lock ();
3531 copy = g_list_copy (loaded_assemblies);
3532 mono_assemblies_unlock ();
3534 g_list_foreach (loaded_assemblies, func, user_data);
3540 * mono_assemblies_cleanup:
3542 * Free all resources used by this module.
3545 mono_assemblies_cleanup (void)
3549 mono_os_mutex_destroy (&assemblies_mutex);
3550 mono_os_mutex_destroy (&assembly_binding_mutex);
3552 for (l = loaded_assembly_bindings; l; l = l->next) {
3553 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3555 mono_assembly_binding_info_free (info);
3558 g_slist_free (loaded_assembly_bindings);
3560 free_assembly_load_hooks ();
3561 free_assembly_search_hooks ();
3562 free_assembly_preload_hooks ();
3565 /*LOCKING takes the assembly_binding lock*/
3567 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3571 mono_assembly_binding_lock ();
3572 iter = &loaded_assembly_bindings;
3575 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3577 if (info->domain_id == domain_id) {
3579 mono_assembly_binding_info_free (info);
3586 mono_assembly_binding_unlock ();
3590 * Holds the assembly of the application, for
3591 * System.Diagnostics.Process::MainModule
3593 static MonoAssembly *main_assembly=NULL;
3596 mono_assembly_set_main (MonoAssembly *assembly)
3598 main_assembly = assembly;
3602 * mono_assembly_get_main:
3604 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3607 mono_assembly_get_main (void)
3609 return (main_assembly);
3613 * mono_assembly_get_image:
3614 * @assembly: The assembly to retrieve the image from
3616 * Returns: the MonoImage associated with this assembly.
3619 mono_assembly_get_image (MonoAssembly *assembly)
3621 return assembly->image;
3625 * mono_assembly_get_name:
3626 * @assembly: The assembly to retrieve the name from
3628 * The returned name's lifetime is the same as @assembly's.
3630 * Returns: the MonoAssemblyName associated with this assembly.
3633 mono_assembly_get_name (MonoAssembly *assembly)
3635 return &assembly->aname;
3639 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3641 bundles = assemblies;
3644 #define MONO_DECLSEC_FORMAT_10 0x3C
3645 #define MONO_DECLSEC_FORMAT_20 0x2E
3646 #define MONO_DECLSEC_FIELD 0x53
3647 #define MONO_DECLSEC_PROPERTY 0x54
3649 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3650 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3651 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3652 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3653 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3656 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3660 case MONO_DECLSEC_PROPERTY:
3662 case MONO_DECLSEC_FIELD:
3664 *abort_decoding = TRUE;
3669 if (*p++ != MONO_TYPE_BOOLEAN) {
3670 *abort_decoding = TRUE;
3674 /* property name length */
3675 len = mono_metadata_decode_value (p, &p);
3677 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3688 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3690 int i, j, num, len, params_len;
3692 if (*p == MONO_DECLSEC_FORMAT_10) {
3693 gsize read, written;
3694 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3696 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3702 if (*p++ != MONO_DECLSEC_FORMAT_20)
3705 /* number of encoded permission attributes */
3706 num = mono_metadata_decode_value (p, &p);
3707 for (i = 0; i < num; ++i) {
3708 gboolean is_valid = FALSE;
3709 gboolean abort_decoding = FALSE;
3711 /* attribute name length */
3712 len = mono_metadata_decode_value (p, &p);
3714 /* We don't really need to fully decode the type. Comparing the name is enough */
3715 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3719 /*size of the params table*/
3720 params_len = mono_metadata_decode_value (p, &p);
3722 const char *params_end = p + params_len;
3724 /* number of parameters */
3725 len = mono_metadata_decode_value (p, &p);
3727 for (j = 0; j < len; ++j) {
3728 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3744 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3747 guint32 cols [MONO_DECL_SECURITY_SIZE];
3751 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3752 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3754 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3756 for (i = 0; i < t->rows; ++i) {
3757 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3758 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3760 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3763 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3764 len = mono_metadata_decode_blob_size (blob, &blob);
3768 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3769 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3774 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);