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)
1680 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1684 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1685 gboolean load_from_context,
1686 MonoAssemblyOpenPredicate predicate,
1688 MonoImageOpenStatus *status)
1692 MonoImageOpenStatus def_status;
1695 gboolean loaded_from_bundle;
1697 g_return_val_if_fail (filename != NULL, NULL);
1700 status = &def_status;
1701 *status = MONO_IMAGE_OK;
1703 if (strncmp (filename, "file://", 7) == 0) {
1704 GError *error = NULL;
1705 gchar *uri = (gchar *) filename;
1709 * MS allows file://c:/... and fails on file://localhost/c:/...
1710 * They also throw an IndexOutOfRangeException if "file://"
1713 uri = g_strdup_printf ("file:///%s", uri + 7);
1716 uri = mono_escape_uri_string (tmpuri);
1717 fname = g_filename_from_uri (uri, NULL, &error);
1720 if (tmpuri != filename)
1723 if (error != NULL) {
1724 g_warning ("%s\n", error->message);
1725 g_error_free (error);
1726 fname = g_strdup (filename);
1729 fname = g_strdup (filename);
1732 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1733 "Assembly Loader probing location: '%s'.", fname);
1736 if (!mono_assembly_is_in_gac (fname)) {
1738 new_fname = mono_make_shadow_copy (fname, &error);
1739 if (!is_ok (&error)) {
1740 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1741 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1742 mono_error_cleanup (&error);
1743 *status = MONO_IMAGE_IMAGE_INVALID;
1748 if (new_fname && new_fname != fname) {
1751 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1752 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1757 // If VM built with mkbundle
1758 loaded_from_bundle = FALSE;
1759 if (bundles != NULL) {
1760 image = mono_assembly_open_from_bundle (fname, status, refonly);
1761 loaded_from_bundle = image != NULL;
1765 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1768 if (*status == MONO_IMAGE_OK)
1769 *status = MONO_IMAGE_ERROR_ERRNO;
1774 if (image->assembly) {
1775 /* Already loaded by another appdomain */
1776 mono_assembly_invoke_load_hook (image->assembly);
1777 mono_image_close (image);
1779 if (!predicate || predicate (image->assembly, user_data)) {
1780 return image->assembly;
1782 *status = MONO_IMAGE_IMAGE_INVALID;
1787 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1789 if (ass && predicate && !predicate (ass, user_data)) {
1790 *status = MONO_IMAGE_IMAGE_INVALID;
1795 if (!loaded_from_bundle)
1796 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1797 "Assembly Loader loaded assembly from location: '%s'.", filename);
1799 mono_config_for_assembly (ass->image);
1802 /* Clear the reference added by mono_image_open */
1803 mono_image_close (image);
1811 free_item (gpointer val, gpointer user_data)
1817 * mono_assembly_load_friends:
1820 * Load the list of friend assemblies that are allowed to access
1821 * the assembly's internal types and members. They are stored as assembly
1822 * names in custom attributes.
1824 * This is an internal method, we need this because when we load mscorlib
1825 * we do not have the internals visible cattr loaded yet,
1826 * so we need to load these after we initialize the runtime.
1828 * LOCKING: Acquires the assemblies lock plus the loader lock.
1831 mono_assembly_load_friends (MonoAssembly* ass)
1835 MonoCustomAttrInfo* attrs;
1838 if (ass->friend_assembly_names_inited)
1841 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1842 mono_error_assert_ok (&error);
1844 mono_assemblies_lock ();
1845 ass->friend_assembly_names_inited = TRUE;
1846 mono_assemblies_unlock ();
1850 mono_assemblies_lock ();
1851 if (ass->friend_assembly_names_inited) {
1852 mono_assemblies_unlock ();
1855 mono_assemblies_unlock ();
1859 * We build the list outside the assemblies lock, the worse that can happen
1860 * is that we'll need to free the allocated list.
1862 for (i = 0; i < attrs->num_attrs; ++i) {
1863 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1864 MonoAssemblyName *aname;
1866 /* Do some sanity checking */
1867 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1869 if (attr->data_size < 4)
1871 data = (const char*)attr->data;
1872 /* 0xFF means null string, see custom attr format */
1873 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1875 mono_metadata_decode_value (data + 2, &data);
1876 aname = g_new0 (MonoAssemblyName, 1);
1877 /*g_print ("friend ass: %s\n", data);*/
1878 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1879 list = g_slist_prepend (list, aname);
1884 mono_custom_attrs_free (attrs);
1886 mono_assemblies_lock ();
1887 if (ass->friend_assembly_names_inited) {
1888 mono_assemblies_unlock ();
1889 g_slist_foreach (list, free_item, NULL);
1890 g_slist_free (list);
1893 ass->friend_assembly_names = list;
1895 /* Because of the double checked locking pattern above */
1896 mono_memory_barrier ();
1897 ass->friend_assembly_names_inited = TRUE;
1898 mono_assemblies_unlock ();
1901 struct HasReferenceAssemblyAttributeIterData {
1906 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1908 gboolean stop_scanning = FALSE;
1909 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1911 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1912 /* Note we don't check the assembly name, same as coreCLR. */
1913 iter_data->has_attr = TRUE;
1914 stop_scanning = TRUE;
1917 return stop_scanning;
1921 * mono_assembly_has_reference_assembly_attribute:
1922 * @assembly: a MonoAssembly
1923 * @error: set on error.
1925 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1926 * On error returns FALSE and sets @error.
1929 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1934 * This might be called during assembly loading, so do everything using the low-level
1938 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1940 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1942 return iter_data.has_attr;
1946 * mono_assembly_open:
1947 * @filename: Opens the assembly pointed out by this name
1948 * @status: return status code
1950 * This loads an assembly from the specified @filename. The @filename allows
1951 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1952 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1953 * is treated as a local path.
1955 * First, an attempt is made to load the assembly from the bundled executable (for those
1956 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1957 * assembly has been registered as an embedded assembly). If this is not the case, then
1958 * the assembly is loaded from disk using `api:mono_image_open_full`.
1960 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1961 * the assembly is made.
1963 * Return: a pointer to the MonoAssembly if @filename contains a valid
1964 * assembly or NULL on error. Details about the error are stored in the
1968 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1970 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
1974 * mono_assembly_load_from_full:
1975 * @image: Image to load the assembly from
1976 * @fname: assembly name to associate with the assembly
1977 * @status: returns the status condition
1978 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1980 * If the provided @image has an assembly reference, it will process the given
1981 * image as an assembly with the given name.
1983 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1985 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1986 * set to #MONO_IMAGE_OK; or NULL on error.
1988 * If there is an error loading the assembly the @status will indicate the
1989 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1990 * image did not contain an assembly reference table.
1993 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1994 MonoImageOpenStatus *status, gboolean refonly)
1996 MonoAssembly *ass, *ass2;
1999 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2000 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2001 *status = MONO_IMAGE_IMAGE_INVALID;
2005 #if defined (HOST_WIN32)
2010 tmp_fn = g_strdup (fname);
2011 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2012 if (tmp_fn [i] == '/')
2016 base_dir = absolute_dir (tmp_fn);
2020 base_dir = absolute_dir (fname);
2024 * Create assembly struct, and enter it into the assembly cache
2026 ass = g_new0 (MonoAssembly, 1);
2027 ass->basedir = base_dir;
2028 ass->ref_only = refonly;
2031 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2033 mono_assembly_fill_assembly_name (image, &ass->aname);
2035 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2036 // MS.NET doesn't support loading other mscorlibs
2039 mono_image_addref (mono_defaults.corlib);
2040 *status = MONO_IMAGE_OK;
2041 return mono_defaults.corlib->assembly;
2044 /* Add a non-temporary reference because of ass->image */
2045 mono_image_addref (image);
2047 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s[%p] -> %s[%p]: %d", ass->aname.name, ass, image->name, image, image->ref_count);
2050 * The load hooks might take locks so we can't call them while holding the
2053 if (ass->aname.name) {
2054 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2058 mono_image_close (image);
2059 *status = MONO_IMAGE_OK;
2064 /* We need to check for ReferenceAssmeblyAttribute before we
2065 * mark the assembly as loaded and before we fire the load
2066 * hook. Otherwise mono_domain_fire_assembly_load () in
2067 * appdomain.c will cache a mapping from the assembly name to
2068 * this image and we won't be able to look for a different
2072 MonoError refasm_error;
2073 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2074 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2077 mono_image_close (image);
2078 *status = MONO_IMAGE_IMAGE_INVALID;
2081 mono_error_cleanup (&refasm_error);
2084 mono_assemblies_lock ();
2086 if (image->assembly) {
2088 * This means another thread has already loaded the assembly, but not yet
2089 * called the load hooks so the search hook can't find the assembly.
2091 mono_assemblies_unlock ();
2092 ass2 = image->assembly;
2095 mono_image_close (image);
2096 *status = MONO_IMAGE_OK;
2100 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2102 image->assembly = ass;
2104 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2105 mono_assemblies_unlock ();
2108 if (image->is_module_handle)
2109 mono_image_fixup_vtable (image);
2112 mono_assembly_invoke_load_hook (ass);
2114 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2120 * mono_assembly_load_from:
2121 * @image: Image to load the assembly from
2122 * @fname: assembly name to associate with the assembly
2123 * @status: return status code
2125 * If the provided @image has an assembly reference, it will process the given
2126 * image as an assembly with the given name.
2128 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2130 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2131 * @refonly parameter set to FALSE.
2132 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2133 * set to #MONO_IMAGE_OK; or NULL on error.
2135 * If there is an error loading the assembly the @status will indicate the
2136 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2137 * image did not contain an assembly reference table.
2141 mono_assembly_load_from (MonoImage *image, const char *fname,
2142 MonoImageOpenStatus *status)
2144 return mono_assembly_load_from_full (image, fname, status, FALSE);
2148 * mono_assembly_name_free:
2149 * @aname: assembly name to free
2151 * Frees the provided assembly name object.
2152 * (it does not frees the object itself, only the name members).
2155 mono_assembly_name_free (MonoAssemblyName *aname)
2160 g_free ((void *) aname->name);
2161 g_free ((void *) aname->culture);
2162 g_free ((void *) aname->hash_value);
2163 g_free ((guint8*) aname->public_key);
2167 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2170 gchar header [16], val, *arr;
2171 gint i, j, offset, bitlen, keylen, pkeylen;
2173 keylen = strlen (key) >> 1;
2177 /* allow the ECMA standard key */
2178 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2180 *pubkey = g_strdup (key);
2186 val = g_ascii_xdigit_value (key [0]) << 4;
2187 val |= g_ascii_xdigit_value (key [1]);
2192 val = g_ascii_xdigit_value (key [24]);
2193 val |= g_ascii_xdigit_value (key [25]);
2205 /* We need the first 16 bytes
2206 * to check whether this key is valid or not */
2207 pkeylen = strlen (pkey) >> 1;
2211 for (i = 0, j = 0; i < 16; i++) {
2212 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2213 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2216 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2217 header [1] != 0x02 || /* Version (0x02) */
2218 header [2] != 0x00 || /* Reserved (word) */
2219 header [3] != 0x00 ||
2220 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2223 /* Based on this length, we _should_ be able to know if the length is right */
2224 bitlen = read32 (header + 12) >> 3;
2225 if ((bitlen + 16 + 4) != pkeylen)
2228 /* parsing is OK and the public key itself is not requested back */
2232 /* Encode the size of the blob */
2234 if (keylen <= 127) {
2235 arr = (gchar *)g_malloc (keylen + 1);
2236 arr [offset++] = keylen;
2238 arr = (gchar *)g_malloc (keylen + 2);
2239 arr [offset++] = 0x80; /* 10bs */
2240 arr [offset++] = keylen;
2243 for (i = offset, j = 0; i < keylen + offset; i++) {
2244 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2245 arr [i] |= g_ascii_xdigit_value (key [j++]);
2254 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)
2256 gint major, minor, build, revision;
2259 gchar *pkey, *pkeyptr, *encoded, tok [8];
2261 memset (aname, 0, sizeof (MonoAssemblyName));
2264 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2265 if (version_parts < 2 || version_parts > 4)
2268 /* FIXME: we should set build & revision to -1 (instead of 0)
2269 if these are not set in the version string. That way, later on,
2270 we can still determine if these were specified. */
2271 aname->major = major;
2272 aname->minor = minor;
2273 if (version_parts >= 3)
2274 aname->build = build;
2277 if (version_parts == 4)
2278 aname->revision = revision;
2280 aname->revision = 0;
2283 aname->flags = flags;
2285 aname->name = g_strdup (name);
2288 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2289 aname->culture = g_strdup ("");
2291 aname->culture = g_strdup (culture);
2294 if (token && strncmp (token, "null", 4) != 0) {
2297 /* the constant includes the ending NULL, hence the -1 */
2298 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2299 mono_assembly_name_free (aname);
2302 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2303 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2309 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2310 mono_assembly_name_free (aname);
2315 if (save_public_key)
2316 aname->public_key = (guint8*)pkey;
2319 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2323 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2324 // We also need to generate the key token
2325 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2326 encoded = encode_public_tok ((guchar*) tok, 8);
2327 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2330 if (save_public_key)
2331 aname->public_key = (guint8*) pkey;
2340 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2345 parts = g_strsplit (dirname, "_", 3);
2346 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2351 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2357 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2359 char *eqsign = strchr (pair, '=');
2367 *key = (gchar*)pair;
2368 *keylen = eqsign - *key;
2369 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2371 *value = g_strstrip (eqsign + 1);
2376 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2380 gchar *version = NULL;
2382 gchar *culture = NULL;
2384 gchar *token = NULL;
2388 gchar *retargetable = NULL;
2389 gchar *retargetable_uq;
2393 gchar *value, *part_name;
2394 guint32 part_name_len;
2397 gboolean version_defined;
2398 gboolean token_defined;
2400 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2402 if (!is_version_defined)
2403 is_version_defined = &version_defined;
2404 *is_version_defined = FALSE;
2405 if (!is_token_defined)
2406 is_token_defined = &token_defined;
2407 *is_token_defined = FALSE;
2409 parts = tmp = g_strsplit (name, ",", 6);
2410 if (!tmp || !*tmp) {
2415 dllname = g_strstrip (*tmp);
2420 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2421 goto cleanup_and_fail;
2423 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2424 *is_version_defined = TRUE;
2426 if (strlen (version) == 0) {
2427 goto cleanup_and_fail;
2433 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2435 if (strlen (culture) == 0) {
2436 goto cleanup_and_fail;
2442 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2443 *is_token_defined = TRUE;
2445 if (strlen (token) == 0) {
2446 goto cleanup_and_fail;
2452 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2454 if (strlen (key) == 0) {
2455 goto cleanup_and_fail;
2461 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2462 retargetable = value;
2463 retargetable_uq = unquote (retargetable);
2464 if (retargetable_uq != NULL)
2465 retargetable = retargetable_uq;
2467 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2468 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2469 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2470 g_free (retargetable_uq);
2471 goto cleanup_and_fail;
2474 g_free (retargetable_uq);
2479 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2481 procarch_uq = unquote (procarch);
2482 if (procarch_uq != NULL)
2483 procarch = procarch_uq;
2485 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2486 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2487 else if (!g_ascii_strcasecmp (procarch, "X86"))
2488 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2489 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2490 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2491 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2492 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2494 g_free (procarch_uq);
2495 goto cleanup_and_fail;
2498 g_free (procarch_uq);
2507 /* if retargetable flag is set, then we must have a fully qualified name */
2508 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2509 goto cleanup_and_fail;
2512 dllname_uq = unquote (dllname);
2513 version_uq = unquote (version);
2514 culture_uq = unquote (culture);
2515 token_uq = unquote (token);
2516 key_uq = unquote (key);
2518 res = build_assembly_name (
2519 dllname_uq == NULL ? dllname : dllname_uq,
2520 version_uq == NULL ? version : version_uq,
2521 culture_uq == NULL ? culture : culture_uq,
2522 token_uq == NULL ? token : token_uq,
2523 key_uq == NULL ? key : key_uq,
2524 flags, arch, aname, save_public_key);
2526 g_free (dllname_uq);
2527 g_free (version_uq);
2528 g_free (culture_uq);
2541 unquote (const char *str)
2549 slen = strlen (str);
2553 if (*str != '\'' && *str != '\"')
2556 end = str + slen - 1;
2560 return g_strndup (str + 1, slen - 2);
2564 * mono_assembly_name_parse:
2565 * @name: name to parse
2566 * @aname: the destination assembly name
2568 * Parses an assembly qualified type name and assigns the name,
2569 * version, culture and token to the provided assembly name object.
2571 * Returns: TRUE if the name could be parsed.
2574 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2576 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2580 * mono_assembly_name_new:
2581 * @name: name to parse
2583 * Allocate a new MonoAssemblyName and fill its values from the
2586 * Returns: a newly allocated structure or NULL if there was any failure.
2589 mono_assembly_name_new (const char *name)
2591 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2592 if (mono_assembly_name_parse (name, aname))
2599 mono_assembly_name_get_name (MonoAssemblyName *aname)
2605 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2607 return aname->culture;
2611 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2613 if (aname->public_key_token [0])
2614 return aname->public_key_token;
2619 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2622 *minor = aname->minor;
2624 *build = aname->build;
2626 *revision = aname->revision;
2627 return aname->major;
2630 static MonoAssembly*
2631 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2633 gchar *fullpath = NULL;
2635 const char* direntry;
2636 MonoAssemblyName gac_aname;
2637 gint major=-1, minor=0, build=0, revision=0;
2638 gboolean exact_version;
2640 dirhandle = g_dir_open (basepath, 0, NULL);
2644 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2646 while ((direntry = g_dir_read_name (dirhandle))) {
2647 gboolean match = TRUE;
2649 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2652 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2655 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2656 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2660 if (exact_version) {
2661 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2662 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2664 else if (gac_aname.major < major)
2666 else if (gac_aname.major == major) {
2667 if (gac_aname.minor < minor)
2669 else if (gac_aname.minor == minor) {
2670 if (gac_aname.build < build)
2672 else if (gac_aname.build == build && gac_aname.revision <= revision)
2679 major = gac_aname.major;
2680 minor = gac_aname.minor;
2681 build = gac_aname.build;
2682 revision = gac_aname.revision;
2684 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2687 mono_assembly_name_free (&gac_aname);
2690 g_dir_close (dirhandle);
2692 if (fullpath == NULL)
2695 MonoAssembly *res = mono_assembly_open (fullpath, status);
2702 * mono_assembly_load_with_partial_name:
2703 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2704 * @status: return status code
2706 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2707 * so it might contain a qualified type name, version, culture and token.
2709 * This will load the assembly from the file whose name is derived from the assembly name
2710 * by appending the .dll extension.
2712 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2713 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2714 * if that fails from the GAC.
2716 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2719 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2723 MonoAssemblyName *aname, base_name;
2724 MonoAssemblyName mapped_aname;
2725 gchar *fullname, *gacpath;
2728 memset (&base_name, 0, sizeof (MonoAssemblyName));
2731 if (!mono_assembly_name_parse (name, aname))
2735 * If no specific version has been requested, make sure we load the
2736 * correct version for system assemblies.
2738 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2739 aname = mono_assembly_remap_version (aname, &mapped_aname);
2741 res = mono_assembly_loaded (aname);
2743 mono_assembly_name_free (aname);
2747 res = invoke_assembly_preload_hook (aname, assemblies_path);
2749 res->in_gac = FALSE;
2750 mono_assembly_name_free (aname);
2754 fullname = g_strdup_printf ("%s.dll", aname->name);
2756 if (extra_gac_paths) {
2757 paths = extra_gac_paths;
2758 while (!res && *paths) {
2759 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2760 res = probe_for_partial_name (gacpath, fullname, aname, status);
2769 mono_assembly_name_free (aname);
2773 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2774 res = probe_for_partial_name (gacpath, fullname, aname, status);
2778 mono_assembly_name_free (aname);
2783 MonoDomain *domain = mono_domain_get ();
2785 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2786 if (!is_ok (&error)) {
2787 mono_error_cleanup (&error);
2788 if (*status == MONO_IMAGE_OK)
2789 *status = MONO_IMAGE_IMAGE_INVALID;
2797 mono_assembly_is_in_gac (const gchar *filename)
2799 const gchar *rootdir;
2803 if (filename == NULL)
2806 for (paths = extra_gac_paths; paths && *paths; paths++) {
2807 if (strstr (*paths, filename) != *paths)
2810 gp = (gchar *) (filename + strlen (*paths));
2811 if (*gp != G_DIR_SEPARATOR)
2814 if (strncmp (gp, "lib", 3))
2817 if (*gp != G_DIR_SEPARATOR)
2820 if (strncmp (gp, "mono", 4))
2823 if (*gp != G_DIR_SEPARATOR)
2826 if (strncmp (gp, "gac", 3))
2829 if (*gp != G_DIR_SEPARATOR)
2835 rootdir = mono_assembly_getrootdir ();
2836 if (strstr (filename, rootdir) != filename)
2839 gp = (gchar *) (filename + strlen (rootdir));
2840 if (*gp != G_DIR_SEPARATOR)
2843 if (strncmp (gp, "mono", 4))
2846 if (*gp != G_DIR_SEPARATOR)
2849 if (strncmp (gp, "gac", 3))
2852 if (*gp != G_DIR_SEPARATOR)
2858 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2861 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2865 if (strstr (aname->name, ".dll")) {
2866 len = strlen (aname->name) - 4;
2867 name = (gchar *)g_malloc (len + 1);
2868 memcpy (name, aname->name, len);
2871 name = g_strdup (aname->name);
2874 culture = g_utf8_strdown (aname->culture, -1);
2876 culture = g_strdup ("");
2878 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2879 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2883 filename = g_strconcat (pname, ".dll", NULL);
2884 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2890 if (extra_gac_paths) {
2891 paths = extra_gac_paths;
2892 while (!image && *paths) {
2893 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2894 "lib", "mono", "gac", subpath, NULL);
2895 image = mono_image_open (fullpath, NULL);
2906 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2907 "mono", "gac", subpath, NULL);
2908 image = mono_image_open (fullpath, NULL);
2915 static MonoAssemblyName*
2916 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2918 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2919 dest_name->major = info->new_version.major;
2920 dest_name->minor = info->new_version.minor;
2921 dest_name->build = info->new_version.build;
2922 dest_name->revision = info->new_version.revision;
2927 /* LOCKING: assembly_binding lock must be held */
2928 static MonoAssemblyBindingInfo*
2929 search_binding_loaded (MonoAssemblyName *aname)
2933 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2934 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2935 if (assembly_binding_maps_name (info, aname))
2942 static inline gboolean
2943 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2945 if (left->major != right->major || left->minor != right->minor ||
2946 left->build != right->build || left->revision != right->revision)
2952 static inline gboolean
2953 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2955 if (left->has_old_version_bottom != right->has_old_version_bottom)
2958 if (left->has_old_version_top != right->has_old_version_top)
2961 if (left->has_new_version != right->has_new_version)
2964 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2967 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2970 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2976 /* LOCKING: assumes all the necessary locks are held */
2978 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2980 MonoAssemblyBindingInfo *info_copy;
2982 MonoAssemblyBindingInfo *info_tmp;
2983 MonoDomain *domain = (MonoDomain*)user_data;
2988 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2989 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2990 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2994 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2995 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2997 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2999 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3001 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3005 get_version_number (int major, int minor)
3007 return major * 256 + minor;
3010 static inline gboolean
3011 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3013 int aname_version_number = get_version_number (aname->major, aname->minor);
3014 if (!info->has_old_version_bottom)
3017 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3020 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3023 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3024 info->major = aname->major;
3025 info->minor = aname->minor;
3030 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3031 static MonoAssemblyBindingInfo*
3032 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3034 MonoAssemblyBindingInfo *info;
3037 if (!domain->assembly_bindings)
3041 for (list = domain->assembly_bindings; list; list = list->next) {
3042 info = (MonoAssemblyBindingInfo *)list->data;
3043 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3049 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3050 info->has_new_version && assembly_binding_maps_name (info, aname))
3051 info->is_valid = TRUE;
3053 info->is_valid = FALSE;
3059 static MonoAssemblyName*
3060 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3063 MonoAssemblyBindingInfo *info, *info2;
3067 if (aname->public_key_token [0] == 0)
3070 domain = mono_domain_get ();
3072 mono_assembly_binding_lock ();
3073 info = search_binding_loaded (aname);
3074 mono_assembly_binding_unlock ();
3077 mono_domain_lock (domain);
3078 info = get_per_domain_assembly_binding_info (domain, aname);
3079 mono_domain_unlock (domain);
3083 if (!check_policy_versions (info, aname))
3086 mono_assembly_bind_version (info, aname, dest_name);
3090 if (domain && domain->setup && domain->setup->configuration_file) {
3091 mono_domain_lock (domain);
3092 if (!domain->assembly_bindings_parsed) {
3093 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3094 /* expect this to succeed because mono_domain_set_options_from_config () did
3095 * the same thing when the domain was created. */
3096 mono_error_assert_ok (&error);
3098 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3100 if (!domain_config_file_path)
3101 domain_config_file_path = domain_config_file_name;
3103 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3104 domain->assembly_bindings_parsed = TRUE;
3105 if (domain_config_file_name != domain_config_file_path)
3106 g_free (domain_config_file_name);
3107 g_free (domain_config_file_path);
3110 info2 = get_per_domain_assembly_binding_info (domain, aname);
3113 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3114 info->name = g_strdup (info2->name);
3115 info->culture = g_strdup (info2->culture);
3116 info->domain_id = domain->domain_id;
3119 mono_domain_unlock (domain);
3123 info = g_new0 (MonoAssemblyBindingInfo, 1);
3124 info->major = aname->major;
3125 info->minor = aname->minor;
3128 if (!info->is_valid) {
3129 ppimage = mono_assembly_load_publisher_policy (aname);
3131 get_publisher_policy_info (ppimage, aname, info);
3132 mono_image_close (ppimage);
3136 /* Define default error value if needed */
3137 if (!info->is_valid) {
3138 info->name = g_strdup (aname->name);
3139 info->culture = g_strdup (aname->culture);
3140 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3143 mono_assembly_binding_lock ();
3144 info2 = search_binding_loaded (aname);
3146 /* This binding was added by another thread
3148 mono_assembly_binding_info_free (info);
3153 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3155 mono_assembly_binding_unlock ();
3157 if (!info->is_valid || !check_policy_versions (info, aname))
3160 mono_assembly_bind_version (info, aname, dest_name);
3165 * mono_assembly_load_from_gac
3167 * @aname: The assembly name object
3169 static MonoAssembly*
3170 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3172 MonoAssembly *result = NULL;
3173 gchar *name, *version, *culture, *fullpath, *subpath;
3178 if (aname->public_key_token [0] == 0) {
3182 if (strstr (aname->name, ".dll")) {
3183 len = strlen (filename) - 4;
3184 name = (gchar *)g_malloc (len + 1);
3185 memcpy (name, aname->name, len);
3188 name = g_strdup (aname->name);
3191 if (aname->culture) {
3192 culture = g_utf8_strdown (aname->culture, -1);
3194 culture = g_strdup ("");
3197 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3198 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3199 aname->minor, aname->build, aname->revision,
3203 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3208 if (extra_gac_paths) {
3209 paths = extra_gac_paths;
3210 while (!result && *paths) {
3211 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3212 result = mono_assembly_open_full (fullpath, status, refonly);
3219 result->in_gac = TRUE;
3224 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3225 "mono", "gac", subpath, NULL);
3226 result = mono_assembly_open_full (fullpath, status, refonly);
3230 result->in_gac = TRUE;
3238 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3241 MonoAssemblyName *aname;
3244 /* g_print ("corlib already loaded\n"); */
3248 // In native client, Corlib is embedded in the executable as static variable corlibData
3249 #if defined(__native_client__)
3250 if (corlibData != NULL && corlibSize != 0) {
3252 /* First "FALSE" instructs mono not to make a copy. */
3253 /* Second "FALSE" says this is not just a ref. */
3254 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3255 if (image == NULL || status != 0)
3256 g_print("mono_image_open_from_data_full failed: %d\n", status);
3257 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3258 if (corlib == NULL || status != 0)
3259 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3265 // A nonstandard preload hook may provide a special mscorlib assembly
3266 aname = mono_assembly_name_new ("mscorlib.dll");
3267 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3268 mono_assembly_name_free (aname);
3271 goto return_corlib_and_facades;
3273 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3274 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3275 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3277 goto return_corlib_and_facades;
3280 /* Normal case: Load corlib from mono/<version> */
3281 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3282 if (assemblies_path) { // Custom assemblies path
3283 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3285 g_free (corlib_file);
3286 goto return_corlib_and_facades;
3289 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3290 g_free (corlib_file);
3292 return_corlib_and_facades:
3293 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3294 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3299 static MonoAssembly*
3300 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3302 MonoError refasm_error;
3303 error_init (&refasm_error);
3304 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3307 mono_error_cleanup (&refasm_error);
3313 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3314 const char *basedir,
3315 MonoImageOpenStatus *status,
3318 MonoAssembly *result;
3319 char *fullpath, *filename;
3320 MonoAssemblyName maped_aname;
3321 MonoAssemblyName maped_name_pp;
3326 aname = mono_assembly_remap_version (aname, &maped_aname);
3328 /* Reflection only assemblies don't get assembly binding */
3330 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3332 result = mono_assembly_loaded_full (aname, refonly);
3336 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3338 result->in_gac = FALSE;
3342 /* Currently we retrieve the loaded corlib for reflection
3343 * only requests, like a common reflection only assembly
3345 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3346 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3349 len = strlen (aname->name);
3350 for (ext_index = 0; ext_index < 2; ext_index ++) {
3351 ext = ext_index == 0 ? ".dll" : ".exe";
3352 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3353 filename = g_strdup (aname->name);
3354 /* Don't try appending .dll/.exe if it already has one of those extensions */
3357 filename = g_strconcat (aname->name, ext, NULL);
3360 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3367 fullpath = g_build_filename (basedir, filename, NULL);
3368 result = mono_assembly_open_full (fullpath, status, refonly);
3371 result->in_gac = FALSE;
3377 result = load_in_path (filename, default_path, status, refonly);
3379 result->in_gac = FALSE;
3389 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3391 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3394 /* Try a postload search hook */
3395 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3396 result = prevent_reference_assembly_from_running (result, refonly);
3402 * mono_assembly_load_full:
3403 * @aname: A MonoAssemblyName with the assembly name to load.
3404 * @basedir: A directory to look up the assembly at.
3405 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3406 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3408 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3409 * attempts to load the assembly from that directory before probing the standard locations.
3411 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3412 * assembly binding takes place.
3414 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3415 * value pointed by status is updated with an error code.
3418 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3420 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3424 * mono_assembly_load:
3425 * @aname: A MonoAssemblyName with the assembly name to load.
3426 * @basedir: A directory to look up the assembly at.
3427 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3429 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3430 * attempts to load the assembly from that directory before probing the standard locations.
3432 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3433 * value pointed by status is updated with an error code.
3436 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3438 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3442 * mono_assembly_loaded_full:
3443 * @aname: an assembly to look for.
3444 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3446 * This is used to determine if the specified assembly has been loaded
3447 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3448 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3451 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3454 MonoAssemblyName maped_aname;
3456 aname = mono_assembly_remap_version (aname, &maped_aname);
3458 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3464 * mono_assembly_loaded:
3465 * @aname: an assembly to look for.
3467 * This is used to determine if the specified assembly has been loaded
3469 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3470 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3473 mono_assembly_loaded (MonoAssemblyName *aname)
3475 return mono_assembly_loaded_full (aname, FALSE);
3479 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3481 if (assembly == NULL || assembly == REFERENCE_MISSING)
3484 if (assembly_is_dynamic (assembly)) {
3486 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3487 for (i = 0; i < dynimg->image.module_count; ++i)
3488 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3489 mono_dynamic_image_release_gc_roots (dynimg);
3494 * Returns whether mono_assembly_close_finish() must be called as
3495 * well. See comment for mono_image_close_except_pools() for why we
3496 * unload in two steps.
3499 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3502 g_return_val_if_fail (assembly != NULL, FALSE);
3504 if (assembly == REFERENCE_MISSING)
3507 /* Might be 0 already */
3508 if (InterlockedDecrement (&assembly->ref_count) > 0)
3511 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3513 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3515 mono_debug_close_image (assembly->image);
3517 mono_assemblies_lock ();
3518 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3519 mono_assemblies_unlock ();
3521 assembly->image->assembly = NULL;
3523 if (!mono_image_close_except_pools (assembly->image))
3524 assembly->image = NULL;
3526 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3527 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3528 mono_assembly_name_free (fname);
3531 g_slist_free (assembly->friend_assembly_names);
3532 g_free (assembly->basedir);
3534 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3540 mono_assembly_close_finish (MonoAssembly *assembly)
3542 g_assert (assembly && assembly != REFERENCE_MISSING);
3544 if (assembly->image)
3545 mono_image_close_finish (assembly->image);
3547 if (assembly_is_dynamic (assembly)) {
3548 g_free ((char*)assembly->aname.culture);
3555 * mono_assembly_close:
3556 * @assembly: the assembly to release.
3558 * This method releases a reference to the @assembly. The assembly is
3559 * only released when all the outstanding references to it are released.
3562 mono_assembly_close (MonoAssembly *assembly)
3564 if (mono_assembly_close_except_image_pools (assembly))
3565 mono_assembly_close_finish (assembly);
3569 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3572 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3573 mono_error_assert_ok (&error);
3578 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3580 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3585 * mono_assembly_foreach:
3586 * @func: function to invoke for each assembly loaded
3587 * @user_data: data passed to the callback
3589 * Invokes the provided @func callback for each assembly loaded into
3590 * the runtime. The first parameter passed to the callback is the
3591 * `MonoAssembly*`, and the second parameter is the @user_data.
3593 * This is done for all assemblies loaded in the runtime, not just
3594 * those loaded in the current application domain.
3597 mono_assembly_foreach (GFunc func, gpointer user_data)
3602 * We make a copy of the list to avoid calling the callback inside the
3603 * lock, which could lead to deadlocks.
3605 mono_assemblies_lock ();
3606 copy = g_list_copy (loaded_assemblies);
3607 mono_assemblies_unlock ();
3609 g_list_foreach (loaded_assemblies, func, user_data);
3615 * mono_assemblies_cleanup:
3617 * Free all resources used by this module.
3620 mono_assemblies_cleanup (void)
3624 mono_os_mutex_destroy (&assemblies_mutex);
3625 mono_os_mutex_destroy (&assembly_binding_mutex);
3627 for (l = loaded_assembly_bindings; l; l = l->next) {
3628 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3630 mono_assembly_binding_info_free (info);
3633 g_slist_free (loaded_assembly_bindings);
3635 free_assembly_load_hooks ();
3636 free_assembly_search_hooks ();
3637 free_assembly_preload_hooks ();
3640 /*LOCKING takes the assembly_binding lock*/
3642 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3646 mono_assembly_binding_lock ();
3647 iter = &loaded_assembly_bindings;
3650 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3652 if (info->domain_id == domain_id) {
3654 mono_assembly_binding_info_free (info);
3661 mono_assembly_binding_unlock ();
3665 * Holds the assembly of the application, for
3666 * System.Diagnostics.Process::MainModule
3668 static MonoAssembly *main_assembly=NULL;
3671 mono_assembly_set_main (MonoAssembly *assembly)
3673 main_assembly = assembly;
3677 * mono_assembly_get_main:
3679 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3682 mono_assembly_get_main (void)
3684 return (main_assembly);
3688 * mono_assembly_get_image:
3689 * @assembly: The assembly to retrieve the image from
3691 * Returns: the MonoImage associated with this assembly.
3694 mono_assembly_get_image (MonoAssembly *assembly)
3696 return assembly->image;
3700 * mono_assembly_get_name:
3701 * @assembly: The assembly to retrieve the name from
3703 * The returned name's lifetime is the same as @assembly's.
3705 * Returns: the MonoAssemblyName associated with this assembly.
3708 mono_assembly_get_name (MonoAssembly *assembly)
3710 return &assembly->aname;
3714 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3716 bundles = assemblies;
3719 #define MONO_DECLSEC_FORMAT_10 0x3C
3720 #define MONO_DECLSEC_FORMAT_20 0x2E
3721 #define MONO_DECLSEC_FIELD 0x53
3722 #define MONO_DECLSEC_PROPERTY 0x54
3724 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3725 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3726 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3727 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3728 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3731 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3735 case MONO_DECLSEC_PROPERTY:
3737 case MONO_DECLSEC_FIELD:
3739 *abort_decoding = TRUE;
3744 if (*p++ != MONO_TYPE_BOOLEAN) {
3745 *abort_decoding = TRUE;
3749 /* property name length */
3750 len = mono_metadata_decode_value (p, &p);
3752 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3763 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3765 int i, j, num, len, params_len;
3767 if (*p == MONO_DECLSEC_FORMAT_10) {
3768 gsize read, written;
3769 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3771 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3777 if (*p++ != MONO_DECLSEC_FORMAT_20)
3780 /* number of encoded permission attributes */
3781 num = mono_metadata_decode_value (p, &p);
3782 for (i = 0; i < num; ++i) {
3783 gboolean is_valid = FALSE;
3784 gboolean abort_decoding = FALSE;
3786 /* attribute name length */
3787 len = mono_metadata_decode_value (p, &p);
3789 /* We don't really need to fully decode the type. Comparing the name is enough */
3790 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3794 /*size of the params table*/
3795 params_len = mono_metadata_decode_value (p, &p);
3797 const char *params_end = p + params_len;
3799 /* number of parameters */
3800 len = mono_metadata_decode_value (p, &p);
3802 for (j = 0; j < len; ++j) {
3803 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3819 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3822 guint32 cols [MONO_DECL_SECURITY_SIZE];
3826 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3827 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3829 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3831 for (i = 0; i < t->rows; ++i) {
3832 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3833 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3835 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3838 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3839 len = mono_metadata_decode_blob_size (blob, &blob);
3843 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3844 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3849 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);