3 * Routines for loading assemblies.
6 * Miguel de Icaza (miguel@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "assembly-internals.h"
22 #include "image-internals.h"
23 #include "object-internals.h"
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/custom-attrs-internals.h>
27 #include <mono/metadata/metadata-internals.h>
28 #include <mono/metadata/profiler-private.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/domain-internals.h>
31 #include <mono/metadata/reflection-internals.h>
32 #include <mono/metadata/mono-endian.h>
33 #include <mono/metadata/mono-debug.h>
34 #include <mono/utils/mono-uri.h>
35 #include <mono/metadata/mono-config.h>
36 #include <mono/metadata/mono-config-dirs.h>
37 #include <mono/utils/mono-digest.h>
38 #include <mono/utils/mono-logger-internals.h>
39 #include <mono/utils/mono-path.h>
40 #include <mono/metadata/reflection.h>
41 #include <mono/metadata/coree.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/utils/mono-io-portability.h>
44 #include <mono/utils/atomic.h>
45 #include <mono/utils/mono-os-mutex.h>
48 #include <sys/types.h>
53 #ifdef PLATFORM_MACOSX
54 #include <mach-o/dyld.h>
57 /* 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 */
59 const char* assembly_name;
60 guint8 version_set_index;
61 const char* new_assembly_name;
62 gboolean only_lower_versions;
65 /* Flag bits for assembly_names_equal_flags (). */
67 /* Default comparison: all fields must match */
69 /* Don't compare public key token */
70 ANAME_EQ_IGNORE_PUBKEY = 0x1,
73 } AssemblyNameEqFlags;
75 /* the default search path is empty, the first slot is replaced with the computed value */
83 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
84 static char **assemblies_path = NULL;
86 /* Contains the list of directories that point to auxiliary GACs */
87 static char **extra_gac_paths = NULL;
89 #ifndef DISABLE_ASSEMBLY_REMAPPING
91 static GHashTable* assembly_remapping_table;
92 /* The list of system assemblies what will be remapped to the running
94 * This list is stored in @assembly_remapping_table during initialization.
95 * Keep it sorted just to make maintenance easier.
97 * The integer number is an index in the MonoRuntimeInfo structure, whose
98 * values can be found in domain.c - supported_runtimes. Look there
99 * to understand what remapping will be made.
101 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
104 static const AssemblyVersionMap framework_assemblies [] = {
105 {"Accessibility", 0},
106 {"Commons.Xml.Relaxng", 0},
113 {"Microsoft.Build.Engine", 2, NULL, TRUE},
114 {"Microsoft.Build.Framework", 2, NULL, TRUE},
115 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
116 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
117 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
118 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
119 {"Microsoft.VisualBasic", 1},
120 {"Microsoft.VisualC", 1},
122 {"Mono.CompilerServices.SymbolWriter", 0},
124 {"Mono.Data.SybaseClient", 0},
125 {"Mono.Data.Tds", 0},
126 {"Mono.Data.TdsClient", 0},
127 {"Mono.GetOptions", 0},
130 {"Mono.Security", 0},
131 {"Mono.Security.Win32", 0},
133 {"Novell.Directory.Ldap", 0},
136 {"System.ComponentModel.Composition", 2},
137 {"System.ComponentModel.DataAnnotations", 2},
138 {"System.Configuration", 0},
139 {"System.Configuration.Install", 0},
142 {"System.Data.Linq", 2},
143 {"System.Data.OracleClient", 0},
144 {"System.Data.Services", 2},
145 {"System.Data.Services.Client", 2},
146 {"System.Data.SqlXml", 0},
147 {"System.Design", 0},
148 {"System.DirectoryServices", 0},
149 {"System.Drawing", 0},
150 {"System.Drawing.Design", 0},
151 {"System.EnterpriseServices", 0},
152 {"System.IO.Compression", 2},
153 {"System.IdentityModel", 3},
154 {"System.IdentityModel.Selectors", 3},
155 {"System.Management", 0},
156 {"System.Messaging", 0},
158 {"System.Net.Http", 4},
159 {"System.Numerics.Vectors", 3},
160 {"System.Runtime.InteropServices.RuntimeInformation", 2},
161 {"System.Runtime.Remoting", 0},
162 {"System.Runtime.Serialization", 3},
163 {"System.Runtime.Serialization.Formatters", 3},
164 {"System.Runtime.Serialization.Formatters.Soap", 0},
165 {"System.Security", 0},
166 {"System.ServiceModel", 3},
167 {"System.ServiceModel.Duplex", 3},
168 {"System.ServiceModel.Http", 3},
169 {"System.ServiceModel.NetTcp", 3},
170 {"System.ServiceModel.Primitives", 3},
171 {"System.ServiceModel.Security", 3},
172 {"System.ServiceModel.Web", 2},
173 {"System.ServiceProcess", 0},
174 {"System.Text.Encoding.CodePages", 3},
175 {"System.Transactions", 0},
177 {"System.Web.Abstractions", 2},
178 {"System.Web.DynamicData", 2},
179 {"System.Web.Extensions", 2},
180 {"System.Web.Mobile", 0},
181 {"System.Web.Routing", 2},
182 {"System.Web.Services", 0},
183 {"System.Windows.Forms", 0},
185 {"System.Xml.Linq", 2},
186 {"System.Xml.ReaderWriter", 3},
187 {"System.Xml.XPath.XmlDocument", 3},
194 * keeps track of loaded assemblies
196 static GList *loaded_assemblies = NULL;
197 static MonoAssembly *corlib;
199 #if defined(__native_client__)
201 /* On Native Client, allow mscorlib to be loaded from memory */
202 /* instead of loaded off disk. If these are not set, default */
203 /* mscorlib loading will take place */
205 /* NOTE: If mscorlib data is passed to mono in this way then */
206 /* it needs to remain allocated during the use of mono. */
208 static void *corlibData = NULL;
209 static size_t corlibSize = 0;
212 mono_set_corlib_data (void *data, size_t size)
220 static char* unquote (const char *str);
222 /* This protects loaded_assemblies and image->references */
223 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
224 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
225 static mono_mutex_t assemblies_mutex;
227 /* If defined, points to the bundled assembly information */
228 const MonoBundledAssembly **bundles;
230 static mono_mutex_t assembly_binding_mutex;
232 /* Loaded assembly binding info */
233 static GSList *loaded_assembly_bindings = NULL;
235 /* Class lazy loading functions */
236 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
238 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
240 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
242 mono_assembly_is_in_gac (const gchar *filanem);
245 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
248 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags);
250 /* Assembly name matching */
252 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
254 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
257 encode_public_tok (const guchar *token, gint32 len)
259 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
263 res = (gchar *)g_malloc (len * 2 + 1);
264 for (i = 0; i < len; i++) {
265 res [i * 2] = allowed [token [i] >> 4];
266 res [i * 2 + 1] = allowed [token [i] & 0xF];
273 * mono_public_tokens_are_equal:
274 * \param pubt1 first public key token
275 * \param pubt2 second public key token
277 * Compare two public key tokens and return TRUE is they are equal and FALSE
281 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
283 return memcmp (pubt1, pubt2, 16) == 0;
287 * mono_set_assemblies_path:
288 * \param path list of paths that contain directories where Mono will look for assemblies
290 * Use this method to override the standard assembly lookup system and
291 * override any assemblies coming from the GAC. This is the method
292 * that supports the \c MONO_PATH variable.
294 * Notice that \c MONO_PATH and this method are really a very bad idea as
295 * it prevents the GAC from working and it prevents the standard
296 * resolution mechanisms from working. Nonetheless, for some debugging
297 * situations and bootstrapping setups, this is useful to have.
300 mono_set_assemblies_path (const char* path)
302 char **splitted, **dest;
304 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
306 g_strfreev (assemblies_path);
307 assemblies_path = dest = splitted;
309 char *tmp = *splitted;
311 *dest++ = mono_path_canonicalize (tmp);
317 if (g_hasenv ("MONO_DEBUG"))
320 splitted = assemblies_path;
322 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
323 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
329 /* Native Client can't get this info from an environment variable so */
330 /* it's passed in to the runtime, or set manually by embedding code. */
331 #ifdef __native_client__
332 char* nacl_mono_path = NULL;
336 check_path_env (void)
338 if (assemblies_path != NULL)
341 char* path = g_getenv ("MONO_PATH");
342 #ifdef __native_client__
344 path = strdup (nacl_mono_path);
349 mono_set_assemblies_path(path);
354 check_extra_gac_path_env (void)
357 char **splitted, **dest;
359 path = g_getenv ("MONO_GAC_PREFIX");
363 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
367 g_strfreev (extra_gac_paths);
368 extra_gac_paths = dest = splitted;
376 if (!g_hasenv ("MONO_DEBUG"))
380 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
381 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
388 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
390 if (!info || !info->name)
393 if (strcmp (info->name, aname->name))
396 if (info->major != aname->major || info->minor != aname->minor)
399 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
402 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
405 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
412 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
418 g_free (info->culture);
422 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
425 guint32 cols [MONO_MANIFEST_SIZE];
426 const gchar *filename;
427 gchar *subpath, *fullpath;
429 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
430 /* MS Impl. accepts policy assemblies with more than
431 * one manifest resource, and only takes the first one */
433 binding_info->is_valid = FALSE;
437 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
438 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
439 binding_info->is_valid = FALSE;
443 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
444 g_assert (filename != NULL);
446 subpath = g_path_get_dirname (image->name);
447 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
448 mono_config_parse_publisher_policy (fullpath, binding_info);
452 /* Define the optional elements/attributes before checking */
453 if (!binding_info->culture)
454 binding_info->culture = g_strdup ("");
456 /* Check that the most important elements/attributes exist */
457 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
458 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
459 mono_assembly_binding_info_free (binding_info);
460 binding_info->is_valid = FALSE;
464 binding_info->is_valid = TRUE;
468 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
470 if (v->major > aname->major)
472 else if (v->major < aname->major)
475 if (v->minor > aname->minor)
477 else if (v->minor < aname->minor)
480 if (v->build > aname->build)
482 else if (v->build < aname->build)
485 if (v->revision > aname->revision)
487 else if (v->revision < aname->revision)
494 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
499 /* If has_old_version_top doesn't exist, we don't have an interval */
500 if (!info->has_old_version_top) {
501 if (compare_versions (&info->old_version_bottom, name) == 0)
507 /* Check that the version defined by name is valid for the interval */
508 if (compare_versions (&info->old_version_top, name) < 0)
511 /* We should be greater or equal than the small version */
512 if (compare_versions (&info->old_version_bottom, name) > 0)
519 * mono_assembly_names_equal:
520 * \param l first assembly
521 * \param r second assembly.
523 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
525 * This compares the names, the cultures, the release version and their
528 * \returns TRUE if both assembly names are equal.
531 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
533 return assembly_names_equal_flags (l, r, ANAME_EQ_NONE);
537 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags)
539 if (!l->name || !r->name)
542 if (strcmp (l->name, r->name))
545 if (l->culture && r->culture && strcmp (l->culture, r->culture))
548 if (l->major != r->major || l->minor != r->minor ||
549 l->build != r->build || l->revision != r->revision)
550 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)))
553 if (!l->public_key_token [0] || !r->public_key_token [0] || (flags & ANAME_EQ_IGNORE_PUBKEY) != 0)
556 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
562 static MonoAssembly *
563 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
567 MonoAssembly *result;
569 for (i = 0; search_path [i]; ++i) {
570 fullpath = g_build_filename (search_path [i], basename, NULL);
571 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
580 * mono_assembly_setrootdir:
581 * \param root_dir The pathname of the root directory where we will locate assemblies
583 * This routine sets the internal default root directory for looking up
586 * This is used by Windows installations to compute dynamically the
587 * place where the Mono assemblies are located.
591 mono_assembly_setrootdir (const char *root_dir)
594 * Override the MONO_ASSEMBLIES directory configured at compile time.
596 /* Leak if called more than once */
597 default_path [0] = g_strdup (root_dir);
601 * mono_assembly_getrootdir:
603 * Obtains the root directory used for looking up assemblies.
605 * Returns: a string with the directory, this string should not be freed.
607 G_CONST_RETURN gchar *
608 mono_assembly_getrootdir (void)
610 return default_path [0];
614 * mono_native_getrootdir:
616 * Obtains the root directory used for looking up native libs (.so, .dylib).
618 * Returns: a string with the directory, this string should be freed by
622 mono_native_getrootdir (void)
624 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
630 * \param assembly_dir the base directory for assemblies
631 * \param config_dir the base directory for configuration files
633 * This routine is used internally and by developers embedding
634 * the runtime into their own applications.
636 * There are a number of cases to consider: Mono as a system-installed
637 * package that is available on the location preconfigured or Mono in
638 * a relocated location.
640 * If you are using a system-installed Mono, you can pass NULL
641 * to both parameters. If you are not, you should compute both
642 * directory values and call this routine.
644 * The values for a given PREFIX are:
646 * assembly_dir: PREFIX/lib
647 * config_dir: PREFIX/etc
649 * Notice that embedders that use Mono in a relocated way must
650 * compute the location at runtime, as they will be in control
651 * of where Mono is installed.
654 mono_set_dirs (const char *assembly_dir, const char *config_dir)
656 if (assembly_dir == NULL)
657 assembly_dir = mono_config_get_assemblies_dir ();
658 if (config_dir == NULL)
659 config_dir = mono_config_get_cfg_dir ();
660 mono_assembly_setrootdir (assembly_dir);
661 mono_set_config_dir (config_dir);
667 compute_base (char *path)
669 char *p = strrchr (path, '/');
673 /* Not a well known Mono executable, we are embedded, cant guess the base */
674 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
678 p = strrchr (path, '/');
682 if (strcmp (p, "/bin") != 0)
691 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
694 static G_GNUC_UNUSED void
698 char *config, *lib, *mono;
703 * Only /usr prefix is treated specially
705 bindir = mono_config_get_bin_dir ();
707 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
712 config = g_build_filename (base, "etc", NULL);
713 lib = g_build_filename (base, "lib", NULL);
714 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
715 if (stat (mono, &buf) == -1)
718 mono_set_dirs (lib, config);
726 #endif /* HOST_WIN32 */
731 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
732 * this auto-detects the prefix where Mono was installed.
735 mono_set_rootdir (void)
737 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
738 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
741 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
745 * _NSGetExecutablePath may return -1 to indicate buf is not large
746 * enough, but we ignore that case to avoid having to do extra dynamic
747 * allocation for the path and hope that 4096 is enough - this is
748 * ok in the Linux/Solaris case below at least...
752 guint buf_size = sizeof (buf);
755 if (_NSGetExecutablePath (buf, &buf_size) == 0)
756 name = g_strdup (buf);
765 resolvedname = mono_path_resolve_symlinks (name);
767 bindir = g_path_get_dirname (resolvedname);
768 installdir = g_path_get_dirname (bindir);
769 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
771 config = g_build_filename (root, "..", "etc", NULL);
773 mono_set_dirs (root, config);
775 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
776 mono_set_dirs (root, config);
786 g_free (resolvedname);
787 #elif defined(DISABLE_MONO_AUTODETECTION)
795 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
803 /* Solaris 10 style */
804 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
805 s = readlink (str, buf, sizeof (buf)-1);
817 * mono_assemblies_init:
819 * Initialize global variables used by this module.
822 mono_assemblies_init (void)
825 * Initialize our internal paths if we have not been initialized yet.
826 * This happens when embedders use Mono.
828 if (mono_assembly_getrootdir () == NULL)
832 check_extra_gac_path_env ();
834 mono_os_mutex_init_recursive (&assemblies_mutex);
835 mono_os_mutex_init (&assembly_binding_mutex);
837 #ifndef DISABLE_ASSEMBLY_REMAPPING
838 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
841 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
842 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
848 mono_assembly_binding_lock (void)
850 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
854 mono_assembly_binding_unlock (void)
856 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
860 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
862 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
863 guint32 cols [MONO_ASSEMBLY_SIZE];
864 gint32 machine, flags;
869 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
872 aname->hash_value = NULL;
873 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
875 aname->name = g_strdup (aname->name);
876 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
878 aname->culture = g_strdup (aname->culture);
879 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
880 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
881 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
882 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
883 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
884 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
885 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
886 guchar* token = (guchar *)g_malloc (8);
891 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
892 len = mono_metadata_decode_blob_size (pkey, &pkey);
893 aname->public_key = (guchar*)pkey;
895 mono_digest_get_public_token (token, aname->public_key, len);
896 encoded = encode_public_tok (token, 8);
897 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
903 aname->public_key = NULL;
904 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
907 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
908 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
910 const gchar *pkey_end;
911 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
912 pkey_end += len; /* move to end */
913 size_t size = pkey_end - (const gchar*)aname->public_key;
914 guchar *tmp = g_new (guchar, size);
915 memcpy (tmp, aname->public_key, size);
916 aname->public_key = tmp;
921 aname->public_key = 0;
923 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
924 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
926 case COFF_MACHINE_I386:
927 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
928 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
929 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
930 else if ((flags & 0x70) == 0x70)
931 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
933 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
935 case COFF_MACHINE_IA64:
936 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
938 case COFF_MACHINE_AMD64:
939 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
941 case COFF_MACHINE_ARM:
942 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
952 * mono_assembly_fill_assembly_name:
955 * \returns TRUE if successful
958 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
960 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
964 * mono_stringify_assembly_name:
965 * \param aname the assembly name.
967 * Convert \p aname into its string format. The returned string is dynamically
968 * allocated and should be freed by the caller.
970 * \returns a newly allocated string with a string representation of
974 mono_stringify_assembly_name (MonoAssemblyName *aname)
976 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
978 return g_strdup_printf (
979 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
980 quote, aname->name, quote,
981 aname->major, aname->minor, aname->build, aname->revision,
982 aname->culture && *aname->culture? aname->culture: "neutral",
983 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
984 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
988 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
990 const gchar *public_tok;
993 public_tok = mono_metadata_blob_heap (image, key_index);
994 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
996 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
998 mono_digest_get_public_token (token, (guchar*)public_tok, len);
999 return encode_public_tok (token, 8);
1002 return encode_public_tok ((guchar*)public_tok, len);
1006 * mono_assembly_addref:
1007 * \param assembly the assembly to reference
1009 * This routine increments the reference count on a MonoAssembly.
1010 * The reference count is reduced every time the method mono_assembly_close() is
1014 mono_assembly_addref (MonoAssembly *assembly)
1016 InterlockedIncrement (&assembly->ref_count);
1020 * CAUTION: This table must be kept in sync with
1021 * ivkm/reflect/Fusion.cs
1024 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1025 #define WINFX_KEY "31bf3856ad364e35"
1026 #define ECMA_KEY "b77a5c561934e089"
1027 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1028 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1036 static KeyRemapEntry key_remap_table[] = {
1037 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1038 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1039 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1040 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1041 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1042 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1043 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1044 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1045 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1046 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1047 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1048 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1049 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1050 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1051 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1052 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1053 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1054 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1055 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1056 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1057 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1058 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1059 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1060 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1061 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1062 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1063 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1064 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1065 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1069 remap_keys (MonoAssemblyName *aname)
1072 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1073 const KeyRemapEntry *entry = &key_remap_table [i];
1075 if (strcmp (aname->name, entry->name) ||
1076 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1079 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1081 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1082 "Remapped public key token of retargetable assembly %s from %s to %s",
1083 aname->name, entry->from, entry->to);
1088 static MonoAssemblyName *
1089 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1091 const MonoRuntimeInfo *current_runtime;
1093 if (aname->name == NULL) return aname;
1095 current_runtime = mono_get_runtime_info ();
1097 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1098 const AssemblyVersionSet* vset;
1100 /* Remap to current runtime */
1101 vset = ¤t_runtime->version_sets [0];
1103 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1104 dest_aname->major = vset->major;
1105 dest_aname->minor = vset->minor;
1106 dest_aname->build = vset->build;
1107 dest_aname->revision = vset->revision;
1108 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1110 /* Remap assembly name */
1111 if (!strcmp (aname->name, "System.Net"))
1112 dest_aname->name = g_strdup ("System");
1114 remap_keys (dest_aname);
1116 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1117 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1119 aname->major, aname->minor, aname->build, aname->revision,
1121 vset->major, vset->minor, vset->build, vset->revision
1127 #ifndef DISABLE_ASSEMBLY_REMAPPING
1128 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1130 const AssemblyVersionSet* vset;
1131 int index = vmap->version_set_index;
1132 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1133 vset = ¤t_runtime->version_sets [index];
1135 if (aname->major == vset->major && aname->minor == vset->minor &&
1136 aname->build == vset->build && aname->revision == vset->revision) {
1137 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1139 aname->major, aname->minor, aname->build, aname->revision);
1143 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1144 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1145 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1147 aname->major, aname->minor, aname->build, aname->revision,
1148 vset->major, vset->minor, vset->build, vset->revision
1153 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1154 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1155 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1157 aname->major, aname->minor, aname->build, aname->revision,
1158 vset->major, vset->minor, vset->build, vset->revision
1161 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1162 dest_aname->major = vset->major;
1163 dest_aname->minor = vset->minor;
1164 dest_aname->build = vset->build;
1165 dest_aname->revision = vset->revision;
1166 if (vmap->new_assembly_name != NULL) {
1167 dest_aname->name = vmap->new_assembly_name;
1168 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1169 "The assembly name %s was remapped to %s",
1181 * mono_assembly_get_assemblyref:
1182 * \param image pointer to the \c MonoImage to extract the information from.
1183 * \param index index to the assembly reference in the image.
1184 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1186 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1189 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1192 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1195 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1197 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1199 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1200 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1201 aname->hash_value = hash;
1202 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1203 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1204 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1205 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1206 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1207 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1208 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1210 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1211 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1212 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1215 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1220 * mono_assembly_load_reference:
1223 mono_assembly_load_reference (MonoImage *image, int index)
1225 MonoAssembly *reference;
1226 MonoAssemblyName aname;
1227 MonoImageOpenStatus status;
1230 * image->references is shared between threads, so we need to access
1231 * it inside a critical section.
1233 mono_assemblies_lock ();
1234 if (!image->references) {
1235 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1237 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1238 image->nreferences = t->rows;
1240 reference = image->references [index];
1241 mono_assemblies_unlock ();
1245 mono_assembly_get_assemblyref (image, index, &aname);
1247 if (image->assembly && image->assembly->ref_only) {
1248 /* We use the loaded corlib */
1249 if (!strcmp (aname.name, "mscorlib"))
1250 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1252 reference = mono_assembly_loaded_full (&aname, TRUE);
1254 /* Try a postload search hook */
1255 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1259 * Here we must advice that the error was due to
1260 * a non loaded reference using the ReflectionOnly api
1263 reference = (MonoAssembly *)REFERENCE_MISSING;
1265 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1266 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1267 * accordingly, it would fail on the MS runtime before).
1268 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1269 * example bug-349190.2.cs and who knows how much more code in the wild.
1271 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1272 if (!reference && image->assembly)
1273 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1276 if (reference == NULL){
1279 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1280 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 : "" );
1281 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1282 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1283 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1284 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1285 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1286 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1288 extra_msg = g_strdup ("");
1291 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1292 " Assembly: %s (assemblyref_index=%d)\n"
1293 " Version: %d.%d.%d.%d\n"
1294 " Public Key: %s\n%s",
1295 image->name, aname.name, index,
1296 aname.major, aname.minor, aname.build, aname.revision,
1297 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1302 mono_assemblies_lock ();
1303 if (reference == NULL) {
1304 /* Flag as not found */
1305 reference = (MonoAssembly *)REFERENCE_MISSING;
1308 if (!image->references [index]) {
1309 if (reference != REFERENCE_MISSING){
1310 mono_assembly_addref (reference);
1311 if (image->assembly)
1312 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1313 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1315 if (image->assembly)
1316 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1317 image->assembly->aname.name, image->assembly);
1320 image->references [index] = reference;
1322 mono_assemblies_unlock ();
1324 if (image->references [index] != reference) {
1325 /* Somebody loaded it before us */
1326 mono_assembly_close (reference);
1331 * mono_assembly_load_references:
1334 * \deprecated There is no reason to use this method anymore, it does nothing
1336 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1339 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1341 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1342 *status = MONO_IMAGE_OK;
1345 typedef struct AssemblyLoadHook AssemblyLoadHook;
1346 struct AssemblyLoadHook {
1347 AssemblyLoadHook *next;
1348 MonoAssemblyLoadFunc func;
1352 AssemblyLoadHook *assembly_load_hook = NULL;
1355 * mono_assembly_invoke_load_hook:
1358 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1360 AssemblyLoadHook *hook;
1362 for (hook = assembly_load_hook; hook; hook = hook->next) {
1363 hook->func (ass, hook->user_data);
1368 * mono_install_assembly_load_hook:
1371 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1373 AssemblyLoadHook *hook;
1375 g_return_if_fail (func != NULL);
1377 hook = g_new0 (AssemblyLoadHook, 1);
1379 hook->user_data = user_data;
1380 hook->next = assembly_load_hook;
1381 assembly_load_hook = hook;
1385 free_assembly_load_hooks (void)
1387 AssemblyLoadHook *hook, *next;
1389 for (hook = assembly_load_hook; hook; hook = next) {
1395 typedef struct AssemblySearchHook AssemblySearchHook;
1396 struct AssemblySearchHook {
1397 AssemblySearchHook *next;
1398 MonoAssemblySearchFunc func;
1404 AssemblySearchHook *assembly_search_hook = NULL;
1406 static MonoAssembly*
1407 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1409 AssemblySearchHook *hook;
1411 for (hook = assembly_search_hook; hook; hook = hook->next) {
1412 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1415 * A little explanation is in order here.
1417 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1418 * The embedding API exposes a search hook that doesn't take such argument.
1420 * The original fix would call the default search hook before all the registered ones and pass
1421 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1422 * rely on. Which is the ordering between user hooks and the default runtime hook.
1424 * Registering the hook after mono_jit_init would let your hook run before the default one and
1425 * when using it to handle non standard app layouts this could save your app from a massive amount
1426 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1427 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1429 * So what's the fix? We register the default hook using regular means and special case it when iterating
1430 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1433 if (hook->func == (void*)mono_domain_assembly_postload_search)
1434 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1436 ass = hook->func (aname, hook->user_data);
1446 * mono_assembly_invoke_search_hook:
1449 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1451 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1455 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1457 AssemblySearchHook *hook;
1459 g_return_if_fail (func != NULL);
1461 hook = g_new0 (AssemblySearchHook, 1);
1463 hook->user_data = user_data;
1464 hook->refonly = refonly;
1465 hook->postload = postload;
1466 hook->next = assembly_search_hook;
1467 assembly_search_hook = hook;
1471 * mono_install_assembly_search_hook:
1474 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1476 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1480 free_assembly_search_hooks (void)
1482 AssemblySearchHook *hook, *next;
1484 for (hook = assembly_search_hook; hook; hook = next) {
1491 * mono_install_assembly_refonly_search_hook:
1494 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1496 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1500 * mono_install_assembly_postload_search_hook:
1503 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1505 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1509 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1511 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1514 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1515 struct AssemblyPreLoadHook {
1516 AssemblyPreLoadHook *next;
1517 MonoAssemblyPreLoadFunc func;
1521 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1522 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1524 static MonoAssembly *
1525 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1527 AssemblyPreLoadHook *hook;
1528 MonoAssembly *assembly;
1530 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1531 assembly = hook->func (aname, assemblies_path, hook->user_data);
1532 if (assembly != NULL)
1539 static MonoAssembly *
1540 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1542 AssemblyPreLoadHook *hook;
1543 MonoAssembly *assembly;
1545 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1546 assembly = hook->func (aname, assemblies_path, hook->user_data);
1547 if (assembly != NULL)
1555 * mono_install_assembly_preload_hook:
1558 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1560 AssemblyPreLoadHook *hook;
1562 g_return_if_fail (func != NULL);
1564 hook = g_new0 (AssemblyPreLoadHook, 1);
1566 hook->user_data = user_data;
1567 hook->next = assembly_preload_hook;
1568 assembly_preload_hook = hook;
1572 * mono_install_assembly_refonly_preload_hook:
1575 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1577 AssemblyPreLoadHook *hook;
1579 g_return_if_fail (func != NULL);
1581 hook = g_new0 (AssemblyPreLoadHook, 1);
1583 hook->user_data = user_data;
1584 hook->next = assembly_refonly_preload_hook;
1585 assembly_refonly_preload_hook = hook;
1589 free_assembly_preload_hooks (void)
1591 AssemblyPreLoadHook *hook, *next;
1593 for (hook = assembly_preload_hook; hook; hook = next) {
1598 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1605 absolute_dir (const gchar *filename)
1616 if (g_path_is_absolute (filename)) {
1617 part = g_path_get_dirname (filename);
1618 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1623 cwd = g_get_current_dir ();
1624 mixed = g_build_filename (cwd, filename, NULL);
1625 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1630 for (i = 0; (part = parts [i]) != NULL; i++) {
1631 if (!strcmp (part, "."))
1634 if (!strcmp (part, "..")) {
1635 if (list && list->next) /* Don't remove root */
1636 list = g_list_delete_link (list, list);
1638 list = g_list_prepend (list, part);
1642 result = g_string_new ("");
1643 list = g_list_reverse (list);
1645 /* Ignores last data pointer, which should be the filename */
1646 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1648 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1653 g_string_free (result, FALSE);
1658 return g_strdup (".");
1665 * mono_assembly_open_from_bundle:
1666 * \param filename Filename requested
1667 * \param status return status code
1669 * This routine tries to open the assembly specified by \p filename from the
1670 * defined bundles, if found, returns the MonoImage for it, if not found
1674 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1678 gchar *lowercase_filename;
1679 MonoImage *image = NULL;
1680 gboolean is_satellite = FALSE;
1682 * we do a very simple search for bundled assemblies: it's not a general
1683 * purpose assembly loading mechanism.
1689 lowercase_filename = g_utf8_strdown (filename, -1);
1690 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1691 g_free (lowercase_filename);
1692 name = g_path_get_basename (filename);
1693 mono_assemblies_lock ();
1694 for (i = 0; !image && bundles [i]; ++i) {
1695 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1696 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1700 mono_assemblies_unlock ();
1702 mono_image_addref (image);
1703 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1712 * mono_assembly_open_full:
1713 * \param filename the file to load
1714 * \param status return status code
1715 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1717 * This loads an assembly from the specified \p filename. The \p filename allows
1718 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1719 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1720 * is treated as a local path.
1722 * First, an attempt is made to load the assembly from the bundled executable (for those
1723 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1724 * assembly has been registered as an embedded assembly). If this is not the case, then
1725 * the assembly is loaded from disk using `api:mono_image_open_full`.
1727 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1728 * the assembly is made.
1730 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1731 * the \c System.Reflection API.
1733 * \returns NULL on error, with the \p status set to an error code, or a pointer
1737 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1739 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1743 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1745 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1749 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1750 gboolean load_from_context,
1751 MonoAssemblyCandidatePredicate predicate,
1753 MonoImageOpenStatus *status)
1757 MonoImageOpenStatus def_status;
1760 gboolean loaded_from_bundle;
1762 g_return_val_if_fail (filename != NULL, NULL);
1765 status = &def_status;
1766 *status = MONO_IMAGE_OK;
1768 if (strncmp (filename, "file://", 7) == 0) {
1769 GError *error = NULL;
1770 gchar *uri = (gchar *) filename;
1774 * MS allows file://c:/... and fails on file://localhost/c:/...
1775 * They also throw an IndexOutOfRangeException if "file://"
1778 uri = g_strdup_printf ("file:///%s", uri + 7);
1781 uri = mono_escape_uri_string (tmpuri);
1782 fname = g_filename_from_uri (uri, NULL, &error);
1785 if (tmpuri != filename)
1788 if (error != NULL) {
1789 g_warning ("%s\n", error->message);
1790 g_error_free (error);
1791 fname = g_strdup (filename);
1794 fname = g_strdup (filename);
1797 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1798 "Assembly Loader probing location: '%s'.", fname);
1801 if (!mono_assembly_is_in_gac (fname)) {
1803 new_fname = mono_make_shadow_copy (fname, &error);
1804 if (!is_ok (&error)) {
1805 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1806 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1807 mono_error_cleanup (&error);
1808 *status = MONO_IMAGE_IMAGE_INVALID;
1813 if (new_fname && new_fname != fname) {
1816 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1817 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1822 // If VM built with mkbundle
1823 loaded_from_bundle = FALSE;
1824 if (bundles != NULL) {
1825 image = mono_assembly_open_from_bundle (fname, status, refonly);
1826 loaded_from_bundle = image != NULL;
1830 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1833 if (*status == MONO_IMAGE_OK)
1834 *status = MONO_IMAGE_ERROR_ERRNO;
1839 if (image->assembly) {
1840 /* Already loaded by another appdomain */
1841 mono_assembly_invoke_load_hook (image->assembly);
1842 mono_image_close (image);
1844 return image->assembly;
1847 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1850 if (!loaded_from_bundle)
1851 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1852 "Assembly Loader loaded assembly from location: '%s'.", filename);
1854 mono_config_for_assembly (ass->image);
1857 /* Clear the reference added by mono_image_open */
1858 mono_image_close (image);
1866 free_item (gpointer val, gpointer user_data)
1872 * mono_assembly_load_friends:
1873 * \param ass an assembly
1875 * Load the list of friend assemblies that are allowed to access
1876 * the assembly's internal types and members. They are stored as assembly
1877 * names in custom attributes.
1879 * This is an internal method, we need this because when we load mscorlib
1880 * we do not have the internals visible cattr loaded yet,
1881 * so we need to load these after we initialize the runtime.
1883 * LOCKING: Acquires the assemblies lock plus the loader lock.
1886 mono_assembly_load_friends (MonoAssembly* ass)
1890 MonoCustomAttrInfo* attrs;
1893 if (ass->friend_assembly_names_inited)
1896 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1897 mono_error_assert_ok (&error);
1899 mono_assemblies_lock ();
1900 ass->friend_assembly_names_inited = TRUE;
1901 mono_assemblies_unlock ();
1905 mono_assemblies_lock ();
1906 if (ass->friend_assembly_names_inited) {
1907 mono_assemblies_unlock ();
1910 mono_assemblies_unlock ();
1914 * We build the list outside the assemblies lock, the worse that can happen
1915 * is that we'll need to free the allocated list.
1917 for (i = 0; i < attrs->num_attrs; ++i) {
1918 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1919 MonoAssemblyName *aname;
1921 /* Do some sanity checking */
1922 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1924 if (attr->data_size < 4)
1926 data = (const char*)attr->data;
1927 /* 0xFF means null string, see custom attr format */
1928 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1930 mono_metadata_decode_value (data + 2, &data);
1931 aname = g_new0 (MonoAssemblyName, 1);
1932 /*g_print ("friend ass: %s\n", data);*/
1933 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1934 list = g_slist_prepend (list, aname);
1939 mono_custom_attrs_free (attrs);
1941 mono_assemblies_lock ();
1942 if (ass->friend_assembly_names_inited) {
1943 mono_assemblies_unlock ();
1944 g_slist_foreach (list, free_item, NULL);
1945 g_slist_free (list);
1948 ass->friend_assembly_names = list;
1950 /* Because of the double checked locking pattern above */
1951 mono_memory_barrier ();
1952 ass->friend_assembly_names_inited = TRUE;
1953 mono_assemblies_unlock ();
1956 struct HasReferenceAssemblyAttributeIterData {
1961 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1963 gboolean stop_scanning = FALSE;
1964 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1966 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1967 /* Note we don't check the assembly name, same as coreCLR. */
1968 iter_data->has_attr = TRUE;
1969 stop_scanning = TRUE;
1972 return stop_scanning;
1976 * mono_assembly_has_reference_assembly_attribute:
1977 * \param assembly a MonoAssembly
1978 * \param error set on error.
1980 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1981 * On error returns FALSE and sets \p error.
1984 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1989 * This might be called during assembly loading, so do everything using the low-level
1993 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1995 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1997 return iter_data.has_attr;
2001 * mono_assembly_open:
2002 * \param filename Opens the assembly pointed out by this name
2003 * \param status return status code
2005 * This loads an assembly from the specified \p filename. The \p filename allows
2006 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2007 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2008 * is treated as a local path.
2010 * First, an attempt is made to load the assembly from the bundled executable (for those
2011 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2012 * assembly has been registered as an embedded assembly). If this is not the case, then
2013 * the assembly is loaded from disk using `api:mono_image_open_full`.
2015 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2016 * the assembly is made.
2018 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2019 * assembly or NULL on error. Details about the error are stored in the
2020 * \p status variable.
2023 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2025 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2029 * mono_assembly_load_from_full:
2030 * \param image Image to load the assembly from
2031 * \param fname assembly name to associate with the assembly
2032 * \param status returns the status condition
2033 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2035 * If the provided \p image has an assembly reference, it will process the given
2036 * image as an assembly with the given name.
2038 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2040 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2041 * set to \c MONO_IMAGE_OK; or NULL on error.
2043 * If there is an error loading the assembly the \p status will indicate the
2044 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2045 * image did not contain an assembly reference table.
2048 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2049 MonoImageOpenStatus *status, gboolean refonly)
2051 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2055 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2057 MonoAssemblyCandidatePredicate predicate,
2059 MonoImageOpenStatus *status)
2061 MonoAssembly *ass, *ass2;
2064 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2065 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2066 *status = MONO_IMAGE_IMAGE_INVALID;
2070 #if defined (HOST_WIN32)
2075 tmp_fn = g_strdup (fname);
2076 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2077 if (tmp_fn [i] == '/')
2081 base_dir = absolute_dir (tmp_fn);
2085 base_dir = absolute_dir (fname);
2089 * Create assembly struct, and enter it into the assembly cache
2091 ass = g_new0 (MonoAssembly, 1);
2092 ass->basedir = base_dir;
2093 ass->ref_only = refonly;
2096 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2098 mono_assembly_fill_assembly_name (image, &ass->aname);
2100 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2101 // MS.NET doesn't support loading other mscorlibs
2104 mono_image_addref (mono_defaults.corlib);
2105 *status = MONO_IMAGE_OK;
2106 return mono_defaults.corlib->assembly;
2109 /* Add a non-temporary reference because of ass->image */
2110 mono_image_addref (image);
2112 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);
2115 * The load hooks might take locks so we can't call them while holding the
2118 if (ass->aname.name) {
2119 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2123 mono_image_close (image);
2124 *status = MONO_IMAGE_OK;
2129 /* We need to check for ReferenceAssmeblyAttribute before we
2130 * mark the assembly as loaded and before we fire the load
2131 * hook. Otherwise mono_domain_fire_assembly_load () in
2132 * appdomain.c will cache a mapping from the assembly name to
2133 * this image and we won't be able to look for a different
2137 MonoError refasm_error;
2138 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2139 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2142 mono_image_close (image);
2143 *status = MONO_IMAGE_IMAGE_INVALID;
2146 mono_error_cleanup (&refasm_error);
2149 if (predicate && !predicate (ass, user_data)) {
2150 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2153 mono_image_close (image);
2154 *status = MONO_IMAGE_IMAGE_INVALID;
2158 mono_assemblies_lock ();
2160 if (image->assembly) {
2162 * This means another thread has already loaded the assembly, but not yet
2163 * called the load hooks so the search hook can't find the assembly.
2165 mono_assemblies_unlock ();
2166 ass2 = image->assembly;
2169 mono_image_close (image);
2170 *status = MONO_IMAGE_OK;
2174 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2176 image->assembly = ass;
2178 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2179 mono_assemblies_unlock ();
2182 if (image->is_module_handle)
2183 mono_image_fixup_vtable (image);
2186 mono_assembly_invoke_load_hook (ass);
2188 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2194 * mono_assembly_load_from:
2195 * \param image Image to load the assembly from
2196 * \param fname assembly name to associate with the assembly
2197 * \param status return status code
2199 * If the provided \p image has an assembly reference, it will process the given
2200 * image as an assembly with the given name.
2202 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2204 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2205 * \p refonly parameter set to FALSE.
2206 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2207 * set to \c MONO_IMAGE_OK; or NULL on error.
2209 * If there is an error loading the assembly the \p status will indicate the
2210 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2211 * image did not contain an assembly reference table.
2215 mono_assembly_load_from (MonoImage *image, const char *fname,
2216 MonoImageOpenStatus *status)
2218 return mono_assembly_load_from_full (image, fname, status, FALSE);
2222 * mono_assembly_name_free:
2223 * \param aname assembly name to free
2225 * Frees the provided assembly name object.
2226 * (it does not frees the object itself, only the name members).
2229 mono_assembly_name_free (MonoAssemblyName *aname)
2234 g_free ((void *) aname->name);
2235 g_free ((void *) aname->culture);
2236 g_free ((void *) aname->hash_value);
2237 g_free ((guint8*) aname->public_key);
2241 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2244 gchar header [16], val, *arr;
2245 gint i, j, offset, bitlen, keylen, pkeylen;
2247 keylen = strlen (key) >> 1;
2251 /* allow the ECMA standard key */
2252 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2254 *pubkey = g_strdup (key);
2260 val = g_ascii_xdigit_value (key [0]) << 4;
2261 val |= g_ascii_xdigit_value (key [1]);
2266 val = g_ascii_xdigit_value (key [24]);
2267 val |= g_ascii_xdigit_value (key [25]);
2279 /* We need the first 16 bytes
2280 * to check whether this key is valid or not */
2281 pkeylen = strlen (pkey) >> 1;
2285 for (i = 0, j = 0; i < 16; i++) {
2286 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2287 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2290 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2291 header [1] != 0x02 || /* Version (0x02) */
2292 header [2] != 0x00 || /* Reserved (word) */
2293 header [3] != 0x00 ||
2294 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2297 /* Based on this length, we _should_ be able to know if the length is right */
2298 bitlen = read32 (header + 12) >> 3;
2299 if ((bitlen + 16 + 4) != pkeylen)
2302 /* parsing is OK and the public key itself is not requested back */
2306 /* Encode the size of the blob */
2308 if (keylen <= 127) {
2309 arr = (gchar *)g_malloc (keylen + 1);
2310 arr [offset++] = keylen;
2312 arr = (gchar *)g_malloc (keylen + 2);
2313 arr [offset++] = 0x80; /* 10bs */
2314 arr [offset++] = keylen;
2317 for (i = offset, j = 0; i < keylen + offset; i++) {
2318 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2319 arr [i] |= g_ascii_xdigit_value (key [j++]);
2328 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)
2330 gint major, minor, build, revision;
2333 gchar *pkey, *pkeyptr, *encoded, tok [8];
2335 memset (aname, 0, sizeof (MonoAssemblyName));
2338 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2339 if (version_parts < 2 || version_parts > 4)
2342 /* FIXME: we should set build & revision to -1 (instead of 0)
2343 if these are not set in the version string. That way, later on,
2344 we can still determine if these were specified. */
2345 aname->major = major;
2346 aname->minor = minor;
2347 if (version_parts >= 3)
2348 aname->build = build;
2351 if (version_parts == 4)
2352 aname->revision = revision;
2354 aname->revision = 0;
2357 aname->flags = flags;
2359 aname->name = g_strdup (name);
2362 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2363 aname->culture = g_strdup ("");
2365 aname->culture = g_strdup (culture);
2368 if (token && strncmp (token, "null", 4) != 0) {
2371 /* the constant includes the ending NULL, hence the -1 */
2372 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2373 mono_assembly_name_free (aname);
2376 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2377 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2383 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2384 mono_assembly_name_free (aname);
2389 if (save_public_key)
2390 aname->public_key = (guint8*)pkey;
2393 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2397 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2398 // We also need to generate the key token
2399 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2400 encoded = encode_public_tok ((guchar*) tok, 8);
2401 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2404 if (save_public_key)
2405 aname->public_key = (guint8*) pkey;
2414 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2419 parts = g_strsplit (dirname, "_", 3);
2420 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2425 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2431 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2433 char *eqsign = strchr (pair, '=');
2441 *key = (gchar*)pair;
2442 *keylen = eqsign - *key;
2443 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2445 *value = g_strstrip (eqsign + 1);
2450 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2454 gchar *version = NULL;
2456 gchar *culture = NULL;
2458 gchar *token = NULL;
2462 gchar *retargetable = NULL;
2463 gchar *retargetable_uq;
2467 gchar *value, *part_name;
2468 guint32 part_name_len;
2471 gboolean version_defined;
2472 gboolean token_defined;
2474 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2476 if (!is_version_defined)
2477 is_version_defined = &version_defined;
2478 *is_version_defined = FALSE;
2479 if (!is_token_defined)
2480 is_token_defined = &token_defined;
2481 *is_token_defined = FALSE;
2483 parts = tmp = g_strsplit (name, ",", 6);
2484 if (!tmp || !*tmp) {
2489 dllname = g_strstrip (*tmp);
2494 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2495 goto cleanup_and_fail;
2497 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2498 *is_version_defined = TRUE;
2500 if (strlen (version) == 0) {
2501 goto cleanup_and_fail;
2507 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2509 if (strlen (culture) == 0) {
2510 goto cleanup_and_fail;
2516 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2517 *is_token_defined = TRUE;
2519 if (strlen (token) == 0) {
2520 goto cleanup_and_fail;
2526 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2528 if (strlen (key) == 0) {
2529 goto cleanup_and_fail;
2535 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2536 retargetable = value;
2537 retargetable_uq = unquote (retargetable);
2538 if (retargetable_uq != NULL)
2539 retargetable = retargetable_uq;
2541 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2542 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2543 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2544 g_free (retargetable_uq);
2545 goto cleanup_and_fail;
2548 g_free (retargetable_uq);
2553 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2555 procarch_uq = unquote (procarch);
2556 if (procarch_uq != NULL)
2557 procarch = procarch_uq;
2559 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2560 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2561 else if (!g_ascii_strcasecmp (procarch, "X86"))
2562 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2563 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2564 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2565 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2566 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2568 g_free (procarch_uq);
2569 goto cleanup_and_fail;
2572 g_free (procarch_uq);
2581 /* if retargetable flag is set, then we must have a fully qualified name */
2582 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2583 goto cleanup_and_fail;
2586 dllname_uq = unquote (dllname);
2587 version_uq = unquote (version);
2588 culture_uq = unquote (culture);
2589 token_uq = unquote (token);
2590 key_uq = unquote (key);
2592 res = build_assembly_name (
2593 dllname_uq == NULL ? dllname : dllname_uq,
2594 version_uq == NULL ? version : version_uq,
2595 culture_uq == NULL ? culture : culture_uq,
2596 token_uq == NULL ? token : token_uq,
2597 key_uq == NULL ? key : key_uq,
2598 flags, arch, aname, save_public_key);
2600 g_free (dllname_uq);
2601 g_free (version_uq);
2602 g_free (culture_uq);
2615 unquote (const char *str)
2623 slen = strlen (str);
2627 if (*str != '\'' && *str != '\"')
2630 end = str + slen - 1;
2634 return g_strndup (str + 1, slen - 2);
2638 * mono_assembly_name_parse:
2639 * \param name name to parse
2640 * \param aname the destination assembly name
2642 * Parses an assembly qualified type name and assigns the name,
2643 * version, culture and token to the provided assembly name object.
2645 * \returns TRUE if the name could be parsed.
2648 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2650 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2654 * mono_assembly_name_new:
2655 * \param name name to parse
2657 * Allocate a new \c MonoAssemblyName and fill its values from the
2660 * \returns a newly allocated structure or NULL if there was any failure.
2663 mono_assembly_name_new (const char *name)
2665 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2666 if (mono_assembly_name_parse (name, aname))
2673 * mono_assembly_name_get_name:
2676 mono_assembly_name_get_name (MonoAssemblyName *aname)
2682 * mono_assembly_name_get_culture:
2685 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2687 return aname->culture;
2691 * mono_assembly_name_get_pubkeytoken:
2694 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2696 if (aname->public_key_token [0])
2697 return aname->public_key_token;
2702 * mono_assembly_name_get_version:
2705 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2708 *minor = aname->minor;
2710 *build = aname->build;
2712 *revision = aname->revision;
2713 return aname->major;
2716 static MonoAssembly*
2717 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2719 gchar *fullpath = NULL;
2721 const char* direntry;
2722 MonoAssemblyName gac_aname;
2723 gint major=-1, minor=0, build=0, revision=0;
2724 gboolean exact_version;
2726 dirhandle = g_dir_open (basepath, 0, NULL);
2730 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2732 while ((direntry = g_dir_read_name (dirhandle))) {
2733 gboolean match = TRUE;
2735 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2738 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2741 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2742 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2746 if (exact_version) {
2747 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2748 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2750 else if (gac_aname.major < major)
2752 else if (gac_aname.major == major) {
2753 if (gac_aname.minor < minor)
2755 else if (gac_aname.minor == minor) {
2756 if (gac_aname.build < build)
2758 else if (gac_aname.build == build && gac_aname.revision <= revision)
2765 major = gac_aname.major;
2766 minor = gac_aname.minor;
2767 build = gac_aname.build;
2768 revision = gac_aname.revision;
2770 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2773 mono_assembly_name_free (&gac_aname);
2776 g_dir_close (dirhandle);
2778 if (fullpath == NULL)
2781 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2788 * mono_assembly_load_with_partial_name:
2789 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2790 * \param status return status code
2792 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2793 * so it might contain a qualified type name, version, culture and token.
2795 * This will load the assembly from the file whose name is derived from the assembly name
2796 * by appending the \c .dll extension.
2798 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2799 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2800 * if that fails from the GAC.
2802 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2805 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2809 MonoAssemblyName *aname, base_name;
2810 MonoAssemblyName mapped_aname;
2811 gchar *fullname, *gacpath;
2814 memset (&base_name, 0, sizeof (MonoAssemblyName));
2817 if (!mono_assembly_name_parse (name, aname))
2821 * If no specific version has been requested, make sure we load the
2822 * correct version for system assemblies.
2824 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2825 aname = mono_assembly_remap_version (aname, &mapped_aname);
2827 res = mono_assembly_loaded (aname);
2829 mono_assembly_name_free (aname);
2833 res = invoke_assembly_preload_hook (aname, assemblies_path);
2835 res->in_gac = FALSE;
2836 mono_assembly_name_free (aname);
2840 fullname = g_strdup_printf ("%s.dll", aname->name);
2842 if (extra_gac_paths) {
2843 paths = extra_gac_paths;
2844 while (!res && *paths) {
2845 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2846 res = probe_for_partial_name (gacpath, fullname, aname, status);
2855 mono_assembly_name_free (aname);
2859 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2860 res = probe_for_partial_name (gacpath, fullname, aname, status);
2864 mono_assembly_name_free (aname);
2869 MonoDomain *domain = mono_domain_get ();
2871 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2872 if (!is_ok (&error)) {
2873 mono_error_cleanup (&error);
2874 if (*status == MONO_IMAGE_OK)
2875 *status = MONO_IMAGE_IMAGE_INVALID;
2883 mono_assembly_is_in_gac (const gchar *filename)
2885 const gchar *rootdir;
2889 if (filename == NULL)
2892 for (paths = extra_gac_paths; paths && *paths; paths++) {
2893 if (strstr (*paths, filename) != *paths)
2896 gp = (gchar *) (filename + strlen (*paths));
2897 if (*gp != G_DIR_SEPARATOR)
2900 if (strncmp (gp, "lib", 3))
2903 if (*gp != G_DIR_SEPARATOR)
2906 if (strncmp (gp, "mono", 4))
2909 if (*gp != G_DIR_SEPARATOR)
2912 if (strncmp (gp, "gac", 3))
2915 if (*gp != G_DIR_SEPARATOR)
2921 rootdir = mono_assembly_getrootdir ();
2922 if (strstr (filename, rootdir) != filename)
2925 gp = (gchar *) (filename + strlen (rootdir));
2926 if (*gp != G_DIR_SEPARATOR)
2929 if (strncmp (gp, "mono", 4))
2932 if (*gp != G_DIR_SEPARATOR)
2935 if (strncmp (gp, "gac", 3))
2938 if (*gp != G_DIR_SEPARATOR)
2944 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2947 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2951 if (strstr (aname->name, ".dll")) {
2952 len = strlen (aname->name) - 4;
2953 name = (gchar *)g_malloc (len + 1);
2954 memcpy (name, aname->name, len);
2957 name = g_strdup (aname->name);
2960 culture = g_utf8_strdown (aname->culture, -1);
2962 culture = g_strdup ("");
2964 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2965 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2969 filename = g_strconcat (pname, ".dll", NULL);
2970 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2976 if (extra_gac_paths) {
2977 paths = extra_gac_paths;
2978 while (!image && *paths) {
2979 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2980 "lib", "mono", "gac", subpath, NULL);
2981 image = mono_image_open (fullpath, NULL);
2992 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2993 "mono", "gac", subpath, NULL);
2994 image = mono_image_open (fullpath, NULL);
3001 static MonoAssemblyName*
3002 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3004 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3005 dest_name->major = info->new_version.major;
3006 dest_name->minor = info->new_version.minor;
3007 dest_name->build = info->new_version.build;
3008 dest_name->revision = info->new_version.revision;
3013 /* LOCKING: assembly_binding lock must be held */
3014 static MonoAssemblyBindingInfo*
3015 search_binding_loaded (MonoAssemblyName *aname)
3019 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3020 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3021 if (assembly_binding_maps_name (info, aname))
3028 static inline gboolean
3029 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3031 if (left->major != right->major || left->minor != right->minor ||
3032 left->build != right->build || left->revision != right->revision)
3038 static inline gboolean
3039 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3041 if (left->has_old_version_bottom != right->has_old_version_bottom)
3044 if (left->has_old_version_top != right->has_old_version_top)
3047 if (left->has_new_version != right->has_new_version)
3050 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3053 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3056 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3062 /* LOCKING: assumes all the necessary locks are held */
3064 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3066 MonoAssemblyBindingInfo *info_copy;
3068 MonoAssemblyBindingInfo *info_tmp;
3069 MonoDomain *domain = (MonoDomain*)user_data;
3074 if (info->has_new_version && mono_assembly_is_problematic_version (info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision)) {
3075 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3076 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3080 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3081 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3082 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3086 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3087 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3089 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3091 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3093 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3097 get_version_number (int major, int minor)
3099 return major * 256 + minor;
3102 static inline gboolean
3103 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3105 int aname_version_number = get_version_number (aname->major, aname->minor);
3106 if (!info->has_old_version_bottom)
3109 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3112 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3115 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3116 info->major = aname->major;
3117 info->minor = aname->minor;
3122 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3123 static MonoAssemblyBindingInfo*
3124 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3126 MonoAssemblyBindingInfo *info;
3129 if (!domain->assembly_bindings)
3133 for (list = domain->assembly_bindings; list; list = list->next) {
3134 info = (MonoAssemblyBindingInfo *)list->data;
3135 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3141 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3142 info->has_new_version && assembly_binding_maps_name (info, aname))
3143 info->is_valid = TRUE;
3145 info->is_valid = FALSE;
3151 static MonoAssemblyName*
3152 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3155 MonoAssemblyBindingInfo *info, *info2;
3159 if (aname->public_key_token [0] == 0)
3162 domain = mono_domain_get ();
3164 mono_assembly_binding_lock ();
3165 info = search_binding_loaded (aname);
3166 mono_assembly_binding_unlock ();
3169 mono_domain_lock (domain);
3170 info = get_per_domain_assembly_binding_info (domain, aname);
3171 mono_domain_unlock (domain);
3175 if (!check_policy_versions (info, aname))
3178 mono_assembly_bind_version (info, aname, dest_name);
3182 if (domain && domain->setup && domain->setup->configuration_file) {
3183 mono_domain_lock (domain);
3184 if (!domain->assembly_bindings_parsed) {
3185 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3186 /* expect this to succeed because mono_domain_set_options_from_config () did
3187 * the same thing when the domain was created. */
3188 mono_error_assert_ok (&error);
3190 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3192 if (!domain_config_file_path)
3193 domain_config_file_path = domain_config_file_name;
3195 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3196 domain->assembly_bindings_parsed = TRUE;
3197 if (domain_config_file_name != domain_config_file_path)
3198 g_free (domain_config_file_name);
3199 g_free (domain_config_file_path);
3202 info2 = get_per_domain_assembly_binding_info (domain, aname);
3205 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3206 info->name = g_strdup (info2->name);
3207 info->culture = g_strdup (info2->culture);
3208 info->domain_id = domain->domain_id;
3211 mono_domain_unlock (domain);
3215 info = g_new0 (MonoAssemblyBindingInfo, 1);
3216 info->major = aname->major;
3217 info->minor = aname->minor;
3220 if (!info->is_valid) {
3221 ppimage = mono_assembly_load_publisher_policy (aname);
3223 get_publisher_policy_info (ppimage, aname, info);
3224 mono_image_close (ppimage);
3228 /* Define default error value if needed */
3229 if (!info->is_valid) {
3230 info->name = g_strdup (aname->name);
3231 info->culture = g_strdup (aname->culture);
3232 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3235 mono_assembly_binding_lock ();
3236 info2 = search_binding_loaded (aname);
3238 /* This binding was added by another thread
3240 mono_assembly_binding_info_free (info);
3245 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3247 mono_assembly_binding_unlock ();
3249 if (!info->is_valid || !check_policy_versions (info, aname))
3252 mono_assembly_bind_version (info, aname, dest_name);
3257 * mono_assembly_load_from_gac
3259 * \param aname The assembly name object
3261 static MonoAssembly*
3262 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3264 MonoAssembly *result = NULL;
3265 gchar *name, *version, *culture, *fullpath, *subpath;
3270 if (aname->public_key_token [0] == 0) {
3274 if (strstr (aname->name, ".dll")) {
3275 len = strlen (filename) - 4;
3276 name = (gchar *)g_malloc (len + 1);
3277 memcpy (name, aname->name, len);
3280 name = g_strdup (aname->name);
3283 if (aname->culture) {
3284 culture = g_utf8_strdown (aname->culture, -1);
3286 culture = g_strdup ("");
3289 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3290 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3291 aname->minor, aname->build, aname->revision,
3295 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3300 if (extra_gac_paths) {
3301 paths = extra_gac_paths;
3302 while (!result && *paths) {
3303 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3304 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3311 result->in_gac = TRUE;
3316 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3317 "mono", "gac", subpath, NULL);
3318 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3322 result->in_gac = TRUE;
3330 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3333 MonoAssemblyName *aname;
3336 /* g_print ("corlib already loaded\n"); */
3340 // In native client, Corlib is embedded in the executable as static variable corlibData
3341 #if defined(__native_client__)
3342 if (corlibData != NULL && corlibSize != 0) {
3344 /* First "FALSE" instructs mono not to make a copy. */
3345 /* Second "FALSE" says this is not just a ref. */
3346 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3347 if (image == NULL || status != 0)
3348 g_print("mono_image_open_from_data_full failed: %d\n", status);
3349 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3350 if (corlib == NULL || status != 0)
3351 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3357 // A nonstandard preload hook may provide a special mscorlib assembly
3358 aname = mono_assembly_name_new ("mscorlib.dll");
3359 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3360 mono_assembly_name_free (aname);
3363 goto return_corlib_and_facades;
3365 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3366 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3367 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3369 goto return_corlib_and_facades;
3372 /* Normal case: Load corlib from mono/<version> */
3373 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3374 if (assemblies_path) { // Custom assemblies path
3375 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3377 g_free (corlib_file);
3378 goto return_corlib_and_facades;
3381 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3382 g_free (corlib_file);
3384 return_corlib_and_facades:
3385 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3386 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3391 static MonoAssembly*
3392 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3394 MonoError refasm_error;
3395 error_init (&refasm_error);
3396 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3399 mono_error_cleanup (&refasm_error);
3404 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3406 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3407 MonoAssemblyName *candidate_name = &candidate->aname;
3409 g_assert (wanted_name != NULL);
3410 g_assert (candidate_name != NULL);
3412 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3413 char * s = mono_stringify_assembly_name (wanted_name);
3414 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3416 s = mono_stringify_assembly_name (candidate_name);
3417 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3422 /* Wanted name has no token, not strongly named: always matches. */
3423 if (0 == wanted_name->public_key_token [0]) {
3424 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3428 /* Candidate name has no token, not strongly named: never matches */
3429 if (0 == candidate_name->public_key_token [0]) {
3430 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3434 return exact_sn_match (wanted_name, candidate_name) ||
3435 framework_assembly_sn_match (wanted_name, candidate_name);
3439 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3441 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3443 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3444 result ? "match, returning TRUE" : "don't match, returning FALSE");
3450 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3452 #ifndef DISABLE_ASSEMBLY_REMAPPING
3453 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3455 /* If the wanted name is a framework assembly, it's enough for the name/version/culture to match. If the assembly was remapped, the public key token is likely unrelated. */
3456 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3457 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s (ignoring the public key token)", result ? "match, returning TRUE" : "don't match, returning FALSE");
3465 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3466 const char *basedir,
3467 MonoImageOpenStatus *status,
3470 MonoAssembly *result;
3471 char *fullpath, *filename;
3472 MonoAssemblyName maped_aname;
3473 MonoAssemblyName maped_name_pp;
3478 aname = mono_assembly_remap_version (aname, &maped_aname);
3480 /* Reflection only assemblies don't get assembly binding */
3482 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3484 result = mono_assembly_loaded_full (aname, refonly);
3488 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3490 result->in_gac = FALSE;
3494 /* Currently we retrieve the loaded corlib for reflection
3495 * only requests, like a common reflection only assembly
3497 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3498 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3501 len = strlen (aname->name);
3502 for (ext_index = 0; ext_index < 2; ext_index ++) {
3503 ext = ext_index == 0 ? ".dll" : ".exe";
3504 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3505 filename = g_strdup (aname->name);
3506 /* Don't try appending .dll/.exe if it already has one of those extensions */
3509 filename = g_strconcat (aname->name, ext, NULL);
3512 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3519 fullpath = g_build_filename (basedir, filename, NULL);
3520 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3523 result->in_gac = FALSE;
3529 result = load_in_path (filename, default_path, status, refonly, NULL, NULL);
3531 result->in_gac = FALSE;
3541 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3543 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3546 /* Try a postload search hook */
3547 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3548 result = prevent_reference_assembly_from_running (result, refonly);
3554 * mono_assembly_load_full:
3555 * \param aname A MonoAssemblyName with the assembly name to load.
3556 * \param basedir A directory to look up the assembly at.
3557 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3558 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3560 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3561 * attempts to load the assembly from that directory before probing the standard locations.
3563 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3564 * assembly binding takes place.
3566 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3567 * value pointed by \p status is updated with an error code.
3570 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3572 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3576 * mono_assembly_load:
3577 * \param aname A MonoAssemblyName with the assembly name to load.
3578 * \param basedir A directory to look up the assembly at.
3579 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3581 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3582 * attempts to load the assembly from that directory before probing the standard locations.
3584 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3585 * value pointed by \p status is updated with an error code.
3588 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3590 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3594 * mono_assembly_loaded_full:
3595 * \param aname an assembly to look for.
3596 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3598 * This is used to determine if the specified assembly has been loaded
3599 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3600 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3603 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3606 MonoAssemblyName maped_aname;
3608 aname = mono_assembly_remap_version (aname, &maped_aname);
3610 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3616 * mono_assembly_loaded:
3617 * \param aname an assembly to look for.
3619 * This is used to determine if the specified assembly has been loaded
3621 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3622 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3625 mono_assembly_loaded (MonoAssemblyName *aname)
3627 return mono_assembly_loaded_full (aname, FALSE);
3631 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3633 if (assembly == NULL || assembly == REFERENCE_MISSING)
3636 if (assembly_is_dynamic (assembly)) {
3638 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3639 for (i = 0; i < dynimg->image.module_count; ++i)
3640 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3641 mono_dynamic_image_release_gc_roots (dynimg);
3646 * Returns whether mono_assembly_close_finish() must be called as
3647 * well. See comment for mono_image_close_except_pools() for why we
3648 * unload in two steps.
3651 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3654 g_return_val_if_fail (assembly != NULL, FALSE);
3656 if (assembly == REFERENCE_MISSING)
3659 /* Might be 0 already */
3660 if (InterlockedDecrement (&assembly->ref_count) > 0)
3663 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3665 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3667 mono_debug_close_image (assembly->image);
3669 mono_assemblies_lock ();
3670 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3671 mono_assemblies_unlock ();
3673 assembly->image->assembly = NULL;
3675 if (!mono_image_close_except_pools (assembly->image))
3676 assembly->image = NULL;
3678 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3679 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3680 mono_assembly_name_free (fname);
3683 g_slist_free (assembly->friend_assembly_names);
3684 g_free (assembly->basedir);
3686 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3692 mono_assembly_close_finish (MonoAssembly *assembly)
3694 g_assert (assembly && assembly != REFERENCE_MISSING);
3696 if (assembly->image)
3697 mono_image_close_finish (assembly->image);
3699 if (assembly_is_dynamic (assembly)) {
3700 g_free ((char*)assembly->aname.culture);
3707 * mono_assembly_close:
3708 * \param assembly the assembly to release.
3710 * This method releases a reference to the \p assembly. The assembly is
3711 * only released when all the outstanding references to it are released.
3714 mono_assembly_close (MonoAssembly *assembly)
3716 if (mono_assembly_close_except_image_pools (assembly))
3717 mono_assembly_close_finish (assembly);
3721 * mono_assembly_load_module:
3724 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3727 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3728 mono_error_assert_ok (&error);
3733 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3735 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3740 * mono_assembly_foreach:
3741 * \param func function to invoke for each assembly loaded
3742 * \param user_data data passed to the callback
3744 * Invokes the provided \p func callback for each assembly loaded into
3745 * the runtime. The first parameter passed to the callback is the
3746 * \c MonoAssembly*, and the second parameter is the \p user_data.
3748 * This is done for all assemblies loaded in the runtime, not just
3749 * those loaded in the current application domain.
3752 mono_assembly_foreach (GFunc func, gpointer user_data)
3757 * We make a copy of the list to avoid calling the callback inside the
3758 * lock, which could lead to deadlocks.
3760 mono_assemblies_lock ();
3761 copy = g_list_copy (loaded_assemblies);
3762 mono_assemblies_unlock ();
3764 g_list_foreach (loaded_assemblies, func, user_data);
3770 * mono_assemblies_cleanup:
3772 * Free all resources used by this module.
3775 mono_assemblies_cleanup (void)
3779 mono_os_mutex_destroy (&assemblies_mutex);
3780 mono_os_mutex_destroy (&assembly_binding_mutex);
3782 for (l = loaded_assembly_bindings; l; l = l->next) {
3783 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3785 mono_assembly_binding_info_free (info);
3788 g_slist_free (loaded_assembly_bindings);
3790 free_assembly_load_hooks ();
3791 free_assembly_search_hooks ();
3792 free_assembly_preload_hooks ();
3795 /*LOCKING takes the assembly_binding lock*/
3797 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3801 mono_assembly_binding_lock ();
3802 iter = &loaded_assembly_bindings;
3805 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3807 if (info->domain_id == domain_id) {
3809 mono_assembly_binding_info_free (info);
3816 mono_assembly_binding_unlock ();
3820 * Holds the assembly of the application, for
3821 * System.Diagnostics.Process::MainModule
3823 static MonoAssembly *main_assembly=NULL;
3826 * mono_assembly_set_main:
3829 mono_assembly_set_main (MonoAssembly *assembly)
3831 main_assembly = assembly;
3835 * mono_assembly_get_main:
3837 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3840 mono_assembly_get_main (void)
3842 return (main_assembly);
3846 * mono_assembly_get_image:
3847 * \param assembly The assembly to retrieve the image from
3849 * \returns the \c MonoImage associated with this assembly.
3852 mono_assembly_get_image (MonoAssembly *assembly)
3854 return assembly->image;
3858 * mono_assembly_get_name:
3859 * \param assembly The assembly to retrieve the name from
3861 * The returned name's lifetime is the same as \p assembly's.
3863 * \returns the \c MonoAssemblyName associated with this assembly.
3866 mono_assembly_get_name (MonoAssembly *assembly)
3868 return &assembly->aname;
3872 * mono_register_bundled_assemblies:
3875 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3877 bundles = assemblies;
3880 #define MONO_DECLSEC_FORMAT_10 0x3C
3881 #define MONO_DECLSEC_FORMAT_20 0x2E
3882 #define MONO_DECLSEC_FIELD 0x53
3883 #define MONO_DECLSEC_PROPERTY 0x54
3885 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3886 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3887 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3888 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3889 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3892 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3896 case MONO_DECLSEC_PROPERTY:
3898 case MONO_DECLSEC_FIELD:
3900 *abort_decoding = TRUE;
3905 if (*p++ != MONO_TYPE_BOOLEAN) {
3906 *abort_decoding = TRUE;
3910 /* property name length */
3911 len = mono_metadata_decode_value (p, &p);
3913 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3924 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3926 int i, j, num, len, params_len;
3928 if (*p == MONO_DECLSEC_FORMAT_10) {
3929 gsize read, written;
3930 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3932 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3938 if (*p++ != MONO_DECLSEC_FORMAT_20)
3941 /* number of encoded permission attributes */
3942 num = mono_metadata_decode_value (p, &p);
3943 for (i = 0; i < num; ++i) {
3944 gboolean is_valid = FALSE;
3945 gboolean abort_decoding = FALSE;
3947 /* attribute name length */
3948 len = mono_metadata_decode_value (p, &p);
3950 /* We don't really need to fully decode the type. Comparing the name is enough */
3951 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3955 /*size of the params table*/
3956 params_len = mono_metadata_decode_value (p, &p);
3958 const char *params_end = p + params_len;
3960 /* number of parameters */
3961 len = mono_metadata_decode_value (p, &p);
3963 for (j = 0; j < len; ++j) {
3964 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3980 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3983 guint32 cols [MONO_DECL_SECURITY_SIZE];
3987 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3988 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3990 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3992 for (i = 0; i < t->rows; ++i) {
3993 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3994 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3996 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3999 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4000 len = mono_metadata_decode_blob_size (blob, &blob);
4004 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4005 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4010 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);