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,
71 /* Don't compare the versions */
72 ANAME_EQ_IGNORE_VERSION = 0x2,
75 } AssemblyNameEqFlags;
77 /* the default search path is empty, the first slot is replaced with the computed value */
85 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
86 static char **assemblies_path = NULL;
88 /* Contains the list of directories that point to auxiliary GACs */
89 static char **extra_gac_paths = NULL;
91 #ifndef DISABLE_ASSEMBLY_REMAPPING
93 static GHashTable* assembly_remapping_table;
94 /* The list of system assemblies what will be remapped to the running
96 * This list is stored in @assembly_remapping_table during initialization.
97 * Keep it sorted just to make maintenance easier.
99 * The integer number is an index in the MonoRuntimeInfo structure, whose
100 * values can be found in domain.c - supported_runtimes. Look there
101 * to understand what remapping will be made.
103 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
106 static const AssemblyVersionMap framework_assemblies [] = {
107 {"Accessibility", 0},
108 {"Commons.Xml.Relaxng", 0},
115 {"Microsoft.Build.Engine", 2, NULL, TRUE},
116 {"Microsoft.Build.Framework", 2, NULL, TRUE},
117 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
118 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
119 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
120 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
121 {"Microsoft.VisualBasic", 1},
122 {"Microsoft.VisualC", 1},
124 {"Mono.CompilerServices.SymbolWriter", 0},
126 {"Mono.Data.SybaseClient", 0},
127 {"Mono.Data.Tds", 0},
128 {"Mono.Data.TdsClient", 0},
129 {"Mono.GetOptions", 0},
132 {"Mono.Security", 0},
133 {"Mono.Security.Win32", 0},
135 {"Novell.Directory.Ldap", 0},
138 {"System.ComponentModel.Composition", 2},
139 {"System.ComponentModel.DataAnnotations", 2},
140 {"System.Configuration", 0},
141 {"System.Configuration.Install", 0},
144 {"System.Data.Linq", 2},
145 {"System.Data.OracleClient", 0},
146 {"System.Data.Services", 2},
147 {"System.Data.Services.Client", 2},
148 {"System.Data.SqlXml", 0},
149 {"System.Design", 0},
150 {"System.DirectoryServices", 0},
151 {"System.Drawing", 0},
152 {"System.Drawing.Design", 0},
153 {"System.EnterpriseServices", 0},
154 {"System.IO.Compression", 2},
155 {"System.IdentityModel", 3},
156 {"System.IdentityModel.Selectors", 3},
157 {"System.Management", 0},
158 {"System.Messaging", 0},
160 {"System.Net.Http", 4},
161 {"System.Numerics.Vectors", 3},
162 {"System.Runtime.InteropServices.RuntimeInformation", 2},
163 {"System.Runtime.Remoting", 0},
164 {"System.Runtime.Serialization", 3},
165 {"System.Runtime.Serialization.Formatters", 3},
166 {"System.Runtime.Serialization.Formatters.Soap", 0},
167 {"System.Security", 0},
168 {"System.ServiceModel", 3},
169 {"System.ServiceModel.Duplex", 3},
170 {"System.ServiceModel.Http", 3},
171 {"System.ServiceModel.NetTcp", 3},
172 {"System.ServiceModel.Primitives", 3},
173 {"System.ServiceModel.Security", 3},
174 {"System.ServiceModel.Web", 2},
175 {"System.ServiceProcess", 0},
176 {"System.Text.Encoding.CodePages", 3},
177 {"System.Transactions", 0},
179 {"System.Web.Abstractions", 2},
180 {"System.Web.DynamicData", 2},
181 {"System.Web.Extensions", 2},
182 {"System.Web.Mobile", 0},
183 {"System.Web.Routing", 2},
184 {"System.Web.Services", 0},
185 {"System.Windows.Forms", 0},
187 {"System.Xml.Linq", 2},
188 {"System.Xml.ReaderWriter", 3},
189 {"System.Xml.XPath.XmlDocument", 3},
196 * keeps track of loaded assemblies
198 static GList *loaded_assemblies = NULL;
199 static MonoAssembly *corlib;
201 #if defined(__native_client__)
203 /* On Native Client, allow mscorlib to be loaded from memory */
204 /* instead of loaded off disk. If these are not set, default */
205 /* mscorlib loading will take place */
207 /* NOTE: If mscorlib data is passed to mono in this way then */
208 /* it needs to remain allocated during the use of mono. */
210 static void *corlibData = NULL;
211 static size_t corlibSize = 0;
214 mono_set_corlib_data (void *data, size_t size)
222 static char* unquote (const char *str);
224 /* This protects loaded_assemblies and image->references */
225 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
226 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
227 static mono_mutex_t assemblies_mutex;
229 /* If defined, points to the bundled assembly information */
230 const MonoBundledAssembly **bundles;
232 static mono_mutex_t assembly_binding_mutex;
234 /* Loaded assembly binding info */
235 static GSList *loaded_assembly_bindings = NULL;
237 /* Class lazy loading functions */
238 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
240 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
242 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
244 mono_assembly_is_in_gac (const gchar *filanem);
247 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
250 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags);
252 /* Assembly name matching */
254 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
256 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
259 encode_public_tok (const guchar *token, gint32 len)
261 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
265 res = (gchar *)g_malloc (len * 2 + 1);
266 for (i = 0; i < len; i++) {
267 res [i * 2] = allowed [token [i] >> 4];
268 res [i * 2 + 1] = allowed [token [i] & 0xF];
275 * mono_public_tokens_are_equal:
276 * \param pubt1 first public key token
277 * \param pubt2 second public key token
279 * Compare two public key tokens and return TRUE is they are equal and FALSE
283 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
285 return memcmp (pubt1, pubt2, 16) == 0;
289 * mono_set_assemblies_path:
290 * \param path list of paths that contain directories where Mono will look for assemblies
292 * Use this method to override the standard assembly lookup system and
293 * override any assemblies coming from the GAC. This is the method
294 * that supports the \c MONO_PATH variable.
296 * Notice that \c MONO_PATH and this method are really a very bad idea as
297 * it prevents the GAC from working and it prevents the standard
298 * resolution mechanisms from working. Nonetheless, for some debugging
299 * situations and bootstrapping setups, this is useful to have.
302 mono_set_assemblies_path (const char* path)
304 char **splitted, **dest;
306 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
308 g_strfreev (assemblies_path);
309 assemblies_path = dest = splitted;
311 char *tmp = *splitted;
313 *dest++ = mono_path_canonicalize (tmp);
319 if (g_hasenv ("MONO_DEBUG"))
322 splitted = assemblies_path;
324 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
325 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
331 /* Native Client can't get this info from an environment variable so */
332 /* it's passed in to the runtime, or set manually by embedding code. */
333 #ifdef __native_client__
334 char* nacl_mono_path = NULL;
338 check_path_env (void)
340 if (assemblies_path != NULL)
343 char* path = g_getenv ("MONO_PATH");
344 #ifdef __native_client__
346 path = strdup (nacl_mono_path);
351 mono_set_assemblies_path(path);
356 check_extra_gac_path_env (void)
359 char **splitted, **dest;
361 path = g_getenv ("MONO_GAC_PREFIX");
365 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
369 g_strfreev (extra_gac_paths);
370 extra_gac_paths = dest = splitted;
378 if (!g_hasenv ("MONO_DEBUG"))
382 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
383 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
390 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
392 if (!info || !info->name)
395 if (strcmp (info->name, aname->name))
398 if (info->major != aname->major || info->minor != aname->minor)
401 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
404 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
407 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
414 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
420 g_free (info->culture);
424 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
427 guint32 cols [MONO_MANIFEST_SIZE];
428 const gchar *filename;
429 gchar *subpath, *fullpath;
431 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
432 /* MS Impl. accepts policy assemblies with more than
433 * one manifest resource, and only takes the first one */
435 binding_info->is_valid = FALSE;
439 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
440 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
441 binding_info->is_valid = FALSE;
445 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
446 g_assert (filename != NULL);
448 subpath = g_path_get_dirname (image->name);
449 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
450 mono_config_parse_publisher_policy (fullpath, binding_info);
454 /* Define the optional elements/attributes before checking */
455 if (!binding_info->culture)
456 binding_info->culture = g_strdup ("");
458 /* Check that the most important elements/attributes exist */
459 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
460 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
461 mono_assembly_binding_info_free (binding_info);
462 binding_info->is_valid = FALSE;
466 binding_info->is_valid = TRUE;
470 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
472 if (v->major > aname->major)
474 else if (v->major < aname->major)
477 if (v->minor > aname->minor)
479 else if (v->minor < aname->minor)
482 if (v->build > aname->build)
484 else if (v->build < aname->build)
487 if (v->revision > aname->revision)
489 else if (v->revision < aname->revision)
496 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
501 /* If has_old_version_top doesn't exist, we don't have an interval */
502 if (!info->has_old_version_top) {
503 if (compare_versions (&info->old_version_bottom, name) == 0)
509 /* Check that the version defined by name is valid for the interval */
510 if (compare_versions (&info->old_version_top, name) < 0)
513 /* We should be greater or equal than the small version */
514 if (compare_versions (&info->old_version_bottom, name) > 0)
521 * mono_assembly_names_equal:
522 * \param l first assembly
523 * \param r second assembly.
525 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
527 * This compares the names, the cultures, the release version and their
530 * \returns TRUE if both assembly names are equal.
533 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
535 return assembly_names_equal_flags (l, r, ANAME_EQ_NONE);
539 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags)
541 if (!l->name || !r->name)
544 if (strcmp (l->name, r->name))
547 if (l->culture && r->culture && strcmp (l->culture, r->culture))
550 if ((l->major != r->major || l->minor != r->minor ||
551 l->build != r->build || l->revision != r->revision) &&
552 (flags & ANAME_EQ_IGNORE_VERSION) == 0)
553 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)))
556 if (!l->public_key_token [0] || !r->public_key_token [0] || (flags & ANAME_EQ_IGNORE_PUBKEY) != 0)
559 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
565 static MonoAssembly *
566 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
570 MonoAssembly *result;
572 for (i = 0; search_path [i]; ++i) {
573 fullpath = g_build_filename (search_path [i], basename, NULL);
574 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
583 * mono_assembly_setrootdir:
584 * \param root_dir The pathname of the root directory where we will locate assemblies
586 * This routine sets the internal default root directory for looking up
589 * This is used by Windows installations to compute dynamically the
590 * place where the Mono assemblies are located.
594 mono_assembly_setrootdir (const char *root_dir)
597 * Override the MONO_ASSEMBLIES directory configured at compile time.
599 /* Leak if called more than once */
600 default_path [0] = g_strdup (root_dir);
604 * mono_assembly_getrootdir:
606 * Obtains the root directory used for looking up assemblies.
608 * Returns: a string with the directory, this string should not be freed.
610 G_CONST_RETURN gchar *
611 mono_assembly_getrootdir (void)
613 return default_path [0];
617 * mono_native_getrootdir:
619 * Obtains the root directory used for looking up native libs (.so, .dylib).
621 * Returns: a string with the directory, this string should be freed by
625 mono_native_getrootdir (void)
627 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
633 * \param assembly_dir the base directory for assemblies
634 * \param config_dir the base directory for configuration files
636 * This routine is used internally and by developers embedding
637 * the runtime into their own applications.
639 * There are a number of cases to consider: Mono as a system-installed
640 * package that is available on the location preconfigured or Mono in
641 * a relocated location.
643 * If you are using a system-installed Mono, you can pass NULL
644 * to both parameters. If you are not, you should compute both
645 * directory values and call this routine.
647 * The values for a given PREFIX are:
649 * assembly_dir: PREFIX/lib
650 * config_dir: PREFIX/etc
652 * Notice that embedders that use Mono in a relocated way must
653 * compute the location at runtime, as they will be in control
654 * of where Mono is installed.
657 mono_set_dirs (const char *assembly_dir, const char *config_dir)
659 if (assembly_dir == NULL)
660 assembly_dir = mono_config_get_assemblies_dir ();
661 if (config_dir == NULL)
662 config_dir = mono_config_get_cfg_dir ();
663 mono_assembly_setrootdir (assembly_dir);
664 mono_set_config_dir (config_dir);
670 compute_base (char *path)
672 char *p = strrchr (path, '/');
676 /* Not a well known Mono executable, we are embedded, cant guess the base */
677 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
681 p = strrchr (path, '/');
685 if (strcmp (p, "/bin") != 0)
694 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
697 static G_GNUC_UNUSED void
701 char *config, *lib, *mono;
706 * Only /usr prefix is treated specially
708 bindir = mono_config_get_bin_dir ();
710 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
715 config = g_build_filename (base, "etc", NULL);
716 lib = g_build_filename (base, "lib", NULL);
717 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
718 if (stat (mono, &buf) == -1)
721 mono_set_dirs (lib, config);
729 #endif /* HOST_WIN32 */
734 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
735 * this auto-detects the prefix where Mono was installed.
738 mono_set_rootdir (void)
740 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
741 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
744 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
748 * _NSGetExecutablePath may return -1 to indicate buf is not large
749 * enough, but we ignore that case to avoid having to do extra dynamic
750 * allocation for the path and hope that 4096 is enough - this is
751 * ok in the Linux/Solaris case below at least...
755 guint buf_size = sizeof (buf);
758 if (_NSGetExecutablePath (buf, &buf_size) == 0)
759 name = g_strdup (buf);
768 resolvedname = mono_path_resolve_symlinks (name);
770 bindir = g_path_get_dirname (resolvedname);
771 installdir = g_path_get_dirname (bindir);
772 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
774 config = g_build_filename (root, "..", "etc", NULL);
776 mono_set_dirs (root, config);
778 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
779 mono_set_dirs (root, config);
789 g_free (resolvedname);
790 #elif defined(DISABLE_MONO_AUTODETECTION)
798 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
806 /* Solaris 10 style */
807 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
808 s = readlink (str, buf, sizeof (buf)-1);
820 * mono_assemblies_init:
822 * Initialize global variables used by this module.
825 mono_assemblies_init (void)
828 * Initialize our internal paths if we have not been initialized yet.
829 * This happens when embedders use Mono.
831 if (mono_assembly_getrootdir () == NULL)
835 check_extra_gac_path_env ();
837 mono_os_mutex_init_recursive (&assemblies_mutex);
838 mono_os_mutex_init (&assembly_binding_mutex);
840 #ifndef DISABLE_ASSEMBLY_REMAPPING
841 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
844 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
845 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
851 mono_assembly_binding_lock (void)
853 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
857 mono_assembly_binding_unlock (void)
859 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
863 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
865 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
866 guint32 cols [MONO_ASSEMBLY_SIZE];
867 gint32 machine, flags;
872 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
875 aname->hash_value = NULL;
876 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
878 aname->name = g_strdup (aname->name);
879 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
881 aname->culture = g_strdup (aname->culture);
882 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
883 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
884 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
885 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
886 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
887 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
888 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
889 guchar* token = (guchar *)g_malloc (8);
894 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
895 len = mono_metadata_decode_blob_size (pkey, &pkey);
896 aname->public_key = (guchar*)pkey;
898 mono_digest_get_public_token (token, aname->public_key, len);
899 encoded = encode_public_tok (token, 8);
900 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
906 aname->public_key = NULL;
907 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
910 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
911 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
913 const gchar *pkey_end;
914 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
915 pkey_end += len; /* move to end */
916 size_t size = pkey_end - (const gchar*)aname->public_key;
917 guchar *tmp = g_new (guchar, size);
918 memcpy (tmp, aname->public_key, size);
919 aname->public_key = tmp;
924 aname->public_key = 0;
926 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
927 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
929 case COFF_MACHINE_I386:
930 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
931 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
932 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
933 else if ((flags & 0x70) == 0x70)
934 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
936 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
938 case COFF_MACHINE_IA64:
939 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
941 case COFF_MACHINE_AMD64:
942 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
944 case COFF_MACHINE_ARM:
945 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
955 * mono_assembly_fill_assembly_name:
958 * \returns TRUE if successful
961 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
963 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
967 * mono_stringify_assembly_name:
968 * \param aname the assembly name.
970 * Convert \p aname into its string format. The returned string is dynamically
971 * allocated and should be freed by the caller.
973 * \returns a newly allocated string with a string representation of
977 mono_stringify_assembly_name (MonoAssemblyName *aname)
979 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
981 return g_strdup_printf (
982 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
983 quote, aname->name, quote,
984 aname->major, aname->minor, aname->build, aname->revision,
985 aname->culture && *aname->culture? aname->culture: "neutral",
986 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
987 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
991 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
993 const gchar *public_tok;
996 public_tok = mono_metadata_blob_heap (image, key_index);
997 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
999 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
1001 mono_digest_get_public_token (token, (guchar*)public_tok, len);
1002 return encode_public_tok (token, 8);
1005 return encode_public_tok ((guchar*)public_tok, len);
1009 * mono_assembly_addref:
1010 * \param assembly the assembly to reference
1012 * This routine increments the reference count on a MonoAssembly.
1013 * The reference count is reduced every time the method mono_assembly_close() is
1017 mono_assembly_addref (MonoAssembly *assembly)
1019 InterlockedIncrement (&assembly->ref_count);
1023 * CAUTION: This table must be kept in sync with
1024 * ivkm/reflect/Fusion.cs
1027 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1028 #define WINFX_KEY "31bf3856ad364e35"
1029 #define ECMA_KEY "b77a5c561934e089"
1030 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1031 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1039 static KeyRemapEntry key_remap_table[] = {
1040 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1041 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1042 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1043 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1044 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1045 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1046 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1047 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1048 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1049 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1050 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1051 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1052 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1053 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1054 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1055 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1056 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1057 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1058 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1059 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1060 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1061 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1062 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1063 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1064 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1065 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1066 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1067 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1068 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1072 remap_keys (MonoAssemblyName *aname)
1075 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1076 const KeyRemapEntry *entry = &key_remap_table [i];
1078 if (strcmp (aname->name, entry->name) ||
1079 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1082 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1084 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1085 "Remapped public key token of retargetable assembly %s from %s to %s",
1086 aname->name, entry->from, entry->to);
1091 static MonoAssemblyName *
1092 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1094 const MonoRuntimeInfo *current_runtime;
1096 if (aname->name == NULL) return aname;
1098 current_runtime = mono_get_runtime_info ();
1100 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1101 const AssemblyVersionSet* vset;
1103 /* Remap to current runtime */
1104 vset = ¤t_runtime->version_sets [0];
1106 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1107 dest_aname->major = vset->major;
1108 dest_aname->minor = vset->minor;
1109 dest_aname->build = vset->build;
1110 dest_aname->revision = vset->revision;
1111 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1113 /* Remap assembly name */
1114 if (!strcmp (aname->name, "System.Net"))
1115 dest_aname->name = g_strdup ("System");
1117 remap_keys (dest_aname);
1119 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1120 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1122 aname->major, aname->minor, aname->build, aname->revision,
1124 vset->major, vset->minor, vset->build, vset->revision
1130 #ifndef DISABLE_ASSEMBLY_REMAPPING
1131 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1133 const AssemblyVersionSet* vset;
1134 int index = vmap->version_set_index;
1135 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1136 vset = ¤t_runtime->version_sets [index];
1138 if (aname->major == vset->major && aname->minor == vset->minor &&
1139 aname->build == vset->build && aname->revision == vset->revision) {
1140 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1142 aname->major, aname->minor, aname->build, aname->revision);
1146 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1147 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1148 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1150 aname->major, aname->minor, aname->build, aname->revision,
1151 vset->major, vset->minor, vset->build, vset->revision
1156 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1157 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1158 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1160 aname->major, aname->minor, aname->build, aname->revision,
1161 vset->major, vset->minor, vset->build, vset->revision
1164 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1165 dest_aname->major = vset->major;
1166 dest_aname->minor = vset->minor;
1167 dest_aname->build = vset->build;
1168 dest_aname->revision = vset->revision;
1169 if (vmap->new_assembly_name != NULL) {
1170 dest_aname->name = vmap->new_assembly_name;
1171 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1172 "The assembly name %s was remapped to %s",
1184 * mono_assembly_get_assemblyref:
1185 * \param image pointer to the \c MonoImage to extract the information from.
1186 * \param index index to the assembly reference in the image.
1187 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1189 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1192 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1195 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1198 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1200 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1202 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1203 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1204 aname->hash_value = hash;
1205 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1206 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1207 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1208 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1209 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1210 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1211 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1213 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1214 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1215 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1218 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1223 * mono_assembly_load_reference:
1226 mono_assembly_load_reference (MonoImage *image, int index)
1228 MonoAssembly *reference;
1229 MonoAssemblyName aname;
1230 MonoImageOpenStatus status;
1233 * image->references is shared between threads, so we need to access
1234 * it inside a critical section.
1236 mono_assemblies_lock ();
1237 if (!image->references) {
1238 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1240 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1241 image->nreferences = t->rows;
1243 reference = image->references [index];
1244 mono_assemblies_unlock ();
1248 mono_assembly_get_assemblyref (image, index, &aname);
1250 if (image->assembly && image->assembly->ref_only) {
1251 /* We use the loaded corlib */
1252 if (!strcmp (aname.name, "mscorlib"))
1253 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1255 reference = mono_assembly_loaded_full (&aname, TRUE);
1257 /* Try a postload search hook */
1258 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1262 * Here we must advice that the error was due to
1263 * a non loaded reference using the ReflectionOnly api
1266 reference = (MonoAssembly *)REFERENCE_MISSING;
1268 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1269 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1270 * accordingly, it would fail on the MS runtime before).
1271 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1272 * example bug-349190.2.cs and who knows how much more code in the wild.
1274 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1275 if (!reference && image->assembly)
1276 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1279 if (reference == NULL){
1282 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1283 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 : "" );
1284 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1285 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1286 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1287 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1288 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1289 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1291 extra_msg = g_strdup ("");
1294 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1295 " Assembly: %s (assemblyref_index=%d)\n"
1296 " Version: %d.%d.%d.%d\n"
1297 " Public Key: %s\n%s",
1298 image->name, aname.name, index,
1299 aname.major, aname.minor, aname.build, aname.revision,
1300 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1305 mono_assemblies_lock ();
1306 if (reference == NULL) {
1307 /* Flag as not found */
1308 reference = (MonoAssembly *)REFERENCE_MISSING;
1311 if (!image->references [index]) {
1312 if (reference != REFERENCE_MISSING){
1313 mono_assembly_addref (reference);
1314 if (image->assembly)
1315 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1316 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1318 if (image->assembly)
1319 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1320 image->assembly->aname.name, image->assembly);
1323 image->references [index] = reference;
1325 mono_assemblies_unlock ();
1327 if (image->references [index] != reference) {
1328 /* Somebody loaded it before us */
1329 mono_assembly_close (reference);
1334 * mono_assembly_load_references:
1337 * \deprecated There is no reason to use this method anymore, it does nothing
1339 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1342 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1344 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1345 *status = MONO_IMAGE_OK;
1348 typedef struct AssemblyLoadHook AssemblyLoadHook;
1349 struct AssemblyLoadHook {
1350 AssemblyLoadHook *next;
1351 MonoAssemblyLoadFunc func;
1355 AssemblyLoadHook *assembly_load_hook = NULL;
1358 * mono_assembly_invoke_load_hook:
1361 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1363 AssemblyLoadHook *hook;
1365 for (hook = assembly_load_hook; hook; hook = hook->next) {
1366 hook->func (ass, hook->user_data);
1371 * mono_install_assembly_load_hook:
1374 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1376 AssemblyLoadHook *hook;
1378 g_return_if_fail (func != NULL);
1380 hook = g_new0 (AssemblyLoadHook, 1);
1382 hook->user_data = user_data;
1383 hook->next = assembly_load_hook;
1384 assembly_load_hook = hook;
1388 free_assembly_load_hooks (void)
1390 AssemblyLoadHook *hook, *next;
1392 for (hook = assembly_load_hook; hook; hook = next) {
1398 typedef struct AssemblySearchHook AssemblySearchHook;
1399 struct AssemblySearchHook {
1400 AssemblySearchHook *next;
1401 MonoAssemblySearchFunc func;
1407 AssemblySearchHook *assembly_search_hook = NULL;
1409 static MonoAssembly*
1410 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1412 AssemblySearchHook *hook;
1414 for (hook = assembly_search_hook; hook; hook = hook->next) {
1415 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1418 * A little explanation is in order here.
1420 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1421 * The embedding API exposes a search hook that doesn't take such argument.
1423 * The original fix would call the default search hook before all the registered ones and pass
1424 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1425 * rely on. Which is the ordering between user hooks and the default runtime hook.
1427 * Registering the hook after mono_jit_init would let your hook run before the default one and
1428 * when using it to handle non standard app layouts this could save your app from a massive amount
1429 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1430 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1432 * So what's the fix? We register the default hook using regular means and special case it when iterating
1433 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1436 if (hook->func == (void*)mono_domain_assembly_postload_search)
1437 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1439 ass = hook->func (aname, hook->user_data);
1449 * mono_assembly_invoke_search_hook:
1452 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1454 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1458 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1460 AssemblySearchHook *hook;
1462 g_return_if_fail (func != NULL);
1464 hook = g_new0 (AssemblySearchHook, 1);
1466 hook->user_data = user_data;
1467 hook->refonly = refonly;
1468 hook->postload = postload;
1469 hook->next = assembly_search_hook;
1470 assembly_search_hook = hook;
1474 * mono_install_assembly_search_hook:
1477 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1479 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1483 free_assembly_search_hooks (void)
1485 AssemblySearchHook *hook, *next;
1487 for (hook = assembly_search_hook; hook; hook = next) {
1494 * mono_install_assembly_refonly_search_hook:
1497 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1499 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1503 * mono_install_assembly_postload_search_hook:
1506 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1508 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1512 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1514 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1517 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1518 struct AssemblyPreLoadHook {
1519 AssemblyPreLoadHook *next;
1520 MonoAssemblyPreLoadFunc func;
1524 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1525 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1527 static MonoAssembly *
1528 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1530 AssemblyPreLoadHook *hook;
1531 MonoAssembly *assembly;
1533 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1534 assembly = hook->func (aname, assemblies_path, hook->user_data);
1535 if (assembly != NULL)
1542 static MonoAssembly *
1543 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1545 AssemblyPreLoadHook *hook;
1546 MonoAssembly *assembly;
1548 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1549 assembly = hook->func (aname, assemblies_path, hook->user_data);
1550 if (assembly != NULL)
1558 * mono_install_assembly_preload_hook:
1561 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1563 AssemblyPreLoadHook *hook;
1565 g_return_if_fail (func != NULL);
1567 hook = g_new0 (AssemblyPreLoadHook, 1);
1569 hook->user_data = user_data;
1570 hook->next = assembly_preload_hook;
1571 assembly_preload_hook = hook;
1575 * mono_install_assembly_refonly_preload_hook:
1578 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1580 AssemblyPreLoadHook *hook;
1582 g_return_if_fail (func != NULL);
1584 hook = g_new0 (AssemblyPreLoadHook, 1);
1586 hook->user_data = user_data;
1587 hook->next = assembly_refonly_preload_hook;
1588 assembly_refonly_preload_hook = hook;
1592 free_assembly_preload_hooks (void)
1594 AssemblyPreLoadHook *hook, *next;
1596 for (hook = assembly_preload_hook; hook; hook = next) {
1601 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1608 absolute_dir (const gchar *filename)
1619 if (g_path_is_absolute (filename)) {
1620 part = g_path_get_dirname (filename);
1621 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1626 cwd = g_get_current_dir ();
1627 mixed = g_build_filename (cwd, filename, NULL);
1628 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1633 for (i = 0; (part = parts [i]) != NULL; i++) {
1634 if (!strcmp (part, "."))
1637 if (!strcmp (part, "..")) {
1638 if (list && list->next) /* Don't remove root */
1639 list = g_list_delete_link (list, list);
1641 list = g_list_prepend (list, part);
1645 result = g_string_new ("");
1646 list = g_list_reverse (list);
1648 /* Ignores last data pointer, which should be the filename */
1649 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1651 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1656 g_string_free (result, FALSE);
1661 return g_strdup (".");
1668 * mono_assembly_open_from_bundle:
1669 * \param filename Filename requested
1670 * \param status return status code
1672 * This routine tries to open the assembly specified by \p filename from the
1673 * defined bundles, if found, returns the MonoImage for it, if not found
1677 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1681 gchar *lowercase_filename;
1682 MonoImage *image = NULL;
1683 gboolean is_satellite = FALSE;
1685 * we do a very simple search for bundled assemblies: it's not a general
1686 * purpose assembly loading mechanism.
1692 lowercase_filename = g_utf8_strdown (filename, -1);
1693 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1694 g_free (lowercase_filename);
1695 name = g_path_get_basename (filename);
1696 mono_assemblies_lock ();
1697 for (i = 0; !image && bundles [i]; ++i) {
1698 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1699 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1703 mono_assemblies_unlock ();
1705 mono_image_addref (image);
1706 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1715 * mono_assembly_open_full:
1716 * \param filename the file to load
1717 * \param status return status code
1718 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1720 * This loads an assembly from the specified \p filename. The \p filename allows
1721 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1722 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1723 * is treated as a local path.
1725 * First, an attempt is made to load the assembly from the bundled executable (for those
1726 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1727 * assembly has been registered as an embedded assembly). If this is not the case, then
1728 * the assembly is loaded from disk using `api:mono_image_open_full`.
1730 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1731 * the assembly is made.
1733 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1734 * the \c System.Reflection API.
1736 * \returns NULL on error, with the \p status set to an error code, or a pointer
1740 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1742 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1746 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1748 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1752 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1753 gboolean load_from_context,
1754 MonoAssemblyCandidatePredicate predicate,
1756 MonoImageOpenStatus *status)
1760 MonoImageOpenStatus def_status;
1763 gboolean loaded_from_bundle;
1765 g_return_val_if_fail (filename != NULL, NULL);
1768 status = &def_status;
1769 *status = MONO_IMAGE_OK;
1771 if (strncmp (filename, "file://", 7) == 0) {
1772 GError *error = NULL;
1773 gchar *uri = (gchar *) filename;
1777 * MS allows file://c:/... and fails on file://localhost/c:/...
1778 * They also throw an IndexOutOfRangeException if "file://"
1781 uri = g_strdup_printf ("file:///%s", uri + 7);
1784 uri = mono_escape_uri_string (tmpuri);
1785 fname = g_filename_from_uri (uri, NULL, &error);
1788 if (tmpuri != filename)
1791 if (error != NULL) {
1792 g_warning ("%s\n", error->message);
1793 g_error_free (error);
1794 fname = g_strdup (filename);
1797 fname = g_strdup (filename);
1800 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1801 "Assembly Loader probing location: '%s'.", fname);
1804 if (!mono_assembly_is_in_gac (fname)) {
1806 new_fname = mono_make_shadow_copy (fname, &error);
1807 if (!is_ok (&error)) {
1808 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1809 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1810 mono_error_cleanup (&error);
1811 *status = MONO_IMAGE_IMAGE_INVALID;
1816 if (new_fname && new_fname != fname) {
1819 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1820 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1825 // If VM built with mkbundle
1826 loaded_from_bundle = FALSE;
1827 if (bundles != NULL) {
1828 image = mono_assembly_open_from_bundle (fname, status, refonly);
1829 loaded_from_bundle = image != NULL;
1833 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1836 if (*status == MONO_IMAGE_OK)
1837 *status = MONO_IMAGE_ERROR_ERRNO;
1842 if (image->assembly) {
1843 /* Already loaded by another appdomain */
1844 mono_assembly_invoke_load_hook (image->assembly);
1845 mono_image_close (image);
1847 return image->assembly;
1850 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1853 if (!loaded_from_bundle)
1854 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1855 "Assembly Loader loaded assembly from location: '%s'.", filename);
1857 mono_config_for_assembly (ass->image);
1860 /* Clear the reference added by mono_image_open */
1861 mono_image_close (image);
1869 free_item (gpointer val, gpointer user_data)
1875 * mono_assembly_load_friends:
1876 * \param ass an assembly
1878 * Load the list of friend assemblies that are allowed to access
1879 * the assembly's internal types and members. They are stored as assembly
1880 * names in custom attributes.
1882 * This is an internal method, we need this because when we load mscorlib
1883 * we do not have the internals visible cattr loaded yet,
1884 * so we need to load these after we initialize the runtime.
1886 * LOCKING: Acquires the assemblies lock plus the loader lock.
1889 mono_assembly_load_friends (MonoAssembly* ass)
1893 MonoCustomAttrInfo* attrs;
1896 if (ass->friend_assembly_names_inited)
1899 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1900 mono_error_assert_ok (&error);
1902 mono_assemblies_lock ();
1903 ass->friend_assembly_names_inited = TRUE;
1904 mono_assemblies_unlock ();
1908 mono_assemblies_lock ();
1909 if (ass->friend_assembly_names_inited) {
1910 mono_assemblies_unlock ();
1913 mono_assemblies_unlock ();
1917 * We build the list outside the assemblies lock, the worse that can happen
1918 * is that we'll need to free the allocated list.
1920 for (i = 0; i < attrs->num_attrs; ++i) {
1921 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1922 MonoAssemblyName *aname;
1924 /* Do some sanity checking */
1925 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1927 if (attr->data_size < 4)
1929 data = (const char*)attr->data;
1930 /* 0xFF means null string, see custom attr format */
1931 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1933 mono_metadata_decode_value (data + 2, &data);
1934 aname = g_new0 (MonoAssemblyName, 1);
1935 /*g_print ("friend ass: %s\n", data);*/
1936 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1937 list = g_slist_prepend (list, aname);
1942 mono_custom_attrs_free (attrs);
1944 mono_assemblies_lock ();
1945 if (ass->friend_assembly_names_inited) {
1946 mono_assemblies_unlock ();
1947 g_slist_foreach (list, free_item, NULL);
1948 g_slist_free (list);
1951 ass->friend_assembly_names = list;
1953 /* Because of the double checked locking pattern above */
1954 mono_memory_barrier ();
1955 ass->friend_assembly_names_inited = TRUE;
1956 mono_assemblies_unlock ();
1959 struct HasReferenceAssemblyAttributeIterData {
1964 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1966 gboolean stop_scanning = FALSE;
1967 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1969 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1970 /* Note we don't check the assembly name, same as coreCLR. */
1971 iter_data->has_attr = TRUE;
1972 stop_scanning = TRUE;
1975 return stop_scanning;
1979 * mono_assembly_has_reference_assembly_attribute:
1980 * \param assembly a MonoAssembly
1981 * \param error set on error.
1983 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1984 * On error returns FALSE and sets \p error.
1987 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1992 * This might be called during assembly loading, so do everything using the low-level
1996 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1998 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
2000 return iter_data.has_attr;
2004 * mono_assembly_open:
2005 * \param filename Opens the assembly pointed out by this name
2006 * \param status return status code
2008 * This loads an assembly from the specified \p filename. The \p filename allows
2009 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2010 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2011 * is treated as a local path.
2013 * First, an attempt is made to load the assembly from the bundled executable (for those
2014 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2015 * assembly has been registered as an embedded assembly). If this is not the case, then
2016 * the assembly is loaded from disk using `api:mono_image_open_full`.
2018 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2019 * the assembly is made.
2021 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2022 * assembly or NULL on error. Details about the error are stored in the
2023 * \p status variable.
2026 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2028 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2032 * mono_assembly_load_from_full:
2033 * \param image Image to load the assembly from
2034 * \param fname assembly name to associate with the assembly
2035 * \param status returns the status condition
2036 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2038 * If the provided \p image has an assembly reference, it will process the given
2039 * image as an assembly with the given name.
2041 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2043 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2044 * set to \c MONO_IMAGE_OK; or NULL on error.
2046 * If there is an error loading the assembly the \p status will indicate the
2047 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2048 * image did not contain an assembly reference table.
2051 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2052 MonoImageOpenStatus *status, gboolean refonly)
2054 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2058 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2060 MonoAssemblyCandidatePredicate predicate,
2062 MonoImageOpenStatus *status)
2064 MonoAssembly *ass, *ass2;
2067 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2068 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2069 *status = MONO_IMAGE_IMAGE_INVALID;
2073 #if defined (HOST_WIN32)
2078 tmp_fn = g_strdup (fname);
2079 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2080 if (tmp_fn [i] == '/')
2084 base_dir = absolute_dir (tmp_fn);
2088 base_dir = absolute_dir (fname);
2092 * Create assembly struct, and enter it into the assembly cache
2094 ass = g_new0 (MonoAssembly, 1);
2095 ass->basedir = base_dir;
2096 ass->ref_only = refonly;
2099 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2101 mono_assembly_fill_assembly_name (image, &ass->aname);
2103 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2104 // MS.NET doesn't support loading other mscorlibs
2107 mono_image_addref (mono_defaults.corlib);
2108 *status = MONO_IMAGE_OK;
2109 return mono_defaults.corlib->assembly;
2112 /* Add a non-temporary reference because of ass->image */
2113 mono_image_addref (image);
2115 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);
2118 * The load hooks might take locks so we can't call them while holding the
2121 if (ass->aname.name) {
2122 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2126 mono_image_close (image);
2127 *status = MONO_IMAGE_OK;
2132 /* We need to check for ReferenceAssmeblyAttribute before we
2133 * mark the assembly as loaded and before we fire the load
2134 * hook. Otherwise mono_domain_fire_assembly_load () in
2135 * appdomain.c will cache a mapping from the assembly name to
2136 * this image and we won't be able to look for a different
2140 MonoError refasm_error;
2141 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2142 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2145 mono_image_close (image);
2146 *status = MONO_IMAGE_IMAGE_INVALID;
2149 mono_error_cleanup (&refasm_error);
2152 if (predicate && !predicate (ass, user_data)) {
2153 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2156 mono_image_close (image);
2157 *status = MONO_IMAGE_IMAGE_INVALID;
2161 mono_assemblies_lock ();
2163 if (image->assembly) {
2165 * This means another thread has already loaded the assembly, but not yet
2166 * called the load hooks so the search hook can't find the assembly.
2168 mono_assemblies_unlock ();
2169 ass2 = image->assembly;
2172 mono_image_close (image);
2173 *status = MONO_IMAGE_OK;
2177 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2179 image->assembly = ass;
2181 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2182 mono_assemblies_unlock ();
2185 if (image->is_module_handle)
2186 mono_image_fixup_vtable (image);
2189 mono_assembly_invoke_load_hook (ass);
2191 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2197 * mono_assembly_load_from:
2198 * \param image Image to load the assembly from
2199 * \param fname assembly name to associate with the assembly
2200 * \param status return status code
2202 * If the provided \p image has an assembly reference, it will process the given
2203 * image as an assembly with the given name.
2205 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2207 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2208 * \p refonly parameter set to FALSE.
2209 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2210 * set to \c MONO_IMAGE_OK; or NULL on error.
2212 * If there is an error loading the assembly the \p status will indicate the
2213 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2214 * image did not contain an assembly reference table.
2218 mono_assembly_load_from (MonoImage *image, const char *fname,
2219 MonoImageOpenStatus *status)
2221 return mono_assembly_load_from_full (image, fname, status, FALSE);
2225 * mono_assembly_name_free:
2226 * \param aname assembly name to free
2228 * Frees the provided assembly name object.
2229 * (it does not frees the object itself, only the name members).
2232 mono_assembly_name_free (MonoAssemblyName *aname)
2237 g_free ((void *) aname->name);
2238 g_free ((void *) aname->culture);
2239 g_free ((void *) aname->hash_value);
2240 g_free ((guint8*) aname->public_key);
2244 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2247 gchar header [16], val, *arr;
2248 gint i, j, offset, bitlen, keylen, pkeylen;
2250 keylen = strlen (key) >> 1;
2254 /* allow the ECMA standard key */
2255 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2257 *pubkey = g_strdup (key);
2263 val = g_ascii_xdigit_value (key [0]) << 4;
2264 val |= g_ascii_xdigit_value (key [1]);
2269 val = g_ascii_xdigit_value (key [24]);
2270 val |= g_ascii_xdigit_value (key [25]);
2282 /* We need the first 16 bytes
2283 * to check whether this key is valid or not */
2284 pkeylen = strlen (pkey) >> 1;
2288 for (i = 0, j = 0; i < 16; i++) {
2289 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2290 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2293 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2294 header [1] != 0x02 || /* Version (0x02) */
2295 header [2] != 0x00 || /* Reserved (word) */
2296 header [3] != 0x00 ||
2297 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2300 /* Based on this length, we _should_ be able to know if the length is right */
2301 bitlen = read32 (header + 12) >> 3;
2302 if ((bitlen + 16 + 4) != pkeylen)
2305 /* parsing is OK and the public key itself is not requested back */
2309 /* Encode the size of the blob */
2311 if (keylen <= 127) {
2312 arr = (gchar *)g_malloc (keylen + 1);
2313 arr [offset++] = keylen;
2315 arr = (gchar *)g_malloc (keylen + 2);
2316 arr [offset++] = 0x80; /* 10bs */
2317 arr [offset++] = keylen;
2320 for (i = offset, j = 0; i < keylen + offset; i++) {
2321 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2322 arr [i] |= g_ascii_xdigit_value (key [j++]);
2331 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)
2333 gint major, minor, build, revision;
2336 gchar *pkey, *pkeyptr, *encoded, tok [8];
2338 memset (aname, 0, sizeof (MonoAssemblyName));
2341 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2342 if (version_parts < 2 || version_parts > 4)
2345 /* FIXME: we should set build & revision to -1 (instead of 0)
2346 if these are not set in the version string. That way, later on,
2347 we can still determine if these were specified. */
2348 aname->major = major;
2349 aname->minor = minor;
2350 if (version_parts >= 3)
2351 aname->build = build;
2354 if (version_parts == 4)
2355 aname->revision = revision;
2357 aname->revision = 0;
2360 aname->flags = flags;
2362 aname->name = g_strdup (name);
2365 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2366 aname->culture = g_strdup ("");
2368 aname->culture = g_strdup (culture);
2371 if (token && strncmp (token, "null", 4) != 0) {
2374 /* the constant includes the ending NULL, hence the -1 */
2375 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2376 mono_assembly_name_free (aname);
2379 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2380 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2386 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2387 mono_assembly_name_free (aname);
2392 if (save_public_key)
2393 aname->public_key = (guint8*)pkey;
2396 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2400 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2401 // We also need to generate the key token
2402 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2403 encoded = encode_public_tok ((guchar*) tok, 8);
2404 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2407 if (save_public_key)
2408 aname->public_key = (guint8*) pkey;
2417 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2422 parts = g_strsplit (dirname, "_", 3);
2423 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2428 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2434 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2436 char *eqsign = strchr (pair, '=');
2444 *key = (gchar*)pair;
2445 *keylen = eqsign - *key;
2446 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2448 *value = g_strstrip (eqsign + 1);
2453 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2457 gchar *version = NULL;
2459 gchar *culture = NULL;
2461 gchar *token = NULL;
2465 gchar *retargetable = NULL;
2466 gchar *retargetable_uq;
2470 gchar *value, *part_name;
2471 guint32 part_name_len;
2474 gboolean version_defined;
2475 gboolean token_defined;
2477 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2479 if (!is_version_defined)
2480 is_version_defined = &version_defined;
2481 *is_version_defined = FALSE;
2482 if (!is_token_defined)
2483 is_token_defined = &token_defined;
2484 *is_token_defined = FALSE;
2486 parts = tmp = g_strsplit (name, ",", 6);
2487 if (!tmp || !*tmp) {
2492 dllname = g_strstrip (*tmp);
2497 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2498 goto cleanup_and_fail;
2500 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2501 *is_version_defined = TRUE;
2503 if (strlen (version) == 0) {
2504 goto cleanup_and_fail;
2510 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2512 if (strlen (culture) == 0) {
2513 goto cleanup_and_fail;
2519 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2520 *is_token_defined = TRUE;
2522 if (strlen (token) == 0) {
2523 goto cleanup_and_fail;
2529 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2531 if (strlen (key) == 0) {
2532 goto cleanup_and_fail;
2538 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2539 retargetable = value;
2540 retargetable_uq = unquote (retargetable);
2541 if (retargetable_uq != NULL)
2542 retargetable = retargetable_uq;
2544 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2545 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2546 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2547 g_free (retargetable_uq);
2548 goto cleanup_and_fail;
2551 g_free (retargetable_uq);
2556 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2558 procarch_uq = unquote (procarch);
2559 if (procarch_uq != NULL)
2560 procarch = procarch_uq;
2562 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2563 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2564 else if (!g_ascii_strcasecmp (procarch, "X86"))
2565 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2566 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2567 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2568 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2569 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2571 g_free (procarch_uq);
2572 goto cleanup_and_fail;
2575 g_free (procarch_uq);
2584 /* if retargetable flag is set, then we must have a fully qualified name */
2585 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2586 goto cleanup_and_fail;
2589 dllname_uq = unquote (dllname);
2590 version_uq = unquote (version);
2591 culture_uq = unquote (culture);
2592 token_uq = unquote (token);
2593 key_uq = unquote (key);
2595 res = build_assembly_name (
2596 dllname_uq == NULL ? dllname : dllname_uq,
2597 version_uq == NULL ? version : version_uq,
2598 culture_uq == NULL ? culture : culture_uq,
2599 token_uq == NULL ? token : token_uq,
2600 key_uq == NULL ? key : key_uq,
2601 flags, arch, aname, save_public_key);
2603 g_free (dllname_uq);
2604 g_free (version_uq);
2605 g_free (culture_uq);
2618 unquote (const char *str)
2626 slen = strlen (str);
2630 if (*str != '\'' && *str != '\"')
2633 end = str + slen - 1;
2637 return g_strndup (str + 1, slen - 2);
2641 * mono_assembly_name_parse:
2642 * \param name name to parse
2643 * \param aname the destination assembly name
2645 * Parses an assembly qualified type name and assigns the name,
2646 * version, culture and token to the provided assembly name object.
2648 * \returns TRUE if the name could be parsed.
2651 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2653 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2657 * mono_assembly_name_new:
2658 * \param name name to parse
2660 * Allocate a new \c MonoAssemblyName and fill its values from the
2663 * \returns a newly allocated structure or NULL if there was any failure.
2666 mono_assembly_name_new (const char *name)
2668 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2669 if (mono_assembly_name_parse (name, aname))
2676 * mono_assembly_name_get_name:
2679 mono_assembly_name_get_name (MonoAssemblyName *aname)
2685 * mono_assembly_name_get_culture:
2688 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2690 return aname->culture;
2694 * mono_assembly_name_get_pubkeytoken:
2697 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2699 if (aname->public_key_token [0])
2700 return aname->public_key_token;
2705 * mono_assembly_name_get_version:
2708 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2711 *minor = aname->minor;
2713 *build = aname->build;
2715 *revision = aname->revision;
2716 return aname->major;
2719 static MonoAssembly*
2720 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2722 gchar *fullpath = NULL;
2724 const char* direntry;
2725 MonoAssemblyName gac_aname;
2726 gint major=-1, minor=0, build=0, revision=0;
2727 gboolean exact_version;
2729 dirhandle = g_dir_open (basepath, 0, NULL);
2733 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2735 while ((direntry = g_dir_read_name (dirhandle))) {
2736 gboolean match = TRUE;
2738 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2741 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2744 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2745 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2749 if (exact_version) {
2750 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2751 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2753 else if (gac_aname.major < major)
2755 else if (gac_aname.major == major) {
2756 if (gac_aname.minor < minor)
2758 else if (gac_aname.minor == minor) {
2759 if (gac_aname.build < build)
2761 else if (gac_aname.build == build && gac_aname.revision <= revision)
2768 major = gac_aname.major;
2769 minor = gac_aname.minor;
2770 build = gac_aname.build;
2771 revision = gac_aname.revision;
2773 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2776 mono_assembly_name_free (&gac_aname);
2779 g_dir_close (dirhandle);
2781 if (fullpath == NULL)
2784 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2791 * mono_assembly_load_with_partial_name:
2792 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2793 * \param status return status code
2795 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2796 * so it might contain a qualified type name, version, culture and token.
2798 * This will load the assembly from the file whose name is derived from the assembly name
2799 * by appending the \c .dll extension.
2801 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2802 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2803 * if that fails from the GAC.
2805 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2808 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2812 MonoAssemblyName *aname, base_name;
2813 MonoAssemblyName mapped_aname;
2814 gchar *fullname, *gacpath;
2817 memset (&base_name, 0, sizeof (MonoAssemblyName));
2820 if (!mono_assembly_name_parse (name, aname))
2824 * If no specific version has been requested, make sure we load the
2825 * correct version for system assemblies.
2827 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2828 aname = mono_assembly_remap_version (aname, &mapped_aname);
2830 res = mono_assembly_loaded (aname);
2832 mono_assembly_name_free (aname);
2836 res = invoke_assembly_preload_hook (aname, assemblies_path);
2838 res->in_gac = FALSE;
2839 mono_assembly_name_free (aname);
2843 fullname = g_strdup_printf ("%s.dll", aname->name);
2845 if (extra_gac_paths) {
2846 paths = extra_gac_paths;
2847 while (!res && *paths) {
2848 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2849 res = probe_for_partial_name (gacpath, fullname, aname, status);
2858 mono_assembly_name_free (aname);
2862 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2863 res = probe_for_partial_name (gacpath, fullname, aname, status);
2867 mono_assembly_name_free (aname);
2872 MonoDomain *domain = mono_domain_get ();
2874 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2875 if (!is_ok (&error)) {
2876 mono_error_cleanup (&error);
2877 if (*status == MONO_IMAGE_OK)
2878 *status = MONO_IMAGE_IMAGE_INVALID;
2886 mono_assembly_is_in_gac (const gchar *filename)
2888 const gchar *rootdir;
2892 if (filename == NULL)
2895 for (paths = extra_gac_paths; paths && *paths; paths++) {
2896 if (strstr (*paths, filename) != *paths)
2899 gp = (gchar *) (filename + strlen (*paths));
2900 if (*gp != G_DIR_SEPARATOR)
2903 if (strncmp (gp, "lib", 3))
2906 if (*gp != G_DIR_SEPARATOR)
2909 if (strncmp (gp, "mono", 4))
2912 if (*gp != G_DIR_SEPARATOR)
2915 if (strncmp (gp, "gac", 3))
2918 if (*gp != G_DIR_SEPARATOR)
2924 rootdir = mono_assembly_getrootdir ();
2925 if (strstr (filename, rootdir) != filename)
2928 gp = (gchar *) (filename + strlen (rootdir));
2929 if (*gp != G_DIR_SEPARATOR)
2932 if (strncmp (gp, "mono", 4))
2935 if (*gp != G_DIR_SEPARATOR)
2938 if (strncmp (gp, "gac", 3))
2941 if (*gp != G_DIR_SEPARATOR)
2947 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2950 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2954 if (strstr (aname->name, ".dll")) {
2955 len = strlen (aname->name) - 4;
2956 name = (gchar *)g_malloc (len + 1);
2957 memcpy (name, aname->name, len);
2960 name = g_strdup (aname->name);
2963 culture = g_utf8_strdown (aname->culture, -1);
2965 culture = g_strdup ("");
2967 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2968 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2972 filename = g_strconcat (pname, ".dll", NULL);
2973 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2979 if (extra_gac_paths) {
2980 paths = extra_gac_paths;
2981 while (!image && *paths) {
2982 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2983 "lib", "mono", "gac", subpath, NULL);
2984 image = mono_image_open (fullpath, NULL);
2995 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2996 "mono", "gac", subpath, NULL);
2997 image = mono_image_open (fullpath, NULL);
3004 static MonoAssemblyName*
3005 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3007 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3008 dest_name->major = info->new_version.major;
3009 dest_name->minor = info->new_version.minor;
3010 dest_name->build = info->new_version.build;
3011 dest_name->revision = info->new_version.revision;
3016 /* LOCKING: assembly_binding lock must be held */
3017 static MonoAssemblyBindingInfo*
3018 search_binding_loaded (MonoAssemblyName *aname)
3022 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3023 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3024 if (assembly_binding_maps_name (info, aname))
3031 static inline gboolean
3032 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3034 if (left->major != right->major || left->minor != right->minor ||
3035 left->build != right->build || left->revision != right->revision)
3041 static inline gboolean
3042 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3044 if (left->has_old_version_bottom != right->has_old_version_bottom)
3047 if (left->has_old_version_top != right->has_old_version_top)
3050 if (left->has_new_version != right->has_new_version)
3053 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3056 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3059 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3065 /* LOCKING: assumes all the necessary locks are held */
3067 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3069 MonoAssemblyBindingInfo *info_copy;
3071 MonoAssemblyBindingInfo *info_tmp;
3072 MonoDomain *domain = (MonoDomain*)user_data;
3077 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)) {
3078 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3079 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3083 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3084 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3085 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3089 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3090 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3092 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3094 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3096 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3100 get_version_number (int major, int minor)
3102 return major * 256 + minor;
3105 static inline gboolean
3106 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3108 int aname_version_number = get_version_number (aname->major, aname->minor);
3109 if (!info->has_old_version_bottom)
3112 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3115 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3118 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3119 info->major = aname->major;
3120 info->minor = aname->minor;
3125 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3126 static MonoAssemblyBindingInfo*
3127 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3129 MonoAssemblyBindingInfo *info;
3132 if (!domain->assembly_bindings)
3136 for (list = domain->assembly_bindings; list; list = list->next) {
3137 info = (MonoAssemblyBindingInfo *)list->data;
3138 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3144 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3145 info->has_new_version && assembly_binding_maps_name (info, aname))
3146 info->is_valid = TRUE;
3148 info->is_valid = FALSE;
3155 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3157 if (domain->assembly_bindings_parsed)
3159 mono_domain_lock (domain);
3160 if (!domain->assembly_bindings_parsed) {
3162 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3164 if (!domain_config_file_path)
3165 domain_config_file_path = domain_config_file_name;
3167 mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3168 domain->assembly_bindings_parsed = TRUE;
3169 if (domain_config_file_name != domain_config_file_path)
3170 g_free (domain_config_file_path);
3173 mono_domain_unlock (domain);
3176 static MonoAssemblyName*
3177 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3180 MonoAssemblyBindingInfo *info, *info2;
3184 if (aname->public_key_token [0] == 0)
3187 domain = mono_domain_get ();
3189 mono_assembly_binding_lock ();
3190 info = search_binding_loaded (aname);
3191 mono_assembly_binding_unlock ();
3194 mono_domain_lock (domain);
3195 info = get_per_domain_assembly_binding_info (domain, aname);
3196 mono_domain_unlock (domain);
3200 if (!check_policy_versions (info, aname))
3203 mono_assembly_bind_version (info, aname, dest_name);
3207 if (domain && domain->setup && domain->setup->configuration_file) {
3208 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3209 /* expect this to succeed because mono_domain_set_options_from_config () did
3210 * the same thing when the domain was created. */
3211 mono_error_assert_ok (&error);
3212 mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3213 g_free (domain_config_file_name);
3215 mono_domain_lock (domain);
3216 info2 = get_per_domain_assembly_binding_info (domain, aname);
3219 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3220 info->name = g_strdup (info2->name);
3221 info->culture = g_strdup (info2->culture);
3222 info->domain_id = domain->domain_id;
3225 mono_domain_unlock (domain);
3230 info = g_new0 (MonoAssemblyBindingInfo, 1);
3231 info->major = aname->major;
3232 info->minor = aname->minor;
3235 if (!info->is_valid) {
3236 ppimage = mono_assembly_load_publisher_policy (aname);
3238 get_publisher_policy_info (ppimage, aname, info);
3239 mono_image_close (ppimage);
3243 /* Define default error value if needed */
3244 if (!info->is_valid) {
3245 info->name = g_strdup (aname->name);
3246 info->culture = g_strdup (aname->culture);
3247 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3250 mono_assembly_binding_lock ();
3251 info2 = search_binding_loaded (aname);
3253 /* This binding was added by another thread
3255 mono_assembly_binding_info_free (info);
3260 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3262 mono_assembly_binding_unlock ();
3264 if (!info->is_valid || !check_policy_versions (info, aname))
3267 mono_assembly_bind_version (info, aname, dest_name);
3272 * mono_assembly_load_from_gac
3274 * \param aname The assembly name object
3276 static MonoAssembly*
3277 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3279 MonoAssembly *result = NULL;
3280 gchar *name, *version, *culture, *fullpath, *subpath;
3285 if (aname->public_key_token [0] == 0) {
3289 if (strstr (aname->name, ".dll")) {
3290 len = strlen (filename) - 4;
3291 name = (gchar *)g_malloc (len + 1);
3292 memcpy (name, aname->name, len);
3295 name = g_strdup (aname->name);
3298 if (aname->culture) {
3299 culture = g_utf8_strdown (aname->culture, -1);
3301 culture = g_strdup ("");
3304 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3305 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3306 aname->minor, aname->build, aname->revision,
3310 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3315 if (extra_gac_paths) {
3316 paths = extra_gac_paths;
3317 while (!result && *paths) {
3318 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3319 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3326 result->in_gac = TRUE;
3331 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3332 "mono", "gac", subpath, NULL);
3333 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3337 result->in_gac = TRUE;
3345 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3348 MonoAssemblyName *aname;
3351 /* g_print ("corlib already loaded\n"); */
3355 // In native client, Corlib is embedded in the executable as static variable corlibData
3356 #if defined(__native_client__)
3357 if (corlibData != NULL && corlibSize != 0) {
3359 /* First "FALSE" instructs mono not to make a copy. */
3360 /* Second "FALSE" says this is not just a ref. */
3361 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3362 if (image == NULL || status != 0)
3363 g_print("mono_image_open_from_data_full failed: %d\n", status);
3364 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3365 if (corlib == NULL || status != 0)
3366 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3372 // A nonstandard preload hook may provide a special mscorlib assembly
3373 aname = mono_assembly_name_new ("mscorlib.dll");
3374 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3375 mono_assembly_name_free (aname);
3378 goto return_corlib_and_facades;
3380 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3381 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3382 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3384 goto return_corlib_and_facades;
3387 /* Normal case: Load corlib from mono/<version> */
3388 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3389 if (assemblies_path) { // Custom assemblies path
3390 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3392 g_free (corlib_file);
3393 goto return_corlib_and_facades;
3396 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3397 g_free (corlib_file);
3399 return_corlib_and_facades:
3400 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3401 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3406 static MonoAssembly*
3407 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3409 MonoError refasm_error;
3410 error_init (&refasm_error);
3411 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3414 mono_error_cleanup (&refasm_error);
3419 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3421 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3422 MonoAssemblyName *candidate_name = &candidate->aname;
3424 g_assert (wanted_name != NULL);
3425 g_assert (candidate_name != NULL);
3427 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3428 char * s = mono_stringify_assembly_name (wanted_name);
3429 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3431 s = mono_stringify_assembly_name (candidate_name);
3432 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3437 /* Wanted name has no token, not strongly named: always matches. */
3438 if (0 == wanted_name->public_key_token [0]) {
3439 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3443 /* Candidate name has no token, not strongly named: never matches */
3444 if (0 == candidate_name->public_key_token [0]) {
3445 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3449 return exact_sn_match (wanted_name, candidate_name) ||
3450 framework_assembly_sn_match (wanted_name, candidate_name);
3454 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3456 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3458 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3459 result ? "match, returning TRUE" : "don't match, returning FALSE");
3465 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3467 #ifndef DISABLE_ASSEMBLY_REMAPPING
3468 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3470 /* 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. */
3471 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3472 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");
3480 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3481 const char *basedir,
3482 MonoImageOpenStatus *status,
3485 MonoAssembly *result;
3486 char *fullpath, *filename;
3487 MonoAssemblyName maped_aname;
3488 MonoAssemblyName maped_name_pp;
3493 aname = mono_assembly_remap_version (aname, &maped_aname);
3495 /* Reflection only assemblies don't get assembly binding */
3497 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3499 result = mono_assembly_loaded_full (aname, refonly);
3503 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3505 result->in_gac = FALSE;
3509 /* Currently we retrieve the loaded corlib for reflection
3510 * only requests, like a common reflection only assembly
3512 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3513 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3516 len = strlen (aname->name);
3517 for (ext_index = 0; ext_index < 2; ext_index ++) {
3518 ext = ext_index == 0 ? ".dll" : ".exe";
3519 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3520 filename = g_strdup (aname->name);
3521 /* Don't try appending .dll/.exe if it already has one of those extensions */
3524 filename = g_strconcat (aname->name, ext, NULL);
3527 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3534 fullpath = g_build_filename (basedir, filename, NULL);
3535 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, &mono_assembly_candidate_predicate_sn_same_name, aname, status);
3538 result->in_gac = FALSE;
3544 result = load_in_path (filename, default_path, status, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
3546 result->in_gac = FALSE;
3556 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3558 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3561 /* Try a postload search hook */
3562 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3563 result = prevent_reference_assembly_from_running (result, refonly);
3569 * mono_assembly_load_full:
3570 * \param aname A MonoAssemblyName with the assembly name to load.
3571 * \param basedir A directory to look up the assembly at.
3572 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3573 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3575 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3576 * attempts to load the assembly from that directory before probing the standard locations.
3578 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3579 * assembly binding takes place.
3581 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3582 * value pointed by \p status is updated with an error code.
3585 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3587 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3591 * mono_assembly_load:
3592 * \param aname A MonoAssemblyName with the assembly name to load.
3593 * \param basedir A directory to look up the assembly at.
3594 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3596 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3597 * attempts to load the assembly from that directory before probing the standard locations.
3599 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3600 * value pointed by \p status is updated with an error code.
3603 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3605 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3609 * mono_assembly_loaded_full:
3610 * \param aname an assembly to look for.
3611 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3613 * This is used to determine if the specified assembly has been loaded
3614 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3615 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3618 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3621 MonoAssemblyName maped_aname;
3623 aname = mono_assembly_remap_version (aname, &maped_aname);
3625 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3631 * mono_assembly_loaded:
3632 * \param aname an assembly to look for.
3634 * This is used to determine if the specified assembly has been loaded
3636 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3637 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3640 mono_assembly_loaded (MonoAssemblyName *aname)
3642 return mono_assembly_loaded_full (aname, FALSE);
3646 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3648 if (assembly == NULL || assembly == REFERENCE_MISSING)
3651 if (assembly_is_dynamic (assembly)) {
3653 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3654 for (i = 0; i < dynimg->image.module_count; ++i)
3655 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3656 mono_dynamic_image_release_gc_roots (dynimg);
3661 * Returns whether mono_assembly_close_finish() must be called as
3662 * well. See comment for mono_image_close_except_pools() for why we
3663 * unload in two steps.
3666 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3669 g_return_val_if_fail (assembly != NULL, FALSE);
3671 if (assembly == REFERENCE_MISSING)
3674 /* Might be 0 already */
3675 if (InterlockedDecrement (&assembly->ref_count) > 0)
3678 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3680 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3682 mono_debug_close_image (assembly->image);
3684 mono_assemblies_lock ();
3685 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3686 mono_assemblies_unlock ();
3688 assembly->image->assembly = NULL;
3690 if (!mono_image_close_except_pools (assembly->image))
3691 assembly->image = NULL;
3693 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3694 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3695 mono_assembly_name_free (fname);
3698 g_slist_free (assembly->friend_assembly_names);
3699 g_free (assembly->basedir);
3701 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3707 mono_assembly_close_finish (MonoAssembly *assembly)
3709 g_assert (assembly && assembly != REFERENCE_MISSING);
3711 if (assembly->image)
3712 mono_image_close_finish (assembly->image);
3714 if (assembly_is_dynamic (assembly)) {
3715 g_free ((char*)assembly->aname.culture);
3722 * mono_assembly_close:
3723 * \param assembly the assembly to release.
3725 * This method releases a reference to the \p assembly. The assembly is
3726 * only released when all the outstanding references to it are released.
3729 mono_assembly_close (MonoAssembly *assembly)
3731 if (mono_assembly_close_except_image_pools (assembly))
3732 mono_assembly_close_finish (assembly);
3736 * mono_assembly_load_module:
3739 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3742 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3743 mono_error_assert_ok (&error);
3748 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3750 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3755 * mono_assembly_foreach:
3756 * \param func function to invoke for each assembly loaded
3757 * \param user_data data passed to the callback
3759 * Invokes the provided \p func callback for each assembly loaded into
3760 * the runtime. The first parameter passed to the callback is the
3761 * \c MonoAssembly*, and the second parameter is the \p user_data.
3763 * This is done for all assemblies loaded in the runtime, not just
3764 * those loaded in the current application domain.
3767 mono_assembly_foreach (GFunc func, gpointer user_data)
3772 * We make a copy of the list to avoid calling the callback inside the
3773 * lock, which could lead to deadlocks.
3775 mono_assemblies_lock ();
3776 copy = g_list_copy (loaded_assemblies);
3777 mono_assemblies_unlock ();
3779 g_list_foreach (loaded_assemblies, func, user_data);
3785 * mono_assemblies_cleanup:
3787 * Free all resources used by this module.
3790 mono_assemblies_cleanup (void)
3794 mono_os_mutex_destroy (&assemblies_mutex);
3795 mono_os_mutex_destroy (&assembly_binding_mutex);
3797 for (l = loaded_assembly_bindings; l; l = l->next) {
3798 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3800 mono_assembly_binding_info_free (info);
3803 g_slist_free (loaded_assembly_bindings);
3805 free_assembly_load_hooks ();
3806 free_assembly_search_hooks ();
3807 free_assembly_preload_hooks ();
3810 /*LOCKING takes the assembly_binding lock*/
3812 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3816 mono_assembly_binding_lock ();
3817 iter = &loaded_assembly_bindings;
3820 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3822 if (info->domain_id == domain_id) {
3824 mono_assembly_binding_info_free (info);
3831 mono_assembly_binding_unlock ();
3835 * Holds the assembly of the application, for
3836 * System.Diagnostics.Process::MainModule
3838 static MonoAssembly *main_assembly=NULL;
3841 * mono_assembly_set_main:
3844 mono_assembly_set_main (MonoAssembly *assembly)
3846 main_assembly = assembly;
3850 * mono_assembly_get_main:
3852 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3855 mono_assembly_get_main (void)
3857 return (main_assembly);
3861 * mono_assembly_get_image:
3862 * \param assembly The assembly to retrieve the image from
3864 * \returns the \c MonoImage associated with this assembly.
3867 mono_assembly_get_image (MonoAssembly *assembly)
3869 return assembly->image;
3873 * mono_assembly_get_name:
3874 * \param assembly The assembly to retrieve the name from
3876 * The returned name's lifetime is the same as \p assembly's.
3878 * \returns the \c MonoAssemblyName associated with this assembly.
3881 mono_assembly_get_name (MonoAssembly *assembly)
3883 return &assembly->aname;
3887 * mono_register_bundled_assemblies:
3890 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3892 bundles = assemblies;
3895 #define MONO_DECLSEC_FORMAT_10 0x3C
3896 #define MONO_DECLSEC_FORMAT_20 0x2E
3897 #define MONO_DECLSEC_FIELD 0x53
3898 #define MONO_DECLSEC_PROPERTY 0x54
3900 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3901 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3902 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3903 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3904 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3907 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3911 case MONO_DECLSEC_PROPERTY:
3913 case MONO_DECLSEC_FIELD:
3915 *abort_decoding = TRUE;
3920 if (*p++ != MONO_TYPE_BOOLEAN) {
3921 *abort_decoding = TRUE;
3925 /* property name length */
3926 len = mono_metadata_decode_value (p, &p);
3928 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3939 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3941 int i, j, num, len, params_len;
3943 if (*p == MONO_DECLSEC_FORMAT_10) {
3944 gsize read, written;
3945 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3947 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3953 if (*p++ != MONO_DECLSEC_FORMAT_20)
3956 /* number of encoded permission attributes */
3957 num = mono_metadata_decode_value (p, &p);
3958 for (i = 0; i < num; ++i) {
3959 gboolean is_valid = FALSE;
3960 gboolean abort_decoding = FALSE;
3962 /* attribute name length */
3963 len = mono_metadata_decode_value (p, &p);
3965 /* We don't really need to fully decode the type. Comparing the name is enough */
3966 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3970 /*size of the params table*/
3971 params_len = mono_metadata_decode_value (p, &p);
3973 const char *params_end = p + params_len;
3975 /* number of parameters */
3976 len = mono_metadata_decode_value (p, &p);
3978 for (j = 0; j < len; ++j) {
3979 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3995 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3998 guint32 cols [MONO_DECL_SECURITY_SIZE];
4002 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4003 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4005 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4007 for (i = 0; i < t->rows; ++i) {
4008 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4009 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4011 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4014 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4015 len = mono_metadata_decode_blob_size (blob, &blob);
4019 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4020 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4025 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);