2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include "assembly-internals.h"
21 #include "image-internals.h"
22 #include "object-internals.h"
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/custom-attrs-internals.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/class-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include <mono/metadata/reflection-internals.h>
31 #include <mono/metadata/mono-endian.h>
32 #include <mono/metadata/mono-debug.h>
33 #include <mono/utils/mono-uri.h>
34 #include <mono/metadata/mono-config.h>
35 #include <mono/metadata/mono-config-dirs.h>
36 #include <mono/utils/mono-digest.h>
37 #include <mono/utils/mono-logger-internals.h>
38 #include <mono/utils/mono-path.h>
39 #include <mono/metadata/reflection.h>
40 #include <mono/metadata/coree.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/utils/mono-io-portability.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-os-mutex.h>
47 #include <sys/types.h>
52 #ifdef PLATFORM_MACOSX
53 #include <mach-o/dyld.h>
56 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
58 const char* assembly_name;
59 guint8 version_set_index;
60 const char* new_assembly_name;
61 gboolean only_lower_versions;
64 /* the default search path is empty, the first slot is replaced with the computed value */
72 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
73 static char **assemblies_path = NULL;
75 /* Contains the list of directories that point to auxiliary GACs */
76 static char **extra_gac_paths = NULL;
78 #ifndef DISABLE_ASSEMBLY_REMAPPING
80 static GHashTable* assembly_remapping_table;
81 /* The list of system assemblies what will be remapped to the running
83 * This list is stored in @assembly_remapping_table during initialization.
84 * Keep it sorted just to make maintenance easier.
86 * The integer number is an index in the MonoRuntimeInfo structure, whose
87 * values can be found in domain.c - supported_runtimes. Look there
88 * to understand what remapping will be made.
90 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
93 static const AssemblyVersionMap framework_assemblies [] = {
95 {"Commons.Xml.Relaxng", 0},
102 {"Microsoft.Build.Engine", 2, NULL, TRUE},
103 {"Microsoft.Build.Framework", 2, NULL, TRUE},
104 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
105 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
106 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
107 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
108 {"Microsoft.VisualBasic", 1},
109 {"Microsoft.VisualC", 1},
111 {"Mono.CompilerServices.SymbolWriter", 0},
113 {"Mono.Data.SybaseClient", 0},
114 {"Mono.Data.Tds", 0},
115 {"Mono.Data.TdsClient", 0},
116 {"Mono.GetOptions", 0},
119 {"Mono.Security", 0},
120 {"Mono.Security.Win32", 0},
122 {"Novell.Directory.Ldap", 0},
125 {"System.ComponentModel.Composition", 2},
126 {"System.ComponentModel.DataAnnotations", 2},
127 {"System.Configuration", 0},
128 {"System.Configuration.Install", 0},
131 {"System.Data.Linq", 2},
132 {"System.Data.OracleClient", 0},
133 {"System.Data.Services", 2},
134 {"System.Data.Services.Client", 2},
135 {"System.Data.SqlXml", 0},
136 {"System.Design", 0},
137 {"System.DirectoryServices", 0},
138 {"System.Drawing", 0},
139 {"System.Drawing.Design", 0},
140 {"System.EnterpriseServices", 0},
141 {"System.IO.Compression", 2},
142 {"System.IdentityModel", 3},
143 {"System.IdentityModel.Selectors", 3},
144 {"System.Management", 0},
145 {"System.Messaging", 0},
147 {"System.Net.Http", 4},
148 {"System.Numerics.Vectors", 3},
149 {"System.Runtime.InteropServices.RuntimeInformation", 2},
150 {"System.Runtime.Remoting", 0},
151 {"System.Runtime.Serialization", 3},
152 {"System.Runtime.Serialization.Formatters", 3},
153 {"System.Runtime.Serialization.Formatters.Soap", 0},
154 {"System.Security", 0},
155 {"System.ServiceModel", 3},
156 {"System.ServiceModel.Duplex", 3},
157 {"System.ServiceModel.Http", 3},
158 {"System.ServiceModel.NetTcp", 3},
159 {"System.ServiceModel.Primitives", 3},
160 {"System.ServiceModel.Security", 3},
161 {"System.ServiceModel.Web", 2},
162 {"System.ServiceProcess", 0},
163 {"System.Text.Encoding.CodePages", 3},
164 {"System.Transactions", 0},
166 {"System.Web.Abstractions", 2},
167 {"System.Web.DynamicData", 2},
168 {"System.Web.Extensions", 2},
169 {"System.Web.Mobile", 0},
170 {"System.Web.Routing", 2},
171 {"System.Web.Services", 0},
172 {"System.Windows.Forms", 0},
174 {"System.Xml.Linq", 2},
175 {"System.Xml.ReaderWriter", 3},
176 {"System.Xml.XPath.XmlDocument", 3},
183 * keeps track of loaded assemblies
185 static GList *loaded_assemblies = NULL;
186 static MonoAssembly *corlib;
188 #if defined(__native_client__)
190 /* On Native Client, allow mscorlib to be loaded from memory */
191 /* instead of loaded off disk. If these are not set, default */
192 /* mscorlib loading will take place */
194 /* NOTE: If mscorlib data is passed to mono in this way then */
195 /* it needs to remain allocated during the use of mono. */
197 static void *corlibData = NULL;
198 static size_t corlibSize = 0;
201 mono_set_corlib_data (void *data, size_t size)
209 static char* unquote (const char *str);
211 /* This protects loaded_assemblies and image->references */
212 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
213 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
214 static mono_mutex_t assemblies_mutex;
216 /* If defined, points to the bundled assembly information */
217 const MonoBundledAssembly **bundles;
219 static mono_mutex_t assembly_binding_mutex;
221 /* Loaded assembly binding info */
222 static GSList *loaded_assembly_bindings = NULL;
224 /* Class lazy loading functions */
225 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
227 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
229 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
231 mono_assembly_is_in_gac (const gchar *filanem);
234 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
237 encode_public_tok (const guchar *token, gint32 len)
239 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
243 res = (gchar *)g_malloc (len * 2 + 1);
244 for (i = 0; i < len; i++) {
245 res [i * 2] = allowed [token [i] >> 4];
246 res [i * 2 + 1] = allowed [token [i] & 0xF];
253 * mono_public_tokens_are_equal:
254 * @pubt1: first public key token
255 * @pubt2: second public key token
257 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
261 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
263 return memcmp (pubt1, pubt2, 16) == 0;
267 * mono_set_assemblies_path:
268 * @path: list of paths that contain directories where Mono will look for assemblies
270 * Use this method to override the standard assembly lookup system and
271 * override any assemblies coming from the GAC. This is the method
272 * that supports the MONO_PATH variable.
274 * Notice that MONO_PATH and this method are really a very bad idea as
275 * it prevents the GAC from working and it prevents the standard
276 * resolution mechanisms from working. Nonetheless, for some debugging
277 * situations and bootstrapping setups, this is useful to have.
280 mono_set_assemblies_path (const char* path)
282 char **splitted, **dest;
284 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
286 g_strfreev (assemblies_path);
287 assemblies_path = dest = splitted;
289 char *tmp = *splitted;
291 *dest++ = mono_path_canonicalize (tmp);
297 if (g_getenv ("MONO_DEBUG") == NULL)
300 splitted = assemblies_path;
302 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
303 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
309 /* Native Client can't get this info from an environment variable so */
310 /* it's passed in to the runtime, or set manually by embedding code. */
311 #ifdef __native_client__
312 char* nacl_mono_path = NULL;
316 check_path_env (void)
319 path = g_getenv ("MONO_PATH");
320 #ifdef __native_client__
322 path = nacl_mono_path;
324 if (!path || assemblies_path != NULL)
327 mono_set_assemblies_path(path);
331 check_extra_gac_path_env (void) {
333 char **splitted, **dest;
335 path = g_getenv ("MONO_GAC_PREFIX");
339 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
341 g_strfreev (extra_gac_paths);
342 extra_gac_paths = dest = splitted;
350 if (g_getenv ("MONO_DEBUG") == NULL)
354 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
355 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
362 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
364 if (!info || !info->name)
367 if (strcmp (info->name, aname->name))
370 if (info->major != aname->major || info->minor != aname->minor)
373 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
376 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
379 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
386 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
392 g_free (info->culture);
396 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
399 guint32 cols [MONO_MANIFEST_SIZE];
400 const gchar *filename;
401 gchar *subpath, *fullpath;
403 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
404 /* MS Impl. accepts policy assemblies with more than
405 * one manifest resource, and only takes the first one */
407 binding_info->is_valid = FALSE;
411 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
412 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
413 binding_info->is_valid = FALSE;
417 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
418 g_assert (filename != NULL);
420 subpath = g_path_get_dirname (image->name);
421 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
422 mono_config_parse_publisher_policy (fullpath, binding_info);
426 /* Define the optional elements/attributes before checking */
427 if (!binding_info->culture)
428 binding_info->culture = g_strdup ("");
430 /* Check that the most important elements/attributes exist */
431 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
432 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
433 mono_assembly_binding_info_free (binding_info);
434 binding_info->is_valid = FALSE;
438 binding_info->is_valid = TRUE;
442 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
444 if (v->major > aname->major)
446 else if (v->major < aname->major)
449 if (v->minor > aname->minor)
451 else if (v->minor < aname->minor)
454 if (v->build > aname->build)
456 else if (v->build < aname->build)
459 if (v->revision > aname->revision)
461 else if (v->revision < aname->revision)
468 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
473 /* If has_old_version_top doesn't exist, we don't have an interval */
474 if (!info->has_old_version_top) {
475 if (compare_versions (&info->old_version_bottom, name) == 0)
481 /* Check that the version defined by name is valid for the interval */
482 if (compare_versions (&info->old_version_top, name) < 0)
485 /* We should be greater or equal than the small version */
486 if (compare_versions (&info->old_version_bottom, name) > 0)
493 * mono_assembly_names_equal:
495 * @r: second assembly.
497 * Compares two MonoAssemblyNames and returns whether they are equal.
499 * This compares the names, the cultures, the release version and their
502 * Returns: TRUE if both assembly names are equal.
505 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
507 if (!l->name || !r->name)
510 if (strcmp (l->name, r->name))
513 if (l->culture && r->culture && strcmp (l->culture, r->culture))
516 if (l->major != r->major || l->minor != r->minor ||
517 l->build != r->build || l->revision != r->revision)
518 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)))
521 if (!l->public_key_token [0] || !r->public_key_token [0])
524 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
530 static MonoAssembly *
531 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
535 MonoAssembly *result;
537 for (i = 0; search_path [i]; ++i) {
538 fullpath = g_build_filename (search_path [i], basename, NULL);
539 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
548 * mono_assembly_setrootdir:
549 * @root_dir: The pathname of the root directory where we will locate assemblies
551 * This routine sets the internal default root directory for looking up
554 * This is used by Windows installations to compute dynamically the
555 * place where the Mono assemblies are located.
559 mono_assembly_setrootdir (const char *root_dir)
562 * Override the MONO_ASSEMBLIES directory configured at compile time.
564 /* Leak if called more than once */
565 default_path [0] = g_strdup (root_dir);
569 * mono_assembly_getrootdir:
571 * Obtains the root directory used for looking up assemblies.
573 * Returns: a string with the directory, this string should not be freed.
575 G_CONST_RETURN gchar *
576 mono_assembly_getrootdir (void)
578 return default_path [0];
582 * mono_native_getrootdir:
584 * Obtains the root directory used for looking up native libs (.so, .dylib).
586 * Returns: a string with the directory, this string should be freed by
590 mono_native_getrootdir (void)
592 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
598 * @assembly_dir: the base directory for assemblies
599 * @config_dir: the base directory for configuration files
601 * This routine is used internally and by developers embedding
602 * the runtime into their own applications.
604 * There are a number of cases to consider: Mono as a system-installed
605 * package that is available on the location preconfigured or Mono in
606 * a relocated location.
608 * If you are using a system-installed Mono, you can pass NULL
609 * to both parameters. If you are not, you should compute both
610 * directory values and call this routine.
612 * The values for a given PREFIX are:
614 * assembly_dir: PREFIX/lib
615 * config_dir: PREFIX/etc
617 * Notice that embedders that use Mono in a relocated way must
618 * compute the location at runtime, as they will be in control
619 * of where Mono is installed.
622 mono_set_dirs (const char *assembly_dir, const char *config_dir)
624 if (assembly_dir == NULL)
625 assembly_dir = mono_config_get_assemblies_dir ();
626 if (config_dir == NULL)
627 config_dir = mono_config_get_cfg_dir ();
628 mono_assembly_setrootdir (assembly_dir);
629 mono_set_config_dir (config_dir);
635 compute_base (char *path)
637 char *p = strrchr (path, '/');
641 /* Not a well known Mono executable, we are embedded, cant guess the base */
642 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
646 p = strrchr (path, '/');
650 if (strcmp (p, "/bin") != 0)
659 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
662 static G_GNUC_UNUSED void
666 char *config, *lib, *mono;
671 * Only /usr prefix is treated specially
673 bindir = mono_config_get_bin_dir ();
675 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
680 config = g_build_filename (base, "etc", NULL);
681 lib = g_build_filename (base, "lib", NULL);
682 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
683 if (stat (mono, &buf) == -1)
686 mono_set_dirs (lib, config);
694 #endif /* HOST_WIN32 */
699 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
700 * this auto-detects the prefix where Mono was installed.
703 mono_set_rootdir (void)
705 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
706 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
709 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
713 * _NSGetExecutablePath may return -1 to indicate buf is not large
714 * enough, but we ignore that case to avoid having to do extra dynamic
715 * allocation for the path and hope that 4096 is enough - this is
716 * ok in the Linux/Solaris case below at least...
720 guint buf_size = sizeof (buf);
723 if (_NSGetExecutablePath (buf, &buf_size) == 0)
724 name = g_strdup (buf);
733 resolvedname = mono_path_resolve_symlinks (name);
735 bindir = g_path_get_dirname (resolvedname);
736 installdir = g_path_get_dirname (bindir);
737 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
739 config = g_build_filename (root, "..", "etc", NULL);
741 mono_set_dirs (root, config);
743 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
744 mono_set_dirs (root, config);
754 g_free (resolvedname);
755 #elif defined(DISABLE_MONO_AUTODETECTION)
763 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
771 /* Solaris 10 style */
772 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
773 s = readlink (str, buf, sizeof (buf)-1);
785 * mono_assemblies_init:
787 * Initialize global variables used by this module.
790 mono_assemblies_init (void)
793 * Initialize our internal paths if we have not been initialized yet.
794 * This happens when embedders use Mono.
796 if (mono_assembly_getrootdir () == NULL)
800 check_extra_gac_path_env ();
802 mono_os_mutex_init_recursive (&assemblies_mutex);
803 mono_os_mutex_init (&assembly_binding_mutex);
805 #ifndef DISABLE_ASSEMBLY_REMAPPING
806 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
809 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
810 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
816 mono_assembly_binding_lock (void)
818 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
822 mono_assembly_binding_unlock (void)
824 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
828 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
830 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
831 guint32 cols [MONO_ASSEMBLY_SIZE];
832 gint32 machine, flags;
837 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
840 aname->hash_value = NULL;
841 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
843 aname->name = g_strdup (aname->name);
844 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
846 aname->culture = g_strdup (aname->culture);
847 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
848 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
849 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
850 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
851 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
852 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
853 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
854 guchar* token = (guchar *)g_malloc (8);
859 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
860 len = mono_metadata_decode_blob_size (pkey, &pkey);
861 aname->public_key = (guchar*)pkey;
863 mono_digest_get_public_token (token, aname->public_key, len);
864 encoded = encode_public_tok (token, 8);
865 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
871 aname->public_key = NULL;
872 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
875 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
876 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
878 const gchar *pkey_end;
879 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
880 pkey_end += len; /* move to end */
881 size_t size = pkey_end - (const gchar*)aname->public_key;
882 guchar *tmp = g_new (guchar, size);
883 memcpy (tmp, aname->public_key, size);
884 aname->public_key = tmp;
889 aname->public_key = 0;
891 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
892 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
894 case COFF_MACHINE_I386:
895 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
896 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
897 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
898 else if ((flags & 0x70) == 0x70)
899 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
901 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
903 case COFF_MACHINE_IA64:
904 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
906 case COFF_MACHINE_AMD64:
907 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
909 case COFF_MACHINE_ARM:
910 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
920 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
922 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
926 * mono_stringify_assembly_name:
927 * @aname: the assembly name.
929 * Convert @aname into its string format. The returned string is dynamically
930 * allocated and should be freed by the caller.
932 * Returns: a newly allocated string with a string representation of
936 mono_stringify_assembly_name (MonoAssemblyName *aname)
938 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
940 return g_strdup_printf (
941 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
942 quote, aname->name, quote,
943 aname->major, aname->minor, aname->build, aname->revision,
944 aname->culture && *aname->culture? aname->culture: "neutral",
945 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
946 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
950 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
952 const gchar *public_tok;
955 public_tok = mono_metadata_blob_heap (image, key_index);
956 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
958 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
960 mono_digest_get_public_token (token, (guchar*)public_tok, len);
961 return encode_public_tok (token, 8);
964 return encode_public_tok ((guchar*)public_tok, len);
968 * mono_assembly_addref:
969 * @assemnly: the assembly to reference
971 * This routine increments the reference count on a MonoAssembly.
972 * The reference count is reduced every time the method mono_assembly_close() is
976 mono_assembly_addref (MonoAssembly *assembly)
978 InterlockedIncrement (&assembly->ref_count);
982 * CAUTION: This table must be kept in sync with
983 * ivkm/reflect/Fusion.cs
986 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
987 #define WINFX_KEY "31bf3856ad364e35"
988 #define ECMA_KEY "b77a5c561934e089"
989 #define MSFINAL_KEY "b03f5f7f11d50a3a"
990 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
998 static KeyRemapEntry key_remap_table[] = {
999 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1000 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1001 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1002 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1003 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1004 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1005 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1006 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1007 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1008 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1009 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1010 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1011 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1012 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1013 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1014 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1015 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1016 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1017 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1018 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1019 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1020 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1021 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1022 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1023 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1024 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1025 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1026 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1027 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1031 remap_keys (MonoAssemblyName *aname)
1034 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1035 const KeyRemapEntry *entry = &key_remap_table [i];
1037 if (strcmp (aname->name, entry->name) ||
1038 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1041 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1043 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1044 "Remapped public key token of retargetable assembly %s from %s to %s",
1045 aname->name, entry->from, entry->to);
1050 static MonoAssemblyName *
1051 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1053 const MonoRuntimeInfo *current_runtime;
1055 if (aname->name == NULL) return aname;
1057 current_runtime = mono_get_runtime_info ();
1059 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1060 const AssemblyVersionSet* vset;
1062 /* Remap to current runtime */
1063 vset = ¤t_runtime->version_sets [0];
1065 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1066 dest_aname->major = vset->major;
1067 dest_aname->minor = vset->minor;
1068 dest_aname->build = vset->build;
1069 dest_aname->revision = vset->revision;
1070 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1072 /* Remap assembly name */
1073 if (!strcmp (aname->name, "System.Net"))
1074 dest_aname->name = g_strdup ("System");
1076 remap_keys (dest_aname);
1078 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1079 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1081 aname->major, aname->minor, aname->build, aname->revision,
1083 vset->major, vset->minor, vset->build, vset->revision
1089 #ifndef DISABLE_ASSEMBLY_REMAPPING
1090 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1092 const AssemblyVersionSet* vset;
1093 int index = vmap->version_set_index;
1094 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1095 vset = ¤t_runtime->version_sets [index];
1097 if (aname->major == vset->major && aname->minor == vset->minor &&
1098 aname->build == vset->build && aname->revision == vset->revision) {
1099 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1101 aname->major, aname->minor, aname->build, aname->revision);
1105 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1106 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1107 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1109 aname->major, aname->minor, aname->build, aname->revision,
1110 vset->major, vset->minor, vset->build, vset->revision
1115 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1116 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1117 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1119 aname->major, aname->minor, aname->build, aname->revision,
1120 vset->major, vset->minor, vset->build, vset->revision
1123 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1124 dest_aname->major = vset->major;
1125 dest_aname->minor = vset->minor;
1126 dest_aname->build = vset->build;
1127 dest_aname->revision = vset->revision;
1128 if (current_runtime->public_key_token != NULL &&
1129 dest_aname->public_key_token [0] != 0 &&
1130 !mono_public_tokens_are_equal (dest_aname->public_key_token, (const mono_byte *)current_runtime->public_key_token)) {
1131 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1132 "The request for assembly name '%s' with PublicKeyToken=%s was remapped to PublicKeyToken=%s",
1134 dest_aname->public_key_token,
1135 current_runtime->public_key_token);
1136 memcpy (dest_aname->public_key_token, current_runtime->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1138 if (vmap->new_assembly_name != NULL) {
1139 dest_aname->name = vmap->new_assembly_name;
1140 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1141 "The assembly name %s was remapped to %s",
1153 * mono_assembly_get_assemblyref:
1154 * @image: pointer to the MonoImage to extract the information from.
1155 * @index: index to the assembly reference in the image.
1156 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1158 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1161 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1164 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1167 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1169 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1171 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1172 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1173 aname->hash_value = hash;
1174 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1175 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1176 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1177 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1178 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1179 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1180 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1182 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1183 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1184 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1187 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1192 mono_assembly_load_reference (MonoImage *image, int index)
1194 MonoAssembly *reference;
1195 MonoAssemblyName aname;
1196 MonoImageOpenStatus status;
1199 * image->references is shared between threads, so we need to access
1200 * it inside a critical section.
1202 mono_assemblies_lock ();
1203 if (!image->references) {
1204 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1206 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1207 image->nreferences = t->rows;
1209 reference = image->references [index];
1210 mono_assemblies_unlock ();
1214 mono_assembly_get_assemblyref (image, index, &aname);
1216 if (image->assembly && image->assembly->ref_only) {
1217 /* We use the loaded corlib */
1218 if (!strcmp (aname.name, "mscorlib"))
1219 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1221 reference = mono_assembly_loaded_full (&aname, TRUE);
1223 /* Try a postload search hook */
1224 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1228 * Here we must advice that the error was due to
1229 * a non loaded reference using the ReflectionOnly api
1232 reference = (MonoAssembly *)REFERENCE_MISSING;
1234 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1235 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1236 * accordingly, it would fail on the MS runtime before).
1237 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1238 * example bug-349190.2.cs and who knows how much more code in the wild.
1240 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1241 if (!reference && image->assembly)
1242 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1245 if (reference == NULL){
1248 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1249 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 : "" );
1250 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1251 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1252 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1253 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1254 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1255 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1257 extra_msg = g_strdup ("");
1260 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1261 " Assembly: %s (assemblyref_index=%d)\n"
1262 " Version: %d.%d.%d.%d\n"
1263 " Public Key: %s\n%s",
1264 image->name, aname.name, index,
1265 aname.major, aname.minor, aname.build, aname.revision,
1266 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1271 mono_assemblies_lock ();
1272 if (reference == NULL) {
1273 /* Flag as not found */
1274 reference = (MonoAssembly *)REFERENCE_MISSING;
1277 if (!image->references [index]) {
1278 if (reference != REFERENCE_MISSING){
1279 mono_assembly_addref (reference);
1280 if (image->assembly)
1281 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1282 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1284 if (image->assembly)
1285 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1286 image->assembly->aname.name, image->assembly);
1289 image->references [index] = reference;
1291 mono_assemblies_unlock ();
1293 if (image->references [index] != reference) {
1294 /* Somebody loaded it before us */
1295 mono_assembly_close (reference);
1300 * mono_assembly_load_references:
1303 * @deprecated: There is no reason to use this method anymore, it does nothing
1305 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1308 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1310 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1311 *status = MONO_IMAGE_OK;
1314 typedef struct AssemblyLoadHook AssemblyLoadHook;
1315 struct AssemblyLoadHook {
1316 AssemblyLoadHook *next;
1317 MonoAssemblyLoadFunc func;
1321 AssemblyLoadHook *assembly_load_hook = NULL;
1324 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1326 AssemblyLoadHook *hook;
1328 for (hook = assembly_load_hook; hook; hook = hook->next) {
1329 hook->func (ass, hook->user_data);
1334 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1336 AssemblyLoadHook *hook;
1338 g_return_if_fail (func != NULL);
1340 hook = g_new0 (AssemblyLoadHook, 1);
1342 hook->user_data = user_data;
1343 hook->next = assembly_load_hook;
1344 assembly_load_hook = hook;
1348 free_assembly_load_hooks (void)
1350 AssemblyLoadHook *hook, *next;
1352 for (hook = assembly_load_hook; hook; hook = next) {
1358 typedef struct AssemblySearchHook AssemblySearchHook;
1359 struct AssemblySearchHook {
1360 AssemblySearchHook *next;
1361 MonoAssemblySearchFunc func;
1367 AssemblySearchHook *assembly_search_hook = NULL;
1369 static MonoAssembly*
1370 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1372 AssemblySearchHook *hook;
1374 for (hook = assembly_search_hook; hook; hook = hook->next) {
1375 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1378 * A little explanation is in order here.
1380 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1381 * The embedding API exposes a search hook that doesn't take such argument.
1383 * The original fix would call the default search hook before all the registered ones and pass
1384 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1385 * rely on. Which is the ordering between user hooks and the default runtime hook.
1387 * Registering the hook after mono_jit_init would let your hook run before the default one and
1388 * when using it to handle non standard app layouts this could save your app from a massive amount
1389 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1390 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1392 * So what's the fix? We register the default hook using regular means and special case it when iterating
1393 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1396 if (hook->func == (void*)mono_domain_assembly_postload_search)
1397 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1399 ass = hook->func (aname, hook->user_data);
1409 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1411 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1415 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1417 AssemblySearchHook *hook;
1419 g_return_if_fail (func != NULL);
1421 hook = g_new0 (AssemblySearchHook, 1);
1423 hook->user_data = user_data;
1424 hook->refonly = refonly;
1425 hook->postload = postload;
1426 hook->next = assembly_search_hook;
1427 assembly_search_hook = hook;
1431 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1433 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1437 free_assembly_search_hooks (void)
1439 AssemblySearchHook *hook, *next;
1441 for (hook = assembly_search_hook; hook; hook = next) {
1448 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1450 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1454 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1456 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1460 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1462 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1465 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1466 struct AssemblyPreLoadHook {
1467 AssemblyPreLoadHook *next;
1468 MonoAssemblyPreLoadFunc func;
1472 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1473 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1475 static MonoAssembly *
1476 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1478 AssemblyPreLoadHook *hook;
1479 MonoAssembly *assembly;
1481 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1482 assembly = hook->func (aname, assemblies_path, hook->user_data);
1483 if (assembly != NULL)
1490 static MonoAssembly *
1491 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1493 AssemblyPreLoadHook *hook;
1494 MonoAssembly *assembly;
1496 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1497 assembly = hook->func (aname, assemblies_path, hook->user_data);
1498 if (assembly != NULL)
1506 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1508 AssemblyPreLoadHook *hook;
1510 g_return_if_fail (func != NULL);
1512 hook = g_new0 (AssemblyPreLoadHook, 1);
1514 hook->user_data = user_data;
1515 hook->next = assembly_preload_hook;
1516 assembly_preload_hook = hook;
1520 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1522 AssemblyPreLoadHook *hook;
1524 g_return_if_fail (func != NULL);
1526 hook = g_new0 (AssemblyPreLoadHook, 1);
1528 hook->user_data = user_data;
1529 hook->next = assembly_refonly_preload_hook;
1530 assembly_refonly_preload_hook = hook;
1534 free_assembly_preload_hooks (void)
1536 AssemblyPreLoadHook *hook, *next;
1538 for (hook = assembly_preload_hook; hook; hook = next) {
1543 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1550 absolute_dir (const gchar *filename)
1561 if (g_path_is_absolute (filename)) {
1562 part = g_path_get_dirname (filename);
1563 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1568 cwd = g_get_current_dir ();
1569 mixed = g_build_filename (cwd, filename, NULL);
1570 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1575 for (i = 0; (part = parts [i]) != NULL; i++) {
1576 if (!strcmp (part, "."))
1579 if (!strcmp (part, "..")) {
1580 if (list && list->next) /* Don't remove root */
1581 list = g_list_delete_link (list, list);
1583 list = g_list_prepend (list, part);
1587 result = g_string_new ("");
1588 list = g_list_reverse (list);
1590 /* Ignores last data pointer, which should be the filename */
1591 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1593 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1598 g_string_free (result, FALSE);
1603 return g_strdup (".");
1610 * mono_assembly_open_from_bundle:
1611 * @filename: Filename requested
1612 * @status: return status code
1614 * This routine tries to open the assembly specified by `filename' from the
1615 * defined bundles, if found, returns the MonoImage for it, if not found
1619 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1623 gchar *lowercase_filename;
1624 MonoImage *image = NULL;
1625 gboolean is_satellite = FALSE;
1627 * we do a very simple search for bundled assemblies: it's not a general
1628 * purpose assembly loading mechanism.
1634 lowercase_filename = g_utf8_strdown (filename, -1);
1635 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1636 g_free (lowercase_filename);
1637 name = g_path_get_basename (filename);
1638 mono_assemblies_lock ();
1639 for (i = 0; !image && bundles [i]; ++i) {
1640 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1641 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1645 mono_assemblies_unlock ();
1647 mono_image_addref (image);
1648 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1657 * mono_assemblies_open_full:
1658 * @filename: the file to load
1659 * @status: return status code
1660 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1662 * This loads an assembly from the specified @filename. The @filename allows
1663 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1664 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1665 * is treated as a local path.
1667 * First, an attempt is made to load the assembly from the bundled executable (for those
1668 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1669 * assembly has been registered as an embedded assembly). If this is not the case, then
1670 * the assembly is loaded from disk using `api:mono_image_open_full`.
1672 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1673 * the assembly is made.
1675 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1676 * the `System.Reflection` API.
1678 * Returns: NULL on error, with the @status set to an error code, or a pointer
1682 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1684 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1688 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1690 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1694 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1695 gboolean load_from_context,
1696 MonoAssemblyCandidatePredicate predicate,
1698 MonoImageOpenStatus *status)
1702 MonoImageOpenStatus def_status;
1705 gboolean loaded_from_bundle;
1707 g_return_val_if_fail (filename != NULL, NULL);
1710 status = &def_status;
1711 *status = MONO_IMAGE_OK;
1713 if (strncmp (filename, "file://", 7) == 0) {
1714 GError *error = NULL;
1715 gchar *uri = (gchar *) filename;
1719 * MS allows file://c:/... and fails on file://localhost/c:/...
1720 * They also throw an IndexOutOfRangeException if "file://"
1723 uri = g_strdup_printf ("file:///%s", uri + 7);
1726 uri = mono_escape_uri_string (tmpuri);
1727 fname = g_filename_from_uri (uri, NULL, &error);
1730 if (tmpuri != filename)
1733 if (error != NULL) {
1734 g_warning ("%s\n", error->message);
1735 g_error_free (error);
1736 fname = g_strdup (filename);
1739 fname = g_strdup (filename);
1742 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1743 "Assembly Loader probing location: '%s'.", fname);
1746 if (!mono_assembly_is_in_gac (fname)) {
1748 new_fname = mono_make_shadow_copy (fname, &error);
1749 if (!is_ok (&error)) {
1750 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1751 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1752 mono_error_cleanup (&error);
1753 *status = MONO_IMAGE_IMAGE_INVALID;
1758 if (new_fname && new_fname != fname) {
1761 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1762 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1767 // If VM built with mkbundle
1768 loaded_from_bundle = FALSE;
1769 if (bundles != NULL) {
1770 image = mono_assembly_open_from_bundle (fname, status, refonly);
1771 loaded_from_bundle = image != NULL;
1775 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1778 if (*status == MONO_IMAGE_OK)
1779 *status = MONO_IMAGE_ERROR_ERRNO;
1784 if (image->assembly) {
1785 /* Already loaded by another appdomain */
1786 mono_assembly_invoke_load_hook (image->assembly);
1787 mono_image_close (image);
1789 return image->assembly;
1792 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1795 if (!loaded_from_bundle)
1796 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1797 "Assembly Loader loaded assembly from location: '%s'.", filename);
1799 mono_config_for_assembly (ass->image);
1802 /* Clear the reference added by mono_image_open */
1803 mono_image_close (image);
1811 free_item (gpointer val, gpointer user_data)
1817 * mono_assembly_load_friends:
1820 * Load the list of friend assemblies that are allowed to access
1821 * the assembly's internal types and members. They are stored as assembly
1822 * names in custom attributes.
1824 * This is an internal method, we need this because when we load mscorlib
1825 * we do not have the internals visible cattr loaded yet,
1826 * so we need to load these after we initialize the runtime.
1828 * LOCKING: Acquires the assemblies lock plus the loader lock.
1831 mono_assembly_load_friends (MonoAssembly* ass)
1835 MonoCustomAttrInfo* attrs;
1838 if (ass->friend_assembly_names_inited)
1841 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1842 mono_error_assert_ok (&error);
1844 mono_assemblies_lock ();
1845 ass->friend_assembly_names_inited = TRUE;
1846 mono_assemblies_unlock ();
1850 mono_assemblies_lock ();
1851 if (ass->friend_assembly_names_inited) {
1852 mono_assemblies_unlock ();
1855 mono_assemblies_unlock ();
1859 * We build the list outside the assemblies lock, the worse that can happen
1860 * is that we'll need to free the allocated list.
1862 for (i = 0; i < attrs->num_attrs; ++i) {
1863 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1864 MonoAssemblyName *aname;
1866 /* Do some sanity checking */
1867 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1869 if (attr->data_size < 4)
1871 data = (const char*)attr->data;
1872 /* 0xFF means null string, see custom attr format */
1873 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1875 mono_metadata_decode_value (data + 2, &data);
1876 aname = g_new0 (MonoAssemblyName, 1);
1877 /*g_print ("friend ass: %s\n", data);*/
1878 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1879 list = g_slist_prepend (list, aname);
1884 mono_custom_attrs_free (attrs);
1886 mono_assemblies_lock ();
1887 if (ass->friend_assembly_names_inited) {
1888 mono_assemblies_unlock ();
1889 g_slist_foreach (list, free_item, NULL);
1890 g_slist_free (list);
1893 ass->friend_assembly_names = list;
1895 /* Because of the double checked locking pattern above */
1896 mono_memory_barrier ();
1897 ass->friend_assembly_names_inited = TRUE;
1898 mono_assemblies_unlock ();
1901 struct HasReferenceAssemblyAttributeIterData {
1906 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1908 gboolean stop_scanning = FALSE;
1909 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1911 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1912 /* Note we don't check the assembly name, same as coreCLR. */
1913 iter_data->has_attr = TRUE;
1914 stop_scanning = TRUE;
1917 return stop_scanning;
1921 * mono_assembly_has_reference_assembly_attribute:
1922 * @assembly: a MonoAssembly
1923 * @error: set on error.
1925 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1926 * On error returns FALSE and sets @error.
1929 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1934 * This might be called during assembly loading, so do everything using the low-level
1938 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1940 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1942 return iter_data.has_attr;
1946 * mono_assembly_open:
1947 * @filename: Opens the assembly pointed out by this name
1948 * @status: return status code
1950 * This loads an assembly from the specified @filename. The @filename allows
1951 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1952 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1953 * is treated as a local path.
1955 * First, an attempt is made to load the assembly from the bundled executable (for those
1956 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1957 * assembly has been registered as an embedded assembly). If this is not the case, then
1958 * the assembly is loaded from disk using `api:mono_image_open_full`.
1960 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1961 * the assembly is made.
1963 * Return: a pointer to the MonoAssembly if @filename contains a valid
1964 * assembly or NULL on error. Details about the error are stored in the
1968 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1970 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
1974 * mono_assembly_load_from_full:
1975 * @image: Image to load the assembly from
1976 * @fname: assembly name to associate with the assembly
1977 * @status: returns the status condition
1978 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1980 * If the provided @image has an assembly reference, it will process the given
1981 * image as an assembly with the given name.
1983 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1985 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1986 * set to #MONO_IMAGE_OK; or NULL on error.
1988 * If there is an error loading the assembly the @status will indicate the
1989 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1990 * image did not contain an assembly reference table.
1993 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1994 MonoImageOpenStatus *status, gboolean refonly)
1996 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2000 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2002 MonoAssemblyCandidatePredicate predicate,
2004 MonoImageOpenStatus *status)
2006 MonoAssembly *ass, *ass2;
2009 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2010 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2011 *status = MONO_IMAGE_IMAGE_INVALID;
2015 #if defined (HOST_WIN32)
2020 tmp_fn = g_strdup (fname);
2021 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2022 if (tmp_fn [i] == '/')
2026 base_dir = absolute_dir (tmp_fn);
2030 base_dir = absolute_dir (fname);
2034 * Create assembly struct, and enter it into the assembly cache
2036 ass = g_new0 (MonoAssembly, 1);
2037 ass->basedir = base_dir;
2038 ass->ref_only = refonly;
2041 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2043 mono_assembly_fill_assembly_name (image, &ass->aname);
2045 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2046 // MS.NET doesn't support loading other mscorlibs
2049 mono_image_addref (mono_defaults.corlib);
2050 *status = MONO_IMAGE_OK;
2051 return mono_defaults.corlib->assembly;
2054 /* Add a non-temporary reference because of ass->image */
2055 mono_image_addref (image);
2057 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);
2060 * The load hooks might take locks so we can't call them while holding the
2063 if (ass->aname.name) {
2064 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2068 mono_image_close (image);
2069 *status = MONO_IMAGE_OK;
2074 /* We need to check for ReferenceAssmeblyAttribute before we
2075 * mark the assembly as loaded and before we fire the load
2076 * hook. Otherwise mono_domain_fire_assembly_load () in
2077 * appdomain.c will cache a mapping from the assembly name to
2078 * this image and we won't be able to look for a different
2082 MonoError refasm_error;
2083 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2084 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2087 mono_image_close (image);
2088 *status = MONO_IMAGE_IMAGE_INVALID;
2091 mono_error_cleanup (&refasm_error);
2094 if (predicate && !predicate (ass, user_data)) {
2095 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2098 mono_image_close (image);
2099 *status = MONO_IMAGE_IMAGE_INVALID;
2103 mono_assemblies_lock ();
2105 if (image->assembly) {
2107 * This means another thread has already loaded the assembly, but not yet
2108 * called the load hooks so the search hook can't find the assembly.
2110 mono_assemblies_unlock ();
2111 ass2 = image->assembly;
2114 mono_image_close (image);
2115 *status = MONO_IMAGE_OK;
2119 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2121 image->assembly = ass;
2123 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2124 mono_assemblies_unlock ();
2127 if (image->is_module_handle)
2128 mono_image_fixup_vtable (image);
2131 mono_assembly_invoke_load_hook (ass);
2133 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2139 * mono_assembly_load_from:
2140 * @image: Image to load the assembly from
2141 * @fname: assembly name to associate with the assembly
2142 * @status: return status code
2144 * If the provided @image has an assembly reference, it will process the given
2145 * image as an assembly with the given name.
2147 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2149 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2150 * @refonly parameter set to FALSE.
2151 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2152 * set to #MONO_IMAGE_OK; or NULL on error.
2154 * If there is an error loading the assembly the @status will indicate the
2155 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2156 * image did not contain an assembly reference table.
2160 mono_assembly_load_from (MonoImage *image, const char *fname,
2161 MonoImageOpenStatus *status)
2163 return mono_assembly_load_from_full (image, fname, status, FALSE);
2167 * mono_assembly_name_free:
2168 * @aname: assembly name to free
2170 * Frees the provided assembly name object.
2171 * (it does not frees the object itself, only the name members).
2174 mono_assembly_name_free (MonoAssemblyName *aname)
2179 g_free ((void *) aname->name);
2180 g_free ((void *) aname->culture);
2181 g_free ((void *) aname->hash_value);
2182 g_free ((guint8*) aname->public_key);
2186 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2189 gchar header [16], val, *arr;
2190 gint i, j, offset, bitlen, keylen, pkeylen;
2192 keylen = strlen (key) >> 1;
2196 /* allow the ECMA standard key */
2197 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2199 *pubkey = g_strdup (key);
2205 val = g_ascii_xdigit_value (key [0]) << 4;
2206 val |= g_ascii_xdigit_value (key [1]);
2211 val = g_ascii_xdigit_value (key [24]);
2212 val |= g_ascii_xdigit_value (key [25]);
2224 /* We need the first 16 bytes
2225 * to check whether this key is valid or not */
2226 pkeylen = strlen (pkey) >> 1;
2230 for (i = 0, j = 0; i < 16; i++) {
2231 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2232 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2235 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2236 header [1] != 0x02 || /* Version (0x02) */
2237 header [2] != 0x00 || /* Reserved (word) */
2238 header [3] != 0x00 ||
2239 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2242 /* Based on this length, we _should_ be able to know if the length is right */
2243 bitlen = read32 (header + 12) >> 3;
2244 if ((bitlen + 16 + 4) != pkeylen)
2247 /* parsing is OK and the public key itself is not requested back */
2251 /* Encode the size of the blob */
2253 if (keylen <= 127) {
2254 arr = (gchar *)g_malloc (keylen + 1);
2255 arr [offset++] = keylen;
2257 arr = (gchar *)g_malloc (keylen + 2);
2258 arr [offset++] = 0x80; /* 10bs */
2259 arr [offset++] = keylen;
2262 for (i = offset, j = 0; i < keylen + offset; i++) {
2263 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2264 arr [i] |= g_ascii_xdigit_value (key [j++]);
2273 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)
2275 gint major, minor, build, revision;
2278 gchar *pkey, *pkeyptr, *encoded, tok [8];
2280 memset (aname, 0, sizeof (MonoAssemblyName));
2283 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2284 if (version_parts < 2 || version_parts > 4)
2287 /* FIXME: we should set build & revision to -1 (instead of 0)
2288 if these are not set in the version string. That way, later on,
2289 we can still determine if these were specified. */
2290 aname->major = major;
2291 aname->minor = minor;
2292 if (version_parts >= 3)
2293 aname->build = build;
2296 if (version_parts == 4)
2297 aname->revision = revision;
2299 aname->revision = 0;
2302 aname->flags = flags;
2304 aname->name = g_strdup (name);
2307 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2308 aname->culture = g_strdup ("");
2310 aname->culture = g_strdup (culture);
2313 if (token && strncmp (token, "null", 4) != 0) {
2316 /* the constant includes the ending NULL, hence the -1 */
2317 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2318 mono_assembly_name_free (aname);
2321 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2322 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2328 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2329 mono_assembly_name_free (aname);
2334 if (save_public_key)
2335 aname->public_key = (guint8*)pkey;
2338 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2342 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2343 // We also need to generate the key token
2344 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2345 encoded = encode_public_tok ((guchar*) tok, 8);
2346 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2349 if (save_public_key)
2350 aname->public_key = (guint8*) pkey;
2359 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2364 parts = g_strsplit (dirname, "_", 3);
2365 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2370 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2376 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2378 char *eqsign = strchr (pair, '=');
2386 *key = (gchar*)pair;
2387 *keylen = eqsign - *key;
2388 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2390 *value = g_strstrip (eqsign + 1);
2395 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2399 gchar *version = NULL;
2401 gchar *culture = NULL;
2403 gchar *token = NULL;
2407 gchar *retargetable = NULL;
2408 gchar *retargetable_uq;
2412 gchar *value, *part_name;
2413 guint32 part_name_len;
2416 gboolean version_defined;
2417 gboolean token_defined;
2419 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2421 if (!is_version_defined)
2422 is_version_defined = &version_defined;
2423 *is_version_defined = FALSE;
2424 if (!is_token_defined)
2425 is_token_defined = &token_defined;
2426 *is_token_defined = FALSE;
2428 parts = tmp = g_strsplit (name, ",", 6);
2429 if (!tmp || !*tmp) {
2434 dllname = g_strstrip (*tmp);
2439 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2440 goto cleanup_and_fail;
2442 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2443 *is_version_defined = TRUE;
2445 if (strlen (version) == 0) {
2446 goto cleanup_and_fail;
2452 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2454 if (strlen (culture) == 0) {
2455 goto cleanup_and_fail;
2461 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2462 *is_token_defined = TRUE;
2464 if (strlen (token) == 0) {
2465 goto cleanup_and_fail;
2471 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2473 if (strlen (key) == 0) {
2474 goto cleanup_and_fail;
2480 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2481 retargetable = value;
2482 retargetable_uq = unquote (retargetable);
2483 if (retargetable_uq != NULL)
2484 retargetable = retargetable_uq;
2486 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2487 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2488 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2489 g_free (retargetable_uq);
2490 goto cleanup_and_fail;
2493 g_free (retargetable_uq);
2498 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2500 procarch_uq = unquote (procarch);
2501 if (procarch_uq != NULL)
2502 procarch = procarch_uq;
2504 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2505 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2506 else if (!g_ascii_strcasecmp (procarch, "X86"))
2507 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2508 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2509 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2510 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2511 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2513 g_free (procarch_uq);
2514 goto cleanup_and_fail;
2517 g_free (procarch_uq);
2526 /* if retargetable flag is set, then we must have a fully qualified name */
2527 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2528 goto cleanup_and_fail;
2531 dllname_uq = unquote (dllname);
2532 version_uq = unquote (version);
2533 culture_uq = unquote (culture);
2534 token_uq = unquote (token);
2535 key_uq = unquote (key);
2537 res = build_assembly_name (
2538 dllname_uq == NULL ? dllname : dllname_uq,
2539 version_uq == NULL ? version : version_uq,
2540 culture_uq == NULL ? culture : culture_uq,
2541 token_uq == NULL ? token : token_uq,
2542 key_uq == NULL ? key : key_uq,
2543 flags, arch, aname, save_public_key);
2545 g_free (dllname_uq);
2546 g_free (version_uq);
2547 g_free (culture_uq);
2560 unquote (const char *str)
2568 slen = strlen (str);
2572 if (*str != '\'' && *str != '\"')
2575 end = str + slen - 1;
2579 return g_strndup (str + 1, slen - 2);
2583 * mono_assembly_name_parse:
2584 * @name: name to parse
2585 * @aname: the destination assembly name
2587 * Parses an assembly qualified type name and assigns the name,
2588 * version, culture and token to the provided assembly name object.
2590 * Returns: TRUE if the name could be parsed.
2593 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2595 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2599 * mono_assembly_name_new:
2600 * @name: name to parse
2602 * Allocate a new MonoAssemblyName and fill its values from the
2605 * Returns: a newly allocated structure or NULL if there was any failure.
2608 mono_assembly_name_new (const char *name)
2610 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2611 if (mono_assembly_name_parse (name, aname))
2618 mono_assembly_name_get_name (MonoAssemblyName *aname)
2624 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2626 return aname->culture;
2630 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2632 if (aname->public_key_token [0])
2633 return aname->public_key_token;
2638 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2641 *minor = aname->minor;
2643 *build = aname->build;
2645 *revision = aname->revision;
2646 return aname->major;
2649 static MonoAssembly*
2650 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2652 gchar *fullpath = NULL;
2654 const char* direntry;
2655 MonoAssemblyName gac_aname;
2656 gint major=-1, minor=0, build=0, revision=0;
2657 gboolean exact_version;
2659 dirhandle = g_dir_open (basepath, 0, NULL);
2663 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2665 while ((direntry = g_dir_read_name (dirhandle))) {
2666 gboolean match = TRUE;
2668 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2671 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2674 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2675 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2679 if (exact_version) {
2680 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2681 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2683 else if (gac_aname.major < major)
2685 else if (gac_aname.major == major) {
2686 if (gac_aname.minor < minor)
2688 else if (gac_aname.minor == minor) {
2689 if (gac_aname.build < build)
2691 else if (gac_aname.build == build && gac_aname.revision <= revision)
2698 major = gac_aname.major;
2699 minor = gac_aname.minor;
2700 build = gac_aname.build;
2701 revision = gac_aname.revision;
2703 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2706 mono_assembly_name_free (&gac_aname);
2709 g_dir_close (dirhandle);
2711 if (fullpath == NULL)
2714 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2721 * mono_assembly_load_with_partial_name:
2722 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2723 * @status: return status code
2725 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2726 * so it might contain a qualified type name, version, culture and token.
2728 * This will load the assembly from the file whose name is derived from the assembly name
2729 * by appending the .dll extension.
2731 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2732 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2733 * if that fails from the GAC.
2735 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2738 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2742 MonoAssemblyName *aname, base_name;
2743 MonoAssemblyName mapped_aname;
2744 gchar *fullname, *gacpath;
2747 memset (&base_name, 0, sizeof (MonoAssemblyName));
2750 if (!mono_assembly_name_parse (name, aname))
2754 * If no specific version has been requested, make sure we load the
2755 * correct version for system assemblies.
2757 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2758 aname = mono_assembly_remap_version (aname, &mapped_aname);
2760 res = mono_assembly_loaded (aname);
2762 mono_assembly_name_free (aname);
2766 res = invoke_assembly_preload_hook (aname, assemblies_path);
2768 res->in_gac = FALSE;
2769 mono_assembly_name_free (aname);
2773 fullname = g_strdup_printf ("%s.dll", aname->name);
2775 if (extra_gac_paths) {
2776 paths = extra_gac_paths;
2777 while (!res && *paths) {
2778 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2779 res = probe_for_partial_name (gacpath, fullname, aname, status);
2788 mono_assembly_name_free (aname);
2792 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2793 res = probe_for_partial_name (gacpath, fullname, aname, status);
2797 mono_assembly_name_free (aname);
2802 MonoDomain *domain = mono_domain_get ();
2804 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2805 if (!is_ok (&error)) {
2806 mono_error_cleanup (&error);
2807 if (*status == MONO_IMAGE_OK)
2808 *status = MONO_IMAGE_IMAGE_INVALID;
2816 mono_assembly_is_in_gac (const gchar *filename)
2818 const gchar *rootdir;
2822 if (filename == NULL)
2825 for (paths = extra_gac_paths; paths && *paths; paths++) {
2826 if (strstr (*paths, filename) != *paths)
2829 gp = (gchar *) (filename + strlen (*paths));
2830 if (*gp != G_DIR_SEPARATOR)
2833 if (strncmp (gp, "lib", 3))
2836 if (*gp != G_DIR_SEPARATOR)
2839 if (strncmp (gp, "mono", 4))
2842 if (*gp != G_DIR_SEPARATOR)
2845 if (strncmp (gp, "gac", 3))
2848 if (*gp != G_DIR_SEPARATOR)
2854 rootdir = mono_assembly_getrootdir ();
2855 if (strstr (filename, rootdir) != filename)
2858 gp = (gchar *) (filename + strlen (rootdir));
2859 if (*gp != G_DIR_SEPARATOR)
2862 if (strncmp (gp, "mono", 4))
2865 if (*gp != G_DIR_SEPARATOR)
2868 if (strncmp (gp, "gac", 3))
2871 if (*gp != G_DIR_SEPARATOR)
2877 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2880 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2884 if (strstr (aname->name, ".dll")) {
2885 len = strlen (aname->name) - 4;
2886 name = (gchar *)g_malloc (len + 1);
2887 memcpy (name, aname->name, len);
2890 name = g_strdup (aname->name);
2893 culture = g_utf8_strdown (aname->culture, -1);
2895 culture = g_strdup ("");
2897 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2898 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2902 filename = g_strconcat (pname, ".dll", NULL);
2903 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2909 if (extra_gac_paths) {
2910 paths = extra_gac_paths;
2911 while (!image && *paths) {
2912 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2913 "lib", "mono", "gac", subpath, NULL);
2914 image = mono_image_open (fullpath, NULL);
2925 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2926 "mono", "gac", subpath, NULL);
2927 image = mono_image_open (fullpath, NULL);
2934 static MonoAssemblyName*
2935 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2937 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2938 dest_name->major = info->new_version.major;
2939 dest_name->minor = info->new_version.minor;
2940 dest_name->build = info->new_version.build;
2941 dest_name->revision = info->new_version.revision;
2946 /* LOCKING: assembly_binding lock must be held */
2947 static MonoAssemblyBindingInfo*
2948 search_binding_loaded (MonoAssemblyName *aname)
2952 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2953 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2954 if (assembly_binding_maps_name (info, aname))
2961 static inline gboolean
2962 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2964 if (left->major != right->major || left->minor != right->minor ||
2965 left->build != right->build || left->revision != right->revision)
2971 static inline gboolean
2972 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2974 if (left->has_old_version_bottom != right->has_old_version_bottom)
2977 if (left->has_old_version_top != right->has_old_version_top)
2980 if (left->has_new_version != right->has_new_version)
2983 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2986 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2989 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2995 /* LOCKING: assumes all the necessary locks are held */
2997 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2999 MonoAssemblyBindingInfo *info_copy;
3001 MonoAssemblyBindingInfo *info_tmp;
3002 MonoDomain *domain = (MonoDomain*)user_data;
3007 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)) {
3008 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3009 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3013 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3014 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3015 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3019 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3020 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3022 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3024 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3026 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3030 get_version_number (int major, int minor)
3032 return major * 256 + minor;
3035 static inline gboolean
3036 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3038 int aname_version_number = get_version_number (aname->major, aname->minor);
3039 if (!info->has_old_version_bottom)
3042 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3045 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3048 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3049 info->major = aname->major;
3050 info->minor = aname->minor;
3055 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3056 static MonoAssemblyBindingInfo*
3057 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3059 MonoAssemblyBindingInfo *info;
3062 if (!domain->assembly_bindings)
3066 for (list = domain->assembly_bindings; list; list = list->next) {
3067 info = (MonoAssemblyBindingInfo *)list->data;
3068 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3074 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3075 info->has_new_version && assembly_binding_maps_name (info, aname))
3076 info->is_valid = TRUE;
3078 info->is_valid = FALSE;
3084 static MonoAssemblyName*
3085 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3088 MonoAssemblyBindingInfo *info, *info2;
3092 if (aname->public_key_token [0] == 0)
3095 domain = mono_domain_get ();
3097 mono_assembly_binding_lock ();
3098 info = search_binding_loaded (aname);
3099 mono_assembly_binding_unlock ();
3102 mono_domain_lock (domain);
3103 info = get_per_domain_assembly_binding_info (domain, aname);
3104 mono_domain_unlock (domain);
3108 if (!check_policy_versions (info, aname))
3111 mono_assembly_bind_version (info, aname, dest_name);
3115 if (domain && domain->setup && domain->setup->configuration_file) {
3116 mono_domain_lock (domain);
3117 if (!domain->assembly_bindings_parsed) {
3118 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3119 /* expect this to succeed because mono_domain_set_options_from_config () did
3120 * the same thing when the domain was created. */
3121 mono_error_assert_ok (&error);
3123 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3125 if (!domain_config_file_path)
3126 domain_config_file_path = domain_config_file_name;
3128 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3129 domain->assembly_bindings_parsed = TRUE;
3130 if (domain_config_file_name != domain_config_file_path)
3131 g_free (domain_config_file_name);
3132 g_free (domain_config_file_path);
3135 info2 = get_per_domain_assembly_binding_info (domain, aname);
3138 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3139 info->name = g_strdup (info2->name);
3140 info->culture = g_strdup (info2->culture);
3141 info->domain_id = domain->domain_id;
3144 mono_domain_unlock (domain);
3148 info = g_new0 (MonoAssemblyBindingInfo, 1);
3149 info->major = aname->major;
3150 info->minor = aname->minor;
3153 if (!info->is_valid) {
3154 ppimage = mono_assembly_load_publisher_policy (aname);
3156 get_publisher_policy_info (ppimage, aname, info);
3157 mono_image_close (ppimage);
3161 /* Define default error value if needed */
3162 if (!info->is_valid) {
3163 info->name = g_strdup (aname->name);
3164 info->culture = g_strdup (aname->culture);
3165 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3168 mono_assembly_binding_lock ();
3169 info2 = search_binding_loaded (aname);
3171 /* This binding was added by another thread
3173 mono_assembly_binding_info_free (info);
3178 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3180 mono_assembly_binding_unlock ();
3182 if (!info->is_valid || !check_policy_versions (info, aname))
3185 mono_assembly_bind_version (info, aname, dest_name);
3190 * mono_assembly_load_from_gac
3192 * @aname: The assembly name object
3194 static MonoAssembly*
3195 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3197 MonoAssembly *result = NULL;
3198 gchar *name, *version, *culture, *fullpath, *subpath;
3203 if (aname->public_key_token [0] == 0) {
3207 if (strstr (aname->name, ".dll")) {
3208 len = strlen (filename) - 4;
3209 name = (gchar *)g_malloc (len + 1);
3210 memcpy (name, aname->name, len);
3213 name = g_strdup (aname->name);
3216 if (aname->culture) {
3217 culture = g_utf8_strdown (aname->culture, -1);
3219 culture = g_strdup ("");
3222 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3223 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3224 aname->minor, aname->build, aname->revision,
3228 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3233 if (extra_gac_paths) {
3234 paths = extra_gac_paths;
3235 while (!result && *paths) {
3236 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3237 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3244 result->in_gac = TRUE;
3249 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3250 "mono", "gac", subpath, NULL);
3251 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3255 result->in_gac = TRUE;
3263 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3266 MonoAssemblyName *aname;
3269 /* g_print ("corlib already loaded\n"); */
3273 // In native client, Corlib is embedded in the executable as static variable corlibData
3274 #if defined(__native_client__)
3275 if (corlibData != NULL && corlibSize != 0) {
3277 /* First "FALSE" instructs mono not to make a copy. */
3278 /* Second "FALSE" says this is not just a ref. */
3279 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3280 if (image == NULL || status != 0)
3281 g_print("mono_image_open_from_data_full failed: %d\n", status);
3282 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3283 if (corlib == NULL || status != 0)
3284 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3290 // A nonstandard preload hook may provide a special mscorlib assembly
3291 aname = mono_assembly_name_new ("mscorlib.dll");
3292 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3293 mono_assembly_name_free (aname);
3296 goto return_corlib_and_facades;
3298 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3299 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3300 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3302 goto return_corlib_and_facades;
3305 /* Normal case: Load corlib from mono/<version> */
3306 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3307 if (assemblies_path) { // Custom assemblies path
3308 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3310 g_free (corlib_file);
3311 goto return_corlib_and_facades;
3314 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3315 g_free (corlib_file);
3317 return_corlib_and_facades:
3318 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3319 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3324 static MonoAssembly*
3325 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3327 MonoError refasm_error;
3328 error_init (&refasm_error);
3329 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3332 mono_error_cleanup (&refasm_error);
3337 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3339 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3340 MonoAssemblyName *candidate_name = &candidate->aname;
3342 g_assert (wanted_name != NULL);
3343 g_assert (candidate_name != NULL);
3345 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3346 char * s = mono_stringify_assembly_name (wanted_name);
3347 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3349 s = mono_stringify_assembly_name (candidate_name);
3350 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3354 /* No wanted token, bail. */
3355 if (0 == wanted_name->public_key_token [0]) {
3356 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3360 if (0 == candidate_name->public_key_token [0]) {
3361 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3366 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3368 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3369 result ? "match, returning TRUE" : "don't match, returning FALSE");
3376 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3377 const char *basedir,
3378 MonoImageOpenStatus *status,
3381 MonoAssembly *result;
3382 char *fullpath, *filename;
3383 MonoAssemblyName maped_aname;
3384 MonoAssemblyName maped_name_pp;
3389 aname = mono_assembly_remap_version (aname, &maped_aname);
3391 /* Reflection only assemblies don't get assembly binding */
3393 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3395 result = mono_assembly_loaded_full (aname, refonly);
3399 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3401 result->in_gac = FALSE;
3405 /* Currently we retrieve the loaded corlib for reflection
3406 * only requests, like a common reflection only assembly
3408 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3409 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3412 len = strlen (aname->name);
3413 for (ext_index = 0; ext_index < 2; ext_index ++) {
3414 ext = ext_index == 0 ? ".dll" : ".exe";
3415 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3416 filename = g_strdup (aname->name);
3417 /* Don't try appending .dll/.exe if it already has one of those extensions */
3420 filename = g_strconcat (aname->name, ext, NULL);
3423 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3430 fullpath = g_build_filename (basedir, filename, NULL);
3431 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3434 result->in_gac = FALSE;
3440 result = load_in_path (filename, default_path, status, refonly, NULL, NULL);
3442 result->in_gac = FALSE;
3452 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3454 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3457 /* Try a postload search hook */
3458 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3459 result = prevent_reference_assembly_from_running (result, refonly);
3465 * mono_assembly_load_full:
3466 * @aname: A MonoAssemblyName with the assembly name to load.
3467 * @basedir: A directory to look up the assembly at.
3468 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3469 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3471 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3472 * attempts to load the assembly from that directory before probing the standard locations.
3474 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3475 * assembly binding takes place.
3477 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3478 * value pointed by status is updated with an error code.
3481 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3483 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3487 * mono_assembly_load:
3488 * @aname: A MonoAssemblyName with the assembly name to load.
3489 * @basedir: A directory to look up the assembly at.
3490 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3492 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3493 * attempts to load the assembly from that directory before probing the standard locations.
3495 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3496 * value pointed by status is updated with an error code.
3499 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3501 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3505 * mono_assembly_loaded_full:
3506 * @aname: an assembly to look for.
3507 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3509 * This is used to determine if the specified assembly has been loaded
3510 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3511 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3514 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3517 MonoAssemblyName maped_aname;
3519 aname = mono_assembly_remap_version (aname, &maped_aname);
3521 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3527 * mono_assembly_loaded:
3528 * @aname: an assembly to look for.
3530 * This is used to determine if the specified assembly has been loaded
3532 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3533 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3536 mono_assembly_loaded (MonoAssemblyName *aname)
3538 return mono_assembly_loaded_full (aname, FALSE);
3542 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3544 if (assembly == NULL || assembly == REFERENCE_MISSING)
3547 if (assembly_is_dynamic (assembly)) {
3549 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3550 for (i = 0; i < dynimg->image.module_count; ++i)
3551 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3552 mono_dynamic_image_release_gc_roots (dynimg);
3557 * Returns whether mono_assembly_close_finish() must be called as
3558 * well. See comment for mono_image_close_except_pools() for why we
3559 * unload in two steps.
3562 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3565 g_return_val_if_fail (assembly != NULL, FALSE);
3567 if (assembly == REFERENCE_MISSING)
3570 /* Might be 0 already */
3571 if (InterlockedDecrement (&assembly->ref_count) > 0)
3574 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3576 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3578 mono_debug_close_image (assembly->image);
3580 mono_assemblies_lock ();
3581 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3582 mono_assemblies_unlock ();
3584 assembly->image->assembly = NULL;
3586 if (!mono_image_close_except_pools (assembly->image))
3587 assembly->image = NULL;
3589 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3590 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3591 mono_assembly_name_free (fname);
3594 g_slist_free (assembly->friend_assembly_names);
3595 g_free (assembly->basedir);
3597 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3603 mono_assembly_close_finish (MonoAssembly *assembly)
3605 g_assert (assembly && assembly != REFERENCE_MISSING);
3607 if (assembly->image)
3608 mono_image_close_finish (assembly->image);
3610 if (assembly_is_dynamic (assembly)) {
3611 g_free ((char*)assembly->aname.culture);
3618 * mono_assembly_close:
3619 * @assembly: the assembly to release.
3621 * This method releases a reference to the @assembly. The assembly is
3622 * only released when all the outstanding references to it are released.
3625 mono_assembly_close (MonoAssembly *assembly)
3627 if (mono_assembly_close_except_image_pools (assembly))
3628 mono_assembly_close_finish (assembly);
3632 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3635 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3636 mono_error_assert_ok (&error);
3641 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3643 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3648 * mono_assembly_foreach:
3649 * @func: function to invoke for each assembly loaded
3650 * @user_data: data passed to the callback
3652 * Invokes the provided @func callback for each assembly loaded into
3653 * the runtime. The first parameter passed to the callback is the
3654 * `MonoAssembly*`, and the second parameter is the @user_data.
3656 * This is done for all assemblies loaded in the runtime, not just
3657 * those loaded in the current application domain.
3660 mono_assembly_foreach (GFunc func, gpointer user_data)
3665 * We make a copy of the list to avoid calling the callback inside the
3666 * lock, which could lead to deadlocks.
3668 mono_assemblies_lock ();
3669 copy = g_list_copy (loaded_assemblies);
3670 mono_assemblies_unlock ();
3672 g_list_foreach (loaded_assemblies, func, user_data);
3678 * mono_assemblies_cleanup:
3680 * Free all resources used by this module.
3683 mono_assemblies_cleanup (void)
3687 mono_os_mutex_destroy (&assemblies_mutex);
3688 mono_os_mutex_destroy (&assembly_binding_mutex);
3690 for (l = loaded_assembly_bindings; l; l = l->next) {
3691 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3693 mono_assembly_binding_info_free (info);
3696 g_slist_free (loaded_assembly_bindings);
3698 free_assembly_load_hooks ();
3699 free_assembly_search_hooks ();
3700 free_assembly_preload_hooks ();
3703 /*LOCKING takes the assembly_binding lock*/
3705 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3709 mono_assembly_binding_lock ();
3710 iter = &loaded_assembly_bindings;
3713 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3715 if (info->domain_id == domain_id) {
3717 mono_assembly_binding_info_free (info);
3724 mono_assembly_binding_unlock ();
3728 * Holds the assembly of the application, for
3729 * System.Diagnostics.Process::MainModule
3731 static MonoAssembly *main_assembly=NULL;
3734 mono_assembly_set_main (MonoAssembly *assembly)
3736 main_assembly = assembly;
3740 * mono_assembly_get_main:
3742 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3745 mono_assembly_get_main (void)
3747 return (main_assembly);
3751 * mono_assembly_get_image:
3752 * @assembly: The assembly to retrieve the image from
3754 * Returns: the MonoImage associated with this assembly.
3757 mono_assembly_get_image (MonoAssembly *assembly)
3759 return assembly->image;
3763 * mono_assembly_get_name:
3764 * @assembly: The assembly to retrieve the name from
3766 * The returned name's lifetime is the same as @assembly's.
3768 * Returns: the MonoAssemblyName associated with this assembly.
3771 mono_assembly_get_name (MonoAssembly *assembly)
3773 return &assembly->aname;
3777 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3779 bundles = assemblies;
3782 #define MONO_DECLSEC_FORMAT_10 0x3C
3783 #define MONO_DECLSEC_FORMAT_20 0x2E
3784 #define MONO_DECLSEC_FIELD 0x53
3785 #define MONO_DECLSEC_PROPERTY 0x54
3787 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3788 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3789 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3790 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3791 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3794 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3798 case MONO_DECLSEC_PROPERTY:
3800 case MONO_DECLSEC_FIELD:
3802 *abort_decoding = TRUE;
3807 if (*p++ != MONO_TYPE_BOOLEAN) {
3808 *abort_decoding = TRUE;
3812 /* property name length */
3813 len = mono_metadata_decode_value (p, &p);
3815 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3826 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3828 int i, j, num, len, params_len;
3830 if (*p == MONO_DECLSEC_FORMAT_10) {
3831 gsize read, written;
3832 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3834 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3840 if (*p++ != MONO_DECLSEC_FORMAT_20)
3843 /* number of encoded permission attributes */
3844 num = mono_metadata_decode_value (p, &p);
3845 for (i = 0; i < num; ++i) {
3846 gboolean is_valid = FALSE;
3847 gboolean abort_decoding = FALSE;
3849 /* attribute name length */
3850 len = mono_metadata_decode_value (p, &p);
3852 /* We don't really need to fully decode the type. Comparing the name is enough */
3853 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3857 /*size of the params table*/
3858 params_len = mono_metadata_decode_value (p, &p);
3860 const char *params_end = p + params_len;
3862 /* number of parameters */
3863 len = mono_metadata_decode_value (p, &p);
3865 for (j = 0; j < len; ++j) {
3866 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3882 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3885 guint32 cols [MONO_DECL_SECURITY_SIZE];
3889 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3890 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3892 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3894 for (i = 0; i < t->rows; ++i) {
3895 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3896 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3898 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3901 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3902 len = mono_metadata_decode_blob_size (blob, &blob);
3906 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3907 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3912 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);