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
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 /* TODO: mono_custom_attrs_from_assembly_checked returns NULL if a
1846 * single assembly is missing. The custom attr we want is from
1847 * corlib, however, so we need a more robust version that doesn't care
1848 * about missing attributes.
1851 MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
1852 return_val_if_nok (error, FALSE);
1855 MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
1856 g_assert (ref_asm_class != NULL && ref_asm_class != mono_defaults.object_class && !strcmp(ref_asm_class->name, "ReferenceAssemblyAttribute") );
1857 gboolean result = mono_custom_attrs_has_attr (attrs, ref_asm_class);
1858 mono_custom_attrs_free (attrs);
1866 * mono_assembly_open:
1867 * @filename: Opens the assembly pointed out by this name
1868 * @status: return status code
1870 * This loads an assembly from the specified @filename. The @filename allows
1871 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1872 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1873 * is treated as a local path.
1875 * First, an attempt is made to load the assembly from the bundled executable (for those
1876 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1877 * assembly has been registered as an embedded assembly). If this is not the case, then
1878 * the assembly is loaded from disk using `api:mono_image_open_full`.
1880 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1881 * the assembly is made.
1883 * Return: a pointer to the MonoAssembly if @filename contains a valid
1884 * assembly or NULL on error. Details about the error are stored in the
1888 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1890 return mono_assembly_open_full (filename, status, FALSE);
1894 * mono_assembly_load_from_full:
1895 * @image: Image to load the assembly from
1896 * @fname: assembly name to associate with the assembly
1897 * @status: returns the status condition
1898 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1900 * If the provided @image has an assembly reference, it will process the given
1901 * image as an assembly with the given name.
1903 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1905 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1906 * set to #MONO_IMAGE_OK; or NULL on error.
1908 * If there is an error loading the assembly the @status will indicate the
1909 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1910 * image did not contain an assembly reference table.
1913 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1914 MonoImageOpenStatus *status, gboolean refonly)
1916 MonoAssembly *ass, *ass2;
1919 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1920 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1921 *status = MONO_IMAGE_IMAGE_INVALID;
1925 #if defined (HOST_WIN32)
1930 tmp_fn = g_strdup (fname);
1931 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1932 if (tmp_fn [i] == '/')
1936 base_dir = absolute_dir (tmp_fn);
1940 base_dir = absolute_dir (fname);
1944 * Create assembly struct, and enter it into the assembly cache
1946 ass = g_new0 (MonoAssembly, 1);
1947 ass->basedir = base_dir;
1948 ass->ref_only = refonly;
1951 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1953 mono_assembly_fill_assembly_name (image, &ass->aname);
1955 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1956 // MS.NET doesn't support loading other mscorlibs
1959 mono_image_addref (mono_defaults.corlib);
1960 *status = MONO_IMAGE_OK;
1961 return mono_defaults.corlib->assembly;
1964 /* Add a non-temporary reference because of ass->image */
1965 mono_image_addref (image);
1967 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);
1970 * The load hooks might take locks so we can't call them while holding the
1973 if (ass->aname.name) {
1974 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1978 mono_image_close (image);
1979 *status = MONO_IMAGE_OK;
1984 mono_assemblies_lock ();
1986 if (image->assembly) {
1988 * This means another thread has already loaded the assembly, but not yet
1989 * called the load hooks so the search hook can't find the assembly.
1991 mono_assemblies_unlock ();
1992 ass2 = image->assembly;
1995 mono_image_close (image);
1996 *status = MONO_IMAGE_OK;
2000 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2002 /* We need to check for ReferenceAssmeblyAttribute before we
2003 * mark the assembly as loaded and before we fire the load
2004 * hook. Otherwise mono_domain_fire_assembly_load () in
2005 * appdomain.c will cache a mapping from the assembly name to
2006 * this image and we won't be able to look for a different
2009 if (!refonly && strcmp (ass->aname.name, "mscorlib") != 0) {
2010 /* Don't check for reference assmebly attribute for
2011 * corlib here because if corlib isn't loaded yet,
2012 * it's too early to set up the
2013 * ReferenceAssemblyAttribute class. We check that
2014 * we're not running with a reference corlib in
2015 * mono_init_internal().
2017 MonoError refasm_error;
2018 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2019 mono_assemblies_unlock ();
2020 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2023 mono_image_close (image);
2024 *status = MONO_IMAGE_IMAGE_INVALID;
2027 mono_error_cleanup (&refasm_error);
2030 image->assembly = ass;
2032 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2033 mono_assemblies_unlock ();
2036 if (image->is_module_handle)
2037 mono_image_fixup_vtable (image);
2040 mono_assembly_invoke_load_hook (ass);
2042 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2048 * mono_assembly_load_from:
2049 * @image: Image to load the assembly from
2050 * @fname: assembly name to associate with the assembly
2051 * @status: return status code
2053 * If the provided @image has an assembly reference, it will process the given
2054 * image as an assembly with the given name.
2056 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2058 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2059 * @refonly parameter set to FALSE.
2060 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2061 * set to #MONO_IMAGE_OK; or NULL on error.
2063 * If there is an error loading the assembly the @status will indicate the
2064 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2065 * image did not contain an assembly reference table.
2069 mono_assembly_load_from (MonoImage *image, const char *fname,
2070 MonoImageOpenStatus *status)
2072 return mono_assembly_load_from_full (image, fname, status, FALSE);
2076 * mono_assembly_name_free:
2077 * @aname: assembly name to free
2079 * Frees the provided assembly name object.
2080 * (it does not frees the object itself, only the name members).
2083 mono_assembly_name_free (MonoAssemblyName *aname)
2088 g_free ((void *) aname->name);
2089 g_free ((void *) aname->culture);
2090 g_free ((void *) aname->hash_value);
2091 g_free ((guint8*) aname->public_key);
2095 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2098 gchar header [16], val, *arr;
2099 gint i, j, offset, bitlen, keylen, pkeylen;
2101 keylen = strlen (key) >> 1;
2105 /* allow the ECMA standard key */
2106 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2108 *pubkey = g_strdup (key);
2114 val = g_ascii_xdigit_value (key [0]) << 4;
2115 val |= g_ascii_xdigit_value (key [1]);
2120 val = g_ascii_xdigit_value (key [24]);
2121 val |= g_ascii_xdigit_value (key [25]);
2133 /* We need the first 16 bytes
2134 * to check whether this key is valid or not */
2135 pkeylen = strlen (pkey) >> 1;
2139 for (i = 0, j = 0; i < 16; i++) {
2140 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2141 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2144 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2145 header [1] != 0x02 || /* Version (0x02) */
2146 header [2] != 0x00 || /* Reserved (word) */
2147 header [3] != 0x00 ||
2148 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2151 /* Based on this length, we _should_ be able to know if the length is right */
2152 bitlen = read32 (header + 12) >> 3;
2153 if ((bitlen + 16 + 4) != pkeylen)
2156 /* parsing is OK and the public key itself is not requested back */
2160 /* Encode the size of the blob */
2162 if (keylen <= 127) {
2163 arr = (gchar *)g_malloc (keylen + 1);
2164 arr [offset++] = keylen;
2166 arr = (gchar *)g_malloc (keylen + 2);
2167 arr [offset++] = 0x80; /* 10bs */
2168 arr [offset++] = keylen;
2171 for (i = offset, j = 0; i < keylen + offset; i++) {
2172 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2173 arr [i] |= g_ascii_xdigit_value (key [j++]);
2182 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)
2184 gint major, minor, build, revision;
2187 gchar *pkey, *pkeyptr, *encoded, tok [8];
2189 memset (aname, 0, sizeof (MonoAssemblyName));
2192 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2193 if (version_parts < 2 || version_parts > 4)
2196 /* FIXME: we should set build & revision to -1 (instead of 0)
2197 if these are not set in the version string. That way, later on,
2198 we can still determine if these were specified. */
2199 aname->major = major;
2200 aname->minor = minor;
2201 if (version_parts >= 3)
2202 aname->build = build;
2205 if (version_parts == 4)
2206 aname->revision = revision;
2208 aname->revision = 0;
2211 aname->flags = flags;
2213 aname->name = g_strdup (name);
2216 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2217 aname->culture = g_strdup ("");
2219 aname->culture = g_strdup (culture);
2222 if (token && strncmp (token, "null", 4) != 0) {
2225 /* the constant includes the ending NULL, hence the -1 */
2226 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2227 mono_assembly_name_free (aname);
2230 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2231 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2237 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2238 mono_assembly_name_free (aname);
2243 if (save_public_key)
2244 aname->public_key = (guint8*)pkey;
2247 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2251 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2252 // We also need to generate the key token
2253 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2254 encoded = encode_public_tok ((guchar*) tok, 8);
2255 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2258 if (save_public_key)
2259 aname->public_key = (guint8*) pkey;
2268 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2273 parts = g_strsplit (dirname, "_", 3);
2274 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2279 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2285 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2287 char *eqsign = strchr (pair, '=');
2295 *key = (gchar*)pair;
2296 *keylen = eqsign - *key;
2297 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2299 *value = g_strstrip (eqsign + 1);
2304 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2308 gchar *version = NULL;
2310 gchar *culture = NULL;
2312 gchar *token = NULL;
2316 gchar *retargetable = NULL;
2317 gchar *retargetable_uq;
2321 gchar *value, *part_name;
2322 guint32 part_name_len;
2325 gboolean version_defined;
2326 gboolean token_defined;
2328 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2330 if (!is_version_defined)
2331 is_version_defined = &version_defined;
2332 *is_version_defined = FALSE;
2333 if (!is_token_defined)
2334 is_token_defined = &token_defined;
2335 *is_token_defined = FALSE;
2337 parts = tmp = g_strsplit (name, ",", 6);
2338 if (!tmp || !*tmp) {
2343 dllname = g_strstrip (*tmp);
2348 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2349 goto cleanup_and_fail;
2351 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2352 *is_version_defined = TRUE;
2354 if (strlen (version) == 0) {
2355 goto cleanup_and_fail;
2361 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2363 if (strlen (culture) == 0) {
2364 goto cleanup_and_fail;
2370 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2371 *is_token_defined = TRUE;
2373 if (strlen (token) == 0) {
2374 goto cleanup_and_fail;
2380 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2382 if (strlen (key) == 0) {
2383 goto cleanup_and_fail;
2389 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2390 retargetable = value;
2391 retargetable_uq = unquote (retargetable);
2392 if (retargetable_uq != NULL)
2393 retargetable = retargetable_uq;
2395 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2396 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2397 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2398 g_free (retargetable_uq);
2399 goto cleanup_and_fail;
2402 g_free (retargetable_uq);
2407 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2409 procarch_uq = unquote (procarch);
2410 if (procarch_uq != NULL)
2411 procarch = procarch_uq;
2413 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2414 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2415 else if (!g_ascii_strcasecmp (procarch, "X86"))
2416 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2417 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2418 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2419 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2420 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2422 g_free (procarch_uq);
2423 goto cleanup_and_fail;
2426 g_free (procarch_uq);
2435 /* if retargetable flag is set, then we must have a fully qualified name */
2436 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2437 goto cleanup_and_fail;
2440 dllname_uq = unquote (dllname);
2441 version_uq = unquote (version);
2442 culture_uq = unquote (culture);
2443 token_uq = unquote (token);
2444 key_uq = unquote (key);
2446 res = build_assembly_name (
2447 dllname_uq == NULL ? dllname : dllname_uq,
2448 version_uq == NULL ? version : version_uq,
2449 culture_uq == NULL ? culture : culture_uq,
2450 token_uq == NULL ? token : token_uq,
2451 key_uq == NULL ? key : key_uq,
2452 flags, arch, aname, save_public_key);
2454 g_free (dllname_uq);
2455 g_free (version_uq);
2456 g_free (culture_uq);
2469 unquote (const char *str)
2477 slen = strlen (str);
2481 if (*str != '\'' && *str != '\"')
2484 end = str + slen - 1;
2488 return g_strndup (str + 1, slen - 2);
2492 * mono_assembly_name_parse:
2493 * @name: name to parse
2494 * @aname: the destination assembly name
2496 * Parses an assembly qualified type name and assigns the name,
2497 * version, culture and token to the provided assembly name object.
2499 * Returns: TRUE if the name could be parsed.
2502 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2504 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2508 * mono_assembly_name_new:
2509 * @name: name to parse
2511 * Allocate a new MonoAssemblyName and fill its values from the
2514 * Returns: a newly allocated structure or NULL if there was any failure.
2517 mono_assembly_name_new (const char *name)
2519 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2520 if (mono_assembly_name_parse (name, aname))
2527 mono_assembly_name_get_name (MonoAssemblyName *aname)
2533 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2535 return aname->culture;
2539 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2541 if (aname->public_key_token [0])
2542 return aname->public_key_token;
2547 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2550 *minor = aname->minor;
2552 *build = aname->build;
2554 *revision = aname->revision;
2555 return aname->major;
2558 static MonoAssembly*
2559 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2561 gchar *fullpath = NULL;
2563 const char* direntry;
2564 MonoAssemblyName gac_aname;
2565 gint major=-1, minor=0, build=0, revision=0;
2566 gboolean exact_version;
2568 dirhandle = g_dir_open (basepath, 0, NULL);
2572 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2574 while ((direntry = g_dir_read_name (dirhandle))) {
2575 gboolean match = TRUE;
2577 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2580 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2583 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2584 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2588 if (exact_version) {
2589 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2590 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2592 else if (gac_aname.major < major)
2594 else if (gac_aname.major == major) {
2595 if (gac_aname.minor < minor)
2597 else if (gac_aname.minor == minor) {
2598 if (gac_aname.build < build)
2600 else if (gac_aname.build == build && gac_aname.revision <= revision)
2607 major = gac_aname.major;
2608 minor = gac_aname.minor;
2609 build = gac_aname.build;
2610 revision = gac_aname.revision;
2612 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2615 mono_assembly_name_free (&gac_aname);
2618 g_dir_close (dirhandle);
2620 if (fullpath == NULL)
2623 MonoAssembly *res = mono_assembly_open (fullpath, status);
2630 * mono_assembly_load_with_partial_name:
2631 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2632 * @status: return status code
2634 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2635 * so it might contain a qualified type name, version, culture and token.
2637 * This will load the assembly from the file whose name is derived from the assembly name
2638 * by appending the .dll extension.
2640 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2641 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2642 * if that fails from the GAC.
2644 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2647 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2651 MonoAssemblyName *aname, base_name;
2652 MonoAssemblyName mapped_aname;
2653 gchar *fullname, *gacpath;
2656 memset (&base_name, 0, sizeof (MonoAssemblyName));
2659 if (!mono_assembly_name_parse (name, aname))
2663 * If no specific version has been requested, make sure we load the
2664 * correct version for system assemblies.
2666 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2667 aname = mono_assembly_remap_version (aname, &mapped_aname);
2669 res = mono_assembly_loaded (aname);
2671 mono_assembly_name_free (aname);
2675 res = invoke_assembly_preload_hook (aname, assemblies_path);
2677 res->in_gac = FALSE;
2678 mono_assembly_name_free (aname);
2682 fullname = g_strdup_printf ("%s.dll", aname->name);
2684 if (extra_gac_paths) {
2685 paths = extra_gac_paths;
2686 while (!res && *paths) {
2687 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2688 res = probe_for_partial_name (gacpath, fullname, aname, status);
2697 mono_assembly_name_free (aname);
2701 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2702 res = probe_for_partial_name (gacpath, fullname, aname, status);
2708 MonoDomain *domain = mono_domain_get ();
2709 MonoReflectionAssembly *refasm;
2711 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2712 if (!is_ok (&error)) {
2714 mono_assembly_name_free (aname);
2715 mono_error_cleanup (&error);
2716 if (*status == MONO_IMAGE_OK)
2717 *status = MONO_IMAGE_IMAGE_INVALID;
2721 res = refasm->assembly;
2725 mono_assembly_name_free (aname);
2731 mono_assembly_is_in_gac (const gchar *filename)
2733 const gchar *rootdir;
2737 if (filename == NULL)
2740 for (paths = extra_gac_paths; paths && *paths; paths++) {
2741 if (strstr (*paths, filename) != *paths)
2744 gp = (gchar *) (filename + strlen (*paths));
2745 if (*gp != G_DIR_SEPARATOR)
2748 if (strncmp (gp, "lib", 3))
2751 if (*gp != G_DIR_SEPARATOR)
2754 if (strncmp (gp, "mono", 4))
2757 if (*gp != G_DIR_SEPARATOR)
2760 if (strncmp (gp, "gac", 3))
2763 if (*gp != G_DIR_SEPARATOR)
2769 rootdir = mono_assembly_getrootdir ();
2770 if (strstr (filename, rootdir) != filename)
2773 gp = (gchar *) (filename + strlen (rootdir));
2774 if (*gp != G_DIR_SEPARATOR)
2777 if (strncmp (gp, "mono", 4))
2780 if (*gp != G_DIR_SEPARATOR)
2783 if (strncmp (gp, "gac", 3))
2786 if (*gp != G_DIR_SEPARATOR)
2792 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2795 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2799 if (strstr (aname->name, ".dll")) {
2800 len = strlen (aname->name) - 4;
2801 name = (gchar *)g_malloc (len + 1);
2802 strncpy (name, aname->name, len);
2805 name = g_strdup (aname->name);
2808 culture = g_utf8_strdown (aname->culture, -1);
2810 culture = g_strdup ("");
2812 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2813 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2817 filename = g_strconcat (pname, ".dll", NULL);
2818 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2824 if (extra_gac_paths) {
2825 paths = extra_gac_paths;
2826 while (!image && *paths) {
2827 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2828 "lib", "mono", "gac", subpath, NULL);
2829 image = mono_image_open (fullpath, NULL);
2840 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2841 "mono", "gac", subpath, NULL);
2842 image = mono_image_open (fullpath, NULL);
2849 static MonoAssemblyName*
2850 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2852 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2853 dest_name->major = info->new_version.major;
2854 dest_name->minor = info->new_version.minor;
2855 dest_name->build = info->new_version.build;
2856 dest_name->revision = info->new_version.revision;
2861 /* LOCKING: assembly_binding lock must be held */
2862 static MonoAssemblyBindingInfo*
2863 search_binding_loaded (MonoAssemblyName *aname)
2867 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2868 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2869 if (assembly_binding_maps_name (info, aname))
2876 static inline gboolean
2877 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2879 if (left->major != right->major || left->minor != right->minor ||
2880 left->build != right->build || left->revision != right->revision)
2886 static inline gboolean
2887 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2889 if (left->has_old_version_bottom != right->has_old_version_bottom)
2892 if (left->has_old_version_top != right->has_old_version_top)
2895 if (left->has_new_version != right->has_new_version)
2898 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2901 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2904 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2910 /* LOCKING: assumes all the necessary locks are held */
2912 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2914 MonoAssemblyBindingInfo *info_copy;
2916 MonoAssemblyBindingInfo *info_tmp;
2917 MonoDomain *domain = (MonoDomain*)user_data;
2922 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2923 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2924 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2928 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2929 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2931 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2933 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2935 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2939 get_version_number (int major, int minor)
2941 return major * 256 + minor;
2944 static inline gboolean
2945 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2947 int aname_version_number = get_version_number (aname->major, aname->minor);
2948 if (!info->has_old_version_bottom)
2951 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2954 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2957 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2958 info->major = aname->major;
2959 info->minor = aname->minor;
2964 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2965 static MonoAssemblyBindingInfo*
2966 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2968 MonoAssemblyBindingInfo *info;
2971 if (!domain->assembly_bindings)
2975 for (list = domain->assembly_bindings; list; list = list->next) {
2976 info = (MonoAssemblyBindingInfo *)list->data;
2977 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2983 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2984 info->has_new_version && assembly_binding_maps_name (info, aname))
2985 info->is_valid = TRUE;
2987 info->is_valid = FALSE;
2993 static MonoAssemblyName*
2994 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2997 MonoAssemblyBindingInfo *info, *info2;
3001 if (aname->public_key_token [0] == 0)
3004 domain = mono_domain_get ();
3006 mono_assembly_binding_lock ();
3007 info = search_binding_loaded (aname);
3008 mono_assembly_binding_unlock ();
3011 mono_domain_lock (domain);
3012 info = get_per_domain_assembly_binding_info (domain, aname);
3013 mono_domain_unlock (domain);
3017 if (!check_policy_versions (info, aname))
3020 mono_assembly_bind_version (info, aname, dest_name);
3024 if (domain && domain->setup && domain->setup->configuration_file) {
3025 mono_domain_lock (domain);
3026 if (!domain->assembly_bindings_parsed) {
3027 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3028 /* expect this to succeed because mono_domain_set_options_from_config () did
3029 * the same thing when the domain was created. */
3030 mono_error_assert_ok (&error);
3032 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3034 if (!domain_config_file_path)
3035 domain_config_file_path = domain_config_file_name;
3037 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3038 domain->assembly_bindings_parsed = TRUE;
3039 if (domain_config_file_name != domain_config_file_path)
3040 g_free (domain_config_file_name);
3041 g_free (domain_config_file_path);
3044 info2 = get_per_domain_assembly_binding_info (domain, aname);
3047 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3048 info->name = g_strdup (info2->name);
3049 info->culture = g_strdup (info2->culture);
3050 info->domain_id = domain->domain_id;
3053 mono_domain_unlock (domain);
3057 info = g_new0 (MonoAssemblyBindingInfo, 1);
3058 info->major = aname->major;
3059 info->minor = aname->minor;
3062 if (!info->is_valid) {
3063 ppimage = mono_assembly_load_publisher_policy (aname);
3065 get_publisher_policy_info (ppimage, aname, info);
3066 mono_image_close (ppimage);
3070 /* Define default error value if needed */
3071 if (!info->is_valid) {
3072 info->name = g_strdup (aname->name);
3073 info->culture = g_strdup (aname->culture);
3074 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3077 mono_assembly_binding_lock ();
3078 info2 = search_binding_loaded (aname);
3080 /* This binding was added by another thread
3082 mono_assembly_binding_info_free (info);
3087 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3089 mono_assembly_binding_unlock ();
3091 if (!info->is_valid || !check_policy_versions (info, aname))
3094 mono_assembly_bind_version (info, aname, dest_name);
3099 * mono_assembly_load_from_gac
3101 * @aname: The assembly name object
3103 static MonoAssembly*
3104 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3106 MonoAssembly *result = NULL;
3107 gchar *name, *version, *culture, *fullpath, *subpath;
3112 if (aname->public_key_token [0] == 0) {
3116 if (strstr (aname->name, ".dll")) {
3117 len = strlen (filename) - 4;
3118 name = (gchar *)g_malloc (len + 1);
3119 strncpy (name, aname->name, len);
3122 name = g_strdup (aname->name);
3125 if (aname->culture) {
3126 culture = g_utf8_strdown (aname->culture, -1);
3128 culture = g_strdup ("");
3131 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3132 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3133 aname->minor, aname->build, aname->revision,
3137 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3142 if (extra_gac_paths) {
3143 paths = extra_gac_paths;
3144 while (!result && *paths) {
3145 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3146 result = mono_assembly_open_full (fullpath, status, refonly);
3153 result->in_gac = TRUE;
3158 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3159 "mono", "gac", subpath, NULL);
3160 result = mono_assembly_open_full (fullpath, status, refonly);
3164 result->in_gac = TRUE;
3172 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3175 MonoAssemblyName *aname;
3178 /* g_print ("corlib already loaded\n"); */
3182 // In native client, Corlib is embedded in the executable as static variable corlibData
3183 #if defined(__native_client__)
3184 if (corlibData != NULL && corlibSize != 0) {
3186 /* First "FALSE" instructs mono not to make a copy. */
3187 /* Second "FALSE" says this is not just a ref. */
3188 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3189 if (image == NULL || status != 0)
3190 g_print("mono_image_open_from_data_full failed: %d\n", status);
3191 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3192 if (corlib == NULL || status != 0)
3193 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3199 // A nonstandard preload hook may provide a special mscorlib assembly
3200 aname = mono_assembly_name_new ("mscorlib.dll");
3201 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3202 mono_assembly_name_free (aname);
3205 goto return_corlib_and_facades;
3207 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3208 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3209 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3211 goto return_corlib_and_facades;
3214 /* Normal case: Load corlib from mono/<version> */
3215 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3216 if (assemblies_path) { // Custom assemblies path
3217 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3219 g_free (corlib_file);
3220 goto return_corlib_and_facades;
3223 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3224 g_free (corlib_file);
3226 return_corlib_and_facades:
3227 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3228 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3233 static MonoAssembly*
3234 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3236 MonoError refasm_error;
3237 mono_error_init (&refasm_error);
3238 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3241 mono_error_cleanup (&refasm_error);
3247 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3248 const char *basedir,
3249 MonoImageOpenStatus *status,
3252 MonoAssembly *result;
3253 char *fullpath, *filename;
3254 MonoAssemblyName maped_aname;
3255 MonoAssemblyName maped_name_pp;
3260 aname = mono_assembly_remap_version (aname, &maped_aname);
3262 /* Reflection only assemblies don't get assembly binding */
3264 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3266 result = mono_assembly_loaded_full (aname, refonly);
3270 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3272 result->in_gac = FALSE;
3276 /* Currently we retrieve the loaded corlib for reflection
3277 * only requests, like a common reflection only assembly
3279 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3280 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3283 len = strlen (aname->name);
3284 for (ext_index = 0; ext_index < 2; ext_index ++) {
3285 ext = ext_index == 0 ? ".dll" : ".exe";
3286 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3287 filename = g_strdup (aname->name);
3288 /* Don't try appending .dll/.exe if it already has one of those extensions */
3291 filename = g_strconcat (aname->name, ext, NULL);
3294 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3301 fullpath = g_build_filename (basedir, filename, NULL);
3302 result = mono_assembly_open_full (fullpath, status, refonly);
3305 result->in_gac = FALSE;
3311 result = load_in_path (filename, default_path, status, refonly);
3313 result->in_gac = FALSE;
3323 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3325 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3328 /* Try a postload search hook */
3329 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3330 result = prevent_reference_assembly_from_running (result, refonly);
3336 * mono_assembly_load_full:
3337 * @aname: A MonoAssemblyName with the assembly name to load.
3338 * @basedir: A directory to look up the assembly at.
3339 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3340 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3342 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3343 * attempts to load the assembly from that directory before probing the standard locations.
3345 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3346 * assembly binding takes place.
3348 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3349 * value pointed by status is updated with an error code.
3352 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3354 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3358 * mono_assembly_load:
3359 * @aname: A MonoAssemblyName with the assembly name to load.
3360 * @basedir: A directory to look up the assembly at.
3361 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3363 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3364 * attempts to load the assembly from that directory before probing the standard locations.
3366 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3367 * value pointed by status is updated with an error code.
3370 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3372 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3376 * mono_assembly_loaded_full:
3377 * @aname: an assembly to look for.
3378 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3380 * This is used to determine if the specified assembly has been loaded
3381 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3382 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3385 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3388 MonoAssemblyName maped_aname;
3390 aname = mono_assembly_remap_version (aname, &maped_aname);
3392 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3398 * mono_assembly_loaded:
3399 * @aname: an assembly to look for.
3401 * This is used to determine if the specified assembly has been loaded
3403 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3404 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3407 mono_assembly_loaded (MonoAssemblyName *aname)
3409 return mono_assembly_loaded_full (aname, FALSE);
3413 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3415 if (assembly == NULL || assembly == REFERENCE_MISSING)
3418 if (assembly_is_dynamic (assembly)) {
3420 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3421 for (i = 0; i < dynimg->image.module_count; ++i)
3422 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3423 mono_dynamic_image_release_gc_roots (dynimg);
3428 * Returns whether mono_assembly_close_finish() must be called as
3429 * well. See comment for mono_image_close_except_pools() for why we
3430 * unload in two steps.
3433 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3436 g_return_val_if_fail (assembly != NULL, FALSE);
3438 if (assembly == REFERENCE_MISSING)
3441 /* Might be 0 already */
3442 if (InterlockedDecrement (&assembly->ref_count) > 0)
3445 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3447 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3449 mono_debug_close_image (assembly->image);
3451 mono_assemblies_lock ();
3452 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3453 mono_assemblies_unlock ();
3455 assembly->image->assembly = NULL;
3457 if (!mono_image_close_except_pools (assembly->image))
3458 assembly->image = NULL;
3460 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3461 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3462 mono_assembly_name_free (fname);
3465 g_slist_free (assembly->friend_assembly_names);
3466 g_free (assembly->basedir);
3468 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3474 mono_assembly_close_finish (MonoAssembly *assembly)
3476 g_assert (assembly && assembly != REFERENCE_MISSING);
3478 if (assembly->image)
3479 mono_image_close_finish (assembly->image);
3481 if (assembly_is_dynamic (assembly)) {
3482 g_free ((char*)assembly->aname.culture);
3489 * mono_assembly_close:
3490 * @assembly: the assembly to release.
3492 * This method releases a reference to the @assembly. The assembly is
3493 * only released when all the outstanding references to it are released.
3496 mono_assembly_close (MonoAssembly *assembly)
3498 if (mono_assembly_close_except_image_pools (assembly))
3499 mono_assembly_close_finish (assembly);
3503 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3506 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3507 mono_error_assert_ok (&error);
3512 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3514 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3519 * mono_assembly_foreach:
3520 * @func: function to invoke for each assembly loaded
3521 * @user_data: data passed to the callback
3523 * Invokes the provided @func callback for each assembly loaded into
3524 * the runtime. The first parameter passed to the callback is the
3525 * `MonoAssembly*`, and the second parameter is the @user_data.
3527 * This is done for all assemblies loaded in the runtime, not just
3528 * those loaded in the current application domain.
3531 mono_assembly_foreach (GFunc func, gpointer user_data)
3536 * We make a copy of the list to avoid calling the callback inside the
3537 * lock, which could lead to deadlocks.
3539 mono_assemblies_lock ();
3540 copy = g_list_copy (loaded_assemblies);
3541 mono_assemblies_unlock ();
3543 g_list_foreach (loaded_assemblies, func, user_data);
3549 * mono_assemblies_cleanup:
3551 * Free all resources used by this module.
3554 mono_assemblies_cleanup (void)
3558 mono_os_mutex_destroy (&assemblies_mutex);
3559 mono_os_mutex_destroy (&assembly_binding_mutex);
3561 for (l = loaded_assembly_bindings; l; l = l->next) {
3562 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3564 mono_assembly_binding_info_free (info);
3567 g_slist_free (loaded_assembly_bindings);
3569 free_assembly_load_hooks ();
3570 free_assembly_search_hooks ();
3571 free_assembly_preload_hooks ();
3574 /*LOCKING takes the assembly_binding lock*/
3576 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3580 mono_assembly_binding_lock ();
3581 iter = &loaded_assembly_bindings;
3584 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3586 if (info->domain_id == domain_id) {
3588 mono_assembly_binding_info_free (info);
3595 mono_assembly_binding_unlock ();
3599 * Holds the assembly of the application, for
3600 * System.Diagnostics.Process::MainModule
3602 static MonoAssembly *main_assembly=NULL;
3605 mono_assembly_set_main (MonoAssembly *assembly)
3607 main_assembly = assembly;
3611 * mono_assembly_get_main:
3613 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3616 mono_assembly_get_main (void)
3618 return (main_assembly);
3622 * mono_assembly_get_image:
3623 * @assembly: The assembly to retrieve the image from
3625 * Returns: the MonoImage associated with this assembly.
3628 mono_assembly_get_image (MonoAssembly *assembly)
3630 return assembly->image;
3634 * mono_assembly_get_name:
3635 * @assembly: The assembly to retrieve the name from
3637 * The returned name's lifetime is the same as @assembly's.
3639 * Returns: the MonoAssemblyName associated with this assembly.
3642 mono_assembly_get_name (MonoAssembly *assembly)
3644 return &assembly->aname;
3648 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3650 bundles = assemblies;
3653 #define MONO_DECLSEC_FORMAT_10 0x3C
3654 #define MONO_DECLSEC_FORMAT_20 0x2E
3655 #define MONO_DECLSEC_FIELD 0x53
3656 #define MONO_DECLSEC_PROPERTY 0x54
3658 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3659 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3660 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3661 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3662 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3665 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3669 case MONO_DECLSEC_PROPERTY:
3671 case MONO_DECLSEC_FIELD:
3673 *abort_decoding = TRUE;
3678 if (*p++ != MONO_TYPE_BOOLEAN) {
3679 *abort_decoding = TRUE;
3683 /* property name length */
3684 len = mono_metadata_decode_value (p, &p);
3686 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3697 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3699 int i, j, num, len, params_len;
3701 if (*p == MONO_DECLSEC_FORMAT_10) {
3702 gsize read, written;
3703 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3705 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3711 if (*p++ != MONO_DECLSEC_FORMAT_20)
3714 /* number of encoded permission attributes */
3715 num = mono_metadata_decode_value (p, &p);
3716 for (i = 0; i < num; ++i) {
3717 gboolean is_valid = FALSE;
3718 gboolean abort_decoding = FALSE;
3720 /* attribute name length */
3721 len = mono_metadata_decode_value (p, &p);
3723 /* We don't really need to fully decode the type. Comparing the name is enough */
3724 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3728 /*size of the params table*/
3729 params_len = mono_metadata_decode_value (p, &p);
3731 const char *params_end = p + params_len;
3733 /* number of parameters */
3734 len = mono_metadata_decode_value (p, &p);
3736 for (j = 0; j < len; ++j) {
3737 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3753 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3756 guint32 cols [MONO_DECL_SECURITY_SIZE];
3760 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3761 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3763 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3765 for (i = 0; i < t->rows; ++i) {
3766 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3767 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3769 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3772 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3773 len = mono_metadata_decode_blob_size (blob, &blob);
3777 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3778 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3783 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);