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/custom-attrs-internals.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/class-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include <mono/metadata/reflection-internals.h>
31 #include <mono/metadata/mono-endian.h>
32 #include <mono/metadata/mono-debug.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.IO.Compression", 2},
139 {"System.Management", 0},
140 {"System.Messaging", 0},
142 {"System.Net.Http", 3},
143 {"System.Numerics.Vectors", 3},
144 {"System.Runtime.InteropServices.RuntimeInformation", 2},
145 {"System.Runtime.Remoting", 0},
146 {"System.Runtime.Serialization", 3},
147 {"System.Runtime.Serialization.Formatters", 3},
148 {"System.Runtime.Serialization.Formatters.Soap", 0},
149 {"System.Security", 0},
150 {"System.ServiceModel", 3},
151 {"System.ServiceModel.Duplex", 3},
152 {"System.ServiceModel.Http", 3},
153 {"System.ServiceModel.NetTcp", 3},
154 {"System.ServiceModel.Primitives", 3},
155 {"System.ServiceModel.Security", 3},
156 {"System.ServiceModel.Web", 2},
157 {"System.ServiceProcess", 0},
158 {"System.Text.Encoding.CodePages", 3},
159 {"System.Transactions", 0},
161 {"System.Web.Abstractions", 2},
162 {"System.Web.DynamicData", 2},
163 {"System.Web.Extensions", 2},
164 {"System.Web.Mobile", 0},
165 {"System.Web.Routing", 2},
166 {"System.Web.Services", 0},
167 {"System.Windows.Forms", 0},
169 {"System.Xml.Linq", 2},
170 {"System.Xml.ReaderWriter", 3},
171 {"System.Xml.XPath.XmlDocument", 3},
178 * keeps track of loaded assemblies
180 static GList *loaded_assemblies = NULL;
181 static MonoAssembly *corlib;
183 #if defined(__native_client__)
185 /* On Native Client, allow mscorlib to be loaded from memory */
186 /* instead of loaded off disk. If these are not set, default */
187 /* mscorlib loading will take place */
189 /* NOTE: If mscorlib data is passed to mono in this way then */
190 /* it needs to remain allocated during the use of mono. */
192 static void *corlibData = NULL;
193 static size_t corlibSize = 0;
196 mono_set_corlib_data (void *data, size_t size)
204 static char* unquote (const char *str);
206 /* This protects loaded_assemblies and image->references */
207 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
208 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
209 static mono_mutex_t assemblies_mutex;
211 /* If defined, points to the bundled assembly information */
212 const MonoBundledAssembly **bundles;
214 static mono_mutex_t assembly_binding_mutex;
216 /* Loaded assembly binding info */
217 static GSList *loaded_assembly_bindings = NULL;
219 /* Class lazy loading functions */
220 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
222 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
224 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
226 mono_assembly_is_in_gac (const gchar *filanem);
229 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
232 encode_public_tok (const guchar *token, gint32 len)
234 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
238 res = (gchar *)g_malloc (len * 2 + 1);
239 for (i = 0; i < len; i++) {
240 res [i * 2] = allowed [token [i] >> 4];
241 res [i * 2 + 1] = allowed [token [i] & 0xF];
248 * mono_public_tokens_are_equal:
249 * @pubt1: first public key token
250 * @pubt2: second public key token
252 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
256 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
258 return memcmp (pubt1, pubt2, 16) == 0;
262 * mono_set_assemblies_path:
263 * @path: list of paths that contain directories where Mono will look for assemblies
265 * Use this method to override the standard assembly lookup system and
266 * override any assemblies coming from the GAC. This is the method
267 * that supports the MONO_PATH variable.
269 * Notice that MONO_PATH and this method are really a very bad idea as
270 * it prevents the GAC from working and it prevents the standard
271 * resolution mechanisms from working. Nonetheless, for some debugging
272 * situations and bootstrapping setups, this is useful to have.
275 mono_set_assemblies_path (const char* path)
277 char **splitted, **dest;
279 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
281 g_strfreev (assemblies_path);
282 assemblies_path = dest = splitted;
284 char *tmp = *splitted;
286 *dest++ = mono_path_canonicalize (tmp);
292 if (g_getenv ("MONO_DEBUG") == NULL)
295 splitted = assemblies_path;
297 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
298 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
304 /* Native Client can't get this info from an environment variable so */
305 /* it's passed in to the runtime, or set manually by embedding code. */
306 #ifdef __native_client__
307 char* nacl_mono_path = NULL;
311 check_path_env (void)
314 path = g_getenv ("MONO_PATH");
315 #ifdef __native_client__
317 path = nacl_mono_path;
319 if (!path || assemblies_path != NULL)
322 mono_set_assemblies_path(path);
326 check_extra_gac_path_env (void) {
328 char **splitted, **dest;
330 path = g_getenv ("MONO_GAC_PREFIX");
334 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
336 g_strfreev (extra_gac_paths);
337 extra_gac_paths = dest = splitted;
345 if (g_getenv ("MONO_DEBUG") == NULL)
349 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
350 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
357 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
359 if (!info || !info->name)
362 if (strcmp (info->name, aname->name))
365 if (info->major != aname->major || info->minor != aname->minor)
368 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
371 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
374 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
381 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
387 g_free (info->culture);
391 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
394 guint32 cols [MONO_MANIFEST_SIZE];
395 const gchar *filename;
396 gchar *subpath, *fullpath;
398 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
399 /* MS Impl. accepts policy assemblies with more than
400 * one manifest resource, and only takes the first one */
402 binding_info->is_valid = FALSE;
406 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
407 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
408 binding_info->is_valid = FALSE;
412 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
413 g_assert (filename != NULL);
415 subpath = g_path_get_dirname (image->name);
416 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
417 mono_config_parse_publisher_policy (fullpath, binding_info);
421 /* Define the optional elements/attributes before checking */
422 if (!binding_info->culture)
423 binding_info->culture = g_strdup ("");
425 /* Check that the most important elements/attributes exist */
426 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
427 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
428 mono_assembly_binding_info_free (binding_info);
429 binding_info->is_valid = FALSE;
433 binding_info->is_valid = TRUE;
437 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
439 if (v->major > aname->major)
441 else if (v->major < aname->major)
444 if (v->minor > aname->minor)
446 else if (v->minor < aname->minor)
449 if (v->build > aname->build)
451 else if (v->build < aname->build)
454 if (v->revision > aname->revision)
456 else if (v->revision < aname->revision)
463 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
468 /* If has_old_version_top doesn't exist, we don't have an interval */
469 if (!info->has_old_version_top) {
470 if (compare_versions (&info->old_version_bottom, name) == 0)
476 /* Check that the version defined by name is valid for the interval */
477 if (compare_versions (&info->old_version_top, name) < 0)
480 /* We should be greater or equal than the small version */
481 if (compare_versions (&info->old_version_bottom, name) > 0)
488 * mono_assembly_names_equal:
490 * @r: second assembly.
492 * Compares two MonoAssemblyNames and returns whether they are equal.
494 * This compares the names, the cultures, the release version and their
497 * Returns: TRUE if both assembly names are equal.
500 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
502 if (!l->name || !r->name)
505 if (strcmp (l->name, r->name))
508 if (l->culture && r->culture && strcmp (l->culture, r->culture))
511 if (l->major != r->major || l->minor != r->minor ||
512 l->build != r->build || l->revision != r->revision)
513 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)))
516 if (!l->public_key_token [0] || !r->public_key_token [0])
519 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
525 static MonoAssembly *
526 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
530 MonoAssembly *result;
532 for (i = 0; search_path [i]; ++i) {
533 fullpath = g_build_filename (search_path [i], basename, NULL);
534 result = mono_assembly_open_full (fullpath, status, refonly);
543 * mono_assembly_setrootdir:
544 * @root_dir: The pathname of the root directory where we will locate assemblies
546 * This routine sets the internal default root directory for looking up
549 * This is used by Windows installations to compute dynamically the
550 * place where the Mono assemblies are located.
554 mono_assembly_setrootdir (const char *root_dir)
557 * Override the MONO_ASSEMBLIES directory configured at compile time.
559 /* Leak if called more than once */
560 default_path [0] = g_strdup (root_dir);
564 * mono_assembly_getrootdir:
566 * Obtains the root directory used for looking up assemblies.
568 * Returns: a string with the directory, this string should not be freed.
570 G_CONST_RETURN gchar *
571 mono_assembly_getrootdir (void)
573 return default_path [0];
577 * mono_native_getrootdir:
579 * Obtains the root directory used for looking up native libs (.so, .dylib).
581 * Returns: a string with the directory, this string should be freed by
585 mono_native_getrootdir (void)
587 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
593 * @assembly_dir: the base directory for assemblies
594 * @config_dir: the base directory for configuration files
596 * This routine is used internally and by developers embedding
597 * the runtime into their own applications.
599 * There are a number of cases to consider: Mono as a system-installed
600 * package that is available on the location preconfigured or Mono in
601 * a relocated location.
603 * If you are using a system-installed Mono, you can pass NULL
604 * to both parameters. If you are not, you should compute both
605 * directory values and call this routine.
607 * The values for a given PREFIX are:
609 * assembly_dir: PREFIX/lib
610 * config_dir: PREFIX/etc
612 * Notice that embedders that use Mono in a relocated way must
613 * compute the location at runtime, as they will be in control
614 * of where Mono is installed.
617 mono_set_dirs (const char *assembly_dir, const char *config_dir)
619 if (assembly_dir == NULL)
620 assembly_dir = mono_config_get_assemblies_dir ();
621 if (config_dir == NULL)
622 config_dir = mono_config_get_cfg_dir ();
623 mono_assembly_setrootdir (assembly_dir);
624 mono_set_config_dir (config_dir);
630 compute_base (char *path)
632 char *p = strrchr (path, '/');
636 /* Not a well known Mono executable, we are embedded, cant guess the base */
637 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
641 p = strrchr (path, '/');
645 if (strcmp (p, "/bin") != 0)
654 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
657 static G_GNUC_UNUSED void
661 char *config, *lib, *mono;
666 * Only /usr prefix is treated specially
668 bindir = mono_config_get_bin_dir ();
670 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
675 config = g_build_filename (base, "etc", NULL);
676 lib = g_build_filename (base, "lib", NULL);
677 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
678 if (stat (mono, &buf) == -1)
681 mono_set_dirs (lib, config);
689 #endif /* HOST_WIN32 */
694 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
695 * this auto-detects the prefix where Mono was installed.
698 mono_set_rootdir (void)
700 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
701 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
704 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
708 * _NSGetExecutablePath may return -1 to indicate buf is not large
709 * enough, but we ignore that case to avoid having to do extra dynamic
710 * allocation for the path and hope that 4096 is enough - this is
711 * ok in the Linux/Solaris case below at least...
715 guint buf_size = sizeof (buf);
718 if (_NSGetExecutablePath (buf, &buf_size) == 0)
719 name = g_strdup (buf);
728 resolvedname = mono_path_resolve_symlinks (name);
730 bindir = g_path_get_dirname (resolvedname);
731 installdir = g_path_get_dirname (bindir);
732 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
734 config = g_build_filename (root, "..", "etc", NULL);
736 mono_set_dirs (root, config);
738 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
739 mono_set_dirs (root, config);
749 g_free (resolvedname);
750 #elif defined(DISABLE_MONO_AUTODETECTION)
758 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
766 /* Solaris 10 style */
767 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
768 s = readlink (str, buf, sizeof (buf)-1);
780 * mono_assemblies_init:
782 * Initialize global variables used by this module.
785 mono_assemblies_init (void)
788 * Initialize our internal paths if we have not been initialized yet.
789 * This happens when embedders use Mono.
791 if (mono_assembly_getrootdir () == NULL)
795 check_extra_gac_path_env ();
797 mono_os_mutex_init_recursive (&assemblies_mutex);
798 mono_os_mutex_init (&assembly_binding_mutex);
802 mono_assembly_binding_lock (void)
804 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
808 mono_assembly_binding_unlock (void)
810 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
814 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
816 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
817 guint32 cols [MONO_ASSEMBLY_SIZE];
818 gint32 machine, flags;
823 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
826 aname->hash_value = NULL;
827 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
829 aname->name = g_strdup (aname->name);
830 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
832 aname->culture = g_strdup (aname->culture);
833 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
834 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
835 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
836 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
837 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
838 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
839 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
840 guchar* token = (guchar *)g_malloc (8);
845 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
846 len = mono_metadata_decode_blob_size (pkey, &pkey);
847 aname->public_key = (guchar*)pkey;
849 mono_digest_get_public_token (token, aname->public_key, len);
850 encoded = encode_public_tok (token, 8);
851 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
857 aname->public_key = NULL;
858 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
861 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
862 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
864 const gchar *pkey_end;
865 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
866 pkey_end += len; /* move to end */
867 size_t size = pkey_end - (const gchar*)aname->public_key;
868 guchar *tmp = g_new (guchar, size);
869 memcpy (tmp, aname->public_key, size);
870 aname->public_key = tmp;
875 aname->public_key = 0;
877 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
878 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
880 case COFF_MACHINE_I386:
881 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
882 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
883 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
884 else if ((flags & 0x70) == 0x70)
885 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
887 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
889 case COFF_MACHINE_IA64:
890 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
892 case COFF_MACHINE_AMD64:
893 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
895 case COFF_MACHINE_ARM:
896 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
906 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
908 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
912 * mono_stringify_assembly_name:
913 * @aname: the assembly name.
915 * Convert @aname into its string format. The returned string is dynamically
916 * allocated and should be freed by the caller.
918 * Returns: a newly allocated string with a string representation of
922 mono_stringify_assembly_name (MonoAssemblyName *aname)
924 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
926 return g_strdup_printf (
927 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
928 quote, aname->name, quote,
929 aname->major, aname->minor, aname->build, aname->revision,
930 aname->culture && *aname->culture? aname->culture: "neutral",
931 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
932 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
936 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
938 const gchar *public_tok;
941 public_tok = mono_metadata_blob_heap (image, key_index);
942 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
944 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
946 mono_digest_get_public_token (token, (guchar*)public_tok, len);
947 return encode_public_tok (token, 8);
950 return encode_public_tok ((guchar*)public_tok, len);
954 * mono_assembly_addref:
955 * @assemnly: the assembly to reference
957 * This routine increments the reference count on a MonoAssembly.
958 * The reference count is reduced every time the method mono_assembly_close() is
962 mono_assembly_addref (MonoAssembly *assembly)
964 InterlockedIncrement (&assembly->ref_count);
968 * CAUTION: This table must be kept in sync with
969 * ivkm/reflect/Fusion.cs
972 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
973 #define WINFX_KEY "31bf3856ad364e35"
974 #define ECMA_KEY "b77a5c561934e089"
975 #define MSFINAL_KEY "b03f5f7f11d50a3a"
976 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
984 static KeyRemapEntry key_remap_table[] = {
985 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
986 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
987 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
988 { "System", SILVERLIGHT_KEY, ECMA_KEY },
989 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
990 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
991 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
992 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
993 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
994 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
995 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
996 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
997 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
998 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
999 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1000 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1001 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1002 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1003 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1004 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1005 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1006 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1007 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1008 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1009 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1010 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1011 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1012 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1013 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1017 remap_keys (MonoAssemblyName *aname)
1020 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1021 const KeyRemapEntry *entry = &key_remap_table [i];
1023 if (strcmp (aname->name, entry->name) ||
1024 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1027 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1029 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1030 "Remapped public key token of retargetable assembly %s from %s to %s",
1031 aname->name, entry->from, entry->to);
1036 static MonoAssemblyName *
1037 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1039 const MonoRuntimeInfo *current_runtime;
1040 int pos, first, last;
1042 if (aname->name == NULL) return aname;
1044 current_runtime = mono_get_runtime_info ();
1046 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1047 const AssemblyVersionSet* vset;
1049 /* Remap to current runtime */
1050 vset = ¤t_runtime->version_sets [0];
1052 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1053 dest_aname->major = vset->major;
1054 dest_aname->minor = vset->minor;
1055 dest_aname->build = vset->build;
1056 dest_aname->revision = vset->revision;
1057 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1059 /* Remap assembly name */
1060 if (!strcmp (aname->name, "System.Net"))
1061 dest_aname->name = g_strdup ("System");
1063 remap_keys (dest_aname);
1065 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1066 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1068 aname->major, aname->minor, aname->build, aname->revision,
1070 vset->major, vset->minor, vset->build, vset->revision
1076 #ifndef DISABLE_ASSEMBLY_REMAPPING
1078 last = G_N_ELEMENTS (framework_assemblies) - 1;
1080 while (first <= last) {
1082 pos = first + (last - first) / 2;
1083 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1085 const AssemblyVersionSet* vset;
1086 int index = framework_assemblies[pos].version_set_index;
1087 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1088 vset = ¤t_runtime->version_sets [index];
1090 if (aname->major == vset->major && aname->minor == vset->minor &&
1091 aname->build == vset->build && aname->revision == vset->revision)
1094 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1097 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1098 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1099 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1101 aname->major, aname->minor, aname->build, aname->revision,
1102 vset->major, vset->minor, vset->build, vset->revision
1105 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1106 dest_aname->major = vset->major;
1107 dest_aname->minor = vset->minor;
1108 dest_aname->build = vset->build;
1109 dest_aname->revision = vset->revision;
1110 if (framework_assemblies[pos].new_assembly_name != NULL) {
1111 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1112 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1113 "The assembly name %s was remapped to %s",
1118 } else if (res < 0) {
1130 * mono_assembly_get_assemblyref:
1131 * @image: pointer to the MonoImage to extract the information from.
1132 * @index: index to the assembly reference in the image.
1133 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1135 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1138 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1141 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1144 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1146 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1148 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1149 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1150 aname->hash_value = hash;
1151 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1152 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1153 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1154 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1155 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1156 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1157 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1159 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1160 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1161 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1164 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1169 mono_assembly_load_reference (MonoImage *image, int index)
1171 MonoAssembly *reference;
1172 MonoAssemblyName aname;
1173 MonoImageOpenStatus status;
1176 * image->references is shared between threads, so we need to access
1177 * it inside a critical section.
1179 mono_assemblies_lock ();
1180 if (!image->references) {
1181 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1183 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1184 image->nreferences = t->rows;
1186 reference = image->references [index];
1187 mono_assemblies_unlock ();
1191 mono_assembly_get_assemblyref (image, index, &aname);
1193 if (image->assembly && image->assembly->ref_only) {
1194 /* We use the loaded corlib */
1195 if (!strcmp (aname.name, "mscorlib"))
1196 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1198 reference = mono_assembly_loaded_full (&aname, TRUE);
1200 /* Try a postload search hook */
1201 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1205 * Here we must advice that the error was due to
1206 * a non loaded reference using the ReflectionOnly api
1209 reference = (MonoAssembly *)REFERENCE_MISSING;
1211 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1212 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1213 * accordingly, it would fail on the MS runtime before).
1214 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1215 * example bug-349190.2.cs and who knows how much more code in the wild.
1217 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1218 if (!reference && image->assembly)
1219 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1222 if (reference == NULL){
1225 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1226 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 : "" );
1227 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1228 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1229 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1230 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1231 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1232 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1234 extra_msg = g_strdup ("");
1237 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1238 " Assembly: %s (assemblyref_index=%d)\n"
1239 " Version: %d.%d.%d.%d\n"
1240 " Public Key: %s\n%s",
1241 image->name, aname.name, index,
1242 aname.major, aname.minor, aname.build, aname.revision,
1243 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1248 mono_assemblies_lock ();
1249 if (reference == NULL) {
1250 /* Flag as not found */
1251 reference = (MonoAssembly *)REFERENCE_MISSING;
1254 if (!image->references [index]) {
1255 if (reference != REFERENCE_MISSING){
1256 mono_assembly_addref (reference);
1257 if (image->assembly)
1258 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1259 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1261 if (image->assembly)
1262 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1263 image->assembly->aname.name, image->assembly);
1266 image->references [index] = reference;
1268 mono_assemblies_unlock ();
1270 if (image->references [index] != reference) {
1271 /* Somebody loaded it before us */
1272 mono_assembly_close (reference);
1277 * mono_assembly_load_references:
1280 * @deprecated: There is no reason to use this method anymore, it does nothing
1282 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1285 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1287 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1288 *status = MONO_IMAGE_OK;
1291 typedef struct AssemblyLoadHook AssemblyLoadHook;
1292 struct AssemblyLoadHook {
1293 AssemblyLoadHook *next;
1294 MonoAssemblyLoadFunc func;
1298 AssemblyLoadHook *assembly_load_hook = NULL;
1301 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1303 AssemblyLoadHook *hook;
1305 for (hook = assembly_load_hook; hook; hook = hook->next) {
1306 hook->func (ass, hook->user_data);
1311 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1313 AssemblyLoadHook *hook;
1315 g_return_if_fail (func != NULL);
1317 hook = g_new0 (AssemblyLoadHook, 1);
1319 hook->user_data = user_data;
1320 hook->next = assembly_load_hook;
1321 assembly_load_hook = hook;
1325 free_assembly_load_hooks (void)
1327 AssemblyLoadHook *hook, *next;
1329 for (hook = assembly_load_hook; hook; hook = next) {
1335 typedef struct AssemblySearchHook AssemblySearchHook;
1336 struct AssemblySearchHook {
1337 AssemblySearchHook *next;
1338 MonoAssemblySearchFunc func;
1344 AssemblySearchHook *assembly_search_hook = NULL;
1346 static MonoAssembly*
1347 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1349 AssemblySearchHook *hook;
1351 for (hook = assembly_search_hook; hook; hook = hook->next) {
1352 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1355 * A little explanation is in order here.
1357 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1358 * The embedding API exposes a search hook that doesn't take such argument.
1360 * The original fix would call the default search hook before all the registered ones and pass
1361 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1362 * rely on. Which is the ordering between user hooks and the default runtime hook.
1364 * Registering the hook after mono_jit_init would let your hook run before the default one and
1365 * when using it to handle non standard app layouts this could save your app from a massive amount
1366 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1367 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1369 * So what's the fix? We register the default hook using regular means and special case it when iterating
1370 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1373 if (hook->func == (void*)mono_domain_assembly_postload_search)
1374 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1376 ass = hook->func (aname, hook->user_data);
1386 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1388 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1392 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1394 AssemblySearchHook *hook;
1396 g_return_if_fail (func != NULL);
1398 hook = g_new0 (AssemblySearchHook, 1);
1400 hook->user_data = user_data;
1401 hook->refonly = refonly;
1402 hook->postload = postload;
1403 hook->next = assembly_search_hook;
1404 assembly_search_hook = hook;
1408 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1410 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1414 free_assembly_search_hooks (void)
1416 AssemblySearchHook *hook, *next;
1418 for (hook = assembly_search_hook; hook; hook = next) {
1425 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1427 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1431 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1433 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1437 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1439 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1442 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1443 struct AssemblyPreLoadHook {
1444 AssemblyPreLoadHook *next;
1445 MonoAssemblyPreLoadFunc func;
1449 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1450 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1452 static MonoAssembly *
1453 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1455 AssemblyPreLoadHook *hook;
1456 MonoAssembly *assembly;
1458 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1459 assembly = hook->func (aname, assemblies_path, hook->user_data);
1460 if (assembly != NULL)
1467 static MonoAssembly *
1468 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1470 AssemblyPreLoadHook *hook;
1471 MonoAssembly *assembly;
1473 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1474 assembly = hook->func (aname, assemblies_path, hook->user_data);
1475 if (assembly != NULL)
1483 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1485 AssemblyPreLoadHook *hook;
1487 g_return_if_fail (func != NULL);
1489 hook = g_new0 (AssemblyPreLoadHook, 1);
1491 hook->user_data = user_data;
1492 hook->next = assembly_preload_hook;
1493 assembly_preload_hook = hook;
1497 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1499 AssemblyPreLoadHook *hook;
1501 g_return_if_fail (func != NULL);
1503 hook = g_new0 (AssemblyPreLoadHook, 1);
1505 hook->user_data = user_data;
1506 hook->next = assembly_refonly_preload_hook;
1507 assembly_refonly_preload_hook = hook;
1511 free_assembly_preload_hooks (void)
1513 AssemblyPreLoadHook *hook, *next;
1515 for (hook = assembly_preload_hook; hook; hook = next) {
1520 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1527 absolute_dir (const gchar *filename)
1538 if (g_path_is_absolute (filename)) {
1539 part = g_path_get_dirname (filename);
1540 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1545 cwd = g_get_current_dir ();
1546 mixed = g_build_filename (cwd, filename, NULL);
1547 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1552 for (i = 0; (part = parts [i]) != NULL; i++) {
1553 if (!strcmp (part, "."))
1556 if (!strcmp (part, "..")) {
1557 if (list && list->next) /* Don't remove root */
1558 list = g_list_delete_link (list, list);
1560 list = g_list_prepend (list, part);
1564 result = g_string_new ("");
1565 list = g_list_reverse (list);
1567 /* Ignores last data pointer, which should be the filename */
1568 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1570 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1575 g_string_free (result, FALSE);
1580 return g_strdup (".");
1587 * mono_assembly_open_from_bundle:
1588 * @filename: Filename requested
1589 * @status: return status code
1591 * This routine tries to open the assembly specified by `filename' from the
1592 * defined bundles, if found, returns the MonoImage for it, if not found
1596 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1600 gchar *lowercase_filename;
1601 MonoImage *image = NULL;
1602 gboolean is_satellite = FALSE;
1604 * we do a very simple search for bundled assemblies: it's not a general
1605 * purpose assembly loading mechanism.
1611 lowercase_filename = g_utf8_strdown (filename, -1);
1612 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1613 g_free (lowercase_filename);
1614 name = g_path_get_basename (filename);
1615 mono_assemblies_lock ();
1616 for (i = 0; !image && bundles [i]; ++i) {
1617 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1618 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1622 mono_assemblies_unlock ();
1624 mono_image_addref (image);
1625 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1634 * mono_assemblies_open_full:
1635 * @filename: the file to load
1636 * @status: return status code
1637 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1639 * This loads an assembly from the specified @filename. The @filename allows
1640 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1641 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1642 * is treated as a local path.
1644 * First, an attempt is made to load the assembly from the bundled executable (for those
1645 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1646 * assembly has been registered as an embedded assembly). If this is not the case, then
1647 * the assembly is loaded from disk using `api:mono_image_open_full`.
1649 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1650 * the assembly is made.
1652 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1653 * the `System.Reflection` API.
1655 * Returns: NULL on error, with the @status set to an error code, or a pointer
1659 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1663 MonoImageOpenStatus def_status;
1666 gboolean loaded_from_bundle;
1668 g_return_val_if_fail (filename != NULL, NULL);
1671 status = &def_status;
1672 *status = MONO_IMAGE_OK;
1674 if (strncmp (filename, "file://", 7) == 0) {
1675 GError *error = NULL;
1676 gchar *uri = (gchar *) filename;
1680 * MS allows file://c:/... and fails on file://localhost/c:/...
1681 * They also throw an IndexOutOfRangeException if "file://"
1684 uri = g_strdup_printf ("file:///%s", uri + 7);
1687 uri = mono_escape_uri_string (tmpuri);
1688 fname = g_filename_from_uri (uri, NULL, &error);
1691 if (tmpuri != filename)
1694 if (error != NULL) {
1695 g_warning ("%s\n", error->message);
1696 g_error_free (error);
1697 fname = g_strdup (filename);
1700 fname = g_strdup (filename);
1703 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1704 "Assembly Loader probing location: '%s'.", fname);
1707 if (!mono_assembly_is_in_gac (fname)) {
1709 new_fname = mono_make_shadow_copy (fname, &error);
1710 if (!is_ok (&error)) {
1711 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1712 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1713 mono_error_cleanup (&error);
1714 *status = MONO_IMAGE_IMAGE_INVALID;
1719 if (new_fname && new_fname != fname) {
1722 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1723 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1728 // If VM built with mkbundle
1729 loaded_from_bundle = FALSE;
1730 if (bundles != NULL) {
1731 image = mono_assembly_open_from_bundle (fname, status, refonly);
1732 loaded_from_bundle = image != NULL;
1736 image = mono_image_open_full (fname, status, refonly);
1739 if (*status == MONO_IMAGE_OK)
1740 *status = MONO_IMAGE_ERROR_ERRNO;
1745 if (image->assembly) {
1746 /* Already loaded by another appdomain */
1747 mono_assembly_invoke_load_hook (image->assembly);
1748 mono_image_close (image);
1750 return image->assembly;
1753 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1756 if (!loaded_from_bundle)
1757 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1758 "Assembly Loader loaded assembly from location: '%s'.", filename);
1760 mono_config_for_assembly (ass->image);
1763 /* Clear the reference added by mono_image_open */
1764 mono_image_close (image);
1772 free_item (gpointer val, gpointer user_data)
1778 * mono_assembly_load_friends:
1781 * Load the list of friend assemblies that are allowed to access
1782 * the assembly's internal types and members. They are stored as assembly
1783 * names in custom attributes.
1785 * This is an internal method, we need this because when we load mscorlib
1786 * we do not have the internals visible cattr loaded yet,
1787 * so we need to load these after we initialize the runtime.
1789 * LOCKING: Acquires the assemblies lock plus the loader lock.
1792 mono_assembly_load_friends (MonoAssembly* ass)
1796 MonoCustomAttrInfo* attrs;
1799 if (ass->friend_assembly_names_inited)
1802 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1803 mono_error_assert_ok (&error);
1805 mono_assemblies_lock ();
1806 ass->friend_assembly_names_inited = TRUE;
1807 mono_assemblies_unlock ();
1811 mono_assemblies_lock ();
1812 if (ass->friend_assembly_names_inited) {
1813 mono_assemblies_unlock ();
1816 mono_assemblies_unlock ();
1820 * We build the list outside the assemblies lock, the worse that can happen
1821 * is that we'll need to free the allocated list.
1823 for (i = 0; i < attrs->num_attrs; ++i) {
1824 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1825 MonoAssemblyName *aname;
1827 /* Do some sanity checking */
1828 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1830 if (attr->data_size < 4)
1832 data = (const char*)attr->data;
1833 /* 0xFF means null string, see custom attr format */
1834 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1836 mono_metadata_decode_value (data + 2, &data);
1837 aname = g_new0 (MonoAssemblyName, 1);
1838 /*g_print ("friend ass: %s\n", data);*/
1839 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1840 list = g_slist_prepend (list, aname);
1845 mono_custom_attrs_free (attrs);
1847 mono_assemblies_lock ();
1848 if (ass->friend_assembly_names_inited) {
1849 mono_assemblies_unlock ();
1850 g_slist_foreach (list, free_item, NULL);
1851 g_slist_free (list);
1854 ass->friend_assembly_names = list;
1856 /* Because of the double checked locking pattern above */
1857 mono_memory_barrier ();
1858 ass->friend_assembly_names_inited = TRUE;
1859 mono_assemblies_unlock ();
1862 struct HasReferenceAssemblyAttributeIterData {
1867 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1869 gboolean stop_scanning = FALSE;
1870 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1872 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1873 /* Note we don't check the assembly name, same as coreCLR. */
1874 iter_data->has_attr = TRUE;
1875 stop_scanning = TRUE;
1878 return stop_scanning;
1882 * mono_assembly_has_reference_assembly_attribute:
1883 * @assembly: a MonoAssembly
1884 * @error: set on error.
1886 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1887 * On error returns FALSE and sets @error.
1890 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1892 mono_error_init (error);
1895 * This might be called during assembly loading, so do everything using the low-level
1899 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1901 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1903 return iter_data.has_attr;
1907 * mono_assembly_open:
1908 * @filename: Opens the assembly pointed out by this name
1909 * @status: return status code
1911 * This loads an assembly from the specified @filename. The @filename allows
1912 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1913 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1914 * is treated as a local path.
1916 * First, an attempt is made to load the assembly from the bundled executable (for those
1917 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1918 * assembly has been registered as an embedded assembly). If this is not the case, then
1919 * the assembly is loaded from disk using `api:mono_image_open_full`.
1921 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1922 * the assembly is made.
1924 * Return: a pointer to the MonoAssembly if @filename contains a valid
1925 * assembly or NULL on error. Details about the error are stored in the
1929 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1931 return mono_assembly_open_full (filename, status, FALSE);
1935 * mono_assembly_load_from_full:
1936 * @image: Image to load the assembly from
1937 * @fname: assembly name to associate with the assembly
1938 * @status: returns the status condition
1939 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1941 * If the provided @image has an assembly reference, it will process the given
1942 * image as an assembly with the given name.
1944 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1946 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1947 * set to #MONO_IMAGE_OK; or NULL on error.
1949 * If there is an error loading the assembly the @status will indicate the
1950 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1951 * image did not contain an assembly reference table.
1954 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1955 MonoImageOpenStatus *status, gboolean refonly)
1957 MonoAssembly *ass, *ass2;
1960 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1961 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1962 *status = MONO_IMAGE_IMAGE_INVALID;
1966 #if defined (HOST_WIN32)
1971 tmp_fn = g_strdup (fname);
1972 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1973 if (tmp_fn [i] == '/')
1977 base_dir = absolute_dir (tmp_fn);
1981 base_dir = absolute_dir (fname);
1985 * Create assembly struct, and enter it into the assembly cache
1987 ass = g_new0 (MonoAssembly, 1);
1988 ass->basedir = base_dir;
1989 ass->ref_only = refonly;
1992 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1994 mono_assembly_fill_assembly_name (image, &ass->aname);
1996 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1997 // MS.NET doesn't support loading other mscorlibs
2000 mono_image_addref (mono_defaults.corlib);
2001 *status = MONO_IMAGE_OK;
2002 return mono_defaults.corlib->assembly;
2005 /* Add a non-temporary reference because of ass->image */
2006 mono_image_addref (image);
2008 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);
2011 * The load hooks might take locks so we can't call them while holding the
2014 if (ass->aname.name) {
2015 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2019 mono_image_close (image);
2020 *status = MONO_IMAGE_OK;
2025 /* We need to check for ReferenceAssmeblyAttribute before we
2026 * mark the assembly as loaded and before we fire the load
2027 * hook. Otherwise mono_domain_fire_assembly_load () in
2028 * appdomain.c will cache a mapping from the assembly name to
2029 * this image and we won't be able to look for a different
2033 MonoError refasm_error;
2034 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2035 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2038 mono_image_close (image);
2039 *status = MONO_IMAGE_IMAGE_INVALID;
2042 mono_error_cleanup (&refasm_error);
2045 mono_assemblies_lock ();
2047 if (image->assembly) {
2049 * This means another thread has already loaded the assembly, but not yet
2050 * called the load hooks so the search hook can't find the assembly.
2052 mono_assemblies_unlock ();
2053 ass2 = image->assembly;
2056 mono_image_close (image);
2057 *status = MONO_IMAGE_OK;
2061 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2063 image->assembly = ass;
2065 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2066 mono_assemblies_unlock ();
2069 if (image->is_module_handle)
2070 mono_image_fixup_vtable (image);
2073 mono_assembly_invoke_load_hook (ass);
2075 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2081 * mono_assembly_load_from:
2082 * @image: Image to load the assembly from
2083 * @fname: assembly name to associate with the assembly
2084 * @status: return status code
2086 * If the provided @image has an assembly reference, it will process the given
2087 * image as an assembly with the given name.
2089 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2091 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2092 * @refonly parameter set to FALSE.
2093 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2094 * set to #MONO_IMAGE_OK; or NULL on error.
2096 * If there is an error loading the assembly the @status will indicate the
2097 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2098 * image did not contain an assembly reference table.
2102 mono_assembly_load_from (MonoImage *image, const char *fname,
2103 MonoImageOpenStatus *status)
2105 return mono_assembly_load_from_full (image, fname, status, FALSE);
2109 * mono_assembly_name_free:
2110 * @aname: assembly name to free
2112 * Frees the provided assembly name object.
2113 * (it does not frees the object itself, only the name members).
2116 mono_assembly_name_free (MonoAssemblyName *aname)
2121 g_free ((void *) aname->name);
2122 g_free ((void *) aname->culture);
2123 g_free ((void *) aname->hash_value);
2124 g_free ((guint8*) aname->public_key);
2128 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2131 gchar header [16], val, *arr;
2132 gint i, j, offset, bitlen, keylen, pkeylen;
2134 keylen = strlen (key) >> 1;
2138 /* allow the ECMA standard key */
2139 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2141 *pubkey = g_strdup (key);
2147 val = g_ascii_xdigit_value (key [0]) << 4;
2148 val |= g_ascii_xdigit_value (key [1]);
2153 val = g_ascii_xdigit_value (key [24]);
2154 val |= g_ascii_xdigit_value (key [25]);
2166 /* We need the first 16 bytes
2167 * to check whether this key is valid or not */
2168 pkeylen = strlen (pkey) >> 1;
2172 for (i = 0, j = 0; i < 16; i++) {
2173 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2174 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2177 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2178 header [1] != 0x02 || /* Version (0x02) */
2179 header [2] != 0x00 || /* Reserved (word) */
2180 header [3] != 0x00 ||
2181 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2184 /* Based on this length, we _should_ be able to know if the length is right */
2185 bitlen = read32 (header + 12) >> 3;
2186 if ((bitlen + 16 + 4) != pkeylen)
2189 /* parsing is OK and the public key itself is not requested back */
2193 /* Encode the size of the blob */
2195 if (keylen <= 127) {
2196 arr = (gchar *)g_malloc (keylen + 1);
2197 arr [offset++] = keylen;
2199 arr = (gchar *)g_malloc (keylen + 2);
2200 arr [offset++] = 0x80; /* 10bs */
2201 arr [offset++] = keylen;
2204 for (i = offset, j = 0; i < keylen + offset; i++) {
2205 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2206 arr [i] |= g_ascii_xdigit_value (key [j++]);
2215 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)
2217 gint major, minor, build, revision;
2220 gchar *pkey, *pkeyptr, *encoded, tok [8];
2222 memset (aname, 0, sizeof (MonoAssemblyName));
2225 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2226 if (version_parts < 2 || version_parts > 4)
2229 /* FIXME: we should set build & revision to -1 (instead of 0)
2230 if these are not set in the version string. That way, later on,
2231 we can still determine if these were specified. */
2232 aname->major = major;
2233 aname->minor = minor;
2234 if (version_parts >= 3)
2235 aname->build = build;
2238 if (version_parts == 4)
2239 aname->revision = revision;
2241 aname->revision = 0;
2244 aname->flags = flags;
2246 aname->name = g_strdup (name);
2249 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2250 aname->culture = g_strdup ("");
2252 aname->culture = g_strdup (culture);
2255 if (token && strncmp (token, "null", 4) != 0) {
2258 /* the constant includes the ending NULL, hence the -1 */
2259 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2260 mono_assembly_name_free (aname);
2263 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2264 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2270 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2271 mono_assembly_name_free (aname);
2276 if (save_public_key)
2277 aname->public_key = (guint8*)pkey;
2280 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2284 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2285 // We also need to generate the key token
2286 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2287 encoded = encode_public_tok ((guchar*) tok, 8);
2288 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2291 if (save_public_key)
2292 aname->public_key = (guint8*) pkey;
2301 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2306 parts = g_strsplit (dirname, "_", 3);
2307 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2312 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2318 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2320 char *eqsign = strchr (pair, '=');
2328 *key = (gchar*)pair;
2329 *keylen = eqsign - *key;
2330 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2332 *value = g_strstrip (eqsign + 1);
2337 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2341 gchar *version = NULL;
2343 gchar *culture = NULL;
2345 gchar *token = NULL;
2349 gchar *retargetable = NULL;
2350 gchar *retargetable_uq;
2354 gchar *value, *part_name;
2355 guint32 part_name_len;
2358 gboolean version_defined;
2359 gboolean token_defined;
2361 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2363 if (!is_version_defined)
2364 is_version_defined = &version_defined;
2365 *is_version_defined = FALSE;
2366 if (!is_token_defined)
2367 is_token_defined = &token_defined;
2368 *is_token_defined = FALSE;
2370 parts = tmp = g_strsplit (name, ",", 6);
2371 if (!tmp || !*tmp) {
2376 dllname = g_strstrip (*tmp);
2381 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2382 goto cleanup_and_fail;
2384 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2385 *is_version_defined = TRUE;
2387 if (strlen (version) == 0) {
2388 goto cleanup_and_fail;
2394 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2396 if (strlen (culture) == 0) {
2397 goto cleanup_and_fail;
2403 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2404 *is_token_defined = TRUE;
2406 if (strlen (token) == 0) {
2407 goto cleanup_and_fail;
2413 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2415 if (strlen (key) == 0) {
2416 goto cleanup_and_fail;
2422 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2423 retargetable = value;
2424 retargetable_uq = unquote (retargetable);
2425 if (retargetable_uq != NULL)
2426 retargetable = retargetable_uq;
2428 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2429 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2430 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2431 g_free (retargetable_uq);
2432 goto cleanup_and_fail;
2435 g_free (retargetable_uq);
2440 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2442 procarch_uq = unquote (procarch);
2443 if (procarch_uq != NULL)
2444 procarch = procarch_uq;
2446 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2447 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2448 else if (!g_ascii_strcasecmp (procarch, "X86"))
2449 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2450 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2451 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2452 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2453 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2455 g_free (procarch_uq);
2456 goto cleanup_and_fail;
2459 g_free (procarch_uq);
2468 /* if retargetable flag is set, then we must have a fully qualified name */
2469 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2470 goto cleanup_and_fail;
2473 dllname_uq = unquote (dllname);
2474 version_uq = unquote (version);
2475 culture_uq = unquote (culture);
2476 token_uq = unquote (token);
2477 key_uq = unquote (key);
2479 res = build_assembly_name (
2480 dllname_uq == NULL ? dllname : dllname_uq,
2481 version_uq == NULL ? version : version_uq,
2482 culture_uq == NULL ? culture : culture_uq,
2483 token_uq == NULL ? token : token_uq,
2484 key_uq == NULL ? key : key_uq,
2485 flags, arch, aname, save_public_key);
2487 g_free (dllname_uq);
2488 g_free (version_uq);
2489 g_free (culture_uq);
2502 unquote (const char *str)
2510 slen = strlen (str);
2514 if (*str != '\'' && *str != '\"')
2517 end = str + slen - 1;
2521 return g_strndup (str + 1, slen - 2);
2525 * mono_assembly_name_parse:
2526 * @name: name to parse
2527 * @aname: the destination assembly name
2529 * Parses an assembly qualified type name and assigns the name,
2530 * version, culture and token to the provided assembly name object.
2532 * Returns: TRUE if the name could be parsed.
2535 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2537 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2541 * mono_assembly_name_new:
2542 * @name: name to parse
2544 * Allocate a new MonoAssemblyName and fill its values from the
2547 * Returns: a newly allocated structure or NULL if there was any failure.
2550 mono_assembly_name_new (const char *name)
2552 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2553 if (mono_assembly_name_parse (name, aname))
2560 mono_assembly_name_get_name (MonoAssemblyName *aname)
2566 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2568 return aname->culture;
2572 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2574 if (aname->public_key_token [0])
2575 return aname->public_key_token;
2580 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2583 *minor = aname->minor;
2585 *build = aname->build;
2587 *revision = aname->revision;
2588 return aname->major;
2591 static MonoAssembly*
2592 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2594 gchar *fullpath = NULL;
2596 const char* direntry;
2597 MonoAssemblyName gac_aname;
2598 gint major=-1, minor=0, build=0, revision=0;
2599 gboolean exact_version;
2601 dirhandle = g_dir_open (basepath, 0, NULL);
2605 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2607 while ((direntry = g_dir_read_name (dirhandle))) {
2608 gboolean match = TRUE;
2610 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2613 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2616 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2617 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2621 if (exact_version) {
2622 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2623 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2625 else if (gac_aname.major < major)
2627 else if (gac_aname.major == major) {
2628 if (gac_aname.minor < minor)
2630 else if (gac_aname.minor == minor) {
2631 if (gac_aname.build < build)
2633 else if (gac_aname.build == build && gac_aname.revision <= revision)
2640 major = gac_aname.major;
2641 minor = gac_aname.minor;
2642 build = gac_aname.build;
2643 revision = gac_aname.revision;
2645 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2648 mono_assembly_name_free (&gac_aname);
2651 g_dir_close (dirhandle);
2653 if (fullpath == NULL)
2656 MonoAssembly *res = mono_assembly_open (fullpath, status);
2663 * mono_assembly_load_with_partial_name:
2664 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2665 * @status: return status code
2667 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2668 * so it might contain a qualified type name, version, culture and token.
2670 * This will load the assembly from the file whose name is derived from the assembly name
2671 * by appending the .dll extension.
2673 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2674 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2675 * if that fails from the GAC.
2677 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2680 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2684 MonoAssemblyName *aname, base_name;
2685 MonoAssemblyName mapped_aname;
2686 gchar *fullname, *gacpath;
2689 memset (&base_name, 0, sizeof (MonoAssemblyName));
2692 if (!mono_assembly_name_parse (name, aname))
2696 * If no specific version has been requested, make sure we load the
2697 * correct version for system assemblies.
2699 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2700 aname = mono_assembly_remap_version (aname, &mapped_aname);
2702 res = mono_assembly_loaded (aname);
2704 mono_assembly_name_free (aname);
2708 res = invoke_assembly_preload_hook (aname, assemblies_path);
2710 res->in_gac = FALSE;
2711 mono_assembly_name_free (aname);
2715 fullname = g_strdup_printf ("%s.dll", aname->name);
2717 if (extra_gac_paths) {
2718 paths = extra_gac_paths;
2719 while (!res && *paths) {
2720 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2721 res = probe_for_partial_name (gacpath, fullname, aname, status);
2730 mono_assembly_name_free (aname);
2734 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2735 res = probe_for_partial_name (gacpath, fullname, aname, status);
2739 mono_assembly_name_free (aname);
2744 MonoDomain *domain = mono_domain_get ();
2746 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2747 if (!is_ok (&error)) {
2748 mono_error_cleanup (&error);
2749 if (*status == MONO_IMAGE_OK)
2750 *status = MONO_IMAGE_IMAGE_INVALID;
2758 mono_assembly_is_in_gac (const gchar *filename)
2760 const gchar *rootdir;
2764 if (filename == NULL)
2767 for (paths = extra_gac_paths; paths && *paths; paths++) {
2768 if (strstr (*paths, filename) != *paths)
2771 gp = (gchar *) (filename + strlen (*paths));
2772 if (*gp != G_DIR_SEPARATOR)
2775 if (strncmp (gp, "lib", 3))
2778 if (*gp != G_DIR_SEPARATOR)
2781 if (strncmp (gp, "mono", 4))
2784 if (*gp != G_DIR_SEPARATOR)
2787 if (strncmp (gp, "gac", 3))
2790 if (*gp != G_DIR_SEPARATOR)
2796 rootdir = mono_assembly_getrootdir ();
2797 if (strstr (filename, rootdir) != filename)
2800 gp = (gchar *) (filename + strlen (rootdir));
2801 if (*gp != G_DIR_SEPARATOR)
2804 if (strncmp (gp, "mono", 4))
2807 if (*gp != G_DIR_SEPARATOR)
2810 if (strncmp (gp, "gac", 3))
2813 if (*gp != G_DIR_SEPARATOR)
2819 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2822 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2826 if (strstr (aname->name, ".dll")) {
2827 len = strlen (aname->name) - 4;
2828 name = (gchar *)g_malloc (len + 1);
2829 memcpy (name, aname->name, len);
2832 name = g_strdup (aname->name);
2835 culture = g_utf8_strdown (aname->culture, -1);
2837 culture = g_strdup ("");
2839 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2840 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2844 filename = g_strconcat (pname, ".dll", NULL);
2845 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2851 if (extra_gac_paths) {
2852 paths = extra_gac_paths;
2853 while (!image && *paths) {
2854 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2855 "lib", "mono", "gac", subpath, NULL);
2856 image = mono_image_open (fullpath, NULL);
2867 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2868 "mono", "gac", subpath, NULL);
2869 image = mono_image_open (fullpath, NULL);
2876 static MonoAssemblyName*
2877 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2879 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2880 dest_name->major = info->new_version.major;
2881 dest_name->minor = info->new_version.minor;
2882 dest_name->build = info->new_version.build;
2883 dest_name->revision = info->new_version.revision;
2888 /* LOCKING: assembly_binding lock must be held */
2889 static MonoAssemblyBindingInfo*
2890 search_binding_loaded (MonoAssemblyName *aname)
2894 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2895 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2896 if (assembly_binding_maps_name (info, aname))
2903 static inline gboolean
2904 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2906 if (left->major != right->major || left->minor != right->minor ||
2907 left->build != right->build || left->revision != right->revision)
2913 static inline gboolean
2914 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2916 if (left->has_old_version_bottom != right->has_old_version_bottom)
2919 if (left->has_old_version_top != right->has_old_version_top)
2922 if (left->has_new_version != right->has_new_version)
2925 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2928 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2931 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2937 /* LOCKING: assumes all the necessary locks are held */
2939 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2941 MonoAssemblyBindingInfo *info_copy;
2943 MonoAssemblyBindingInfo *info_tmp;
2944 MonoDomain *domain = (MonoDomain*)user_data;
2949 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2950 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2951 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2955 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2956 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2958 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2960 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2962 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2966 get_version_number (int major, int minor)
2968 return major * 256 + minor;
2971 static inline gboolean
2972 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2974 int aname_version_number = get_version_number (aname->major, aname->minor);
2975 if (!info->has_old_version_bottom)
2978 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2981 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2984 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2985 info->major = aname->major;
2986 info->minor = aname->minor;
2991 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2992 static MonoAssemblyBindingInfo*
2993 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2995 MonoAssemblyBindingInfo *info;
2998 if (!domain->assembly_bindings)
3002 for (list = domain->assembly_bindings; list; list = list->next) {
3003 info = (MonoAssemblyBindingInfo *)list->data;
3004 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3010 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3011 info->has_new_version && assembly_binding_maps_name (info, aname))
3012 info->is_valid = TRUE;
3014 info->is_valid = FALSE;
3020 static MonoAssemblyName*
3021 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3024 MonoAssemblyBindingInfo *info, *info2;
3028 if (aname->public_key_token [0] == 0)
3031 domain = mono_domain_get ();
3033 mono_assembly_binding_lock ();
3034 info = search_binding_loaded (aname);
3035 mono_assembly_binding_unlock ();
3038 mono_domain_lock (domain);
3039 info = get_per_domain_assembly_binding_info (domain, aname);
3040 mono_domain_unlock (domain);
3044 if (!check_policy_versions (info, aname))
3047 mono_assembly_bind_version (info, aname, dest_name);
3051 if (domain && domain->setup && domain->setup->configuration_file) {
3052 mono_domain_lock (domain);
3053 if (!domain->assembly_bindings_parsed) {
3054 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3055 /* expect this to succeed because mono_domain_set_options_from_config () did
3056 * the same thing when the domain was created. */
3057 mono_error_assert_ok (&error);
3059 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3061 if (!domain_config_file_path)
3062 domain_config_file_path = domain_config_file_name;
3064 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3065 domain->assembly_bindings_parsed = TRUE;
3066 if (domain_config_file_name != domain_config_file_path)
3067 g_free (domain_config_file_name);
3068 g_free (domain_config_file_path);
3071 info2 = get_per_domain_assembly_binding_info (domain, aname);
3074 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3075 info->name = g_strdup (info2->name);
3076 info->culture = g_strdup (info2->culture);
3077 info->domain_id = domain->domain_id;
3080 mono_domain_unlock (domain);
3084 info = g_new0 (MonoAssemblyBindingInfo, 1);
3085 info->major = aname->major;
3086 info->minor = aname->minor;
3089 if (!info->is_valid) {
3090 ppimage = mono_assembly_load_publisher_policy (aname);
3092 get_publisher_policy_info (ppimage, aname, info);
3093 mono_image_close (ppimage);
3097 /* Define default error value if needed */
3098 if (!info->is_valid) {
3099 info->name = g_strdup (aname->name);
3100 info->culture = g_strdup (aname->culture);
3101 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3104 mono_assembly_binding_lock ();
3105 info2 = search_binding_loaded (aname);
3107 /* This binding was added by another thread
3109 mono_assembly_binding_info_free (info);
3114 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3116 mono_assembly_binding_unlock ();
3118 if (!info->is_valid || !check_policy_versions (info, aname))
3121 mono_assembly_bind_version (info, aname, dest_name);
3126 * mono_assembly_load_from_gac
3128 * @aname: The assembly name object
3130 static MonoAssembly*
3131 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3133 MonoAssembly *result = NULL;
3134 gchar *name, *version, *culture, *fullpath, *subpath;
3139 if (aname->public_key_token [0] == 0) {
3143 if (strstr (aname->name, ".dll")) {
3144 len = strlen (filename) - 4;
3145 name = (gchar *)g_malloc (len + 1);
3146 memcpy (name, aname->name, len);
3149 name = g_strdup (aname->name);
3152 if (aname->culture) {
3153 culture = g_utf8_strdown (aname->culture, -1);
3155 culture = g_strdup ("");
3158 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3159 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3160 aname->minor, aname->build, aname->revision,
3164 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3169 if (extra_gac_paths) {
3170 paths = extra_gac_paths;
3171 while (!result && *paths) {
3172 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3173 result = mono_assembly_open_full (fullpath, status, refonly);
3180 result->in_gac = TRUE;
3185 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3186 "mono", "gac", subpath, NULL);
3187 result = mono_assembly_open_full (fullpath, status, refonly);
3191 result->in_gac = TRUE;
3199 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3202 MonoAssemblyName *aname;
3205 /* g_print ("corlib already loaded\n"); */
3209 // In native client, Corlib is embedded in the executable as static variable corlibData
3210 #if defined(__native_client__)
3211 if (corlibData != NULL && corlibSize != 0) {
3213 /* First "FALSE" instructs mono not to make a copy. */
3214 /* Second "FALSE" says this is not just a ref. */
3215 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3216 if (image == NULL || status != 0)
3217 g_print("mono_image_open_from_data_full failed: %d\n", status);
3218 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3219 if (corlib == NULL || status != 0)
3220 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3226 // A nonstandard preload hook may provide a special mscorlib assembly
3227 aname = mono_assembly_name_new ("mscorlib.dll");
3228 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3229 mono_assembly_name_free (aname);
3232 goto return_corlib_and_facades;
3234 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3235 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3236 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3238 goto return_corlib_and_facades;
3241 /* Normal case: Load corlib from mono/<version> */
3242 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3243 if (assemblies_path) { // Custom assemblies path
3244 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3246 g_free (corlib_file);
3247 goto return_corlib_and_facades;
3250 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3251 g_free (corlib_file);
3253 return_corlib_and_facades:
3254 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3255 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3260 static MonoAssembly*
3261 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3263 MonoError refasm_error;
3264 mono_error_init (&refasm_error);
3265 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3268 mono_error_cleanup (&refasm_error);
3274 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3275 const char *basedir,
3276 MonoImageOpenStatus *status,
3279 MonoAssembly *result;
3280 char *fullpath, *filename;
3281 MonoAssemblyName maped_aname;
3282 MonoAssemblyName maped_name_pp;
3287 aname = mono_assembly_remap_version (aname, &maped_aname);
3289 /* Reflection only assemblies don't get assembly binding */
3291 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3293 result = mono_assembly_loaded_full (aname, refonly);
3297 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3299 result->in_gac = FALSE;
3303 /* Currently we retrieve the loaded corlib for reflection
3304 * only requests, like a common reflection only assembly
3306 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3307 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3310 len = strlen (aname->name);
3311 for (ext_index = 0; ext_index < 2; ext_index ++) {
3312 ext = ext_index == 0 ? ".dll" : ".exe";
3313 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3314 filename = g_strdup (aname->name);
3315 /* Don't try appending .dll/.exe if it already has one of those extensions */
3318 filename = g_strconcat (aname->name, ext, NULL);
3321 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3328 fullpath = g_build_filename (basedir, filename, NULL);
3329 result = mono_assembly_open_full (fullpath, status, refonly);
3332 result->in_gac = FALSE;
3338 result = load_in_path (filename, default_path, status, refonly);
3340 result->in_gac = FALSE;
3350 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3352 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3355 /* Try a postload search hook */
3356 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3357 result = prevent_reference_assembly_from_running (result, refonly);
3363 * mono_assembly_load_full:
3364 * @aname: A MonoAssemblyName with the assembly name to load.
3365 * @basedir: A directory to look up the assembly at.
3366 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3367 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3369 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3370 * attempts to load the assembly from that directory before probing the standard locations.
3372 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3373 * assembly binding takes place.
3375 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3376 * value pointed by status is updated with an error code.
3379 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3381 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3385 * mono_assembly_load:
3386 * @aname: A MonoAssemblyName with the assembly name to load.
3387 * @basedir: A directory to look up the assembly at.
3388 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3390 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3391 * attempts to load the assembly from that directory before probing the standard locations.
3393 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3394 * value pointed by status is updated with an error code.
3397 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3399 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3403 * mono_assembly_loaded_full:
3404 * @aname: an assembly to look for.
3405 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3407 * This is used to determine if the specified assembly has been loaded
3408 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3409 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3412 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3415 MonoAssemblyName maped_aname;
3417 aname = mono_assembly_remap_version (aname, &maped_aname);
3419 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3425 * mono_assembly_loaded:
3426 * @aname: an assembly to look for.
3428 * This is used to determine if the specified assembly has been loaded
3430 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3431 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3434 mono_assembly_loaded (MonoAssemblyName *aname)
3436 return mono_assembly_loaded_full (aname, FALSE);
3440 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3442 if (assembly == NULL || assembly == REFERENCE_MISSING)
3445 if (assembly_is_dynamic (assembly)) {
3447 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3448 for (i = 0; i < dynimg->image.module_count; ++i)
3449 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3450 mono_dynamic_image_release_gc_roots (dynimg);
3455 * Returns whether mono_assembly_close_finish() must be called as
3456 * well. See comment for mono_image_close_except_pools() for why we
3457 * unload in two steps.
3460 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3463 g_return_val_if_fail (assembly != NULL, FALSE);
3465 if (assembly == REFERENCE_MISSING)
3468 /* Might be 0 already */
3469 if (InterlockedDecrement (&assembly->ref_count) > 0)
3472 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3474 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3476 mono_debug_close_image (assembly->image);
3478 mono_assemblies_lock ();
3479 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3480 mono_assemblies_unlock ();
3482 assembly->image->assembly = NULL;
3484 if (!mono_image_close_except_pools (assembly->image))
3485 assembly->image = NULL;
3487 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3488 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3489 mono_assembly_name_free (fname);
3492 g_slist_free (assembly->friend_assembly_names);
3493 g_free (assembly->basedir);
3495 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3501 mono_assembly_close_finish (MonoAssembly *assembly)
3503 g_assert (assembly && assembly != REFERENCE_MISSING);
3505 if (assembly->image)
3506 mono_image_close_finish (assembly->image);
3508 if (assembly_is_dynamic (assembly)) {
3509 g_free ((char*)assembly->aname.culture);
3516 * mono_assembly_close:
3517 * @assembly: the assembly to release.
3519 * This method releases a reference to the @assembly. The assembly is
3520 * only released when all the outstanding references to it are released.
3523 mono_assembly_close (MonoAssembly *assembly)
3525 if (mono_assembly_close_except_image_pools (assembly))
3526 mono_assembly_close_finish (assembly);
3530 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3533 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3534 mono_error_assert_ok (&error);
3539 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3541 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3546 * mono_assembly_foreach:
3547 * @func: function to invoke for each assembly loaded
3548 * @user_data: data passed to the callback
3550 * Invokes the provided @func callback for each assembly loaded into
3551 * the runtime. The first parameter passed to the callback is the
3552 * `MonoAssembly*`, and the second parameter is the @user_data.
3554 * This is done for all assemblies loaded in the runtime, not just
3555 * those loaded in the current application domain.
3558 mono_assembly_foreach (GFunc func, gpointer user_data)
3563 * We make a copy of the list to avoid calling the callback inside the
3564 * lock, which could lead to deadlocks.
3566 mono_assemblies_lock ();
3567 copy = g_list_copy (loaded_assemblies);
3568 mono_assemblies_unlock ();
3570 g_list_foreach (loaded_assemblies, func, user_data);
3576 * mono_assemblies_cleanup:
3578 * Free all resources used by this module.
3581 mono_assemblies_cleanup (void)
3585 mono_os_mutex_destroy (&assemblies_mutex);
3586 mono_os_mutex_destroy (&assembly_binding_mutex);
3588 for (l = loaded_assembly_bindings; l; l = l->next) {
3589 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3591 mono_assembly_binding_info_free (info);
3594 g_slist_free (loaded_assembly_bindings);
3596 free_assembly_load_hooks ();
3597 free_assembly_search_hooks ();
3598 free_assembly_preload_hooks ();
3601 /*LOCKING takes the assembly_binding lock*/
3603 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3607 mono_assembly_binding_lock ();
3608 iter = &loaded_assembly_bindings;
3611 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3613 if (info->domain_id == domain_id) {
3615 mono_assembly_binding_info_free (info);
3622 mono_assembly_binding_unlock ();
3626 * Holds the assembly of the application, for
3627 * System.Diagnostics.Process::MainModule
3629 static MonoAssembly *main_assembly=NULL;
3632 mono_assembly_set_main (MonoAssembly *assembly)
3634 main_assembly = assembly;
3638 * mono_assembly_get_main:
3640 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3643 mono_assembly_get_main (void)
3645 return (main_assembly);
3649 * mono_assembly_get_image:
3650 * @assembly: The assembly to retrieve the image from
3652 * Returns: the MonoImage associated with this assembly.
3655 mono_assembly_get_image (MonoAssembly *assembly)
3657 return assembly->image;
3661 * mono_assembly_get_name:
3662 * @assembly: The assembly to retrieve the name from
3664 * The returned name's lifetime is the same as @assembly's.
3666 * Returns: the MonoAssemblyName associated with this assembly.
3669 mono_assembly_get_name (MonoAssembly *assembly)
3671 return &assembly->aname;
3675 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3677 bundles = assemblies;
3680 #define MONO_DECLSEC_FORMAT_10 0x3C
3681 #define MONO_DECLSEC_FORMAT_20 0x2E
3682 #define MONO_DECLSEC_FIELD 0x53
3683 #define MONO_DECLSEC_PROPERTY 0x54
3685 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3686 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3687 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3688 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3689 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3692 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3696 case MONO_DECLSEC_PROPERTY:
3698 case MONO_DECLSEC_FIELD:
3700 *abort_decoding = TRUE;
3705 if (*p++ != MONO_TYPE_BOOLEAN) {
3706 *abort_decoding = TRUE;
3710 /* property name length */
3711 len = mono_metadata_decode_value (p, &p);
3713 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3724 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3726 int i, j, num, len, params_len;
3728 if (*p == MONO_DECLSEC_FORMAT_10) {
3729 gsize read, written;
3730 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3732 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3738 if (*p++ != MONO_DECLSEC_FORMAT_20)
3741 /* number of encoded permission attributes */
3742 num = mono_metadata_decode_value (p, &p);
3743 for (i = 0; i < num; ++i) {
3744 gboolean is_valid = FALSE;
3745 gboolean abort_decoding = FALSE;
3747 /* attribute name length */
3748 len = mono_metadata_decode_value (p, &p);
3750 /* We don't really need to fully decode the type. Comparing the name is enough */
3751 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3755 /*size of the params table*/
3756 params_len = mono_metadata_decode_value (p, &p);
3758 const char *params_end = p + params_len;
3760 /* number of parameters */
3761 len = mono_metadata_decode_value (p, &p);
3763 for (j = 0; j < len; ++j) {
3764 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3780 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3783 guint32 cols [MONO_DECL_SECURITY_SIZE];
3787 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3788 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3790 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3792 for (i = 0; i < t->rows; ++i) {
3793 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3794 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3796 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3799 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3800 len = mono_metadata_decode_blob_size (blob, &blob);
3804 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3805 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3810 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);