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)
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_full (fullpath, status, refonly);
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)
1683 MonoImageOpenStatus def_status;
1686 gboolean loaded_from_bundle;
1688 g_return_val_if_fail (filename != NULL, NULL);
1691 status = &def_status;
1692 *status = MONO_IMAGE_OK;
1694 if (strncmp (filename, "file://", 7) == 0) {
1695 GError *error = NULL;
1696 gchar *uri = (gchar *) filename;
1700 * MS allows file://c:/... and fails on file://localhost/c:/...
1701 * They also throw an IndexOutOfRangeException if "file://"
1704 uri = g_strdup_printf ("file:///%s", uri + 7);
1707 uri = mono_escape_uri_string (tmpuri);
1708 fname = g_filename_from_uri (uri, NULL, &error);
1711 if (tmpuri != filename)
1714 if (error != NULL) {
1715 g_warning ("%s\n", error->message);
1716 g_error_free (error);
1717 fname = g_strdup (filename);
1720 fname = g_strdup (filename);
1723 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1724 "Assembly Loader probing location: '%s'.", fname);
1727 if (!mono_assembly_is_in_gac (fname)) {
1729 new_fname = mono_make_shadow_copy (fname, &error);
1730 if (!is_ok (&error)) {
1731 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1732 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1733 mono_error_cleanup (&error);
1734 *status = MONO_IMAGE_IMAGE_INVALID;
1739 if (new_fname && new_fname != fname) {
1742 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1743 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1748 // If VM built with mkbundle
1749 loaded_from_bundle = FALSE;
1750 if (bundles != NULL) {
1751 image = mono_assembly_open_from_bundle (fname, status, refonly);
1752 loaded_from_bundle = image != NULL;
1756 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1759 if (*status == MONO_IMAGE_OK)
1760 *status = MONO_IMAGE_ERROR_ERRNO;
1765 if (image->assembly) {
1766 /* Already loaded by another appdomain */
1767 mono_assembly_invoke_load_hook (image->assembly);
1768 mono_image_close (image);
1770 return image->assembly;
1773 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1776 if (!loaded_from_bundle)
1777 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1778 "Assembly Loader loaded assembly from location: '%s'.", filename);
1780 mono_config_for_assembly (ass->image);
1783 /* Clear the reference added by mono_image_open */
1784 mono_image_close (image);
1792 free_item (gpointer val, gpointer user_data)
1798 * mono_assembly_load_friends:
1801 * Load the list of friend assemblies that are allowed to access
1802 * the assembly's internal types and members. They are stored as assembly
1803 * names in custom attributes.
1805 * This is an internal method, we need this because when we load mscorlib
1806 * we do not have the internals visible cattr loaded yet,
1807 * so we need to load these after we initialize the runtime.
1809 * LOCKING: Acquires the assemblies lock plus the loader lock.
1812 mono_assembly_load_friends (MonoAssembly* ass)
1816 MonoCustomAttrInfo* attrs;
1819 if (ass->friend_assembly_names_inited)
1822 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1823 mono_error_assert_ok (&error);
1825 mono_assemblies_lock ();
1826 ass->friend_assembly_names_inited = TRUE;
1827 mono_assemblies_unlock ();
1831 mono_assemblies_lock ();
1832 if (ass->friend_assembly_names_inited) {
1833 mono_assemblies_unlock ();
1836 mono_assemblies_unlock ();
1840 * We build the list outside the assemblies lock, the worse that can happen
1841 * is that we'll need to free the allocated list.
1843 for (i = 0; i < attrs->num_attrs; ++i) {
1844 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1845 MonoAssemblyName *aname;
1847 /* Do some sanity checking */
1848 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1850 if (attr->data_size < 4)
1852 data = (const char*)attr->data;
1853 /* 0xFF means null string, see custom attr format */
1854 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1856 mono_metadata_decode_value (data + 2, &data);
1857 aname = g_new0 (MonoAssemblyName, 1);
1858 /*g_print ("friend ass: %s\n", data);*/
1859 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1860 list = g_slist_prepend (list, aname);
1865 mono_custom_attrs_free (attrs);
1867 mono_assemblies_lock ();
1868 if (ass->friend_assembly_names_inited) {
1869 mono_assemblies_unlock ();
1870 g_slist_foreach (list, free_item, NULL);
1871 g_slist_free (list);
1874 ass->friend_assembly_names = list;
1876 /* Because of the double checked locking pattern above */
1877 mono_memory_barrier ();
1878 ass->friend_assembly_names_inited = TRUE;
1879 mono_assemblies_unlock ();
1882 struct HasReferenceAssemblyAttributeIterData {
1887 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1889 gboolean stop_scanning = FALSE;
1890 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1892 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1893 /* Note we don't check the assembly name, same as coreCLR. */
1894 iter_data->has_attr = TRUE;
1895 stop_scanning = TRUE;
1898 return stop_scanning;
1902 * mono_assembly_has_reference_assembly_attribute:
1903 * @assembly: a MonoAssembly
1904 * @error: set on error.
1906 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1907 * On error returns FALSE and sets @error.
1910 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1915 * This might be called during assembly loading, so do everything using the low-level
1919 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1921 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1923 return iter_data.has_attr;
1927 * mono_assembly_open:
1928 * @filename: Opens the assembly pointed out by this name
1929 * @status: return status code
1931 * This loads an assembly from the specified @filename. The @filename allows
1932 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1933 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1934 * is treated as a local path.
1936 * First, an attempt is made to load the assembly from the bundled executable (for those
1937 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1938 * assembly has been registered as an embedded assembly). If this is not the case, then
1939 * the assembly is loaded from disk using `api:mono_image_open_full`.
1941 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1942 * the assembly is made.
1944 * Return: a pointer to the MonoAssembly if @filename contains a valid
1945 * assembly or NULL on error. Details about the error are stored in the
1949 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1951 return mono_assembly_open_full (filename, status, FALSE);
1955 * mono_assembly_load_from_full:
1956 * @image: Image to load the assembly from
1957 * @fname: assembly name to associate with the assembly
1958 * @status: returns the status condition
1959 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1961 * If the provided @image has an assembly reference, it will process the given
1962 * image as an assembly with the given name.
1964 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1966 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1967 * set to #MONO_IMAGE_OK; or NULL on error.
1969 * If there is an error loading the assembly the @status will indicate the
1970 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1971 * image did not contain an assembly reference table.
1974 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1975 MonoImageOpenStatus *status, gboolean refonly)
1977 MonoAssembly *ass, *ass2;
1980 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1981 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1982 *status = MONO_IMAGE_IMAGE_INVALID;
1986 #if defined (HOST_WIN32)
1991 tmp_fn = g_strdup (fname);
1992 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1993 if (tmp_fn [i] == '/')
1997 base_dir = absolute_dir (tmp_fn);
2001 base_dir = absolute_dir (fname);
2005 * Create assembly struct, and enter it into the assembly cache
2007 ass = g_new0 (MonoAssembly, 1);
2008 ass->basedir = base_dir;
2009 ass->ref_only = refonly;
2012 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2014 mono_assembly_fill_assembly_name (image, &ass->aname);
2016 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2017 // MS.NET doesn't support loading other mscorlibs
2020 mono_image_addref (mono_defaults.corlib);
2021 *status = MONO_IMAGE_OK;
2022 return mono_defaults.corlib->assembly;
2025 /* Add a non-temporary reference because of ass->image */
2026 mono_image_addref (image);
2028 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);
2031 * The load hooks might take locks so we can't call them while holding the
2034 if (ass->aname.name) {
2035 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2039 mono_image_close (image);
2040 *status = MONO_IMAGE_OK;
2045 /* We need to check for ReferenceAssmeblyAttribute before we
2046 * mark the assembly as loaded and before we fire the load
2047 * hook. Otherwise mono_domain_fire_assembly_load () in
2048 * appdomain.c will cache a mapping from the assembly name to
2049 * this image and we won't be able to look for a different
2053 MonoError refasm_error;
2054 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2055 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2058 mono_image_close (image);
2059 *status = MONO_IMAGE_IMAGE_INVALID;
2062 mono_error_cleanup (&refasm_error);
2065 mono_assemblies_lock ();
2067 if (image->assembly) {
2069 * This means another thread has already loaded the assembly, but not yet
2070 * called the load hooks so the search hook can't find the assembly.
2072 mono_assemblies_unlock ();
2073 ass2 = image->assembly;
2076 mono_image_close (image);
2077 *status = MONO_IMAGE_OK;
2081 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2083 image->assembly = ass;
2085 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2086 mono_assemblies_unlock ();
2089 if (image->is_module_handle)
2090 mono_image_fixup_vtable (image);
2093 mono_assembly_invoke_load_hook (ass);
2095 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2101 * mono_assembly_load_from:
2102 * @image: Image to load the assembly from
2103 * @fname: assembly name to associate with the assembly
2104 * @status: return status code
2106 * If the provided @image has an assembly reference, it will process the given
2107 * image as an assembly with the given name.
2109 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2111 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2112 * @refonly parameter set to FALSE.
2113 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2114 * set to #MONO_IMAGE_OK; or NULL on error.
2116 * If there is an error loading the assembly the @status will indicate the
2117 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2118 * image did not contain an assembly reference table.
2122 mono_assembly_load_from (MonoImage *image, const char *fname,
2123 MonoImageOpenStatus *status)
2125 return mono_assembly_load_from_full (image, fname, status, FALSE);
2129 * mono_assembly_name_free:
2130 * @aname: assembly name to free
2132 * Frees the provided assembly name object.
2133 * (it does not frees the object itself, only the name members).
2136 mono_assembly_name_free (MonoAssemblyName *aname)
2141 g_free ((void *) aname->name);
2142 g_free ((void *) aname->culture);
2143 g_free ((void *) aname->hash_value);
2144 g_free ((guint8*) aname->public_key);
2148 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2151 gchar header [16], val, *arr;
2152 gint i, j, offset, bitlen, keylen, pkeylen;
2154 keylen = strlen (key) >> 1;
2158 /* allow the ECMA standard key */
2159 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2161 *pubkey = g_strdup (key);
2167 val = g_ascii_xdigit_value (key [0]) << 4;
2168 val |= g_ascii_xdigit_value (key [1]);
2173 val = g_ascii_xdigit_value (key [24]);
2174 val |= g_ascii_xdigit_value (key [25]);
2186 /* We need the first 16 bytes
2187 * to check whether this key is valid or not */
2188 pkeylen = strlen (pkey) >> 1;
2192 for (i = 0, j = 0; i < 16; i++) {
2193 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2194 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2197 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2198 header [1] != 0x02 || /* Version (0x02) */
2199 header [2] != 0x00 || /* Reserved (word) */
2200 header [3] != 0x00 ||
2201 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2204 /* Based on this length, we _should_ be able to know if the length is right */
2205 bitlen = read32 (header + 12) >> 3;
2206 if ((bitlen + 16 + 4) != pkeylen)
2209 /* parsing is OK and the public key itself is not requested back */
2213 /* Encode the size of the blob */
2215 if (keylen <= 127) {
2216 arr = (gchar *)g_malloc (keylen + 1);
2217 arr [offset++] = keylen;
2219 arr = (gchar *)g_malloc (keylen + 2);
2220 arr [offset++] = 0x80; /* 10bs */
2221 arr [offset++] = keylen;
2224 for (i = offset, j = 0; i < keylen + offset; i++) {
2225 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2226 arr [i] |= g_ascii_xdigit_value (key [j++]);
2235 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)
2237 gint major, minor, build, revision;
2240 gchar *pkey, *pkeyptr, *encoded, tok [8];
2242 memset (aname, 0, sizeof (MonoAssemblyName));
2245 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2246 if (version_parts < 2 || version_parts > 4)
2249 /* FIXME: we should set build & revision to -1 (instead of 0)
2250 if these are not set in the version string. That way, later on,
2251 we can still determine if these were specified. */
2252 aname->major = major;
2253 aname->minor = minor;
2254 if (version_parts >= 3)
2255 aname->build = build;
2258 if (version_parts == 4)
2259 aname->revision = revision;
2261 aname->revision = 0;
2264 aname->flags = flags;
2266 aname->name = g_strdup (name);
2269 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2270 aname->culture = g_strdup ("");
2272 aname->culture = g_strdup (culture);
2275 if (token && strncmp (token, "null", 4) != 0) {
2278 /* the constant includes the ending NULL, hence the -1 */
2279 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2280 mono_assembly_name_free (aname);
2283 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2284 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2290 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2291 mono_assembly_name_free (aname);
2296 if (save_public_key)
2297 aname->public_key = (guint8*)pkey;
2300 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2304 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2305 // We also need to generate the key token
2306 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2307 encoded = encode_public_tok ((guchar*) tok, 8);
2308 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2311 if (save_public_key)
2312 aname->public_key = (guint8*) pkey;
2321 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2326 parts = g_strsplit (dirname, "_", 3);
2327 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2332 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2338 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2340 char *eqsign = strchr (pair, '=');
2348 *key = (gchar*)pair;
2349 *keylen = eqsign - *key;
2350 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2352 *value = g_strstrip (eqsign + 1);
2357 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2361 gchar *version = NULL;
2363 gchar *culture = NULL;
2365 gchar *token = NULL;
2369 gchar *retargetable = NULL;
2370 gchar *retargetable_uq;
2374 gchar *value, *part_name;
2375 guint32 part_name_len;
2378 gboolean version_defined;
2379 gboolean token_defined;
2381 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2383 if (!is_version_defined)
2384 is_version_defined = &version_defined;
2385 *is_version_defined = FALSE;
2386 if (!is_token_defined)
2387 is_token_defined = &token_defined;
2388 *is_token_defined = FALSE;
2390 parts = tmp = g_strsplit (name, ",", 6);
2391 if (!tmp || !*tmp) {
2396 dllname = g_strstrip (*tmp);
2401 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2402 goto cleanup_and_fail;
2404 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2405 *is_version_defined = TRUE;
2407 if (strlen (version) == 0) {
2408 goto cleanup_and_fail;
2414 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2416 if (strlen (culture) == 0) {
2417 goto cleanup_and_fail;
2423 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2424 *is_token_defined = TRUE;
2426 if (strlen (token) == 0) {
2427 goto cleanup_and_fail;
2433 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2435 if (strlen (key) == 0) {
2436 goto cleanup_and_fail;
2442 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2443 retargetable = value;
2444 retargetable_uq = unquote (retargetable);
2445 if (retargetable_uq != NULL)
2446 retargetable = retargetable_uq;
2448 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2449 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2450 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2451 g_free (retargetable_uq);
2452 goto cleanup_and_fail;
2455 g_free (retargetable_uq);
2460 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2462 procarch_uq = unquote (procarch);
2463 if (procarch_uq != NULL)
2464 procarch = procarch_uq;
2466 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2467 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2468 else if (!g_ascii_strcasecmp (procarch, "X86"))
2469 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2470 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2471 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2472 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2473 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2475 g_free (procarch_uq);
2476 goto cleanup_and_fail;
2479 g_free (procarch_uq);
2488 /* if retargetable flag is set, then we must have a fully qualified name */
2489 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2490 goto cleanup_and_fail;
2493 dllname_uq = unquote (dllname);
2494 version_uq = unquote (version);
2495 culture_uq = unquote (culture);
2496 token_uq = unquote (token);
2497 key_uq = unquote (key);
2499 res = build_assembly_name (
2500 dllname_uq == NULL ? dllname : dllname_uq,
2501 version_uq == NULL ? version : version_uq,
2502 culture_uq == NULL ? culture : culture_uq,
2503 token_uq == NULL ? token : token_uq,
2504 key_uq == NULL ? key : key_uq,
2505 flags, arch, aname, save_public_key);
2507 g_free (dllname_uq);
2508 g_free (version_uq);
2509 g_free (culture_uq);
2522 unquote (const char *str)
2530 slen = strlen (str);
2534 if (*str != '\'' && *str != '\"')
2537 end = str + slen - 1;
2541 return g_strndup (str + 1, slen - 2);
2545 * mono_assembly_name_parse:
2546 * @name: name to parse
2547 * @aname: the destination assembly name
2549 * Parses an assembly qualified type name and assigns the name,
2550 * version, culture and token to the provided assembly name object.
2552 * Returns: TRUE if the name could be parsed.
2555 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2557 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2561 * mono_assembly_name_new:
2562 * @name: name to parse
2564 * Allocate a new MonoAssemblyName and fill its values from the
2567 * Returns: a newly allocated structure or NULL if there was any failure.
2570 mono_assembly_name_new (const char *name)
2572 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2573 if (mono_assembly_name_parse (name, aname))
2580 mono_assembly_name_get_name (MonoAssemblyName *aname)
2586 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2588 return aname->culture;
2592 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2594 if (aname->public_key_token [0])
2595 return aname->public_key_token;
2600 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2603 *minor = aname->minor;
2605 *build = aname->build;
2607 *revision = aname->revision;
2608 return aname->major;
2611 static MonoAssembly*
2612 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2614 gchar *fullpath = NULL;
2616 const char* direntry;
2617 MonoAssemblyName gac_aname;
2618 gint major=-1, minor=0, build=0, revision=0;
2619 gboolean exact_version;
2621 dirhandle = g_dir_open (basepath, 0, NULL);
2625 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2627 while ((direntry = g_dir_read_name (dirhandle))) {
2628 gboolean match = TRUE;
2630 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2633 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2636 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2637 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2641 if (exact_version) {
2642 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2643 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2645 else if (gac_aname.major < major)
2647 else if (gac_aname.major == major) {
2648 if (gac_aname.minor < minor)
2650 else if (gac_aname.minor == minor) {
2651 if (gac_aname.build < build)
2653 else if (gac_aname.build == build && gac_aname.revision <= revision)
2660 major = gac_aname.major;
2661 minor = gac_aname.minor;
2662 build = gac_aname.build;
2663 revision = gac_aname.revision;
2665 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2668 mono_assembly_name_free (&gac_aname);
2671 g_dir_close (dirhandle);
2673 if (fullpath == NULL)
2676 MonoAssembly *res = mono_assembly_open (fullpath, status);
2683 * mono_assembly_load_with_partial_name:
2684 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2685 * @status: return status code
2687 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2688 * so it might contain a qualified type name, version, culture and token.
2690 * This will load the assembly from the file whose name is derived from the assembly name
2691 * by appending the .dll extension.
2693 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2694 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2695 * if that fails from the GAC.
2697 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2700 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2704 MonoAssemblyName *aname, base_name;
2705 MonoAssemblyName mapped_aname;
2706 gchar *fullname, *gacpath;
2709 memset (&base_name, 0, sizeof (MonoAssemblyName));
2712 if (!mono_assembly_name_parse (name, aname))
2716 * If no specific version has been requested, make sure we load the
2717 * correct version for system assemblies.
2719 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2720 aname = mono_assembly_remap_version (aname, &mapped_aname);
2722 res = mono_assembly_loaded (aname);
2724 mono_assembly_name_free (aname);
2728 res = invoke_assembly_preload_hook (aname, assemblies_path);
2730 res->in_gac = FALSE;
2731 mono_assembly_name_free (aname);
2735 fullname = g_strdup_printf ("%s.dll", aname->name);
2737 if (extra_gac_paths) {
2738 paths = extra_gac_paths;
2739 while (!res && *paths) {
2740 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2741 res = probe_for_partial_name (gacpath, fullname, aname, status);
2750 mono_assembly_name_free (aname);
2754 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2755 res = probe_for_partial_name (gacpath, fullname, aname, status);
2759 mono_assembly_name_free (aname);
2764 MonoDomain *domain = mono_domain_get ();
2766 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2767 if (!is_ok (&error)) {
2768 mono_error_cleanup (&error);
2769 if (*status == MONO_IMAGE_OK)
2770 *status = MONO_IMAGE_IMAGE_INVALID;
2778 mono_assembly_is_in_gac (const gchar *filename)
2780 const gchar *rootdir;
2784 if (filename == NULL)
2787 for (paths = extra_gac_paths; paths && *paths; paths++) {
2788 if (strstr (*paths, filename) != *paths)
2791 gp = (gchar *) (filename + strlen (*paths));
2792 if (*gp != G_DIR_SEPARATOR)
2795 if (strncmp (gp, "lib", 3))
2798 if (*gp != G_DIR_SEPARATOR)
2801 if (strncmp (gp, "mono", 4))
2804 if (*gp != G_DIR_SEPARATOR)
2807 if (strncmp (gp, "gac", 3))
2810 if (*gp != G_DIR_SEPARATOR)
2816 rootdir = mono_assembly_getrootdir ();
2817 if (strstr (filename, rootdir) != filename)
2820 gp = (gchar *) (filename + strlen (rootdir));
2821 if (*gp != G_DIR_SEPARATOR)
2824 if (strncmp (gp, "mono", 4))
2827 if (*gp != G_DIR_SEPARATOR)
2830 if (strncmp (gp, "gac", 3))
2833 if (*gp != G_DIR_SEPARATOR)
2839 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2842 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2846 if (strstr (aname->name, ".dll")) {
2847 len = strlen (aname->name) - 4;
2848 name = (gchar *)g_malloc (len + 1);
2849 memcpy (name, aname->name, len);
2852 name = g_strdup (aname->name);
2855 culture = g_utf8_strdown (aname->culture, -1);
2857 culture = g_strdup ("");
2859 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2860 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2864 filename = g_strconcat (pname, ".dll", NULL);
2865 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2871 if (extra_gac_paths) {
2872 paths = extra_gac_paths;
2873 while (!image && *paths) {
2874 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2875 "lib", "mono", "gac", subpath, NULL);
2876 image = mono_image_open (fullpath, NULL);
2887 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2888 "mono", "gac", subpath, NULL);
2889 image = mono_image_open (fullpath, NULL);
2896 static MonoAssemblyName*
2897 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2899 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2900 dest_name->major = info->new_version.major;
2901 dest_name->minor = info->new_version.minor;
2902 dest_name->build = info->new_version.build;
2903 dest_name->revision = info->new_version.revision;
2908 /* LOCKING: assembly_binding lock must be held */
2909 static MonoAssemblyBindingInfo*
2910 search_binding_loaded (MonoAssemblyName *aname)
2914 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2915 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2916 if (assembly_binding_maps_name (info, aname))
2923 static inline gboolean
2924 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2926 if (left->major != right->major || left->minor != right->minor ||
2927 left->build != right->build || left->revision != right->revision)
2933 static inline gboolean
2934 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2936 if (left->has_old_version_bottom != right->has_old_version_bottom)
2939 if (left->has_old_version_top != right->has_old_version_top)
2942 if (left->has_new_version != right->has_new_version)
2945 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2948 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2951 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2957 /* LOCKING: assumes all the necessary locks are held */
2959 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2961 MonoAssemblyBindingInfo *info_copy;
2963 MonoAssemblyBindingInfo *info_tmp;
2964 MonoDomain *domain = (MonoDomain*)user_data;
2969 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2970 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2971 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2975 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2976 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2978 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2980 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2982 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2986 get_version_number (int major, int minor)
2988 return major * 256 + minor;
2991 static inline gboolean
2992 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2994 int aname_version_number = get_version_number (aname->major, aname->minor);
2995 if (!info->has_old_version_bottom)
2998 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3001 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3004 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3005 info->major = aname->major;
3006 info->minor = aname->minor;
3011 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3012 static MonoAssemblyBindingInfo*
3013 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3015 MonoAssemblyBindingInfo *info;
3018 if (!domain->assembly_bindings)
3022 for (list = domain->assembly_bindings; list; list = list->next) {
3023 info = (MonoAssemblyBindingInfo *)list->data;
3024 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3030 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3031 info->has_new_version && assembly_binding_maps_name (info, aname))
3032 info->is_valid = TRUE;
3034 info->is_valid = FALSE;
3040 static MonoAssemblyName*
3041 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3044 MonoAssemblyBindingInfo *info, *info2;
3048 if (aname->public_key_token [0] == 0)
3051 domain = mono_domain_get ();
3053 mono_assembly_binding_lock ();
3054 info = search_binding_loaded (aname);
3055 mono_assembly_binding_unlock ();
3058 mono_domain_lock (domain);
3059 info = get_per_domain_assembly_binding_info (domain, aname);
3060 mono_domain_unlock (domain);
3064 if (!check_policy_versions (info, aname))
3067 mono_assembly_bind_version (info, aname, dest_name);
3071 if (domain && domain->setup && domain->setup->configuration_file) {
3072 mono_domain_lock (domain);
3073 if (!domain->assembly_bindings_parsed) {
3074 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3075 /* expect this to succeed because mono_domain_set_options_from_config () did
3076 * the same thing when the domain was created. */
3077 mono_error_assert_ok (&error);
3079 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3081 if (!domain_config_file_path)
3082 domain_config_file_path = domain_config_file_name;
3084 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3085 domain->assembly_bindings_parsed = TRUE;
3086 if (domain_config_file_name != domain_config_file_path)
3087 g_free (domain_config_file_name);
3088 g_free (domain_config_file_path);
3091 info2 = get_per_domain_assembly_binding_info (domain, aname);
3094 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3095 info->name = g_strdup (info2->name);
3096 info->culture = g_strdup (info2->culture);
3097 info->domain_id = domain->domain_id;
3100 mono_domain_unlock (domain);
3104 info = g_new0 (MonoAssemblyBindingInfo, 1);
3105 info->major = aname->major;
3106 info->minor = aname->minor;
3109 if (!info->is_valid) {
3110 ppimage = mono_assembly_load_publisher_policy (aname);
3112 get_publisher_policy_info (ppimage, aname, info);
3113 mono_image_close (ppimage);
3117 /* Define default error value if needed */
3118 if (!info->is_valid) {
3119 info->name = g_strdup (aname->name);
3120 info->culture = g_strdup (aname->culture);
3121 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3124 mono_assembly_binding_lock ();
3125 info2 = search_binding_loaded (aname);
3127 /* This binding was added by another thread
3129 mono_assembly_binding_info_free (info);
3134 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3136 mono_assembly_binding_unlock ();
3138 if (!info->is_valid || !check_policy_versions (info, aname))
3141 mono_assembly_bind_version (info, aname, dest_name);
3146 * mono_assembly_load_from_gac
3148 * @aname: The assembly name object
3150 static MonoAssembly*
3151 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3153 MonoAssembly *result = NULL;
3154 gchar *name, *version, *culture, *fullpath, *subpath;
3159 if (aname->public_key_token [0] == 0) {
3163 if (strstr (aname->name, ".dll")) {
3164 len = strlen (filename) - 4;
3165 name = (gchar *)g_malloc (len + 1);
3166 memcpy (name, aname->name, len);
3169 name = g_strdup (aname->name);
3172 if (aname->culture) {
3173 culture = g_utf8_strdown (aname->culture, -1);
3175 culture = g_strdup ("");
3178 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3179 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3180 aname->minor, aname->build, aname->revision,
3184 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3189 if (extra_gac_paths) {
3190 paths = extra_gac_paths;
3191 while (!result && *paths) {
3192 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3193 result = mono_assembly_open_full (fullpath, status, refonly);
3200 result->in_gac = TRUE;
3205 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3206 "mono", "gac", subpath, NULL);
3207 result = mono_assembly_open_full (fullpath, status, refonly);
3211 result->in_gac = TRUE;
3219 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3222 MonoAssemblyName *aname;
3225 /* g_print ("corlib already loaded\n"); */
3229 // In native client, Corlib is embedded in the executable as static variable corlibData
3230 #if defined(__native_client__)
3231 if (corlibData != NULL && corlibSize != 0) {
3233 /* First "FALSE" instructs mono not to make a copy. */
3234 /* Second "FALSE" says this is not just a ref. */
3235 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3236 if (image == NULL || status != 0)
3237 g_print("mono_image_open_from_data_full failed: %d\n", status);
3238 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3239 if (corlib == NULL || status != 0)
3240 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3246 // A nonstandard preload hook may provide a special mscorlib assembly
3247 aname = mono_assembly_name_new ("mscorlib.dll");
3248 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3249 mono_assembly_name_free (aname);
3252 goto return_corlib_and_facades;
3254 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3255 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3256 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3258 goto return_corlib_and_facades;
3261 /* Normal case: Load corlib from mono/<version> */
3262 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3263 if (assemblies_path) { // Custom assemblies path
3264 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3266 g_free (corlib_file);
3267 goto return_corlib_and_facades;
3270 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3271 g_free (corlib_file);
3273 return_corlib_and_facades:
3274 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3275 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3280 static MonoAssembly*
3281 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3283 MonoError refasm_error;
3284 error_init (&refasm_error);
3285 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3288 mono_error_cleanup (&refasm_error);
3294 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3295 const char *basedir,
3296 MonoImageOpenStatus *status,
3299 MonoAssembly *result;
3300 char *fullpath, *filename;
3301 MonoAssemblyName maped_aname;
3302 MonoAssemblyName maped_name_pp;
3307 aname = mono_assembly_remap_version (aname, &maped_aname);
3309 /* Reflection only assemblies don't get assembly binding */
3311 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3313 result = mono_assembly_loaded_full (aname, refonly);
3317 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3319 result->in_gac = FALSE;
3323 /* Currently we retrieve the loaded corlib for reflection
3324 * only requests, like a common reflection only assembly
3326 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3327 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3330 len = strlen (aname->name);
3331 for (ext_index = 0; ext_index < 2; ext_index ++) {
3332 ext = ext_index == 0 ? ".dll" : ".exe";
3333 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3334 filename = g_strdup (aname->name);
3335 /* Don't try appending .dll/.exe if it already has one of those extensions */
3338 filename = g_strconcat (aname->name, ext, NULL);
3341 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3348 fullpath = g_build_filename (basedir, filename, NULL);
3349 result = mono_assembly_open_full (fullpath, status, refonly);
3352 result->in_gac = FALSE;
3358 result = load_in_path (filename, default_path, status, refonly);
3360 result->in_gac = FALSE;
3370 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3372 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3375 /* Try a postload search hook */
3376 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3377 result = prevent_reference_assembly_from_running (result, refonly);
3383 * mono_assembly_load_full:
3384 * @aname: A MonoAssemblyName with the assembly name to load.
3385 * @basedir: A directory to look up the assembly at.
3386 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3387 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3389 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3390 * attempts to load the assembly from that directory before probing the standard locations.
3392 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3393 * assembly binding takes place.
3395 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3396 * value pointed by status is updated with an error code.
3399 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3401 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3405 * mono_assembly_load:
3406 * @aname: A MonoAssemblyName with the assembly name to load.
3407 * @basedir: A directory to look up the assembly at.
3408 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3410 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3411 * attempts to load the assembly from that directory before probing the standard locations.
3413 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3414 * value pointed by status is updated with an error code.
3417 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3419 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3423 * mono_assembly_loaded_full:
3424 * @aname: an assembly to look for.
3425 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3427 * This is used to determine if the specified assembly has been loaded
3428 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3429 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3432 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3435 MonoAssemblyName maped_aname;
3437 aname = mono_assembly_remap_version (aname, &maped_aname);
3439 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3445 * mono_assembly_loaded:
3446 * @aname: an assembly to look for.
3448 * This is used to determine if the specified assembly has been loaded
3450 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3451 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3454 mono_assembly_loaded (MonoAssemblyName *aname)
3456 return mono_assembly_loaded_full (aname, FALSE);
3460 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3462 if (assembly == NULL || assembly == REFERENCE_MISSING)
3465 if (assembly_is_dynamic (assembly)) {
3467 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3468 for (i = 0; i < dynimg->image.module_count; ++i)
3469 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3470 mono_dynamic_image_release_gc_roots (dynimg);
3475 * Returns whether mono_assembly_close_finish() must be called as
3476 * well. See comment for mono_image_close_except_pools() for why we
3477 * unload in two steps.
3480 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3483 g_return_val_if_fail (assembly != NULL, FALSE);
3485 if (assembly == REFERENCE_MISSING)
3488 /* Might be 0 already */
3489 if (InterlockedDecrement (&assembly->ref_count) > 0)
3492 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3494 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3496 mono_debug_close_image (assembly->image);
3498 mono_assemblies_lock ();
3499 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3500 mono_assemblies_unlock ();
3502 assembly->image->assembly = NULL;
3504 if (!mono_image_close_except_pools (assembly->image))
3505 assembly->image = NULL;
3507 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3508 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3509 mono_assembly_name_free (fname);
3512 g_slist_free (assembly->friend_assembly_names);
3513 g_free (assembly->basedir);
3515 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3521 mono_assembly_close_finish (MonoAssembly *assembly)
3523 g_assert (assembly && assembly != REFERENCE_MISSING);
3525 if (assembly->image)
3526 mono_image_close_finish (assembly->image);
3528 if (assembly_is_dynamic (assembly)) {
3529 g_free ((char*)assembly->aname.culture);
3536 * mono_assembly_close:
3537 * @assembly: the assembly to release.
3539 * This method releases a reference to the @assembly. The assembly is
3540 * only released when all the outstanding references to it are released.
3543 mono_assembly_close (MonoAssembly *assembly)
3545 if (mono_assembly_close_except_image_pools (assembly))
3546 mono_assembly_close_finish (assembly);
3550 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3553 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3554 mono_error_assert_ok (&error);
3559 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3561 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3566 * mono_assembly_foreach:
3567 * @func: function to invoke for each assembly loaded
3568 * @user_data: data passed to the callback
3570 * Invokes the provided @func callback for each assembly loaded into
3571 * the runtime. The first parameter passed to the callback is the
3572 * `MonoAssembly*`, and the second parameter is the @user_data.
3574 * This is done for all assemblies loaded in the runtime, not just
3575 * those loaded in the current application domain.
3578 mono_assembly_foreach (GFunc func, gpointer user_data)
3583 * We make a copy of the list to avoid calling the callback inside the
3584 * lock, which could lead to deadlocks.
3586 mono_assemblies_lock ();
3587 copy = g_list_copy (loaded_assemblies);
3588 mono_assemblies_unlock ();
3590 g_list_foreach (loaded_assemblies, func, user_data);
3596 * mono_assemblies_cleanup:
3598 * Free all resources used by this module.
3601 mono_assemblies_cleanup (void)
3605 mono_os_mutex_destroy (&assemblies_mutex);
3606 mono_os_mutex_destroy (&assembly_binding_mutex);
3608 for (l = loaded_assembly_bindings; l; l = l->next) {
3609 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3611 mono_assembly_binding_info_free (info);
3614 g_slist_free (loaded_assembly_bindings);
3616 free_assembly_load_hooks ();
3617 free_assembly_search_hooks ();
3618 free_assembly_preload_hooks ();
3621 /*LOCKING takes the assembly_binding lock*/
3623 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3627 mono_assembly_binding_lock ();
3628 iter = &loaded_assembly_bindings;
3631 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3633 if (info->domain_id == domain_id) {
3635 mono_assembly_binding_info_free (info);
3642 mono_assembly_binding_unlock ();
3646 * Holds the assembly of the application, for
3647 * System.Diagnostics.Process::MainModule
3649 static MonoAssembly *main_assembly=NULL;
3652 mono_assembly_set_main (MonoAssembly *assembly)
3654 main_assembly = assembly;
3658 * mono_assembly_get_main:
3660 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3663 mono_assembly_get_main (void)
3665 return (main_assembly);
3669 * mono_assembly_get_image:
3670 * @assembly: The assembly to retrieve the image from
3672 * Returns: the MonoImage associated with this assembly.
3675 mono_assembly_get_image (MonoAssembly *assembly)
3677 return assembly->image;
3681 * mono_assembly_get_name:
3682 * @assembly: The assembly to retrieve the name from
3684 * The returned name's lifetime is the same as @assembly's.
3686 * Returns: the MonoAssemblyName associated with this assembly.
3689 mono_assembly_get_name (MonoAssembly *assembly)
3691 return &assembly->aname;
3695 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3697 bundles = assemblies;
3700 #define MONO_DECLSEC_FORMAT_10 0x3C
3701 #define MONO_DECLSEC_FORMAT_20 0x2E
3702 #define MONO_DECLSEC_FIELD 0x53
3703 #define MONO_DECLSEC_PROPERTY 0x54
3705 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3706 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3707 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3708 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3709 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3712 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3716 case MONO_DECLSEC_PROPERTY:
3718 case MONO_DECLSEC_FIELD:
3720 *abort_decoding = TRUE;
3725 if (*p++ != MONO_TYPE_BOOLEAN) {
3726 *abort_decoding = TRUE;
3730 /* property name length */
3731 len = mono_metadata_decode_value (p, &p);
3733 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3744 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3746 int i, j, num, len, params_len;
3748 if (*p == MONO_DECLSEC_FORMAT_10) {
3749 gsize read, written;
3750 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3752 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3758 if (*p++ != MONO_DECLSEC_FORMAT_20)
3761 /* number of encoded permission attributes */
3762 num = mono_metadata_decode_value (p, &p);
3763 for (i = 0; i < num; ++i) {
3764 gboolean is_valid = FALSE;
3765 gboolean abort_decoding = FALSE;
3767 /* attribute name length */
3768 len = mono_metadata_decode_value (p, &p);
3770 /* We don't really need to fully decode the type. Comparing the name is enough */
3771 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3775 /*size of the params table*/
3776 params_len = mono_metadata_decode_value (p, &p);
3778 const char *params_end = p + params_len;
3780 /* number of parameters */
3781 len = mono_metadata_decode_value (p, &p);
3783 for (j = 0; j < len; ++j) {
3784 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3800 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3803 guint32 cols [MONO_DECL_SECURITY_SIZE];
3807 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3808 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3810 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3812 for (i = 0; i < t->rows; ++i) {
3813 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3814 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3816 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3819 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3820 len = mono_metadata_decode_blob_size (blob, &blob);
3824 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3825 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3830 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);