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 (vmap->new_assembly_name != NULL) {
1129 dest_aname->name = vmap->new_assembly_name;
1130 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1131 "The assembly name %s was remapped to %s",
1143 * mono_assembly_get_assemblyref:
1144 * @image: pointer to the MonoImage to extract the information from.
1145 * @index: index to the assembly reference in the image.
1146 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1148 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1151 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1154 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1157 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1159 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1161 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1162 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1163 aname->hash_value = hash;
1164 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1165 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1166 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1167 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1168 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1169 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1170 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1172 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1173 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1174 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1177 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1182 mono_assembly_load_reference (MonoImage *image, int index)
1184 MonoAssembly *reference;
1185 MonoAssemblyName aname;
1186 MonoImageOpenStatus status;
1189 * image->references is shared between threads, so we need to access
1190 * it inside a critical section.
1192 mono_assemblies_lock ();
1193 if (!image->references) {
1194 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1196 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1197 image->nreferences = t->rows;
1199 reference = image->references [index];
1200 mono_assemblies_unlock ();
1204 mono_assembly_get_assemblyref (image, index, &aname);
1206 if (image->assembly && image->assembly->ref_only) {
1207 /* We use the loaded corlib */
1208 if (!strcmp (aname.name, "mscorlib"))
1209 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1211 reference = mono_assembly_loaded_full (&aname, TRUE);
1213 /* Try a postload search hook */
1214 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1218 * Here we must advice that the error was due to
1219 * a non loaded reference using the ReflectionOnly api
1222 reference = (MonoAssembly *)REFERENCE_MISSING;
1224 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1225 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1226 * accordingly, it would fail on the MS runtime before).
1227 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1228 * example bug-349190.2.cs and who knows how much more code in the wild.
1230 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1231 if (!reference && image->assembly)
1232 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1235 if (reference == NULL){
1238 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1239 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 : "" );
1240 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1241 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1242 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1243 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1244 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1245 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1247 extra_msg = g_strdup ("");
1250 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1251 " Assembly: %s (assemblyref_index=%d)\n"
1252 " Version: %d.%d.%d.%d\n"
1253 " Public Key: %s\n%s",
1254 image->name, aname.name, index,
1255 aname.major, aname.minor, aname.build, aname.revision,
1256 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1261 mono_assemblies_lock ();
1262 if (reference == NULL) {
1263 /* Flag as not found */
1264 reference = (MonoAssembly *)REFERENCE_MISSING;
1267 if (!image->references [index]) {
1268 if (reference != REFERENCE_MISSING){
1269 mono_assembly_addref (reference);
1270 if (image->assembly)
1271 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1272 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1274 if (image->assembly)
1275 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1276 image->assembly->aname.name, image->assembly);
1279 image->references [index] = reference;
1281 mono_assemblies_unlock ();
1283 if (image->references [index] != reference) {
1284 /* Somebody loaded it before us */
1285 mono_assembly_close (reference);
1290 * mono_assembly_load_references:
1293 * @deprecated: There is no reason to use this method anymore, it does nothing
1295 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1298 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1300 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1301 *status = MONO_IMAGE_OK;
1304 typedef struct AssemblyLoadHook AssemblyLoadHook;
1305 struct AssemblyLoadHook {
1306 AssemblyLoadHook *next;
1307 MonoAssemblyLoadFunc func;
1311 AssemblyLoadHook *assembly_load_hook = NULL;
1314 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1316 AssemblyLoadHook *hook;
1318 for (hook = assembly_load_hook; hook; hook = hook->next) {
1319 hook->func (ass, hook->user_data);
1324 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1326 AssemblyLoadHook *hook;
1328 g_return_if_fail (func != NULL);
1330 hook = g_new0 (AssemblyLoadHook, 1);
1332 hook->user_data = user_data;
1333 hook->next = assembly_load_hook;
1334 assembly_load_hook = hook;
1338 free_assembly_load_hooks (void)
1340 AssemblyLoadHook *hook, *next;
1342 for (hook = assembly_load_hook; hook; hook = next) {
1348 typedef struct AssemblySearchHook AssemblySearchHook;
1349 struct AssemblySearchHook {
1350 AssemblySearchHook *next;
1351 MonoAssemblySearchFunc func;
1357 AssemblySearchHook *assembly_search_hook = NULL;
1359 static MonoAssembly*
1360 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1362 AssemblySearchHook *hook;
1364 for (hook = assembly_search_hook; hook; hook = hook->next) {
1365 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1368 * A little explanation is in order here.
1370 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1371 * The embedding API exposes a search hook that doesn't take such argument.
1373 * The original fix would call the default search hook before all the registered ones and pass
1374 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1375 * rely on. Which is the ordering between user hooks and the default runtime hook.
1377 * Registering the hook after mono_jit_init would let your hook run before the default one and
1378 * when using it to handle non standard app layouts this could save your app from a massive amount
1379 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1380 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1382 * So what's the fix? We register the default hook using regular means and special case it when iterating
1383 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1386 if (hook->func == (void*)mono_domain_assembly_postload_search)
1387 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1389 ass = hook->func (aname, hook->user_data);
1399 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1401 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1405 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1407 AssemblySearchHook *hook;
1409 g_return_if_fail (func != NULL);
1411 hook = g_new0 (AssemblySearchHook, 1);
1413 hook->user_data = user_data;
1414 hook->refonly = refonly;
1415 hook->postload = postload;
1416 hook->next = assembly_search_hook;
1417 assembly_search_hook = hook;
1421 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1423 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1427 free_assembly_search_hooks (void)
1429 AssemblySearchHook *hook, *next;
1431 for (hook = assembly_search_hook; hook; hook = next) {
1438 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1440 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1444 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1446 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1450 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1452 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1455 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1456 struct AssemblyPreLoadHook {
1457 AssemblyPreLoadHook *next;
1458 MonoAssemblyPreLoadFunc func;
1462 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1463 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1465 static MonoAssembly *
1466 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1468 AssemblyPreLoadHook *hook;
1469 MonoAssembly *assembly;
1471 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1472 assembly = hook->func (aname, assemblies_path, hook->user_data);
1473 if (assembly != NULL)
1480 static MonoAssembly *
1481 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1483 AssemblyPreLoadHook *hook;
1484 MonoAssembly *assembly;
1486 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1487 assembly = hook->func (aname, assemblies_path, hook->user_data);
1488 if (assembly != NULL)
1496 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1498 AssemblyPreLoadHook *hook;
1500 g_return_if_fail (func != NULL);
1502 hook = g_new0 (AssemblyPreLoadHook, 1);
1504 hook->user_data = user_data;
1505 hook->next = assembly_preload_hook;
1506 assembly_preload_hook = hook;
1510 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1512 AssemblyPreLoadHook *hook;
1514 g_return_if_fail (func != NULL);
1516 hook = g_new0 (AssemblyPreLoadHook, 1);
1518 hook->user_data = user_data;
1519 hook->next = assembly_refonly_preload_hook;
1520 assembly_refonly_preload_hook = hook;
1524 free_assembly_preload_hooks (void)
1526 AssemblyPreLoadHook *hook, *next;
1528 for (hook = assembly_preload_hook; hook; hook = next) {
1533 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1540 absolute_dir (const gchar *filename)
1551 if (g_path_is_absolute (filename)) {
1552 part = g_path_get_dirname (filename);
1553 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1558 cwd = g_get_current_dir ();
1559 mixed = g_build_filename (cwd, filename, NULL);
1560 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1565 for (i = 0; (part = parts [i]) != NULL; i++) {
1566 if (!strcmp (part, "."))
1569 if (!strcmp (part, "..")) {
1570 if (list && list->next) /* Don't remove root */
1571 list = g_list_delete_link (list, list);
1573 list = g_list_prepend (list, part);
1577 result = g_string_new ("");
1578 list = g_list_reverse (list);
1580 /* Ignores last data pointer, which should be the filename */
1581 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1583 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1588 g_string_free (result, FALSE);
1593 return g_strdup (".");
1600 * mono_assembly_open_from_bundle:
1601 * @filename: Filename requested
1602 * @status: return status code
1604 * This routine tries to open the assembly specified by `filename' from the
1605 * defined bundles, if found, returns the MonoImage for it, if not found
1609 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1613 gchar *lowercase_filename;
1614 MonoImage *image = NULL;
1615 gboolean is_satellite = FALSE;
1617 * we do a very simple search for bundled assemblies: it's not a general
1618 * purpose assembly loading mechanism.
1624 lowercase_filename = g_utf8_strdown (filename, -1);
1625 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1626 g_free (lowercase_filename);
1627 name = g_path_get_basename (filename);
1628 mono_assemblies_lock ();
1629 for (i = 0; !image && bundles [i]; ++i) {
1630 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1631 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1635 mono_assemblies_unlock ();
1637 mono_image_addref (image);
1638 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1647 * mono_assemblies_open_full:
1648 * @filename: the file to load
1649 * @status: return status code
1650 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1652 * This loads an assembly from the specified @filename. The @filename allows
1653 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1654 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1655 * is treated as a local path.
1657 * First, an attempt is made to load the assembly from the bundled executable (for those
1658 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1659 * assembly has been registered as an embedded assembly). If this is not the case, then
1660 * the assembly is loaded from disk using `api:mono_image_open_full`.
1662 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1663 * the assembly is made.
1665 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1666 * the `System.Reflection` API.
1668 * Returns: NULL on error, with the @status set to an error code, or a pointer
1672 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1674 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1678 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1680 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1684 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1685 gboolean load_from_context,
1686 MonoAssemblyCandidatePredicate predicate,
1688 MonoImageOpenStatus *status)
1692 MonoImageOpenStatus def_status;
1695 gboolean loaded_from_bundle;
1697 g_return_val_if_fail (filename != NULL, NULL);
1700 status = &def_status;
1701 *status = MONO_IMAGE_OK;
1703 if (strncmp (filename, "file://", 7) == 0) {
1704 GError *error = NULL;
1705 gchar *uri = (gchar *) filename;
1709 * MS allows file://c:/... and fails on file://localhost/c:/...
1710 * They also throw an IndexOutOfRangeException if "file://"
1713 uri = g_strdup_printf ("file:///%s", uri + 7);
1716 uri = mono_escape_uri_string (tmpuri);
1717 fname = g_filename_from_uri (uri, NULL, &error);
1720 if (tmpuri != filename)
1723 if (error != NULL) {
1724 g_warning ("%s\n", error->message);
1725 g_error_free (error);
1726 fname = g_strdup (filename);
1729 fname = g_strdup (filename);
1732 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1733 "Assembly Loader probing location: '%s'.", fname);
1736 if (!mono_assembly_is_in_gac (fname)) {
1738 new_fname = mono_make_shadow_copy (fname, &error);
1739 if (!is_ok (&error)) {
1740 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1741 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1742 mono_error_cleanup (&error);
1743 *status = MONO_IMAGE_IMAGE_INVALID;
1748 if (new_fname && new_fname != fname) {
1751 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1752 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1757 // If VM built with mkbundle
1758 loaded_from_bundle = FALSE;
1759 if (bundles != NULL) {
1760 image = mono_assembly_open_from_bundle (fname, status, refonly);
1761 loaded_from_bundle = image != NULL;
1765 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1768 if (*status == MONO_IMAGE_OK)
1769 *status = MONO_IMAGE_ERROR_ERRNO;
1774 if (image->assembly) {
1775 /* Already loaded by another appdomain */
1776 mono_assembly_invoke_load_hook (image->assembly);
1777 mono_image_close (image);
1779 return image->assembly;
1782 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1785 if (!loaded_from_bundle)
1786 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1787 "Assembly Loader loaded assembly from location: '%s'.", filename);
1789 mono_config_for_assembly (ass->image);
1792 /* Clear the reference added by mono_image_open */
1793 mono_image_close (image);
1801 free_item (gpointer val, gpointer user_data)
1807 * mono_assembly_load_friends:
1810 * Load the list of friend assemblies that are allowed to access
1811 * the assembly's internal types and members. They are stored as assembly
1812 * names in custom attributes.
1814 * This is an internal method, we need this because when we load mscorlib
1815 * we do not have the internals visible cattr loaded yet,
1816 * so we need to load these after we initialize the runtime.
1818 * LOCKING: Acquires the assemblies lock plus the loader lock.
1821 mono_assembly_load_friends (MonoAssembly* ass)
1825 MonoCustomAttrInfo* attrs;
1828 if (ass->friend_assembly_names_inited)
1831 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1832 mono_error_assert_ok (&error);
1834 mono_assemblies_lock ();
1835 ass->friend_assembly_names_inited = TRUE;
1836 mono_assemblies_unlock ();
1840 mono_assemblies_lock ();
1841 if (ass->friend_assembly_names_inited) {
1842 mono_assemblies_unlock ();
1845 mono_assemblies_unlock ();
1849 * We build the list outside the assemblies lock, the worse that can happen
1850 * is that we'll need to free the allocated list.
1852 for (i = 0; i < attrs->num_attrs; ++i) {
1853 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1854 MonoAssemblyName *aname;
1856 /* Do some sanity checking */
1857 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1859 if (attr->data_size < 4)
1861 data = (const char*)attr->data;
1862 /* 0xFF means null string, see custom attr format */
1863 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1865 mono_metadata_decode_value (data + 2, &data);
1866 aname = g_new0 (MonoAssemblyName, 1);
1867 /*g_print ("friend ass: %s\n", data);*/
1868 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1869 list = g_slist_prepend (list, aname);
1874 mono_custom_attrs_free (attrs);
1876 mono_assemblies_lock ();
1877 if (ass->friend_assembly_names_inited) {
1878 mono_assemblies_unlock ();
1879 g_slist_foreach (list, free_item, NULL);
1880 g_slist_free (list);
1883 ass->friend_assembly_names = list;
1885 /* Because of the double checked locking pattern above */
1886 mono_memory_barrier ();
1887 ass->friend_assembly_names_inited = TRUE;
1888 mono_assemblies_unlock ();
1891 struct HasReferenceAssemblyAttributeIterData {
1896 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1898 gboolean stop_scanning = FALSE;
1899 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1901 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1902 /* Note we don't check the assembly name, same as coreCLR. */
1903 iter_data->has_attr = TRUE;
1904 stop_scanning = TRUE;
1907 return stop_scanning;
1911 * mono_assembly_has_reference_assembly_attribute:
1912 * @assembly: a MonoAssembly
1913 * @error: set on error.
1915 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1916 * On error returns FALSE and sets @error.
1919 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1924 * This might be called during assembly loading, so do everything using the low-level
1928 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1930 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1932 return iter_data.has_attr;
1936 * mono_assembly_open:
1937 * @filename: Opens the assembly pointed out by this name
1938 * @status: return status code
1940 * This loads an assembly from the specified @filename. The @filename allows
1941 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1942 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1943 * is treated as a local path.
1945 * First, an attempt is made to load the assembly from the bundled executable (for those
1946 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1947 * assembly has been registered as an embedded assembly). If this is not the case, then
1948 * the assembly is loaded from disk using `api:mono_image_open_full`.
1950 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1951 * the assembly is made.
1953 * Return: a pointer to the MonoAssembly if @filename contains a valid
1954 * assembly or NULL on error. Details about the error are stored in the
1958 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1960 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
1964 * mono_assembly_load_from_full:
1965 * @image: Image to load the assembly from
1966 * @fname: assembly name to associate with the assembly
1967 * @status: returns the status condition
1968 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1970 * If the provided @image has an assembly reference, it will process the given
1971 * image as an assembly with the given name.
1973 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1975 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1976 * set to #MONO_IMAGE_OK; or NULL on error.
1978 * If there is an error loading the assembly the @status will indicate the
1979 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1980 * image did not contain an assembly reference table.
1983 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1984 MonoImageOpenStatus *status, gboolean refonly)
1986 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
1990 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
1992 MonoAssemblyCandidatePredicate predicate,
1994 MonoImageOpenStatus *status)
1996 MonoAssembly *ass, *ass2;
1999 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2000 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2001 *status = MONO_IMAGE_IMAGE_INVALID;
2005 #if defined (HOST_WIN32)
2010 tmp_fn = g_strdup (fname);
2011 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2012 if (tmp_fn [i] == '/')
2016 base_dir = absolute_dir (tmp_fn);
2020 base_dir = absolute_dir (fname);
2024 * Create assembly struct, and enter it into the assembly cache
2026 ass = g_new0 (MonoAssembly, 1);
2027 ass->basedir = base_dir;
2028 ass->ref_only = refonly;
2031 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2033 mono_assembly_fill_assembly_name (image, &ass->aname);
2035 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2036 // MS.NET doesn't support loading other mscorlibs
2039 mono_image_addref (mono_defaults.corlib);
2040 *status = MONO_IMAGE_OK;
2041 return mono_defaults.corlib->assembly;
2044 /* Add a non-temporary reference because of ass->image */
2045 mono_image_addref (image);
2047 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);
2050 * The load hooks might take locks so we can't call them while holding the
2053 if (ass->aname.name) {
2054 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2058 mono_image_close (image);
2059 *status = MONO_IMAGE_OK;
2064 /* We need to check for ReferenceAssmeblyAttribute before we
2065 * mark the assembly as loaded and before we fire the load
2066 * hook. Otherwise mono_domain_fire_assembly_load () in
2067 * appdomain.c will cache a mapping from the assembly name to
2068 * this image and we won't be able to look for a different
2072 MonoError refasm_error;
2073 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2074 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2077 mono_image_close (image);
2078 *status = MONO_IMAGE_IMAGE_INVALID;
2081 mono_error_cleanup (&refasm_error);
2084 if (predicate && !predicate (ass, user_data)) {
2085 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2088 mono_image_close (image);
2089 *status = MONO_IMAGE_IMAGE_INVALID;
2093 mono_assemblies_lock ();
2095 if (image->assembly) {
2097 * This means another thread has already loaded the assembly, but not yet
2098 * called the load hooks so the search hook can't find the assembly.
2100 mono_assemblies_unlock ();
2101 ass2 = image->assembly;
2104 mono_image_close (image);
2105 *status = MONO_IMAGE_OK;
2109 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2111 image->assembly = ass;
2113 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2114 mono_assemblies_unlock ();
2117 if (image->is_module_handle)
2118 mono_image_fixup_vtable (image);
2121 mono_assembly_invoke_load_hook (ass);
2123 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2129 * mono_assembly_load_from:
2130 * @image: Image to load the assembly from
2131 * @fname: assembly name to associate with the assembly
2132 * @status: return status code
2134 * If the provided @image has an assembly reference, it will process the given
2135 * image as an assembly with the given name.
2137 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2139 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2140 * @refonly parameter set to FALSE.
2141 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2142 * set to #MONO_IMAGE_OK; or NULL on error.
2144 * If there is an error loading the assembly the @status will indicate the
2145 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2146 * image did not contain an assembly reference table.
2150 mono_assembly_load_from (MonoImage *image, const char *fname,
2151 MonoImageOpenStatus *status)
2153 return mono_assembly_load_from_full (image, fname, status, FALSE);
2157 * mono_assembly_name_free:
2158 * @aname: assembly name to free
2160 * Frees the provided assembly name object.
2161 * (it does not frees the object itself, only the name members).
2164 mono_assembly_name_free (MonoAssemblyName *aname)
2169 g_free ((void *) aname->name);
2170 g_free ((void *) aname->culture);
2171 g_free ((void *) aname->hash_value);
2172 g_free ((guint8*) aname->public_key);
2176 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2179 gchar header [16], val, *arr;
2180 gint i, j, offset, bitlen, keylen, pkeylen;
2182 keylen = strlen (key) >> 1;
2186 /* allow the ECMA standard key */
2187 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2189 *pubkey = g_strdup (key);
2195 val = g_ascii_xdigit_value (key [0]) << 4;
2196 val |= g_ascii_xdigit_value (key [1]);
2201 val = g_ascii_xdigit_value (key [24]);
2202 val |= g_ascii_xdigit_value (key [25]);
2214 /* We need the first 16 bytes
2215 * to check whether this key is valid or not */
2216 pkeylen = strlen (pkey) >> 1;
2220 for (i = 0, j = 0; i < 16; i++) {
2221 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2222 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2225 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2226 header [1] != 0x02 || /* Version (0x02) */
2227 header [2] != 0x00 || /* Reserved (word) */
2228 header [3] != 0x00 ||
2229 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2232 /* Based on this length, we _should_ be able to know if the length is right */
2233 bitlen = read32 (header + 12) >> 3;
2234 if ((bitlen + 16 + 4) != pkeylen)
2237 /* parsing is OK and the public key itself is not requested back */
2241 /* Encode the size of the blob */
2243 if (keylen <= 127) {
2244 arr = (gchar *)g_malloc (keylen + 1);
2245 arr [offset++] = keylen;
2247 arr = (gchar *)g_malloc (keylen + 2);
2248 arr [offset++] = 0x80; /* 10bs */
2249 arr [offset++] = keylen;
2252 for (i = offset, j = 0; i < keylen + offset; i++) {
2253 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2254 arr [i] |= g_ascii_xdigit_value (key [j++]);
2263 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)
2265 gint major, minor, build, revision;
2268 gchar *pkey, *pkeyptr, *encoded, tok [8];
2270 memset (aname, 0, sizeof (MonoAssemblyName));
2273 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2274 if (version_parts < 2 || version_parts > 4)
2277 /* FIXME: we should set build & revision to -1 (instead of 0)
2278 if these are not set in the version string. That way, later on,
2279 we can still determine if these were specified. */
2280 aname->major = major;
2281 aname->minor = minor;
2282 if (version_parts >= 3)
2283 aname->build = build;
2286 if (version_parts == 4)
2287 aname->revision = revision;
2289 aname->revision = 0;
2292 aname->flags = flags;
2294 aname->name = g_strdup (name);
2297 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2298 aname->culture = g_strdup ("");
2300 aname->culture = g_strdup (culture);
2303 if (token && strncmp (token, "null", 4) != 0) {
2306 /* the constant includes the ending NULL, hence the -1 */
2307 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2308 mono_assembly_name_free (aname);
2311 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2312 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2318 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2319 mono_assembly_name_free (aname);
2324 if (save_public_key)
2325 aname->public_key = (guint8*)pkey;
2328 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2332 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2333 // We also need to generate the key token
2334 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2335 encoded = encode_public_tok ((guchar*) tok, 8);
2336 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2339 if (save_public_key)
2340 aname->public_key = (guint8*) pkey;
2349 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2354 parts = g_strsplit (dirname, "_", 3);
2355 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2360 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2366 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2368 char *eqsign = strchr (pair, '=');
2376 *key = (gchar*)pair;
2377 *keylen = eqsign - *key;
2378 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2380 *value = g_strstrip (eqsign + 1);
2385 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2389 gchar *version = NULL;
2391 gchar *culture = NULL;
2393 gchar *token = NULL;
2397 gchar *retargetable = NULL;
2398 gchar *retargetable_uq;
2402 gchar *value, *part_name;
2403 guint32 part_name_len;
2406 gboolean version_defined;
2407 gboolean token_defined;
2409 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2411 if (!is_version_defined)
2412 is_version_defined = &version_defined;
2413 *is_version_defined = FALSE;
2414 if (!is_token_defined)
2415 is_token_defined = &token_defined;
2416 *is_token_defined = FALSE;
2418 parts = tmp = g_strsplit (name, ",", 6);
2419 if (!tmp || !*tmp) {
2424 dllname = g_strstrip (*tmp);
2429 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2430 goto cleanup_and_fail;
2432 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2433 *is_version_defined = TRUE;
2435 if (strlen (version) == 0) {
2436 goto cleanup_and_fail;
2442 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2444 if (strlen (culture) == 0) {
2445 goto cleanup_and_fail;
2451 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2452 *is_token_defined = TRUE;
2454 if (strlen (token) == 0) {
2455 goto cleanup_and_fail;
2461 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2463 if (strlen (key) == 0) {
2464 goto cleanup_and_fail;
2470 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2471 retargetable = value;
2472 retargetable_uq = unquote (retargetable);
2473 if (retargetable_uq != NULL)
2474 retargetable = retargetable_uq;
2476 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2477 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2478 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2479 g_free (retargetable_uq);
2480 goto cleanup_and_fail;
2483 g_free (retargetable_uq);
2488 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2490 procarch_uq = unquote (procarch);
2491 if (procarch_uq != NULL)
2492 procarch = procarch_uq;
2494 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2495 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2496 else if (!g_ascii_strcasecmp (procarch, "X86"))
2497 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2498 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2499 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2500 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2501 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2503 g_free (procarch_uq);
2504 goto cleanup_and_fail;
2507 g_free (procarch_uq);
2516 /* if retargetable flag is set, then we must have a fully qualified name */
2517 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2518 goto cleanup_and_fail;
2521 dllname_uq = unquote (dllname);
2522 version_uq = unquote (version);
2523 culture_uq = unquote (culture);
2524 token_uq = unquote (token);
2525 key_uq = unquote (key);
2527 res = build_assembly_name (
2528 dllname_uq == NULL ? dllname : dllname_uq,
2529 version_uq == NULL ? version : version_uq,
2530 culture_uq == NULL ? culture : culture_uq,
2531 token_uq == NULL ? token : token_uq,
2532 key_uq == NULL ? key : key_uq,
2533 flags, arch, aname, save_public_key);
2535 g_free (dllname_uq);
2536 g_free (version_uq);
2537 g_free (culture_uq);
2550 unquote (const char *str)
2558 slen = strlen (str);
2562 if (*str != '\'' && *str != '\"')
2565 end = str + slen - 1;
2569 return g_strndup (str + 1, slen - 2);
2573 * mono_assembly_name_parse:
2574 * @name: name to parse
2575 * @aname: the destination assembly name
2577 * Parses an assembly qualified type name and assigns the name,
2578 * version, culture and token to the provided assembly name object.
2580 * Returns: TRUE if the name could be parsed.
2583 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2585 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2589 * mono_assembly_name_new:
2590 * @name: name to parse
2592 * Allocate a new MonoAssemblyName and fill its values from the
2595 * Returns: a newly allocated structure or NULL if there was any failure.
2598 mono_assembly_name_new (const char *name)
2600 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2601 if (mono_assembly_name_parse (name, aname))
2608 mono_assembly_name_get_name (MonoAssemblyName *aname)
2614 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2616 return aname->culture;
2620 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2622 if (aname->public_key_token [0])
2623 return aname->public_key_token;
2628 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2631 *minor = aname->minor;
2633 *build = aname->build;
2635 *revision = aname->revision;
2636 return aname->major;
2639 static MonoAssembly*
2640 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2642 gchar *fullpath = NULL;
2644 const char* direntry;
2645 MonoAssemblyName gac_aname;
2646 gint major=-1, minor=0, build=0, revision=0;
2647 gboolean exact_version;
2649 dirhandle = g_dir_open (basepath, 0, NULL);
2653 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2655 while ((direntry = g_dir_read_name (dirhandle))) {
2656 gboolean match = TRUE;
2658 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2661 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2664 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2665 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2669 if (exact_version) {
2670 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2671 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2673 else if (gac_aname.major < major)
2675 else if (gac_aname.major == major) {
2676 if (gac_aname.minor < minor)
2678 else if (gac_aname.minor == minor) {
2679 if (gac_aname.build < build)
2681 else if (gac_aname.build == build && gac_aname.revision <= revision)
2688 major = gac_aname.major;
2689 minor = gac_aname.minor;
2690 build = gac_aname.build;
2691 revision = gac_aname.revision;
2693 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2696 mono_assembly_name_free (&gac_aname);
2699 g_dir_close (dirhandle);
2701 if (fullpath == NULL)
2704 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2711 * mono_assembly_load_with_partial_name:
2712 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2713 * @status: return status code
2715 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2716 * so it might contain a qualified type name, version, culture and token.
2718 * This will load the assembly from the file whose name is derived from the assembly name
2719 * by appending the .dll extension.
2721 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2722 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2723 * if that fails from the GAC.
2725 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2728 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2732 MonoAssemblyName *aname, base_name;
2733 MonoAssemblyName mapped_aname;
2734 gchar *fullname, *gacpath;
2737 memset (&base_name, 0, sizeof (MonoAssemblyName));
2740 if (!mono_assembly_name_parse (name, aname))
2744 * If no specific version has been requested, make sure we load the
2745 * correct version for system assemblies.
2747 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2748 aname = mono_assembly_remap_version (aname, &mapped_aname);
2750 res = mono_assembly_loaded (aname);
2752 mono_assembly_name_free (aname);
2756 res = invoke_assembly_preload_hook (aname, assemblies_path);
2758 res->in_gac = FALSE;
2759 mono_assembly_name_free (aname);
2763 fullname = g_strdup_printf ("%s.dll", aname->name);
2765 if (extra_gac_paths) {
2766 paths = extra_gac_paths;
2767 while (!res && *paths) {
2768 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2769 res = probe_for_partial_name (gacpath, fullname, aname, status);
2778 mono_assembly_name_free (aname);
2782 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2783 res = probe_for_partial_name (gacpath, fullname, aname, status);
2787 mono_assembly_name_free (aname);
2792 MonoDomain *domain = mono_domain_get ();
2794 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2795 if (!is_ok (&error)) {
2796 mono_error_cleanup (&error);
2797 if (*status == MONO_IMAGE_OK)
2798 *status = MONO_IMAGE_IMAGE_INVALID;
2806 mono_assembly_is_in_gac (const gchar *filename)
2808 const gchar *rootdir;
2812 if (filename == NULL)
2815 for (paths = extra_gac_paths; paths && *paths; paths++) {
2816 if (strstr (*paths, filename) != *paths)
2819 gp = (gchar *) (filename + strlen (*paths));
2820 if (*gp != G_DIR_SEPARATOR)
2823 if (strncmp (gp, "lib", 3))
2826 if (*gp != G_DIR_SEPARATOR)
2829 if (strncmp (gp, "mono", 4))
2832 if (*gp != G_DIR_SEPARATOR)
2835 if (strncmp (gp, "gac", 3))
2838 if (*gp != G_DIR_SEPARATOR)
2844 rootdir = mono_assembly_getrootdir ();
2845 if (strstr (filename, rootdir) != filename)
2848 gp = (gchar *) (filename + strlen (rootdir));
2849 if (*gp != G_DIR_SEPARATOR)
2852 if (strncmp (gp, "mono", 4))
2855 if (*gp != G_DIR_SEPARATOR)
2858 if (strncmp (gp, "gac", 3))
2861 if (*gp != G_DIR_SEPARATOR)
2867 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2870 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2874 if (strstr (aname->name, ".dll")) {
2875 len = strlen (aname->name) - 4;
2876 name = (gchar *)g_malloc (len + 1);
2877 memcpy (name, aname->name, len);
2880 name = g_strdup (aname->name);
2883 culture = g_utf8_strdown (aname->culture, -1);
2885 culture = g_strdup ("");
2887 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2888 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2892 filename = g_strconcat (pname, ".dll", NULL);
2893 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2899 if (extra_gac_paths) {
2900 paths = extra_gac_paths;
2901 while (!image && *paths) {
2902 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2903 "lib", "mono", "gac", subpath, NULL);
2904 image = mono_image_open (fullpath, NULL);
2915 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2916 "mono", "gac", subpath, NULL);
2917 image = mono_image_open (fullpath, NULL);
2924 static MonoAssemblyName*
2925 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2927 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2928 dest_name->major = info->new_version.major;
2929 dest_name->minor = info->new_version.minor;
2930 dest_name->build = info->new_version.build;
2931 dest_name->revision = info->new_version.revision;
2936 /* LOCKING: assembly_binding lock must be held */
2937 static MonoAssemblyBindingInfo*
2938 search_binding_loaded (MonoAssemblyName *aname)
2942 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2943 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2944 if (assembly_binding_maps_name (info, aname))
2951 static inline gboolean
2952 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2954 if (left->major != right->major || left->minor != right->minor ||
2955 left->build != right->build || left->revision != right->revision)
2961 static inline gboolean
2962 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2964 if (left->has_old_version_bottom != right->has_old_version_bottom)
2967 if (left->has_old_version_top != right->has_old_version_top)
2970 if (left->has_new_version != right->has_new_version)
2973 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2976 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2979 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2985 /* LOCKING: assumes all the necessary locks are held */
2987 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2989 MonoAssemblyBindingInfo *info_copy;
2991 MonoAssemblyBindingInfo *info_tmp;
2992 MonoDomain *domain = (MonoDomain*)user_data;
2997 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2998 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2999 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3003 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3004 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3006 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3008 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3010 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3014 get_version_number (int major, int minor)
3016 return major * 256 + minor;
3019 static inline gboolean
3020 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3022 int aname_version_number = get_version_number (aname->major, aname->minor);
3023 if (!info->has_old_version_bottom)
3026 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3029 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3032 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3033 info->major = aname->major;
3034 info->minor = aname->minor;
3039 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3040 static MonoAssemblyBindingInfo*
3041 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3043 MonoAssemblyBindingInfo *info;
3046 if (!domain->assembly_bindings)
3050 for (list = domain->assembly_bindings; list; list = list->next) {
3051 info = (MonoAssemblyBindingInfo *)list->data;
3052 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3058 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3059 info->has_new_version && assembly_binding_maps_name (info, aname))
3060 info->is_valid = TRUE;
3062 info->is_valid = FALSE;
3068 static MonoAssemblyName*
3069 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3072 MonoAssemblyBindingInfo *info, *info2;
3076 if (aname->public_key_token [0] == 0)
3079 domain = mono_domain_get ();
3081 mono_assembly_binding_lock ();
3082 info = search_binding_loaded (aname);
3083 mono_assembly_binding_unlock ();
3086 mono_domain_lock (domain);
3087 info = get_per_domain_assembly_binding_info (domain, aname);
3088 mono_domain_unlock (domain);
3092 if (!check_policy_versions (info, aname))
3095 mono_assembly_bind_version (info, aname, dest_name);
3099 if (domain && domain->setup && domain->setup->configuration_file) {
3100 mono_domain_lock (domain);
3101 if (!domain->assembly_bindings_parsed) {
3102 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3103 /* expect this to succeed because mono_domain_set_options_from_config () did
3104 * the same thing when the domain was created. */
3105 mono_error_assert_ok (&error);
3107 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3109 if (!domain_config_file_path)
3110 domain_config_file_path = domain_config_file_name;
3112 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3113 domain->assembly_bindings_parsed = TRUE;
3114 if (domain_config_file_name != domain_config_file_path)
3115 g_free (domain_config_file_name);
3116 g_free (domain_config_file_path);
3119 info2 = get_per_domain_assembly_binding_info (domain, aname);
3122 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3123 info->name = g_strdup (info2->name);
3124 info->culture = g_strdup (info2->culture);
3125 info->domain_id = domain->domain_id;
3128 mono_domain_unlock (domain);
3132 info = g_new0 (MonoAssemblyBindingInfo, 1);
3133 info->major = aname->major;
3134 info->minor = aname->minor;
3137 if (!info->is_valid) {
3138 ppimage = mono_assembly_load_publisher_policy (aname);
3140 get_publisher_policy_info (ppimage, aname, info);
3141 mono_image_close (ppimage);
3145 /* Define default error value if needed */
3146 if (!info->is_valid) {
3147 info->name = g_strdup (aname->name);
3148 info->culture = g_strdup (aname->culture);
3149 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3152 mono_assembly_binding_lock ();
3153 info2 = search_binding_loaded (aname);
3155 /* This binding was added by another thread
3157 mono_assembly_binding_info_free (info);
3162 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3164 mono_assembly_binding_unlock ();
3166 if (!info->is_valid || !check_policy_versions (info, aname))
3169 mono_assembly_bind_version (info, aname, dest_name);
3174 * mono_assembly_load_from_gac
3176 * @aname: The assembly name object
3178 static MonoAssembly*
3179 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3181 MonoAssembly *result = NULL;
3182 gchar *name, *version, *culture, *fullpath, *subpath;
3187 if (aname->public_key_token [0] == 0) {
3191 if (strstr (aname->name, ".dll")) {
3192 len = strlen (filename) - 4;
3193 name = (gchar *)g_malloc (len + 1);
3194 memcpy (name, aname->name, len);
3197 name = g_strdup (aname->name);
3200 if (aname->culture) {
3201 culture = g_utf8_strdown (aname->culture, -1);
3203 culture = g_strdup ("");
3206 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3207 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3208 aname->minor, aname->build, aname->revision,
3212 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3217 if (extra_gac_paths) {
3218 paths = extra_gac_paths;
3219 while (!result && *paths) {
3220 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3221 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3228 result->in_gac = TRUE;
3233 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3234 "mono", "gac", subpath, NULL);
3235 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3239 result->in_gac = TRUE;
3247 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3250 MonoAssemblyName *aname;
3253 /* g_print ("corlib already loaded\n"); */
3257 // In native client, Corlib is embedded in the executable as static variable corlibData
3258 #if defined(__native_client__)
3259 if (corlibData != NULL && corlibSize != 0) {
3261 /* First "FALSE" instructs mono not to make a copy. */
3262 /* Second "FALSE" says this is not just a ref. */
3263 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3264 if (image == NULL || status != 0)
3265 g_print("mono_image_open_from_data_full failed: %d\n", status);
3266 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3267 if (corlib == NULL || status != 0)
3268 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3274 // A nonstandard preload hook may provide a special mscorlib assembly
3275 aname = mono_assembly_name_new ("mscorlib.dll");
3276 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3277 mono_assembly_name_free (aname);
3280 goto return_corlib_and_facades;
3282 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3283 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3284 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3286 goto return_corlib_and_facades;
3289 /* Normal case: Load corlib from mono/<version> */
3290 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3291 if (assemblies_path) { // Custom assemblies path
3292 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3294 g_free (corlib_file);
3295 goto return_corlib_and_facades;
3298 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3299 g_free (corlib_file);
3301 return_corlib_and_facades:
3302 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3303 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3308 static MonoAssembly*
3309 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3311 MonoError refasm_error;
3312 error_init (&refasm_error);
3313 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3316 mono_error_cleanup (&refasm_error);
3322 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3323 const char *basedir,
3324 MonoImageOpenStatus *status,
3327 MonoAssembly *result;
3328 char *fullpath, *filename;
3329 MonoAssemblyName maped_aname;
3330 MonoAssemblyName maped_name_pp;
3335 aname = mono_assembly_remap_version (aname, &maped_aname);
3337 /* Reflection only assemblies don't get assembly binding */
3339 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3341 result = mono_assembly_loaded_full (aname, refonly);
3345 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3347 result->in_gac = FALSE;
3351 /* Currently we retrieve the loaded corlib for reflection
3352 * only requests, like a common reflection only assembly
3354 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3355 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3358 len = strlen (aname->name);
3359 for (ext_index = 0; ext_index < 2; ext_index ++) {
3360 ext = ext_index == 0 ? ".dll" : ".exe";
3361 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3362 filename = g_strdup (aname->name);
3363 /* Don't try appending .dll/.exe if it already has one of those extensions */
3366 filename = g_strconcat (aname->name, ext, NULL);
3369 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3376 fullpath = g_build_filename (basedir, filename, NULL);
3377 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3380 result->in_gac = FALSE;
3386 result = load_in_path (filename, default_path, status, refonly, NULL, NULL);
3388 result->in_gac = FALSE;
3398 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3400 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3403 /* Try a postload search hook */
3404 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3405 result = prevent_reference_assembly_from_running (result, refonly);
3411 * mono_assembly_load_full:
3412 * @aname: A MonoAssemblyName with the assembly name to load.
3413 * @basedir: A directory to look up the assembly at.
3414 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3415 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3417 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3418 * attempts to load the assembly from that directory before probing the standard locations.
3420 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3421 * assembly binding takes place.
3423 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3424 * value pointed by status is updated with an error code.
3427 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3429 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3433 * mono_assembly_load:
3434 * @aname: A MonoAssemblyName with the assembly name to load.
3435 * @basedir: A directory to look up the assembly at.
3436 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3438 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3439 * attempts to load the assembly from that directory before probing the standard locations.
3441 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3442 * value pointed by status is updated with an error code.
3445 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3447 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3451 * mono_assembly_loaded_full:
3452 * @aname: an assembly to look for.
3453 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3455 * This is used to determine if the specified assembly has been loaded
3456 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3457 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3460 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3463 MonoAssemblyName maped_aname;
3465 aname = mono_assembly_remap_version (aname, &maped_aname);
3467 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3473 * mono_assembly_loaded:
3474 * @aname: an assembly to look for.
3476 * This is used to determine if the specified assembly has been loaded
3478 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3479 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3482 mono_assembly_loaded (MonoAssemblyName *aname)
3484 return mono_assembly_loaded_full (aname, FALSE);
3488 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3490 if (assembly == NULL || assembly == REFERENCE_MISSING)
3493 if (assembly_is_dynamic (assembly)) {
3495 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3496 for (i = 0; i < dynimg->image.module_count; ++i)
3497 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3498 mono_dynamic_image_release_gc_roots (dynimg);
3503 * Returns whether mono_assembly_close_finish() must be called as
3504 * well. See comment for mono_image_close_except_pools() for why we
3505 * unload in two steps.
3508 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3511 g_return_val_if_fail (assembly != NULL, FALSE);
3513 if (assembly == REFERENCE_MISSING)
3516 /* Might be 0 already */
3517 if (InterlockedDecrement (&assembly->ref_count) > 0)
3520 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3522 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3524 mono_debug_close_image (assembly->image);
3526 mono_assemblies_lock ();
3527 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3528 mono_assemblies_unlock ();
3530 assembly->image->assembly = NULL;
3532 if (!mono_image_close_except_pools (assembly->image))
3533 assembly->image = NULL;
3535 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3536 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3537 mono_assembly_name_free (fname);
3540 g_slist_free (assembly->friend_assembly_names);
3541 g_free (assembly->basedir);
3543 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3549 mono_assembly_close_finish (MonoAssembly *assembly)
3551 g_assert (assembly && assembly != REFERENCE_MISSING);
3553 if (assembly->image)
3554 mono_image_close_finish (assembly->image);
3556 if (assembly_is_dynamic (assembly)) {
3557 g_free ((char*)assembly->aname.culture);
3564 * mono_assembly_close:
3565 * @assembly: the assembly to release.
3567 * This method releases a reference to the @assembly. The assembly is
3568 * only released when all the outstanding references to it are released.
3571 mono_assembly_close (MonoAssembly *assembly)
3573 if (mono_assembly_close_except_image_pools (assembly))
3574 mono_assembly_close_finish (assembly);
3578 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3581 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3582 mono_error_assert_ok (&error);
3587 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3589 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3594 * mono_assembly_foreach:
3595 * @func: function to invoke for each assembly loaded
3596 * @user_data: data passed to the callback
3598 * Invokes the provided @func callback for each assembly loaded into
3599 * the runtime. The first parameter passed to the callback is the
3600 * `MonoAssembly*`, and the second parameter is the @user_data.
3602 * This is done for all assemblies loaded in the runtime, not just
3603 * those loaded in the current application domain.
3606 mono_assembly_foreach (GFunc func, gpointer user_data)
3611 * We make a copy of the list to avoid calling the callback inside the
3612 * lock, which could lead to deadlocks.
3614 mono_assemblies_lock ();
3615 copy = g_list_copy (loaded_assemblies);
3616 mono_assemblies_unlock ();
3618 g_list_foreach (loaded_assemblies, func, user_data);
3624 * mono_assemblies_cleanup:
3626 * Free all resources used by this module.
3629 mono_assemblies_cleanup (void)
3633 mono_os_mutex_destroy (&assemblies_mutex);
3634 mono_os_mutex_destroy (&assembly_binding_mutex);
3636 for (l = loaded_assembly_bindings; l; l = l->next) {
3637 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3639 mono_assembly_binding_info_free (info);
3642 g_slist_free (loaded_assembly_bindings);
3644 free_assembly_load_hooks ();
3645 free_assembly_search_hooks ();
3646 free_assembly_preload_hooks ();
3649 /*LOCKING takes the assembly_binding lock*/
3651 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3655 mono_assembly_binding_lock ();
3656 iter = &loaded_assembly_bindings;
3659 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3661 if (info->domain_id == domain_id) {
3663 mono_assembly_binding_info_free (info);
3670 mono_assembly_binding_unlock ();
3674 * Holds the assembly of the application, for
3675 * System.Diagnostics.Process::MainModule
3677 static MonoAssembly *main_assembly=NULL;
3680 mono_assembly_set_main (MonoAssembly *assembly)
3682 main_assembly = assembly;
3686 * mono_assembly_get_main:
3688 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3691 mono_assembly_get_main (void)
3693 return (main_assembly);
3697 * mono_assembly_get_image:
3698 * @assembly: The assembly to retrieve the image from
3700 * Returns: the MonoImage associated with this assembly.
3703 mono_assembly_get_image (MonoAssembly *assembly)
3705 return assembly->image;
3709 * mono_assembly_get_name:
3710 * @assembly: The assembly to retrieve the name from
3712 * The returned name's lifetime is the same as @assembly's.
3714 * Returns: the MonoAssemblyName associated with this assembly.
3717 mono_assembly_get_name (MonoAssembly *assembly)
3719 return &assembly->aname;
3723 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3725 bundles = assemblies;
3728 #define MONO_DECLSEC_FORMAT_10 0x3C
3729 #define MONO_DECLSEC_FORMAT_20 0x2E
3730 #define MONO_DECLSEC_FIELD 0x53
3731 #define MONO_DECLSEC_PROPERTY 0x54
3733 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3734 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3735 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3736 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3737 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3740 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3744 case MONO_DECLSEC_PROPERTY:
3746 case MONO_DECLSEC_FIELD:
3748 *abort_decoding = TRUE;
3753 if (*p++ != MONO_TYPE_BOOLEAN) {
3754 *abort_decoding = TRUE;
3758 /* property name length */
3759 len = mono_metadata_decode_value (p, &p);
3761 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3772 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3774 int i, j, num, len, params_len;
3776 if (*p == MONO_DECLSEC_FORMAT_10) {
3777 gsize read, written;
3778 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3780 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3786 if (*p++ != MONO_DECLSEC_FORMAT_20)
3789 /* number of encoded permission attributes */
3790 num = mono_metadata_decode_value (p, &p);
3791 for (i = 0; i < num; ++i) {
3792 gboolean is_valid = FALSE;
3793 gboolean abort_decoding = FALSE;
3795 /* attribute name length */
3796 len = mono_metadata_decode_value (p, &p);
3798 /* We don't really need to fully decode the type. Comparing the name is enough */
3799 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3803 /*size of the params table*/
3804 params_len = mono_metadata_decode_value (p, &p);
3806 const char *params_end = p + params_len;
3808 /* number of parameters */
3809 len = mono_metadata_decode_value (p, &p);
3811 for (j = 0; j < len; ++j) {
3812 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3828 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3831 guint32 cols [MONO_DECL_SECURITY_SIZE];
3835 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3836 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3838 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3840 for (i = 0; i < t->rows; ++i) {
3841 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3842 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3844 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3847 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3848 len = mono_metadata_decode_blob_size (blob, &blob);
3852 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3853 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3858 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);