3 * Routines for loading assemblies.
6 * Miguel de Icaza (miguel@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "assembly-internals.h"
22 #include "image-internals.h"
23 #include "object-internals.h"
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/custom-attrs-internals.h>
27 #include <mono/metadata/metadata-internals.h>
28 #include <mono/metadata/profiler-private.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/domain-internals.h>
31 #include <mono/metadata/reflection-internals.h>
32 #include <mono/metadata/mono-endian.h>
33 #include <mono/metadata/mono-debug.h>
34 #include <mono/utils/mono-uri.h>
35 #include <mono/metadata/mono-config.h>
36 #include <mono/metadata/mono-config-dirs.h>
37 #include <mono/utils/mono-digest.h>
38 #include <mono/utils/mono-logger-internals.h>
39 #include <mono/utils/mono-path.h>
40 #include <mono/metadata/reflection.h>
41 #include <mono/metadata/coree.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/utils/mono-io-portability.h>
44 #include <mono/utils/atomic.h>
45 #include <mono/utils/mono-os-mutex.h>
48 #include <sys/types.h>
53 #ifdef PLATFORM_MACOSX
54 #include <mach-o/dyld.h>
57 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
59 const char* assembly_name;
60 guint8 version_set_index;
61 const char* new_assembly_name;
62 gboolean only_lower_versions;
65 /* the default search path is empty, the first slot is replaced with the computed value */
73 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
74 static char **assemblies_path = NULL;
76 /* Contains the list of directories that point to auxiliary GACs */
77 static char **extra_gac_paths = NULL;
79 #ifndef DISABLE_ASSEMBLY_REMAPPING
81 static GHashTable* assembly_remapping_table;
82 /* The list of system assemblies what will be remapped to the running
84 * This list is stored in @assembly_remapping_table during initialization.
85 * Keep it sorted just to make maintenance easier.
87 * The integer number is an index in the MonoRuntimeInfo structure, whose
88 * values can be found in domain.c - supported_runtimes. Look there
89 * to understand what remapping will be made.
91 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
94 static const AssemblyVersionMap framework_assemblies [] = {
96 {"Commons.Xml.Relaxng", 0},
103 {"Microsoft.Build.Engine", 2, NULL, TRUE},
104 {"Microsoft.Build.Framework", 2, NULL, TRUE},
105 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
106 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
107 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
108 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
109 {"Microsoft.VisualBasic", 1},
110 {"Microsoft.VisualC", 1},
112 {"Mono.CompilerServices.SymbolWriter", 0},
114 {"Mono.Data.SybaseClient", 0},
115 {"Mono.Data.Tds", 0},
116 {"Mono.Data.TdsClient", 0},
117 {"Mono.GetOptions", 0},
120 {"Mono.Security", 0},
121 {"Mono.Security.Win32", 0},
123 {"Novell.Directory.Ldap", 0},
126 {"System.ComponentModel.Composition", 2},
127 {"System.ComponentModel.DataAnnotations", 2},
128 {"System.Configuration", 0},
129 {"System.Configuration.Install", 0},
132 {"System.Data.Linq", 2},
133 {"System.Data.OracleClient", 0},
134 {"System.Data.Services", 2},
135 {"System.Data.Services.Client", 2},
136 {"System.Data.SqlXml", 0},
137 {"System.Design", 0},
138 {"System.DirectoryServices", 0},
139 {"System.Drawing", 0},
140 {"System.Drawing.Design", 0},
141 {"System.EnterpriseServices", 0},
142 {"System.IO.Compression", 2},
143 {"System.IdentityModel", 3},
144 {"System.IdentityModel.Selectors", 3},
145 {"System.Management", 0},
146 {"System.Messaging", 0},
148 {"System.Net.Http", 4},
149 {"System.Numerics.Vectors", 3},
150 {"System.Runtime.InteropServices.RuntimeInformation", 2},
151 {"System.Runtime.Remoting", 0},
152 {"System.Runtime.Serialization", 3},
153 {"System.Runtime.Serialization.Formatters", 3},
154 {"System.Runtime.Serialization.Formatters.Soap", 0},
155 {"System.Security", 0},
156 {"System.ServiceModel", 3},
157 {"System.ServiceModel.Duplex", 3},
158 {"System.ServiceModel.Http", 3},
159 {"System.ServiceModel.NetTcp", 3},
160 {"System.ServiceModel.Primitives", 3},
161 {"System.ServiceModel.Security", 3},
162 {"System.ServiceModel.Web", 2},
163 {"System.ServiceProcess", 0},
164 {"System.Text.Encoding.CodePages", 3},
165 {"System.Transactions", 0},
167 {"System.Web.Abstractions", 2},
168 {"System.Web.DynamicData", 2},
169 {"System.Web.Extensions", 2},
170 {"System.Web.Mobile", 0},
171 {"System.Web.Routing", 2},
172 {"System.Web.Services", 0},
173 {"System.Windows.Forms", 0},
175 {"System.Xml.Linq", 2},
176 {"System.Xml.ReaderWriter", 3},
177 {"System.Xml.XPath.XmlDocument", 3},
184 * keeps track of loaded assemblies
186 static GList *loaded_assemblies = NULL;
187 static MonoAssembly *corlib;
189 #if defined(__native_client__)
191 /* On Native Client, allow mscorlib to be loaded from memory */
192 /* instead of loaded off disk. If these are not set, default */
193 /* mscorlib loading will take place */
195 /* NOTE: If mscorlib data is passed to mono in this way then */
196 /* it needs to remain allocated during the use of mono. */
198 static void *corlibData = NULL;
199 static size_t corlibSize = 0;
202 mono_set_corlib_data (void *data, size_t size)
210 static char* unquote (const char *str);
212 /* This protects loaded_assemblies and image->references */
213 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
214 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
215 static mono_mutex_t assemblies_mutex;
217 /* If defined, points to the bundled assembly information */
218 const MonoBundledAssembly **bundles;
220 static mono_mutex_t assembly_binding_mutex;
222 /* Loaded assembly binding info */
223 static GSList *loaded_assembly_bindings = NULL;
225 /* Class lazy loading functions */
226 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
228 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
230 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
232 mono_assembly_is_in_gac (const gchar *filanem);
235 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
238 encode_public_tok (const guchar *token, gint32 len)
240 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
244 res = (gchar *)g_malloc (len * 2 + 1);
245 for (i = 0; i < len; i++) {
246 res [i * 2] = allowed [token [i] >> 4];
247 res [i * 2 + 1] = allowed [token [i] & 0xF];
254 * mono_public_tokens_are_equal:
255 * \param pubt1 first public key token
256 * \param pubt2 second public key token
258 * Compare two public key tokens and return TRUE is they are equal and FALSE
262 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
264 return memcmp (pubt1, pubt2, 16) == 0;
268 * mono_set_assemblies_path:
269 * \param path list of paths that contain directories where Mono will look for assemblies
271 * Use this method to override the standard assembly lookup system and
272 * override any assemblies coming from the GAC. This is the method
273 * that supports the MONO_PATH variable.
275 * Notice that MONO_PATH and this method are really a very bad idea as
276 * it prevents the GAC from working and it prevents the standard
277 * resolution mechanisms from working. Nonetheless, for some debugging
278 * situations and bootstrapping setups, this is useful to have.
281 mono_set_assemblies_path (const char* path)
283 char **splitted, **dest;
285 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
287 g_strfreev (assemblies_path);
288 assemblies_path = dest = splitted;
290 char *tmp = *splitted;
292 *dest++ = mono_path_canonicalize (tmp);
298 if (g_getenv ("MONO_DEBUG") == NULL)
301 splitted = assemblies_path;
303 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
304 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
310 /* Native Client can't get this info from an environment variable so */
311 /* it's passed in to the runtime, or set manually by embedding code. */
312 #ifdef __native_client__
313 char* nacl_mono_path = NULL;
317 check_path_env (void)
320 path = g_getenv ("MONO_PATH");
321 #ifdef __native_client__
323 path = nacl_mono_path;
325 if (!path || assemblies_path != NULL)
328 mono_set_assemblies_path(path);
332 check_extra_gac_path_env (void) {
334 char **splitted, **dest;
336 path = g_getenv ("MONO_GAC_PREFIX");
340 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
342 g_strfreev (extra_gac_paths);
343 extra_gac_paths = dest = splitted;
351 if (g_getenv ("MONO_DEBUG") == NULL)
355 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
356 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
363 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
365 if (!info || !info->name)
368 if (strcmp (info->name, aname->name))
371 if (info->major != aname->major || info->minor != aname->minor)
374 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
377 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
380 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
387 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
393 g_free (info->culture);
397 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
400 guint32 cols [MONO_MANIFEST_SIZE];
401 const gchar *filename;
402 gchar *subpath, *fullpath;
404 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
405 /* MS Impl. accepts policy assemblies with more than
406 * one manifest resource, and only takes the first one */
408 binding_info->is_valid = FALSE;
412 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
413 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
414 binding_info->is_valid = FALSE;
418 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
419 g_assert (filename != NULL);
421 subpath = g_path_get_dirname (image->name);
422 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
423 mono_config_parse_publisher_policy (fullpath, binding_info);
427 /* Define the optional elements/attributes before checking */
428 if (!binding_info->culture)
429 binding_info->culture = g_strdup ("");
431 /* Check that the most important elements/attributes exist */
432 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
433 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
434 mono_assembly_binding_info_free (binding_info);
435 binding_info->is_valid = FALSE;
439 binding_info->is_valid = TRUE;
443 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
445 if (v->major > aname->major)
447 else if (v->major < aname->major)
450 if (v->minor > aname->minor)
452 else if (v->minor < aname->minor)
455 if (v->build > aname->build)
457 else if (v->build < aname->build)
460 if (v->revision > aname->revision)
462 else if (v->revision < aname->revision)
469 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
474 /* If has_old_version_top doesn't exist, we don't have an interval */
475 if (!info->has_old_version_top) {
476 if (compare_versions (&info->old_version_bottom, name) == 0)
482 /* Check that the version defined by name is valid for the interval */
483 if (compare_versions (&info->old_version_top, name) < 0)
486 /* We should be greater or equal than the small version */
487 if (compare_versions (&info->old_version_bottom, name) > 0)
494 * mono_assembly_names_equal:
495 * \param l first assembly
496 * \param r second assembly.
498 * Compares two MonoAssemblyNames and returns whether they are equal.
500 * This compares the names, the cultures, the release version and their
503 * \returns TRUE if both assembly names are equal.
506 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
508 if (!l->name || !r->name)
511 if (strcmp (l->name, r->name))
514 if (l->culture && r->culture && strcmp (l->culture, r->culture))
517 if (l->major != r->major || l->minor != r->minor ||
518 l->build != r->build || l->revision != r->revision)
519 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)))
522 if (!l->public_key_token [0] || !r->public_key_token [0])
525 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
531 static MonoAssembly *
532 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
536 MonoAssembly *result;
538 for (i = 0; search_path [i]; ++i) {
539 fullpath = g_build_filename (search_path [i], basename, NULL);
540 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
549 * mono_assembly_setrootdir:
550 * \param root_dir The pathname of the root directory where we will locate assemblies
552 * This routine sets the internal default root directory for looking up
555 * This is used by Windows installations to compute dynamically the
556 * place where the Mono assemblies are located.
560 mono_assembly_setrootdir (const char *root_dir)
563 * Override the MONO_ASSEMBLIES directory configured at compile time.
565 /* Leak if called more than once */
566 default_path [0] = g_strdup (root_dir);
570 * mono_assembly_getrootdir:
572 * Obtains the root directory used for looking up assemblies.
574 * Returns: a string with the directory, this string should not be freed.
576 G_CONST_RETURN gchar *
577 mono_assembly_getrootdir (void)
579 return default_path [0];
583 * mono_native_getrootdir:
585 * Obtains the root directory used for looking up native libs (.so, .dylib).
587 * Returns: a string with the directory, this string should be freed by
591 mono_native_getrootdir (void)
593 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
599 * \param assembly_dir the base directory for assemblies
600 * \param config_dir the base directory for configuration files
602 * This routine is used internally and by developers embedding
603 * the runtime into their own applications.
605 * There are a number of cases to consider: Mono as a system-installed
606 * package that is available on the location preconfigured or Mono in
607 * a relocated location.
609 * If you are using a system-installed Mono, you can pass NULL
610 * to both parameters. If you are not, you should compute both
611 * directory values and call this routine.
613 * The values for a given PREFIX are:
615 * assembly_dir: PREFIX/lib
616 * config_dir: PREFIX/etc
618 * Notice that embedders that use Mono in a relocated way must
619 * compute the location at runtime, as they will be in control
620 * of where Mono is installed.
623 mono_set_dirs (const char *assembly_dir, const char *config_dir)
625 if (assembly_dir == NULL)
626 assembly_dir = mono_config_get_assemblies_dir ();
627 if (config_dir == NULL)
628 config_dir = mono_config_get_cfg_dir ();
629 mono_assembly_setrootdir (assembly_dir);
630 mono_set_config_dir (config_dir);
636 compute_base (char *path)
638 char *p = strrchr (path, '/');
642 /* Not a well known Mono executable, we are embedded, cant guess the base */
643 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
647 p = strrchr (path, '/');
651 if (strcmp (p, "/bin") != 0)
660 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
663 static G_GNUC_UNUSED void
667 char *config, *lib, *mono;
672 * Only /usr prefix is treated specially
674 bindir = mono_config_get_bin_dir ();
676 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
681 config = g_build_filename (base, "etc", NULL);
682 lib = g_build_filename (base, "lib", NULL);
683 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
684 if (stat (mono, &buf) == -1)
687 mono_set_dirs (lib, config);
695 #endif /* HOST_WIN32 */
700 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
701 * this auto-detects the prefix where Mono was installed.
704 mono_set_rootdir (void)
706 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
707 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
710 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
714 * _NSGetExecutablePath may return -1 to indicate buf is not large
715 * enough, but we ignore that case to avoid having to do extra dynamic
716 * allocation for the path and hope that 4096 is enough - this is
717 * ok in the Linux/Solaris case below at least...
721 guint buf_size = sizeof (buf);
724 if (_NSGetExecutablePath (buf, &buf_size) == 0)
725 name = g_strdup (buf);
734 resolvedname = mono_path_resolve_symlinks (name);
736 bindir = g_path_get_dirname (resolvedname);
737 installdir = g_path_get_dirname (bindir);
738 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
740 config = g_build_filename (root, "..", "etc", NULL);
742 mono_set_dirs (root, config);
744 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
745 mono_set_dirs (root, config);
755 g_free (resolvedname);
756 #elif defined(DISABLE_MONO_AUTODETECTION)
764 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
772 /* Solaris 10 style */
773 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
774 s = readlink (str, buf, sizeof (buf)-1);
786 * mono_assemblies_init:
788 * Initialize global variables used by this module.
791 mono_assemblies_init (void)
794 * Initialize our internal paths if we have not been initialized yet.
795 * This happens when embedders use Mono.
797 if (mono_assembly_getrootdir () == NULL)
801 check_extra_gac_path_env ();
803 mono_os_mutex_init_recursive (&assemblies_mutex);
804 mono_os_mutex_init (&assembly_binding_mutex);
806 #ifndef DISABLE_ASSEMBLY_REMAPPING
807 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
810 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
811 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
817 mono_assembly_binding_lock (void)
819 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
823 mono_assembly_binding_unlock (void)
825 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
829 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
831 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
832 guint32 cols [MONO_ASSEMBLY_SIZE];
833 gint32 machine, flags;
838 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
841 aname->hash_value = NULL;
842 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
844 aname->name = g_strdup (aname->name);
845 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
847 aname->culture = g_strdup (aname->culture);
848 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
849 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
850 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
851 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
852 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
853 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
854 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
855 guchar* token = (guchar *)g_malloc (8);
860 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
861 len = mono_metadata_decode_blob_size (pkey, &pkey);
862 aname->public_key = (guchar*)pkey;
864 mono_digest_get_public_token (token, aname->public_key, len);
865 encoded = encode_public_tok (token, 8);
866 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
872 aname->public_key = NULL;
873 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
876 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
877 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
879 const gchar *pkey_end;
880 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
881 pkey_end += len; /* move to end */
882 size_t size = pkey_end - (const gchar*)aname->public_key;
883 guchar *tmp = g_new (guchar, size);
884 memcpy (tmp, aname->public_key, size);
885 aname->public_key = tmp;
890 aname->public_key = 0;
892 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
893 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
895 case COFF_MACHINE_I386:
896 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
897 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
898 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
899 else if ((flags & 0x70) == 0x70)
900 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
902 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
904 case COFF_MACHINE_IA64:
905 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
907 case COFF_MACHINE_AMD64:
908 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
910 case COFF_MACHINE_ARM:
911 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
921 * mono_assembly_fill_assembly_name:
924 * \returns TRUE if successful
927 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
929 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
933 * mono_stringify_assembly_name:
934 * \param aname the assembly name.
936 * Convert \p aname into its string format. The returned string is dynamically
937 * allocated and should be freed by the caller.
939 * \returns a newly allocated string with a string representation of
943 mono_stringify_assembly_name (MonoAssemblyName *aname)
945 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
947 return g_strdup_printf (
948 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
949 quote, aname->name, quote,
950 aname->major, aname->minor, aname->build, aname->revision,
951 aname->culture && *aname->culture? aname->culture: "neutral",
952 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
953 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
957 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
959 const gchar *public_tok;
962 public_tok = mono_metadata_blob_heap (image, key_index);
963 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
965 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
967 mono_digest_get_public_token (token, (guchar*)public_tok, len);
968 return encode_public_tok (token, 8);
971 return encode_public_tok ((guchar*)public_tok, len);
975 * mono_assembly_addref:
976 * \param assembly the assembly to reference
978 * This routine increments the reference count on a MonoAssembly.
979 * The reference count is reduced every time the method mono_assembly_close() is
983 mono_assembly_addref (MonoAssembly *assembly)
985 InterlockedIncrement (&assembly->ref_count);
989 * CAUTION: This table must be kept in sync with
990 * ivkm/reflect/Fusion.cs
993 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
994 #define WINFX_KEY "31bf3856ad364e35"
995 #define ECMA_KEY "b77a5c561934e089"
996 #define MSFINAL_KEY "b03f5f7f11d50a3a"
997 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1005 static KeyRemapEntry key_remap_table[] = {
1006 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1007 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1008 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1009 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1010 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1011 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1012 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1013 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1014 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1015 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1016 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1017 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1018 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1019 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1020 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1021 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1022 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1023 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1024 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1025 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1026 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1027 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1028 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1029 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1030 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1031 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1032 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1033 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1034 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1038 remap_keys (MonoAssemblyName *aname)
1041 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1042 const KeyRemapEntry *entry = &key_remap_table [i];
1044 if (strcmp (aname->name, entry->name) ||
1045 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1048 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1050 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1051 "Remapped public key token of retargetable assembly %s from %s to %s",
1052 aname->name, entry->from, entry->to);
1057 static MonoAssemblyName *
1058 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1060 const MonoRuntimeInfo *current_runtime;
1062 if (aname->name == NULL) return aname;
1064 current_runtime = mono_get_runtime_info ();
1066 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1067 const AssemblyVersionSet* vset;
1069 /* Remap to current runtime */
1070 vset = ¤t_runtime->version_sets [0];
1072 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1073 dest_aname->major = vset->major;
1074 dest_aname->minor = vset->minor;
1075 dest_aname->build = vset->build;
1076 dest_aname->revision = vset->revision;
1077 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1079 /* Remap assembly name */
1080 if (!strcmp (aname->name, "System.Net"))
1081 dest_aname->name = g_strdup ("System");
1083 remap_keys (dest_aname);
1085 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1086 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1088 aname->major, aname->minor, aname->build, aname->revision,
1090 vset->major, vset->minor, vset->build, vset->revision
1096 #ifndef DISABLE_ASSEMBLY_REMAPPING
1097 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1099 const AssemblyVersionSet* vset;
1100 int index = vmap->version_set_index;
1101 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1102 vset = ¤t_runtime->version_sets [index];
1104 if (aname->major == vset->major && aname->minor == vset->minor &&
1105 aname->build == vset->build && aname->revision == vset->revision) {
1106 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1108 aname->major, aname->minor, aname->build, aname->revision);
1112 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1113 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1114 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1116 aname->major, aname->minor, aname->build, aname->revision,
1117 vset->major, vset->minor, vset->build, vset->revision
1122 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1123 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1124 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1126 aname->major, aname->minor, aname->build, aname->revision,
1127 vset->major, vset->minor, vset->build, vset->revision
1130 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1131 dest_aname->major = vset->major;
1132 dest_aname->minor = vset->minor;
1133 dest_aname->build = vset->build;
1134 dest_aname->revision = vset->revision;
1135 if (current_runtime->public_key_token != NULL &&
1136 dest_aname->public_key_token [0] != 0 &&
1137 !mono_public_tokens_are_equal (dest_aname->public_key_token, (const mono_byte *)current_runtime->public_key_token)) {
1138 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1139 "The request for assembly name '%s' with PublicKeyToken=%s was remapped to PublicKeyToken=%s",
1141 dest_aname->public_key_token,
1142 current_runtime->public_key_token);
1143 memcpy (dest_aname->public_key_token, current_runtime->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1145 if (vmap->new_assembly_name != NULL) {
1146 dest_aname->name = vmap->new_assembly_name;
1147 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1148 "The assembly name %s was remapped to %s",
1160 * mono_assembly_get_assemblyref:
1161 * \param image pointer to the MonoImage to extract the information from.
1162 * \param index index to the assembly reference in the image.
1163 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1165 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1168 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1171 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1174 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1176 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1178 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1179 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1180 aname->hash_value = hash;
1181 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1182 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1183 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1184 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1185 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1186 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1187 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1189 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1190 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1191 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1194 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1199 mono_assembly_load_reference (MonoImage *image, int index)
1201 MonoAssembly *reference;
1202 MonoAssemblyName aname;
1203 MonoImageOpenStatus status;
1206 * image->references is shared between threads, so we need to access
1207 * it inside a critical section.
1209 mono_assemblies_lock ();
1210 if (!image->references) {
1211 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1213 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1214 image->nreferences = t->rows;
1216 reference = image->references [index];
1217 mono_assemblies_unlock ();
1221 mono_assembly_get_assemblyref (image, index, &aname);
1223 if (image->assembly && image->assembly->ref_only) {
1224 /* We use the loaded corlib */
1225 if (!strcmp (aname.name, "mscorlib"))
1226 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1228 reference = mono_assembly_loaded_full (&aname, TRUE);
1230 /* Try a postload search hook */
1231 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1235 * Here we must advice that the error was due to
1236 * a non loaded reference using the ReflectionOnly api
1239 reference = (MonoAssembly *)REFERENCE_MISSING;
1241 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1242 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1243 * accordingly, it would fail on the MS runtime before).
1244 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1245 * example bug-349190.2.cs and who knows how much more code in the wild.
1247 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1248 if (!reference && image->assembly)
1249 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1252 if (reference == NULL){
1255 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1256 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 : "" );
1257 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1258 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1259 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1260 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1261 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1262 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1264 extra_msg = g_strdup ("");
1267 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1268 " Assembly: %s (assemblyref_index=%d)\n"
1269 " Version: %d.%d.%d.%d\n"
1270 " Public Key: %s\n%s",
1271 image->name, aname.name, index,
1272 aname.major, aname.minor, aname.build, aname.revision,
1273 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1278 mono_assemblies_lock ();
1279 if (reference == NULL) {
1280 /* Flag as not found */
1281 reference = (MonoAssembly *)REFERENCE_MISSING;
1284 if (!image->references [index]) {
1285 if (reference != REFERENCE_MISSING){
1286 mono_assembly_addref (reference);
1287 if (image->assembly)
1288 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1289 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1291 if (image->assembly)
1292 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1293 image->assembly->aname.name, image->assembly);
1296 image->references [index] = reference;
1298 mono_assemblies_unlock ();
1300 if (image->references [index] != reference) {
1301 /* Somebody loaded it before us */
1302 mono_assembly_close (reference);
1307 * mono_assembly_load_references:
1310 * \deprecated There is no reason to use this method anymore, it does nothing
1312 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1315 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1317 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1318 *status = MONO_IMAGE_OK;
1321 typedef struct AssemblyLoadHook AssemblyLoadHook;
1322 struct AssemblyLoadHook {
1323 AssemblyLoadHook *next;
1324 MonoAssemblyLoadFunc func;
1328 AssemblyLoadHook *assembly_load_hook = NULL;
1331 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1333 AssemblyLoadHook *hook;
1335 for (hook = assembly_load_hook; hook; hook = hook->next) {
1336 hook->func (ass, hook->user_data);
1341 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1343 AssemblyLoadHook *hook;
1345 g_return_if_fail (func != NULL);
1347 hook = g_new0 (AssemblyLoadHook, 1);
1349 hook->user_data = user_data;
1350 hook->next = assembly_load_hook;
1351 assembly_load_hook = hook;
1355 free_assembly_load_hooks (void)
1357 AssemblyLoadHook *hook, *next;
1359 for (hook = assembly_load_hook; hook; hook = next) {
1365 typedef struct AssemblySearchHook AssemblySearchHook;
1366 struct AssemblySearchHook {
1367 AssemblySearchHook *next;
1368 MonoAssemblySearchFunc func;
1374 AssemblySearchHook *assembly_search_hook = NULL;
1376 static MonoAssembly*
1377 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1379 AssemblySearchHook *hook;
1381 for (hook = assembly_search_hook; hook; hook = hook->next) {
1382 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1385 * A little explanation is in order here.
1387 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1388 * The embedding API exposes a search hook that doesn't take such argument.
1390 * The original fix would call the default search hook before all the registered ones and pass
1391 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1392 * rely on. Which is the ordering between user hooks and the default runtime hook.
1394 * Registering the hook after mono_jit_init would let your hook run before the default one and
1395 * when using it to handle non standard app layouts this could save your app from a massive amount
1396 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1397 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1399 * So what's the fix? We register the default hook using regular means and special case it when iterating
1400 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1403 if (hook->func == (void*)mono_domain_assembly_postload_search)
1404 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1406 ass = hook->func (aname, hook->user_data);
1416 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1418 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1422 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1424 AssemblySearchHook *hook;
1426 g_return_if_fail (func != NULL);
1428 hook = g_new0 (AssemblySearchHook, 1);
1430 hook->user_data = user_data;
1431 hook->refonly = refonly;
1432 hook->postload = postload;
1433 hook->next = assembly_search_hook;
1434 assembly_search_hook = hook;
1438 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1440 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1444 free_assembly_search_hooks (void)
1446 AssemblySearchHook *hook, *next;
1448 for (hook = assembly_search_hook; hook; hook = next) {
1455 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1457 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1461 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1463 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1467 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1469 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1472 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1473 struct AssemblyPreLoadHook {
1474 AssemblyPreLoadHook *next;
1475 MonoAssemblyPreLoadFunc func;
1479 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1480 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1482 static MonoAssembly *
1483 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1485 AssemblyPreLoadHook *hook;
1486 MonoAssembly *assembly;
1488 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1489 assembly = hook->func (aname, assemblies_path, hook->user_data);
1490 if (assembly != NULL)
1497 static MonoAssembly *
1498 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1500 AssemblyPreLoadHook *hook;
1501 MonoAssembly *assembly;
1503 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1504 assembly = hook->func (aname, assemblies_path, hook->user_data);
1505 if (assembly != NULL)
1513 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1515 AssemblyPreLoadHook *hook;
1517 g_return_if_fail (func != NULL);
1519 hook = g_new0 (AssemblyPreLoadHook, 1);
1521 hook->user_data = user_data;
1522 hook->next = assembly_preload_hook;
1523 assembly_preload_hook = hook;
1527 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1529 AssemblyPreLoadHook *hook;
1531 g_return_if_fail (func != NULL);
1533 hook = g_new0 (AssemblyPreLoadHook, 1);
1535 hook->user_data = user_data;
1536 hook->next = assembly_refonly_preload_hook;
1537 assembly_refonly_preload_hook = hook;
1541 free_assembly_preload_hooks (void)
1543 AssemblyPreLoadHook *hook, *next;
1545 for (hook = assembly_preload_hook; hook; hook = next) {
1550 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1557 absolute_dir (const gchar *filename)
1568 if (g_path_is_absolute (filename)) {
1569 part = g_path_get_dirname (filename);
1570 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1575 cwd = g_get_current_dir ();
1576 mixed = g_build_filename (cwd, filename, NULL);
1577 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1582 for (i = 0; (part = parts [i]) != NULL; i++) {
1583 if (!strcmp (part, "."))
1586 if (!strcmp (part, "..")) {
1587 if (list && list->next) /* Don't remove root */
1588 list = g_list_delete_link (list, list);
1590 list = g_list_prepend (list, part);
1594 result = g_string_new ("");
1595 list = g_list_reverse (list);
1597 /* Ignores last data pointer, which should be the filename */
1598 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1600 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1605 g_string_free (result, FALSE);
1610 return g_strdup (".");
1617 * mono_assembly_open_from_bundle:
1618 * \param filename Filename requested
1619 * \param status return status code
1621 * This routine tries to open the assembly specified by \p filename from the
1622 * defined bundles, if found, returns the MonoImage for it, if not found
1626 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1630 gchar *lowercase_filename;
1631 MonoImage *image = NULL;
1632 gboolean is_satellite = FALSE;
1634 * we do a very simple search for bundled assemblies: it's not a general
1635 * purpose assembly loading mechanism.
1641 lowercase_filename = g_utf8_strdown (filename, -1);
1642 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1643 g_free (lowercase_filename);
1644 name = g_path_get_basename (filename);
1645 mono_assemblies_lock ();
1646 for (i = 0; !image && bundles [i]; ++i) {
1647 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1648 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1652 mono_assemblies_unlock ();
1654 mono_image_addref (image);
1655 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1664 * mono_assembly_open_full:
1665 * \param filename the file to load
1666 * \param status return status code
1667 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1669 * This loads an assembly from the specified \p filename. The \p filename allows
1670 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1671 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1672 * is treated as a local path.
1674 * First, an attempt is made to load the assembly from the bundled executable (for those
1675 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1676 * assembly has been registered as an embedded assembly). If this is not the case, then
1677 * the assembly is loaded from disk using `api:mono_image_open_full`.
1679 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1680 * the assembly is made.
1682 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1683 * the \c System.Reflection API.
1685 * \returns NULL on error, with the \p status set to an error code, or a pointer
1689 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1691 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1695 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1697 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1701 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1702 gboolean load_from_context,
1703 MonoAssemblyCandidatePredicate predicate,
1705 MonoImageOpenStatus *status)
1709 MonoImageOpenStatus def_status;
1712 gboolean loaded_from_bundle;
1714 g_return_val_if_fail (filename != NULL, NULL);
1717 status = &def_status;
1718 *status = MONO_IMAGE_OK;
1720 if (strncmp (filename, "file://", 7) == 0) {
1721 GError *error = NULL;
1722 gchar *uri = (gchar *) filename;
1726 * MS allows file://c:/... and fails on file://localhost/c:/...
1727 * They also throw an IndexOutOfRangeException if "file://"
1730 uri = g_strdup_printf ("file:///%s", uri + 7);
1733 uri = mono_escape_uri_string (tmpuri);
1734 fname = g_filename_from_uri (uri, NULL, &error);
1737 if (tmpuri != filename)
1740 if (error != NULL) {
1741 g_warning ("%s\n", error->message);
1742 g_error_free (error);
1743 fname = g_strdup (filename);
1746 fname = g_strdup (filename);
1749 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1750 "Assembly Loader probing location: '%s'.", fname);
1753 if (!mono_assembly_is_in_gac (fname)) {
1755 new_fname = mono_make_shadow_copy (fname, &error);
1756 if (!is_ok (&error)) {
1757 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1758 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1759 mono_error_cleanup (&error);
1760 *status = MONO_IMAGE_IMAGE_INVALID;
1765 if (new_fname && new_fname != fname) {
1768 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1769 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1774 // If VM built with mkbundle
1775 loaded_from_bundle = FALSE;
1776 if (bundles != NULL) {
1777 image = mono_assembly_open_from_bundle (fname, status, refonly);
1778 loaded_from_bundle = image != NULL;
1782 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1785 if (*status == MONO_IMAGE_OK)
1786 *status = MONO_IMAGE_ERROR_ERRNO;
1791 if (image->assembly) {
1792 /* Already loaded by another appdomain */
1793 mono_assembly_invoke_load_hook (image->assembly);
1794 mono_image_close (image);
1796 return image->assembly;
1799 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1802 if (!loaded_from_bundle)
1803 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1804 "Assembly Loader loaded assembly from location: '%s'.", filename);
1806 mono_config_for_assembly (ass->image);
1809 /* Clear the reference added by mono_image_open */
1810 mono_image_close (image);
1818 free_item (gpointer val, gpointer user_data)
1824 * mono_assembly_load_friends:
1825 * \param ass an assembly
1827 * Load the list of friend assemblies that are allowed to access
1828 * the assembly's internal types and members. They are stored as assembly
1829 * names in custom attributes.
1831 * This is an internal method, we need this because when we load mscorlib
1832 * we do not have the internals visible cattr loaded yet,
1833 * so we need to load these after we initialize the runtime.
1835 * LOCKING: Acquires the assemblies lock plus the loader lock.
1838 mono_assembly_load_friends (MonoAssembly* ass)
1842 MonoCustomAttrInfo* attrs;
1845 if (ass->friend_assembly_names_inited)
1848 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1849 mono_error_assert_ok (&error);
1851 mono_assemblies_lock ();
1852 ass->friend_assembly_names_inited = TRUE;
1853 mono_assemblies_unlock ();
1857 mono_assemblies_lock ();
1858 if (ass->friend_assembly_names_inited) {
1859 mono_assemblies_unlock ();
1862 mono_assemblies_unlock ();
1866 * We build the list outside the assemblies lock, the worse that can happen
1867 * is that we'll need to free the allocated list.
1869 for (i = 0; i < attrs->num_attrs; ++i) {
1870 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1871 MonoAssemblyName *aname;
1873 /* Do some sanity checking */
1874 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1876 if (attr->data_size < 4)
1878 data = (const char*)attr->data;
1879 /* 0xFF means null string, see custom attr format */
1880 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1882 mono_metadata_decode_value (data + 2, &data);
1883 aname = g_new0 (MonoAssemblyName, 1);
1884 /*g_print ("friend ass: %s\n", data);*/
1885 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1886 list = g_slist_prepend (list, aname);
1891 mono_custom_attrs_free (attrs);
1893 mono_assemblies_lock ();
1894 if (ass->friend_assembly_names_inited) {
1895 mono_assemblies_unlock ();
1896 g_slist_foreach (list, free_item, NULL);
1897 g_slist_free (list);
1900 ass->friend_assembly_names = list;
1902 /* Because of the double checked locking pattern above */
1903 mono_memory_barrier ();
1904 ass->friend_assembly_names_inited = TRUE;
1905 mono_assemblies_unlock ();
1908 struct HasReferenceAssemblyAttributeIterData {
1913 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1915 gboolean stop_scanning = FALSE;
1916 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1918 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1919 /* Note we don't check the assembly name, same as coreCLR. */
1920 iter_data->has_attr = TRUE;
1921 stop_scanning = TRUE;
1924 return stop_scanning;
1928 * mono_assembly_has_reference_assembly_attribute:
1929 * \param assembly a MonoAssembly
1930 * \param error set on error.
1932 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1933 * On error returns FALSE and sets \p error.
1936 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1941 * This might be called during assembly loading, so do everything using the low-level
1945 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1947 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1949 return iter_data.has_attr;
1953 * mono_assembly_open:
1954 * \param filename Opens the assembly pointed out by this name
1955 * \param status return status code
1957 * This loads an assembly from the specified \p filename. The \p filename allows
1958 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1959 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1960 * is treated as a local path.
1962 * First, an attempt is made to load the assembly from the bundled executable (for those
1963 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1964 * assembly has been registered as an embedded assembly). If this is not the case, then
1965 * the assembly is loaded from disk using `api:mono_image_open_full`.
1967 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1968 * the assembly is made.
1970 * \returns a pointer to the MonoAssembly if \p filename contains a valid
1971 * assembly or NULL on error. Details about the error are stored in the
1972 * \p status variable.
1975 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1977 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
1981 * mono_assembly_load_from_full:
1982 * \param image Image to load the assembly from
1983 * \param fname assembly name to associate with the assembly
1984 * \param status returns the status condition
1985 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1987 * If the provided \p image has an assembly reference, it will process the given
1988 * image as an assembly with the given name.
1990 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1992 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
1993 * set to \c MONO_IMAGE_OK; or NULL on error.
1995 * If there is an error loading the assembly the \p status will indicate the
1996 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
1997 * image did not contain an assembly reference table.
2000 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2001 MonoImageOpenStatus *status, gboolean refonly)
2003 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2007 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2009 MonoAssemblyCandidatePredicate predicate,
2011 MonoImageOpenStatus *status)
2013 MonoAssembly *ass, *ass2;
2016 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2017 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2018 *status = MONO_IMAGE_IMAGE_INVALID;
2022 #if defined (HOST_WIN32)
2027 tmp_fn = g_strdup (fname);
2028 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2029 if (tmp_fn [i] == '/')
2033 base_dir = absolute_dir (tmp_fn);
2037 base_dir = absolute_dir (fname);
2041 * Create assembly struct, and enter it into the assembly cache
2043 ass = g_new0 (MonoAssembly, 1);
2044 ass->basedir = base_dir;
2045 ass->ref_only = refonly;
2048 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2050 mono_assembly_fill_assembly_name (image, &ass->aname);
2052 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2053 // MS.NET doesn't support loading other mscorlibs
2056 mono_image_addref (mono_defaults.corlib);
2057 *status = MONO_IMAGE_OK;
2058 return mono_defaults.corlib->assembly;
2061 /* Add a non-temporary reference because of ass->image */
2062 mono_image_addref (image);
2064 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);
2067 * The load hooks might take locks so we can't call them while holding the
2070 if (ass->aname.name) {
2071 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2075 mono_image_close (image);
2076 *status = MONO_IMAGE_OK;
2081 /* We need to check for ReferenceAssmeblyAttribute before we
2082 * mark the assembly as loaded and before we fire the load
2083 * hook. Otherwise mono_domain_fire_assembly_load () in
2084 * appdomain.c will cache a mapping from the assembly name to
2085 * this image and we won't be able to look for a different
2089 MonoError refasm_error;
2090 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2091 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2094 mono_image_close (image);
2095 *status = MONO_IMAGE_IMAGE_INVALID;
2098 mono_error_cleanup (&refasm_error);
2101 if (predicate && !predicate (ass, user_data)) {
2102 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2105 mono_image_close (image);
2106 *status = MONO_IMAGE_IMAGE_INVALID;
2110 mono_assemblies_lock ();
2112 if (image->assembly) {
2114 * This means another thread has already loaded the assembly, but not yet
2115 * called the load hooks so the search hook can't find the assembly.
2117 mono_assemblies_unlock ();
2118 ass2 = image->assembly;
2121 mono_image_close (image);
2122 *status = MONO_IMAGE_OK;
2126 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2128 image->assembly = ass;
2130 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2131 mono_assemblies_unlock ();
2134 if (image->is_module_handle)
2135 mono_image_fixup_vtable (image);
2138 mono_assembly_invoke_load_hook (ass);
2140 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2146 * mono_assembly_load_from:
2147 * \param image Image to load the assembly from
2148 * \param fname assembly name to associate with the assembly
2149 * \param status return status code
2151 * If the provided \p image has an assembly reference, it will process the given
2152 * image as an assembly with the given name.
2154 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2156 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2157 * \p refonly parameter set to FALSE.
2158 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2159 * set to \c MONO_IMAGE_OK; or NULL on error.
2161 * If there is an error loading the assembly the \p status will indicate the
2162 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2163 * image did not contain an assembly reference table.
2167 mono_assembly_load_from (MonoImage *image, const char *fname,
2168 MonoImageOpenStatus *status)
2170 return mono_assembly_load_from_full (image, fname, status, FALSE);
2174 * mono_assembly_name_free:
2175 * \param aname assembly name to free
2177 * Frees the provided assembly name object.
2178 * (it does not frees the object itself, only the name members).
2181 mono_assembly_name_free (MonoAssemblyName *aname)
2186 g_free ((void *) aname->name);
2187 g_free ((void *) aname->culture);
2188 g_free ((void *) aname->hash_value);
2189 g_free ((guint8*) aname->public_key);
2193 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2196 gchar header [16], val, *arr;
2197 gint i, j, offset, bitlen, keylen, pkeylen;
2199 keylen = strlen (key) >> 1;
2203 /* allow the ECMA standard key */
2204 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2206 *pubkey = g_strdup (key);
2212 val = g_ascii_xdigit_value (key [0]) << 4;
2213 val |= g_ascii_xdigit_value (key [1]);
2218 val = g_ascii_xdigit_value (key [24]);
2219 val |= g_ascii_xdigit_value (key [25]);
2231 /* We need the first 16 bytes
2232 * to check whether this key is valid or not */
2233 pkeylen = strlen (pkey) >> 1;
2237 for (i = 0, j = 0; i < 16; i++) {
2238 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2239 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2242 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2243 header [1] != 0x02 || /* Version (0x02) */
2244 header [2] != 0x00 || /* Reserved (word) */
2245 header [3] != 0x00 ||
2246 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2249 /* Based on this length, we _should_ be able to know if the length is right */
2250 bitlen = read32 (header + 12) >> 3;
2251 if ((bitlen + 16 + 4) != pkeylen)
2254 /* parsing is OK and the public key itself is not requested back */
2258 /* Encode the size of the blob */
2260 if (keylen <= 127) {
2261 arr = (gchar *)g_malloc (keylen + 1);
2262 arr [offset++] = keylen;
2264 arr = (gchar *)g_malloc (keylen + 2);
2265 arr [offset++] = 0x80; /* 10bs */
2266 arr [offset++] = keylen;
2269 for (i = offset, j = 0; i < keylen + offset; i++) {
2270 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2271 arr [i] |= g_ascii_xdigit_value (key [j++]);
2280 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)
2282 gint major, minor, build, revision;
2285 gchar *pkey, *pkeyptr, *encoded, tok [8];
2287 memset (aname, 0, sizeof (MonoAssemblyName));
2290 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2291 if (version_parts < 2 || version_parts > 4)
2294 /* FIXME: we should set build & revision to -1 (instead of 0)
2295 if these are not set in the version string. That way, later on,
2296 we can still determine if these were specified. */
2297 aname->major = major;
2298 aname->minor = minor;
2299 if (version_parts >= 3)
2300 aname->build = build;
2303 if (version_parts == 4)
2304 aname->revision = revision;
2306 aname->revision = 0;
2309 aname->flags = flags;
2311 aname->name = g_strdup (name);
2314 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2315 aname->culture = g_strdup ("");
2317 aname->culture = g_strdup (culture);
2320 if (token && strncmp (token, "null", 4) != 0) {
2323 /* the constant includes the ending NULL, hence the -1 */
2324 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2325 mono_assembly_name_free (aname);
2328 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2329 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2335 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2336 mono_assembly_name_free (aname);
2341 if (save_public_key)
2342 aname->public_key = (guint8*)pkey;
2345 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2349 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2350 // We also need to generate the key token
2351 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2352 encoded = encode_public_tok ((guchar*) tok, 8);
2353 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2356 if (save_public_key)
2357 aname->public_key = (guint8*) pkey;
2366 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2371 parts = g_strsplit (dirname, "_", 3);
2372 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2377 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2383 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2385 char *eqsign = strchr (pair, '=');
2393 *key = (gchar*)pair;
2394 *keylen = eqsign - *key;
2395 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2397 *value = g_strstrip (eqsign + 1);
2402 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2406 gchar *version = NULL;
2408 gchar *culture = NULL;
2410 gchar *token = NULL;
2414 gchar *retargetable = NULL;
2415 gchar *retargetable_uq;
2419 gchar *value, *part_name;
2420 guint32 part_name_len;
2423 gboolean version_defined;
2424 gboolean token_defined;
2426 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2428 if (!is_version_defined)
2429 is_version_defined = &version_defined;
2430 *is_version_defined = FALSE;
2431 if (!is_token_defined)
2432 is_token_defined = &token_defined;
2433 *is_token_defined = FALSE;
2435 parts = tmp = g_strsplit (name, ",", 6);
2436 if (!tmp || !*tmp) {
2441 dllname = g_strstrip (*tmp);
2446 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2447 goto cleanup_and_fail;
2449 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2450 *is_version_defined = TRUE;
2452 if (strlen (version) == 0) {
2453 goto cleanup_and_fail;
2459 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2461 if (strlen (culture) == 0) {
2462 goto cleanup_and_fail;
2468 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2469 *is_token_defined = TRUE;
2471 if (strlen (token) == 0) {
2472 goto cleanup_and_fail;
2478 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2480 if (strlen (key) == 0) {
2481 goto cleanup_and_fail;
2487 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2488 retargetable = value;
2489 retargetable_uq = unquote (retargetable);
2490 if (retargetable_uq != NULL)
2491 retargetable = retargetable_uq;
2493 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2494 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2495 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2496 g_free (retargetable_uq);
2497 goto cleanup_and_fail;
2500 g_free (retargetable_uq);
2505 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2507 procarch_uq = unquote (procarch);
2508 if (procarch_uq != NULL)
2509 procarch = procarch_uq;
2511 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2512 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2513 else if (!g_ascii_strcasecmp (procarch, "X86"))
2514 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2515 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2516 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2517 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2518 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2520 g_free (procarch_uq);
2521 goto cleanup_and_fail;
2524 g_free (procarch_uq);
2533 /* if retargetable flag is set, then we must have a fully qualified name */
2534 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2535 goto cleanup_and_fail;
2538 dllname_uq = unquote (dllname);
2539 version_uq = unquote (version);
2540 culture_uq = unquote (culture);
2541 token_uq = unquote (token);
2542 key_uq = unquote (key);
2544 res = build_assembly_name (
2545 dllname_uq == NULL ? dllname : dllname_uq,
2546 version_uq == NULL ? version : version_uq,
2547 culture_uq == NULL ? culture : culture_uq,
2548 token_uq == NULL ? token : token_uq,
2549 key_uq == NULL ? key : key_uq,
2550 flags, arch, aname, save_public_key);
2552 g_free (dllname_uq);
2553 g_free (version_uq);
2554 g_free (culture_uq);
2567 unquote (const char *str)
2575 slen = strlen (str);
2579 if (*str != '\'' && *str != '\"')
2582 end = str + slen - 1;
2586 return g_strndup (str + 1, slen - 2);
2590 * mono_assembly_name_parse:
2591 * \param name name to parse
2592 * \param aname the destination assembly name
2594 * Parses an assembly qualified type name and assigns the name,
2595 * version, culture and token to the provided assembly name object.
2597 * \returns TRUE if the name could be parsed.
2600 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2602 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2606 * mono_assembly_name_new:
2607 * \param name name to parse
2609 * Allocate a new MonoAssemblyName and fill its values from the
2612 * \returns a newly allocated structure or NULL if there was any failure.
2615 mono_assembly_name_new (const char *name)
2617 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2618 if (mono_assembly_name_parse (name, aname))
2625 mono_assembly_name_get_name (MonoAssemblyName *aname)
2631 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2633 return aname->culture;
2637 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2639 if (aname->public_key_token [0])
2640 return aname->public_key_token;
2645 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2648 *minor = aname->minor;
2650 *build = aname->build;
2652 *revision = aname->revision;
2653 return aname->major;
2656 static MonoAssembly*
2657 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2659 gchar *fullpath = NULL;
2661 const char* direntry;
2662 MonoAssemblyName gac_aname;
2663 gint major=-1, minor=0, build=0, revision=0;
2664 gboolean exact_version;
2666 dirhandle = g_dir_open (basepath, 0, NULL);
2670 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2672 while ((direntry = g_dir_read_name (dirhandle))) {
2673 gboolean match = TRUE;
2675 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2678 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2681 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2682 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2686 if (exact_version) {
2687 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2688 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2690 else if (gac_aname.major < major)
2692 else if (gac_aname.major == major) {
2693 if (gac_aname.minor < minor)
2695 else if (gac_aname.minor == minor) {
2696 if (gac_aname.build < build)
2698 else if (gac_aname.build == build && gac_aname.revision <= revision)
2705 major = gac_aname.major;
2706 minor = gac_aname.minor;
2707 build = gac_aname.build;
2708 revision = gac_aname.revision;
2710 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2713 mono_assembly_name_free (&gac_aname);
2716 g_dir_close (dirhandle);
2718 if (fullpath == NULL)
2721 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2728 * mono_assembly_load_with_partial_name:
2729 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2730 * \param status return status code
2732 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2733 * so it might contain a qualified type name, version, culture and token.
2735 * This will load the assembly from the file whose name is derived from the assembly name
2736 * by appending the .dll extension.
2738 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2739 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2740 * if that fails from the GAC.
2742 * \returns NULL on failure, or a pointer to a MonoAssembly on success.
2745 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2749 MonoAssemblyName *aname, base_name;
2750 MonoAssemblyName mapped_aname;
2751 gchar *fullname, *gacpath;
2754 memset (&base_name, 0, sizeof (MonoAssemblyName));
2757 if (!mono_assembly_name_parse (name, aname))
2761 * If no specific version has been requested, make sure we load the
2762 * correct version for system assemblies.
2764 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2765 aname = mono_assembly_remap_version (aname, &mapped_aname);
2767 res = mono_assembly_loaded (aname);
2769 mono_assembly_name_free (aname);
2773 res = invoke_assembly_preload_hook (aname, assemblies_path);
2775 res->in_gac = FALSE;
2776 mono_assembly_name_free (aname);
2780 fullname = g_strdup_printf ("%s.dll", aname->name);
2782 if (extra_gac_paths) {
2783 paths = extra_gac_paths;
2784 while (!res && *paths) {
2785 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2786 res = probe_for_partial_name (gacpath, fullname, aname, status);
2795 mono_assembly_name_free (aname);
2799 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2800 res = probe_for_partial_name (gacpath, fullname, aname, status);
2804 mono_assembly_name_free (aname);
2809 MonoDomain *domain = mono_domain_get ();
2811 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2812 if (!is_ok (&error)) {
2813 mono_error_cleanup (&error);
2814 if (*status == MONO_IMAGE_OK)
2815 *status = MONO_IMAGE_IMAGE_INVALID;
2823 mono_assembly_is_in_gac (const gchar *filename)
2825 const gchar *rootdir;
2829 if (filename == NULL)
2832 for (paths = extra_gac_paths; paths && *paths; paths++) {
2833 if (strstr (*paths, filename) != *paths)
2836 gp = (gchar *) (filename + strlen (*paths));
2837 if (*gp != G_DIR_SEPARATOR)
2840 if (strncmp (gp, "lib", 3))
2843 if (*gp != G_DIR_SEPARATOR)
2846 if (strncmp (gp, "mono", 4))
2849 if (*gp != G_DIR_SEPARATOR)
2852 if (strncmp (gp, "gac", 3))
2855 if (*gp != G_DIR_SEPARATOR)
2861 rootdir = mono_assembly_getrootdir ();
2862 if (strstr (filename, rootdir) != filename)
2865 gp = (gchar *) (filename + strlen (rootdir));
2866 if (*gp != G_DIR_SEPARATOR)
2869 if (strncmp (gp, "mono", 4))
2872 if (*gp != G_DIR_SEPARATOR)
2875 if (strncmp (gp, "gac", 3))
2878 if (*gp != G_DIR_SEPARATOR)
2884 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2887 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2891 if (strstr (aname->name, ".dll")) {
2892 len = strlen (aname->name) - 4;
2893 name = (gchar *)g_malloc (len + 1);
2894 memcpy (name, aname->name, len);
2897 name = g_strdup (aname->name);
2900 culture = g_utf8_strdown (aname->culture, -1);
2902 culture = g_strdup ("");
2904 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2905 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2909 filename = g_strconcat (pname, ".dll", NULL);
2910 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2916 if (extra_gac_paths) {
2917 paths = extra_gac_paths;
2918 while (!image && *paths) {
2919 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2920 "lib", "mono", "gac", subpath, NULL);
2921 image = mono_image_open (fullpath, NULL);
2932 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2933 "mono", "gac", subpath, NULL);
2934 image = mono_image_open (fullpath, NULL);
2941 static MonoAssemblyName*
2942 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2944 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2945 dest_name->major = info->new_version.major;
2946 dest_name->minor = info->new_version.minor;
2947 dest_name->build = info->new_version.build;
2948 dest_name->revision = info->new_version.revision;
2953 /* LOCKING: assembly_binding lock must be held */
2954 static MonoAssemblyBindingInfo*
2955 search_binding_loaded (MonoAssemblyName *aname)
2959 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2960 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2961 if (assembly_binding_maps_name (info, aname))
2968 static inline gboolean
2969 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2971 if (left->major != right->major || left->minor != right->minor ||
2972 left->build != right->build || left->revision != right->revision)
2978 static inline gboolean
2979 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2981 if (left->has_old_version_bottom != right->has_old_version_bottom)
2984 if (left->has_old_version_top != right->has_old_version_top)
2987 if (left->has_new_version != right->has_new_version)
2990 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2993 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2996 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3002 /* LOCKING: assumes all the necessary locks are held */
3004 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3006 MonoAssemblyBindingInfo *info_copy;
3008 MonoAssemblyBindingInfo *info_tmp;
3009 MonoDomain *domain = (MonoDomain*)user_data;
3014 if (info->has_new_version && mono_assembly_is_problematic_version (info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision)) {
3015 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3016 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3020 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3021 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3022 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3026 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3027 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3029 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3031 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3033 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3037 get_version_number (int major, int minor)
3039 return major * 256 + minor;
3042 static inline gboolean
3043 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3045 int aname_version_number = get_version_number (aname->major, aname->minor);
3046 if (!info->has_old_version_bottom)
3049 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3052 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3055 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3056 info->major = aname->major;
3057 info->minor = aname->minor;
3062 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3063 static MonoAssemblyBindingInfo*
3064 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3066 MonoAssemblyBindingInfo *info;
3069 if (!domain->assembly_bindings)
3073 for (list = domain->assembly_bindings; list; list = list->next) {
3074 info = (MonoAssemblyBindingInfo *)list->data;
3075 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3081 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3082 info->has_new_version && assembly_binding_maps_name (info, aname))
3083 info->is_valid = TRUE;
3085 info->is_valid = FALSE;
3091 static MonoAssemblyName*
3092 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3095 MonoAssemblyBindingInfo *info, *info2;
3099 if (aname->public_key_token [0] == 0)
3102 domain = mono_domain_get ();
3104 mono_assembly_binding_lock ();
3105 info = search_binding_loaded (aname);
3106 mono_assembly_binding_unlock ();
3109 mono_domain_lock (domain);
3110 info = get_per_domain_assembly_binding_info (domain, aname);
3111 mono_domain_unlock (domain);
3115 if (!check_policy_versions (info, aname))
3118 mono_assembly_bind_version (info, aname, dest_name);
3122 if (domain && domain->setup && domain->setup->configuration_file) {
3123 mono_domain_lock (domain);
3124 if (!domain->assembly_bindings_parsed) {
3125 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3126 /* expect this to succeed because mono_domain_set_options_from_config () did
3127 * the same thing when the domain was created. */
3128 mono_error_assert_ok (&error);
3130 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3132 if (!domain_config_file_path)
3133 domain_config_file_path = domain_config_file_name;
3135 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3136 domain->assembly_bindings_parsed = TRUE;
3137 if (domain_config_file_name != domain_config_file_path)
3138 g_free (domain_config_file_name);
3139 g_free (domain_config_file_path);
3142 info2 = get_per_domain_assembly_binding_info (domain, aname);
3145 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3146 info->name = g_strdup (info2->name);
3147 info->culture = g_strdup (info2->culture);
3148 info->domain_id = domain->domain_id;
3151 mono_domain_unlock (domain);
3155 info = g_new0 (MonoAssemblyBindingInfo, 1);
3156 info->major = aname->major;
3157 info->minor = aname->minor;
3160 if (!info->is_valid) {
3161 ppimage = mono_assembly_load_publisher_policy (aname);
3163 get_publisher_policy_info (ppimage, aname, info);
3164 mono_image_close (ppimage);
3168 /* Define default error value if needed */
3169 if (!info->is_valid) {
3170 info->name = g_strdup (aname->name);
3171 info->culture = g_strdup (aname->culture);
3172 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3175 mono_assembly_binding_lock ();
3176 info2 = search_binding_loaded (aname);
3178 /* This binding was added by another thread
3180 mono_assembly_binding_info_free (info);
3185 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3187 mono_assembly_binding_unlock ();
3189 if (!info->is_valid || !check_policy_versions (info, aname))
3192 mono_assembly_bind_version (info, aname, dest_name);
3197 * mono_assembly_load_from_gac
3199 * \param aname The assembly name object
3201 static MonoAssembly*
3202 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3204 MonoAssembly *result = NULL;
3205 gchar *name, *version, *culture, *fullpath, *subpath;
3210 if (aname->public_key_token [0] == 0) {
3214 if (strstr (aname->name, ".dll")) {
3215 len = strlen (filename) - 4;
3216 name = (gchar *)g_malloc (len + 1);
3217 memcpy (name, aname->name, len);
3220 name = g_strdup (aname->name);
3223 if (aname->culture) {
3224 culture = g_utf8_strdown (aname->culture, -1);
3226 culture = g_strdup ("");
3229 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3230 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3231 aname->minor, aname->build, aname->revision,
3235 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3240 if (extra_gac_paths) {
3241 paths = extra_gac_paths;
3242 while (!result && *paths) {
3243 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3244 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3251 result->in_gac = TRUE;
3256 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3257 "mono", "gac", subpath, NULL);
3258 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3262 result->in_gac = TRUE;
3270 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3273 MonoAssemblyName *aname;
3276 /* g_print ("corlib already loaded\n"); */
3280 // In native client, Corlib is embedded in the executable as static variable corlibData
3281 #if defined(__native_client__)
3282 if (corlibData != NULL && corlibSize != 0) {
3284 /* First "FALSE" instructs mono not to make a copy. */
3285 /* Second "FALSE" says this is not just a ref. */
3286 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3287 if (image == NULL || status != 0)
3288 g_print("mono_image_open_from_data_full failed: %d\n", status);
3289 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3290 if (corlib == NULL || status != 0)
3291 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3297 // A nonstandard preload hook may provide a special mscorlib assembly
3298 aname = mono_assembly_name_new ("mscorlib.dll");
3299 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3300 mono_assembly_name_free (aname);
3303 goto return_corlib_and_facades;
3305 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3306 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3307 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3309 goto return_corlib_and_facades;
3312 /* Normal case: Load corlib from mono/<version> */
3313 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3314 if (assemblies_path) { // Custom assemblies path
3315 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3317 g_free (corlib_file);
3318 goto return_corlib_and_facades;
3321 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3322 g_free (corlib_file);
3324 return_corlib_and_facades:
3325 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3326 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3331 static MonoAssembly*
3332 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3334 MonoError refasm_error;
3335 error_init (&refasm_error);
3336 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3339 mono_error_cleanup (&refasm_error);
3344 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3346 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3347 MonoAssemblyName *candidate_name = &candidate->aname;
3349 g_assert (wanted_name != NULL);
3350 g_assert (candidate_name != NULL);
3352 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3353 char * s = mono_stringify_assembly_name (wanted_name);
3354 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3356 s = mono_stringify_assembly_name (candidate_name);
3357 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3361 /* No wanted token, bail. */
3362 if (0 == wanted_name->public_key_token [0]) {
3363 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3367 if (0 == candidate_name->public_key_token [0]) {
3368 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3373 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3375 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3376 result ? "match, returning TRUE" : "don't match, returning FALSE");
3383 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3384 const char *basedir,
3385 MonoImageOpenStatus *status,
3388 MonoAssembly *result;
3389 char *fullpath, *filename;
3390 MonoAssemblyName maped_aname;
3391 MonoAssemblyName maped_name_pp;
3396 aname = mono_assembly_remap_version (aname, &maped_aname);
3398 /* Reflection only assemblies don't get assembly binding */
3400 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3402 result = mono_assembly_loaded_full (aname, refonly);
3406 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3408 result->in_gac = FALSE;
3412 /* Currently we retrieve the loaded corlib for reflection
3413 * only requests, like a common reflection only assembly
3415 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3416 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3419 len = strlen (aname->name);
3420 for (ext_index = 0; ext_index < 2; ext_index ++) {
3421 ext = ext_index == 0 ? ".dll" : ".exe";
3422 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3423 filename = g_strdup (aname->name);
3424 /* Don't try appending .dll/.exe if it already has one of those extensions */
3427 filename = g_strconcat (aname->name, ext, NULL);
3430 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3437 fullpath = g_build_filename (basedir, filename, NULL);
3438 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3441 result->in_gac = FALSE;
3447 result = load_in_path (filename, default_path, status, refonly, NULL, NULL);
3449 result->in_gac = FALSE;
3459 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3461 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3464 /* Try a postload search hook */
3465 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3466 result = prevent_reference_assembly_from_running (result, refonly);
3472 * mono_assembly_load_full:
3473 * \param aname A MonoAssemblyName with the assembly name to load.
3474 * \param basedir A directory to look up the assembly at.
3475 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3476 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3478 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3479 * attempts to load the assembly from that directory before probing the standard locations.
3481 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3482 * assembly binding takes place.
3484 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3485 * value pointed by \p status is updated with an error code.
3488 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3490 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3494 * mono_assembly_load:
3495 * \param aname A MonoAssemblyName with the assembly name to load.
3496 * \param basedir A directory to look up the assembly at.
3497 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3499 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3500 * attempts to load the assembly from that directory before probing the standard locations.
3502 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3503 * value pointed by \p status is updated with an error code.
3506 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3508 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3512 * mono_assembly_loaded_full:
3513 * \param aname an assembly to look for.
3514 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3516 * This is used to determine if the specified assembly has been loaded
3517 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3518 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3521 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3524 MonoAssemblyName maped_aname;
3526 aname = mono_assembly_remap_version (aname, &maped_aname);
3528 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3534 * mono_assembly_loaded:
3535 * \param aname an assembly to look for.
3537 * This is used to determine if the specified assembly has been loaded
3539 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3540 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3543 mono_assembly_loaded (MonoAssemblyName *aname)
3545 return mono_assembly_loaded_full (aname, FALSE);
3549 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3551 if (assembly == NULL || assembly == REFERENCE_MISSING)
3554 if (assembly_is_dynamic (assembly)) {
3556 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3557 for (i = 0; i < dynimg->image.module_count; ++i)
3558 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3559 mono_dynamic_image_release_gc_roots (dynimg);
3564 * Returns whether mono_assembly_close_finish() must be called as
3565 * well. See comment for mono_image_close_except_pools() for why we
3566 * unload in two steps.
3569 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3572 g_return_val_if_fail (assembly != NULL, FALSE);
3574 if (assembly == REFERENCE_MISSING)
3577 /* Might be 0 already */
3578 if (InterlockedDecrement (&assembly->ref_count) > 0)
3581 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3583 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3585 mono_debug_close_image (assembly->image);
3587 mono_assemblies_lock ();
3588 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3589 mono_assemblies_unlock ();
3591 assembly->image->assembly = NULL;
3593 if (!mono_image_close_except_pools (assembly->image))
3594 assembly->image = NULL;
3596 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3597 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3598 mono_assembly_name_free (fname);
3601 g_slist_free (assembly->friend_assembly_names);
3602 g_free (assembly->basedir);
3604 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3610 mono_assembly_close_finish (MonoAssembly *assembly)
3612 g_assert (assembly && assembly != REFERENCE_MISSING);
3614 if (assembly->image)
3615 mono_image_close_finish (assembly->image);
3617 if (assembly_is_dynamic (assembly)) {
3618 g_free ((char*)assembly->aname.culture);
3625 * mono_assembly_close:
3626 * \param assembly the assembly to release.
3628 * This method releases a reference to the \p assembly. The assembly is
3629 * only released when all the outstanding references to it are released.
3632 mono_assembly_close (MonoAssembly *assembly)
3634 if (mono_assembly_close_except_image_pools (assembly))
3635 mono_assembly_close_finish (assembly);
3639 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3642 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3643 mono_error_assert_ok (&error);
3648 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3650 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3655 * mono_assembly_foreach:
3656 * \param func function to invoke for each assembly loaded
3657 * \param user_data data passed to the callback
3659 * Invokes the provided \p func callback for each assembly loaded into
3660 * the runtime. The first parameter passed to the callback is the
3661 * \c MonoAssembly*, and the second parameter is the \p user_data.
3663 * This is done for all assemblies loaded in the runtime, not just
3664 * those loaded in the current application domain.
3667 mono_assembly_foreach (GFunc func, gpointer user_data)
3672 * We make a copy of the list to avoid calling the callback inside the
3673 * lock, which could lead to deadlocks.
3675 mono_assemblies_lock ();
3676 copy = g_list_copy (loaded_assemblies);
3677 mono_assemblies_unlock ();
3679 g_list_foreach (loaded_assemblies, func, user_data);
3685 * mono_assemblies_cleanup:
3687 * Free all resources used by this module.
3690 mono_assemblies_cleanup (void)
3694 mono_os_mutex_destroy (&assemblies_mutex);
3695 mono_os_mutex_destroy (&assembly_binding_mutex);
3697 for (l = loaded_assembly_bindings; l; l = l->next) {
3698 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3700 mono_assembly_binding_info_free (info);
3703 g_slist_free (loaded_assembly_bindings);
3705 free_assembly_load_hooks ();
3706 free_assembly_search_hooks ();
3707 free_assembly_preload_hooks ();
3710 /*LOCKING takes the assembly_binding lock*/
3712 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3716 mono_assembly_binding_lock ();
3717 iter = &loaded_assembly_bindings;
3720 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3722 if (info->domain_id == domain_id) {
3724 mono_assembly_binding_info_free (info);
3731 mono_assembly_binding_unlock ();
3735 * Holds the assembly of the application, for
3736 * System.Diagnostics.Process::MainModule
3738 static MonoAssembly *main_assembly=NULL;
3741 mono_assembly_set_main (MonoAssembly *assembly)
3743 main_assembly = assembly;
3747 * mono_assembly_get_main:
3749 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3752 mono_assembly_get_main (void)
3754 return (main_assembly);
3758 * mono_assembly_get_image:
3759 * \param assembly The assembly to retrieve the image from
3761 * \returns the MonoImage associated with this assembly.
3764 mono_assembly_get_image (MonoAssembly *assembly)
3766 return assembly->image;
3770 * mono_assembly_get_name:
3771 * \param assembly The assembly to retrieve the name from
3773 * The returned name's lifetime is the same as \p assembly's.
3775 * \returns the MonoAssemblyName associated with this assembly.
3778 mono_assembly_get_name (MonoAssembly *assembly)
3780 return &assembly->aname;
3784 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3786 bundles = assemblies;
3789 #define MONO_DECLSEC_FORMAT_10 0x3C
3790 #define MONO_DECLSEC_FORMAT_20 0x2E
3791 #define MONO_DECLSEC_FIELD 0x53
3792 #define MONO_DECLSEC_PROPERTY 0x54
3794 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3795 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3796 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3797 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3798 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3801 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3805 case MONO_DECLSEC_PROPERTY:
3807 case MONO_DECLSEC_FIELD:
3809 *abort_decoding = TRUE;
3814 if (*p++ != MONO_TYPE_BOOLEAN) {
3815 *abort_decoding = TRUE;
3819 /* property name length */
3820 len = mono_metadata_decode_value (p, &p);
3822 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3833 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3835 int i, j, num, len, params_len;
3837 if (*p == MONO_DECLSEC_FORMAT_10) {
3838 gsize read, written;
3839 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3841 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3847 if (*p++ != MONO_DECLSEC_FORMAT_20)
3850 /* number of encoded permission attributes */
3851 num = mono_metadata_decode_value (p, &p);
3852 for (i = 0; i < num; ++i) {
3853 gboolean is_valid = FALSE;
3854 gboolean abort_decoding = FALSE;
3856 /* attribute name length */
3857 len = mono_metadata_decode_value (p, &p);
3859 /* We don't really need to fully decode the type. Comparing the name is enough */
3860 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3864 /*size of the params table*/
3865 params_len = mono_metadata_decode_value (p, &p);
3867 const char *params_end = p + params_len;
3869 /* number of parameters */
3870 len = mono_metadata_decode_value (p, &p);
3872 for (j = 0; j < len; ++j) {
3873 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3889 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3892 guint32 cols [MONO_DECL_SECURITY_SIZE];
3896 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3897 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3899 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3901 for (i = 0; i < t->rows; ++i) {
3902 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3903 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3905 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3908 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3909 len = mono_metadata_decode_blob_size (blob, &blob);
3913 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3914 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3919 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);