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 \c MONO_PATH variable.
275 * Notice that \c 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_hasenv ("MONO_DEBUG"))
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)
319 if (assemblies_path != NULL)
322 char* path = g_getenv ("MONO_PATH");
323 #ifdef __native_client__
325 path = strdup (nacl_mono_path);
330 mono_set_assemblies_path(path);
335 check_extra_gac_path_env (void)
338 char **splitted, **dest;
340 path = g_getenv ("MONO_GAC_PREFIX");
344 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
348 g_strfreev (extra_gac_paths);
349 extra_gac_paths = dest = splitted;
357 if (!g_hasenv ("MONO_DEBUG"))
361 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
362 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
369 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
371 if (!info || !info->name)
374 if (strcmp (info->name, aname->name))
377 if (info->major != aname->major || info->minor != aname->minor)
380 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
383 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
386 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
393 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
399 g_free (info->culture);
403 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
406 guint32 cols [MONO_MANIFEST_SIZE];
407 const gchar *filename;
408 gchar *subpath, *fullpath;
410 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
411 /* MS Impl. accepts policy assemblies with more than
412 * one manifest resource, and only takes the first one */
414 binding_info->is_valid = FALSE;
418 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
419 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
420 binding_info->is_valid = FALSE;
424 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
425 g_assert (filename != NULL);
427 subpath = g_path_get_dirname (image->name);
428 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
429 mono_config_parse_publisher_policy (fullpath, binding_info);
433 /* Define the optional elements/attributes before checking */
434 if (!binding_info->culture)
435 binding_info->culture = g_strdup ("");
437 /* Check that the most important elements/attributes exist */
438 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
439 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
440 mono_assembly_binding_info_free (binding_info);
441 binding_info->is_valid = FALSE;
445 binding_info->is_valid = TRUE;
449 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
451 if (v->major > aname->major)
453 else if (v->major < aname->major)
456 if (v->minor > aname->minor)
458 else if (v->minor < aname->minor)
461 if (v->build > aname->build)
463 else if (v->build < aname->build)
466 if (v->revision > aname->revision)
468 else if (v->revision < aname->revision)
475 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
480 /* If has_old_version_top doesn't exist, we don't have an interval */
481 if (!info->has_old_version_top) {
482 if (compare_versions (&info->old_version_bottom, name) == 0)
488 /* Check that the version defined by name is valid for the interval */
489 if (compare_versions (&info->old_version_top, name) < 0)
492 /* We should be greater or equal than the small version */
493 if (compare_versions (&info->old_version_bottom, name) > 0)
500 * mono_assembly_names_equal:
501 * \param l first assembly
502 * \param r second assembly.
504 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
506 * This compares the names, the cultures, the release version and their
509 * \returns TRUE if both assembly names are equal.
512 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
514 if (!l->name || !r->name)
517 if (strcmp (l->name, r->name))
520 if (l->culture && r->culture && strcmp (l->culture, r->culture))
523 if (l->major != r->major || l->minor != r->minor ||
524 l->build != r->build || l->revision != r->revision)
525 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)))
528 if (!l->public_key_token [0] || !r->public_key_token [0])
531 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
537 static MonoAssembly *
538 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
542 MonoAssembly *result;
544 for (i = 0; search_path [i]; ++i) {
545 fullpath = g_build_filename (search_path [i], basename, NULL);
546 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
555 * mono_assembly_setrootdir:
556 * \param root_dir The pathname of the root directory where we will locate assemblies
558 * This routine sets the internal default root directory for looking up
561 * This is used by Windows installations to compute dynamically the
562 * place where the Mono assemblies are located.
566 mono_assembly_setrootdir (const char *root_dir)
569 * Override the MONO_ASSEMBLIES directory configured at compile time.
571 /* Leak if called more than once */
572 default_path [0] = g_strdup (root_dir);
576 * mono_assembly_getrootdir:
578 * Obtains the root directory used for looking up assemblies.
580 * Returns: a string with the directory, this string should not be freed.
582 G_CONST_RETURN gchar *
583 mono_assembly_getrootdir (void)
585 return default_path [0];
589 * mono_native_getrootdir:
591 * Obtains the root directory used for looking up native libs (.so, .dylib).
593 * Returns: a string with the directory, this string should be freed by
597 mono_native_getrootdir (void)
599 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
605 * \param assembly_dir the base directory for assemblies
606 * \param config_dir the base directory for configuration files
608 * This routine is used internally and by developers embedding
609 * the runtime into their own applications.
611 * There are a number of cases to consider: Mono as a system-installed
612 * package that is available on the location preconfigured or Mono in
613 * a relocated location.
615 * If you are using a system-installed Mono, you can pass NULL
616 * to both parameters. If you are not, you should compute both
617 * directory values and call this routine.
619 * The values for a given PREFIX are:
621 * assembly_dir: PREFIX/lib
622 * config_dir: PREFIX/etc
624 * Notice that embedders that use Mono in a relocated way must
625 * compute the location at runtime, as they will be in control
626 * of where Mono is installed.
629 mono_set_dirs (const char *assembly_dir, const char *config_dir)
631 if (assembly_dir == NULL)
632 assembly_dir = mono_config_get_assemblies_dir ();
633 if (config_dir == NULL)
634 config_dir = mono_config_get_cfg_dir ();
635 mono_assembly_setrootdir (assembly_dir);
636 mono_set_config_dir (config_dir);
642 compute_base (char *path)
644 char *p = strrchr (path, '/');
648 /* Not a well known Mono executable, we are embedded, cant guess the base */
649 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
653 p = strrchr (path, '/');
657 if (strcmp (p, "/bin") != 0)
666 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
669 static G_GNUC_UNUSED void
673 char *config, *lib, *mono;
678 * Only /usr prefix is treated specially
680 bindir = mono_config_get_bin_dir ();
682 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
687 config = g_build_filename (base, "etc", NULL);
688 lib = g_build_filename (base, "lib", NULL);
689 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
690 if (stat (mono, &buf) == -1)
693 mono_set_dirs (lib, config);
701 #endif /* HOST_WIN32 */
706 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
707 * this auto-detects the prefix where Mono was installed.
710 mono_set_rootdir (void)
712 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
713 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
716 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
720 * _NSGetExecutablePath may return -1 to indicate buf is not large
721 * enough, but we ignore that case to avoid having to do extra dynamic
722 * allocation for the path and hope that 4096 is enough - this is
723 * ok in the Linux/Solaris case below at least...
727 guint buf_size = sizeof (buf);
730 if (_NSGetExecutablePath (buf, &buf_size) == 0)
731 name = g_strdup (buf);
740 resolvedname = mono_path_resolve_symlinks (name);
742 bindir = g_path_get_dirname (resolvedname);
743 installdir = g_path_get_dirname (bindir);
744 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
746 config = g_build_filename (root, "..", "etc", NULL);
748 mono_set_dirs (root, config);
750 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
751 mono_set_dirs (root, config);
761 g_free (resolvedname);
762 #elif defined(DISABLE_MONO_AUTODETECTION)
770 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
778 /* Solaris 10 style */
779 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
780 s = readlink (str, buf, sizeof (buf)-1);
792 * mono_assemblies_init:
794 * Initialize global variables used by this module.
797 mono_assemblies_init (void)
800 * Initialize our internal paths if we have not been initialized yet.
801 * This happens when embedders use Mono.
803 if (mono_assembly_getrootdir () == NULL)
807 check_extra_gac_path_env ();
809 mono_os_mutex_init_recursive (&assemblies_mutex);
810 mono_os_mutex_init (&assembly_binding_mutex);
812 #ifndef DISABLE_ASSEMBLY_REMAPPING
813 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
816 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
817 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
823 mono_assembly_binding_lock (void)
825 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
829 mono_assembly_binding_unlock (void)
831 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
835 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
837 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
838 guint32 cols [MONO_ASSEMBLY_SIZE];
839 gint32 machine, flags;
844 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
847 aname->hash_value = NULL;
848 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
850 aname->name = g_strdup (aname->name);
851 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
853 aname->culture = g_strdup (aname->culture);
854 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
855 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
856 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
857 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
858 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
859 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
860 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
861 guchar* token = (guchar *)g_malloc (8);
866 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
867 len = mono_metadata_decode_blob_size (pkey, &pkey);
868 aname->public_key = (guchar*)pkey;
870 mono_digest_get_public_token (token, aname->public_key, len);
871 encoded = encode_public_tok (token, 8);
872 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
878 aname->public_key = NULL;
879 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
882 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
883 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
885 const gchar *pkey_end;
886 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
887 pkey_end += len; /* move to end */
888 size_t size = pkey_end - (const gchar*)aname->public_key;
889 guchar *tmp = g_new (guchar, size);
890 memcpy (tmp, aname->public_key, size);
891 aname->public_key = tmp;
896 aname->public_key = 0;
898 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
899 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
901 case COFF_MACHINE_I386:
902 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
903 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
904 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
905 else if ((flags & 0x70) == 0x70)
906 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
908 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
910 case COFF_MACHINE_IA64:
911 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
913 case COFF_MACHINE_AMD64:
914 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
916 case COFF_MACHINE_ARM:
917 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
927 * mono_assembly_fill_assembly_name:
930 * \returns TRUE if successful
933 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
935 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
939 * mono_stringify_assembly_name:
940 * \param aname the assembly name.
942 * Convert \p aname into its string format. The returned string is dynamically
943 * allocated and should be freed by the caller.
945 * \returns a newly allocated string with a string representation of
949 mono_stringify_assembly_name (MonoAssemblyName *aname)
951 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
953 return g_strdup_printf (
954 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
955 quote, aname->name, quote,
956 aname->major, aname->minor, aname->build, aname->revision,
957 aname->culture && *aname->culture? aname->culture: "neutral",
958 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
959 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
963 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
965 const gchar *public_tok;
968 public_tok = mono_metadata_blob_heap (image, key_index);
969 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
971 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
973 mono_digest_get_public_token (token, (guchar*)public_tok, len);
974 return encode_public_tok (token, 8);
977 return encode_public_tok ((guchar*)public_tok, len);
981 * mono_assembly_addref:
982 * \param assembly the assembly to reference
984 * This routine increments the reference count on a MonoAssembly.
985 * The reference count is reduced every time the method mono_assembly_close() is
989 mono_assembly_addref (MonoAssembly *assembly)
991 InterlockedIncrement (&assembly->ref_count);
995 * CAUTION: This table must be kept in sync with
996 * ivkm/reflect/Fusion.cs
999 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1000 #define WINFX_KEY "31bf3856ad364e35"
1001 #define ECMA_KEY "b77a5c561934e089"
1002 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1003 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1011 static KeyRemapEntry key_remap_table[] = {
1012 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1013 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1014 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1015 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1016 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1017 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1018 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1019 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1020 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1021 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1022 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1023 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1024 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1025 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1026 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1027 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1028 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1029 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1030 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1031 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1032 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1033 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1034 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1035 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1036 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1037 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1038 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1039 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1040 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1044 remap_keys (MonoAssemblyName *aname)
1047 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1048 const KeyRemapEntry *entry = &key_remap_table [i];
1050 if (strcmp (aname->name, entry->name) ||
1051 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1054 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1056 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1057 "Remapped public key token of retargetable assembly %s from %s to %s",
1058 aname->name, entry->from, entry->to);
1063 static MonoAssemblyName *
1064 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1066 const MonoRuntimeInfo *current_runtime;
1068 if (aname->name == NULL) return aname;
1070 current_runtime = mono_get_runtime_info ();
1072 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1073 const AssemblyVersionSet* vset;
1075 /* Remap to current runtime */
1076 vset = ¤t_runtime->version_sets [0];
1078 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1079 dest_aname->major = vset->major;
1080 dest_aname->minor = vset->minor;
1081 dest_aname->build = vset->build;
1082 dest_aname->revision = vset->revision;
1083 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1085 /* Remap assembly name */
1086 if (!strcmp (aname->name, "System.Net"))
1087 dest_aname->name = g_strdup ("System");
1089 remap_keys (dest_aname);
1091 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1092 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1094 aname->major, aname->minor, aname->build, aname->revision,
1096 vset->major, vset->minor, vset->build, vset->revision
1102 #ifndef DISABLE_ASSEMBLY_REMAPPING
1103 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1105 const AssemblyVersionSet* vset;
1106 int index = vmap->version_set_index;
1107 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1108 vset = ¤t_runtime->version_sets [index];
1110 if (aname->major == vset->major && aname->minor == vset->minor &&
1111 aname->build == vset->build && aname->revision == vset->revision) {
1112 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1114 aname->major, aname->minor, aname->build, aname->revision);
1118 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1119 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1120 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1122 aname->major, aname->minor, aname->build, aname->revision,
1123 vset->major, vset->minor, vset->build, vset->revision
1128 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1129 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1130 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1132 aname->major, aname->minor, aname->build, aname->revision,
1133 vset->major, vset->minor, vset->build, vset->revision
1136 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1137 dest_aname->major = vset->major;
1138 dest_aname->minor = vset->minor;
1139 dest_aname->build = vset->build;
1140 dest_aname->revision = vset->revision;
1141 if (current_runtime->public_key_token != NULL &&
1142 dest_aname->public_key_token [0] != 0 &&
1143 !mono_public_tokens_are_equal (dest_aname->public_key_token, (const mono_byte *)current_runtime->public_key_token)) {
1144 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1145 "The request for assembly name '%s' with PublicKeyToken=%s was remapped to PublicKeyToken=%s",
1147 dest_aname->public_key_token,
1148 current_runtime->public_key_token);
1149 memcpy (dest_aname->public_key_token, current_runtime->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1151 if (vmap->new_assembly_name != NULL) {
1152 dest_aname->name = vmap->new_assembly_name;
1153 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1154 "The assembly name %s was remapped to %s",
1166 * mono_assembly_get_assemblyref:
1167 * \param image pointer to the \c MonoImage to extract the information from.
1168 * \param index index to the assembly reference in the image.
1169 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1171 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1174 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1177 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1180 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1182 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1184 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1185 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1186 aname->hash_value = hash;
1187 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1188 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1189 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1190 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1191 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1192 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1193 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1195 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1196 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1197 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1200 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1205 * mono_assembly_load_reference:
1208 mono_assembly_load_reference (MonoImage *image, int index)
1210 MonoAssembly *reference;
1211 MonoAssemblyName aname;
1212 MonoImageOpenStatus status;
1215 * image->references is shared between threads, so we need to access
1216 * it inside a critical section.
1218 mono_assemblies_lock ();
1219 if (!image->references) {
1220 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1222 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1223 image->nreferences = t->rows;
1225 reference = image->references [index];
1226 mono_assemblies_unlock ();
1230 mono_assembly_get_assemblyref (image, index, &aname);
1232 if (image->assembly && image->assembly->ref_only) {
1233 /* We use the loaded corlib */
1234 if (!strcmp (aname.name, "mscorlib"))
1235 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1237 reference = mono_assembly_loaded_full (&aname, TRUE);
1239 /* Try a postload search hook */
1240 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1244 * Here we must advice that the error was due to
1245 * a non loaded reference using the ReflectionOnly api
1248 reference = (MonoAssembly *)REFERENCE_MISSING;
1250 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1251 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1252 * accordingly, it would fail on the MS runtime before).
1253 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1254 * example bug-349190.2.cs and who knows how much more code in the wild.
1256 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1257 if (!reference && image->assembly)
1258 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1261 if (reference == NULL){
1264 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1265 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 : "" );
1266 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1267 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1268 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1269 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1270 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1271 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1273 extra_msg = g_strdup ("");
1276 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1277 " Assembly: %s (assemblyref_index=%d)\n"
1278 " Version: %d.%d.%d.%d\n"
1279 " Public Key: %s\n%s",
1280 image->name, aname.name, index,
1281 aname.major, aname.minor, aname.build, aname.revision,
1282 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1287 mono_assemblies_lock ();
1288 if (reference == NULL) {
1289 /* Flag as not found */
1290 reference = (MonoAssembly *)REFERENCE_MISSING;
1293 if (!image->references [index]) {
1294 if (reference != REFERENCE_MISSING){
1295 mono_assembly_addref (reference);
1296 if (image->assembly)
1297 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1298 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1300 if (image->assembly)
1301 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1302 image->assembly->aname.name, image->assembly);
1305 image->references [index] = reference;
1307 mono_assemblies_unlock ();
1309 if (image->references [index] != reference) {
1310 /* Somebody loaded it before us */
1311 mono_assembly_close (reference);
1316 * mono_assembly_load_references:
1319 * \deprecated There is no reason to use this method anymore, it does nothing
1321 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1324 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1326 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1327 *status = MONO_IMAGE_OK;
1330 typedef struct AssemblyLoadHook AssemblyLoadHook;
1331 struct AssemblyLoadHook {
1332 AssemblyLoadHook *next;
1333 MonoAssemblyLoadFunc func;
1337 AssemblyLoadHook *assembly_load_hook = NULL;
1340 * mono_assembly_invoke_load_hook:
1343 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1345 AssemblyLoadHook *hook;
1347 for (hook = assembly_load_hook; hook; hook = hook->next) {
1348 hook->func (ass, hook->user_data);
1353 * mono_install_assembly_load_hook:
1356 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1358 AssemblyLoadHook *hook;
1360 g_return_if_fail (func != NULL);
1362 hook = g_new0 (AssemblyLoadHook, 1);
1364 hook->user_data = user_data;
1365 hook->next = assembly_load_hook;
1366 assembly_load_hook = hook;
1370 free_assembly_load_hooks (void)
1372 AssemblyLoadHook *hook, *next;
1374 for (hook = assembly_load_hook; hook; hook = next) {
1380 typedef struct AssemblySearchHook AssemblySearchHook;
1381 struct AssemblySearchHook {
1382 AssemblySearchHook *next;
1383 MonoAssemblySearchFunc func;
1389 AssemblySearchHook *assembly_search_hook = NULL;
1391 static MonoAssembly*
1392 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1394 AssemblySearchHook *hook;
1396 for (hook = assembly_search_hook; hook; hook = hook->next) {
1397 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1400 * A little explanation is in order here.
1402 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1403 * The embedding API exposes a search hook that doesn't take such argument.
1405 * The original fix would call the default search hook before all the registered ones and pass
1406 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1407 * rely on. Which is the ordering between user hooks and the default runtime hook.
1409 * Registering the hook after mono_jit_init would let your hook run before the default one and
1410 * when using it to handle non standard app layouts this could save your app from a massive amount
1411 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1412 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1414 * So what's the fix? We register the default hook using regular means and special case it when iterating
1415 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1418 if (hook->func == (void*)mono_domain_assembly_postload_search)
1419 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1421 ass = hook->func (aname, hook->user_data);
1431 * mono_assembly_invoke_search_hook:
1434 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1436 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1440 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1442 AssemblySearchHook *hook;
1444 g_return_if_fail (func != NULL);
1446 hook = g_new0 (AssemblySearchHook, 1);
1448 hook->user_data = user_data;
1449 hook->refonly = refonly;
1450 hook->postload = postload;
1451 hook->next = assembly_search_hook;
1452 assembly_search_hook = hook;
1456 * mono_install_assembly_search_hook:
1459 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1461 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1465 free_assembly_search_hooks (void)
1467 AssemblySearchHook *hook, *next;
1469 for (hook = assembly_search_hook; hook; hook = next) {
1476 * mono_install_assembly_refonly_search_hook:
1479 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1481 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1485 * mono_install_assembly_postload_search_hook:
1488 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1490 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1494 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1496 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1499 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1500 struct AssemblyPreLoadHook {
1501 AssemblyPreLoadHook *next;
1502 MonoAssemblyPreLoadFunc func;
1506 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1507 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1509 static MonoAssembly *
1510 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1512 AssemblyPreLoadHook *hook;
1513 MonoAssembly *assembly;
1515 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1516 assembly = hook->func (aname, assemblies_path, hook->user_data);
1517 if (assembly != NULL)
1524 static MonoAssembly *
1525 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1527 AssemblyPreLoadHook *hook;
1528 MonoAssembly *assembly;
1530 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1531 assembly = hook->func (aname, assemblies_path, hook->user_data);
1532 if (assembly != NULL)
1540 * mono_install_assembly_preload_hook:
1543 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1545 AssemblyPreLoadHook *hook;
1547 g_return_if_fail (func != NULL);
1549 hook = g_new0 (AssemblyPreLoadHook, 1);
1551 hook->user_data = user_data;
1552 hook->next = assembly_preload_hook;
1553 assembly_preload_hook = hook;
1557 * mono_install_assembly_refonly_preload_hook:
1560 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1562 AssemblyPreLoadHook *hook;
1564 g_return_if_fail (func != NULL);
1566 hook = g_new0 (AssemblyPreLoadHook, 1);
1568 hook->user_data = user_data;
1569 hook->next = assembly_refonly_preload_hook;
1570 assembly_refonly_preload_hook = hook;
1574 free_assembly_preload_hooks (void)
1576 AssemblyPreLoadHook *hook, *next;
1578 for (hook = assembly_preload_hook; hook; hook = next) {
1583 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1590 absolute_dir (const gchar *filename)
1601 if (g_path_is_absolute (filename)) {
1602 part = g_path_get_dirname (filename);
1603 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1608 cwd = g_get_current_dir ();
1609 mixed = g_build_filename (cwd, filename, NULL);
1610 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1615 for (i = 0; (part = parts [i]) != NULL; i++) {
1616 if (!strcmp (part, "."))
1619 if (!strcmp (part, "..")) {
1620 if (list && list->next) /* Don't remove root */
1621 list = g_list_delete_link (list, list);
1623 list = g_list_prepend (list, part);
1627 result = g_string_new ("");
1628 list = g_list_reverse (list);
1630 /* Ignores last data pointer, which should be the filename */
1631 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1633 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1638 g_string_free (result, FALSE);
1643 return g_strdup (".");
1650 * mono_assembly_open_from_bundle:
1651 * \param filename Filename requested
1652 * \param status return status code
1654 * This routine tries to open the assembly specified by \p filename from the
1655 * defined bundles, if found, returns the MonoImage for it, if not found
1659 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1663 gchar *lowercase_filename;
1664 MonoImage *image = NULL;
1665 gboolean is_satellite = FALSE;
1667 * we do a very simple search for bundled assemblies: it's not a general
1668 * purpose assembly loading mechanism.
1674 lowercase_filename = g_utf8_strdown (filename, -1);
1675 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1676 g_free (lowercase_filename);
1677 name = g_path_get_basename (filename);
1678 mono_assemblies_lock ();
1679 for (i = 0; !image && bundles [i]; ++i) {
1680 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1681 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1685 mono_assemblies_unlock ();
1687 mono_image_addref (image);
1688 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1697 * mono_assembly_open_full:
1698 * \param filename the file to load
1699 * \param status return status code
1700 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1702 * This loads an assembly from the specified \p filename. The \p filename allows
1703 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1704 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1705 * is treated as a local path.
1707 * First, an attempt is made to load the assembly from the bundled executable (for those
1708 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1709 * assembly has been registered as an embedded assembly). If this is not the case, then
1710 * the assembly is loaded from disk using `api:mono_image_open_full`.
1712 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1713 * the assembly is made.
1715 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1716 * the \c System.Reflection API.
1718 * \returns NULL on error, with the \p status set to an error code, or a pointer
1722 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1724 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1728 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1730 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1734 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1735 gboolean load_from_context,
1736 MonoAssemblyCandidatePredicate predicate,
1738 MonoImageOpenStatus *status)
1742 MonoImageOpenStatus def_status;
1745 gboolean loaded_from_bundle;
1747 g_return_val_if_fail (filename != NULL, NULL);
1750 status = &def_status;
1751 *status = MONO_IMAGE_OK;
1753 if (strncmp (filename, "file://", 7) == 0) {
1754 GError *error = NULL;
1755 gchar *uri = (gchar *) filename;
1759 * MS allows file://c:/... and fails on file://localhost/c:/...
1760 * They also throw an IndexOutOfRangeException if "file://"
1763 uri = g_strdup_printf ("file:///%s", uri + 7);
1766 uri = mono_escape_uri_string (tmpuri);
1767 fname = g_filename_from_uri (uri, NULL, &error);
1770 if (tmpuri != filename)
1773 if (error != NULL) {
1774 g_warning ("%s\n", error->message);
1775 g_error_free (error);
1776 fname = g_strdup (filename);
1779 fname = g_strdup (filename);
1782 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1783 "Assembly Loader probing location: '%s'.", fname);
1786 if (!mono_assembly_is_in_gac (fname)) {
1788 new_fname = mono_make_shadow_copy (fname, &error);
1789 if (!is_ok (&error)) {
1790 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1791 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1792 mono_error_cleanup (&error);
1793 *status = MONO_IMAGE_IMAGE_INVALID;
1798 if (new_fname && new_fname != fname) {
1801 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1802 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1807 // If VM built with mkbundle
1808 loaded_from_bundle = FALSE;
1809 if (bundles != NULL) {
1810 image = mono_assembly_open_from_bundle (fname, status, refonly);
1811 loaded_from_bundle = image != NULL;
1815 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1818 if (*status == MONO_IMAGE_OK)
1819 *status = MONO_IMAGE_ERROR_ERRNO;
1824 if (image->assembly) {
1825 /* Already loaded by another appdomain */
1826 mono_assembly_invoke_load_hook (image->assembly);
1827 mono_image_close (image);
1829 return image->assembly;
1832 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1835 if (!loaded_from_bundle)
1836 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1837 "Assembly Loader loaded assembly from location: '%s'.", filename);
1839 mono_config_for_assembly (ass->image);
1842 /* Clear the reference added by mono_image_open */
1843 mono_image_close (image);
1851 free_item (gpointer val, gpointer user_data)
1857 * mono_assembly_load_friends:
1858 * \param ass an assembly
1860 * Load the list of friend assemblies that are allowed to access
1861 * the assembly's internal types and members. They are stored as assembly
1862 * names in custom attributes.
1864 * This is an internal method, we need this because when we load mscorlib
1865 * we do not have the internals visible cattr loaded yet,
1866 * so we need to load these after we initialize the runtime.
1868 * LOCKING: Acquires the assemblies lock plus the loader lock.
1871 mono_assembly_load_friends (MonoAssembly* ass)
1875 MonoCustomAttrInfo* attrs;
1878 if (ass->friend_assembly_names_inited)
1881 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1882 mono_error_assert_ok (&error);
1884 mono_assemblies_lock ();
1885 ass->friend_assembly_names_inited = TRUE;
1886 mono_assemblies_unlock ();
1890 mono_assemblies_lock ();
1891 if (ass->friend_assembly_names_inited) {
1892 mono_assemblies_unlock ();
1895 mono_assemblies_unlock ();
1899 * We build the list outside the assemblies lock, the worse that can happen
1900 * is that we'll need to free the allocated list.
1902 for (i = 0; i < attrs->num_attrs; ++i) {
1903 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1904 MonoAssemblyName *aname;
1906 /* Do some sanity checking */
1907 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1909 if (attr->data_size < 4)
1911 data = (const char*)attr->data;
1912 /* 0xFF means null string, see custom attr format */
1913 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1915 mono_metadata_decode_value (data + 2, &data);
1916 aname = g_new0 (MonoAssemblyName, 1);
1917 /*g_print ("friend ass: %s\n", data);*/
1918 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1919 list = g_slist_prepend (list, aname);
1924 mono_custom_attrs_free (attrs);
1926 mono_assemblies_lock ();
1927 if (ass->friend_assembly_names_inited) {
1928 mono_assemblies_unlock ();
1929 g_slist_foreach (list, free_item, NULL);
1930 g_slist_free (list);
1933 ass->friend_assembly_names = list;
1935 /* Because of the double checked locking pattern above */
1936 mono_memory_barrier ();
1937 ass->friend_assembly_names_inited = TRUE;
1938 mono_assemblies_unlock ();
1941 struct HasReferenceAssemblyAttributeIterData {
1946 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1948 gboolean stop_scanning = FALSE;
1949 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1951 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1952 /* Note we don't check the assembly name, same as coreCLR. */
1953 iter_data->has_attr = TRUE;
1954 stop_scanning = TRUE;
1957 return stop_scanning;
1961 * mono_assembly_has_reference_assembly_attribute:
1962 * \param assembly a MonoAssembly
1963 * \param error set on error.
1965 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1966 * On error returns FALSE and sets \p error.
1969 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1974 * This might be called during assembly loading, so do everything using the low-level
1978 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1980 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1982 return iter_data.has_attr;
1986 * mono_assembly_open:
1987 * \param filename Opens the assembly pointed out by this name
1988 * \param status return status code
1990 * This loads an assembly from the specified \p filename. The \p filename allows
1991 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1992 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1993 * is treated as a local path.
1995 * First, an attempt is made to load the assembly from the bundled executable (for those
1996 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1997 * assembly has been registered as an embedded assembly). If this is not the case, then
1998 * the assembly is loaded from disk using `api:mono_image_open_full`.
2000 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2001 * the assembly is made.
2003 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2004 * assembly or NULL on error. Details about the error are stored in the
2005 * \p status variable.
2008 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2010 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2014 * mono_assembly_load_from_full:
2015 * \param image Image to load the assembly from
2016 * \param fname assembly name to associate with the assembly
2017 * \param status returns the status condition
2018 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2020 * If the provided \p image has an assembly reference, it will process the given
2021 * image as an assembly with the given name.
2023 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2025 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2026 * set to \c MONO_IMAGE_OK; or NULL on error.
2028 * If there is an error loading the assembly the \p status will indicate the
2029 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2030 * image did not contain an assembly reference table.
2033 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2034 MonoImageOpenStatus *status, gboolean refonly)
2036 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2040 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2042 MonoAssemblyCandidatePredicate predicate,
2044 MonoImageOpenStatus *status)
2046 MonoAssembly *ass, *ass2;
2049 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2050 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2051 *status = MONO_IMAGE_IMAGE_INVALID;
2055 #if defined (HOST_WIN32)
2060 tmp_fn = g_strdup (fname);
2061 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2062 if (tmp_fn [i] == '/')
2066 base_dir = absolute_dir (tmp_fn);
2070 base_dir = absolute_dir (fname);
2074 * Create assembly struct, and enter it into the assembly cache
2076 ass = g_new0 (MonoAssembly, 1);
2077 ass->basedir = base_dir;
2078 ass->ref_only = refonly;
2081 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2083 mono_assembly_fill_assembly_name (image, &ass->aname);
2085 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2086 // MS.NET doesn't support loading other mscorlibs
2089 mono_image_addref (mono_defaults.corlib);
2090 *status = MONO_IMAGE_OK;
2091 return mono_defaults.corlib->assembly;
2094 /* Add a non-temporary reference because of ass->image */
2095 mono_image_addref (image);
2097 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);
2100 * The load hooks might take locks so we can't call them while holding the
2103 if (ass->aname.name) {
2104 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2108 mono_image_close (image);
2109 *status = MONO_IMAGE_OK;
2114 /* We need to check for ReferenceAssmeblyAttribute before we
2115 * mark the assembly as loaded and before we fire the load
2116 * hook. Otherwise mono_domain_fire_assembly_load () in
2117 * appdomain.c will cache a mapping from the assembly name to
2118 * this image and we won't be able to look for a different
2122 MonoError refasm_error;
2123 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2124 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2127 mono_image_close (image);
2128 *status = MONO_IMAGE_IMAGE_INVALID;
2131 mono_error_cleanup (&refasm_error);
2134 if (predicate && !predicate (ass, user_data)) {
2135 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2138 mono_image_close (image);
2139 *status = MONO_IMAGE_IMAGE_INVALID;
2143 mono_assemblies_lock ();
2145 if (image->assembly) {
2147 * This means another thread has already loaded the assembly, but not yet
2148 * called the load hooks so the search hook can't find the assembly.
2150 mono_assemblies_unlock ();
2151 ass2 = image->assembly;
2154 mono_image_close (image);
2155 *status = MONO_IMAGE_OK;
2159 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2161 image->assembly = ass;
2163 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2164 mono_assemblies_unlock ();
2167 if (image->is_module_handle)
2168 mono_image_fixup_vtable (image);
2171 mono_assembly_invoke_load_hook (ass);
2173 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2179 * mono_assembly_load_from:
2180 * \param image Image to load the assembly from
2181 * \param fname assembly name to associate with the assembly
2182 * \param status return status code
2184 * If the provided \p image has an assembly reference, it will process the given
2185 * image as an assembly with the given name.
2187 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2189 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2190 * \p refonly parameter set to FALSE.
2191 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2192 * set to \c MONO_IMAGE_OK; or NULL on error.
2194 * If there is an error loading the assembly the \p status will indicate the
2195 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2196 * image did not contain an assembly reference table.
2200 mono_assembly_load_from (MonoImage *image, const char *fname,
2201 MonoImageOpenStatus *status)
2203 return mono_assembly_load_from_full (image, fname, status, FALSE);
2207 * mono_assembly_name_free:
2208 * \param aname assembly name to free
2210 * Frees the provided assembly name object.
2211 * (it does not frees the object itself, only the name members).
2214 mono_assembly_name_free (MonoAssemblyName *aname)
2219 g_free ((void *) aname->name);
2220 g_free ((void *) aname->culture);
2221 g_free ((void *) aname->hash_value);
2222 g_free ((guint8*) aname->public_key);
2226 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2229 gchar header [16], val, *arr;
2230 gint i, j, offset, bitlen, keylen, pkeylen;
2232 keylen = strlen (key) >> 1;
2236 /* allow the ECMA standard key */
2237 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2239 *pubkey = g_strdup (key);
2245 val = g_ascii_xdigit_value (key [0]) << 4;
2246 val |= g_ascii_xdigit_value (key [1]);
2251 val = g_ascii_xdigit_value (key [24]);
2252 val |= g_ascii_xdigit_value (key [25]);
2264 /* We need the first 16 bytes
2265 * to check whether this key is valid or not */
2266 pkeylen = strlen (pkey) >> 1;
2270 for (i = 0, j = 0; i < 16; i++) {
2271 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2272 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2275 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2276 header [1] != 0x02 || /* Version (0x02) */
2277 header [2] != 0x00 || /* Reserved (word) */
2278 header [3] != 0x00 ||
2279 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2282 /* Based on this length, we _should_ be able to know if the length is right */
2283 bitlen = read32 (header + 12) >> 3;
2284 if ((bitlen + 16 + 4) != pkeylen)
2287 /* parsing is OK and the public key itself is not requested back */
2291 /* Encode the size of the blob */
2293 if (keylen <= 127) {
2294 arr = (gchar *)g_malloc (keylen + 1);
2295 arr [offset++] = keylen;
2297 arr = (gchar *)g_malloc (keylen + 2);
2298 arr [offset++] = 0x80; /* 10bs */
2299 arr [offset++] = keylen;
2302 for (i = offset, j = 0; i < keylen + offset; i++) {
2303 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2304 arr [i] |= g_ascii_xdigit_value (key [j++]);
2313 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)
2315 gint major, minor, build, revision;
2318 gchar *pkey, *pkeyptr, *encoded, tok [8];
2320 memset (aname, 0, sizeof (MonoAssemblyName));
2323 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2324 if (version_parts < 2 || version_parts > 4)
2327 /* FIXME: we should set build & revision to -1 (instead of 0)
2328 if these are not set in the version string. That way, later on,
2329 we can still determine if these were specified. */
2330 aname->major = major;
2331 aname->minor = minor;
2332 if (version_parts >= 3)
2333 aname->build = build;
2336 if (version_parts == 4)
2337 aname->revision = revision;
2339 aname->revision = 0;
2342 aname->flags = flags;
2344 aname->name = g_strdup (name);
2347 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2348 aname->culture = g_strdup ("");
2350 aname->culture = g_strdup (culture);
2353 if (token && strncmp (token, "null", 4) != 0) {
2356 /* the constant includes the ending NULL, hence the -1 */
2357 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2358 mono_assembly_name_free (aname);
2361 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2362 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2368 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2369 mono_assembly_name_free (aname);
2374 if (save_public_key)
2375 aname->public_key = (guint8*)pkey;
2378 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2382 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2383 // We also need to generate the key token
2384 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2385 encoded = encode_public_tok ((guchar*) tok, 8);
2386 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2389 if (save_public_key)
2390 aname->public_key = (guint8*) pkey;
2399 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2404 parts = g_strsplit (dirname, "_", 3);
2405 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2410 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2416 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2418 char *eqsign = strchr (pair, '=');
2426 *key = (gchar*)pair;
2427 *keylen = eqsign - *key;
2428 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2430 *value = g_strstrip (eqsign + 1);
2435 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2439 gchar *version = NULL;
2441 gchar *culture = NULL;
2443 gchar *token = NULL;
2447 gchar *retargetable = NULL;
2448 gchar *retargetable_uq;
2452 gchar *value, *part_name;
2453 guint32 part_name_len;
2456 gboolean version_defined;
2457 gboolean token_defined;
2459 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2461 if (!is_version_defined)
2462 is_version_defined = &version_defined;
2463 *is_version_defined = FALSE;
2464 if (!is_token_defined)
2465 is_token_defined = &token_defined;
2466 *is_token_defined = FALSE;
2468 parts = tmp = g_strsplit (name, ",", 6);
2469 if (!tmp || !*tmp) {
2474 dllname = g_strstrip (*tmp);
2479 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2480 goto cleanup_and_fail;
2482 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2483 *is_version_defined = TRUE;
2485 if (strlen (version) == 0) {
2486 goto cleanup_and_fail;
2492 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2494 if (strlen (culture) == 0) {
2495 goto cleanup_and_fail;
2501 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2502 *is_token_defined = TRUE;
2504 if (strlen (token) == 0) {
2505 goto cleanup_and_fail;
2511 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2513 if (strlen (key) == 0) {
2514 goto cleanup_and_fail;
2520 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2521 retargetable = value;
2522 retargetable_uq = unquote (retargetable);
2523 if (retargetable_uq != NULL)
2524 retargetable = retargetable_uq;
2526 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2527 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2528 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2529 g_free (retargetable_uq);
2530 goto cleanup_and_fail;
2533 g_free (retargetable_uq);
2538 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2540 procarch_uq = unquote (procarch);
2541 if (procarch_uq != NULL)
2542 procarch = procarch_uq;
2544 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2545 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2546 else if (!g_ascii_strcasecmp (procarch, "X86"))
2547 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2548 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2549 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2550 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2551 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2553 g_free (procarch_uq);
2554 goto cleanup_and_fail;
2557 g_free (procarch_uq);
2566 /* if retargetable flag is set, then we must have a fully qualified name */
2567 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2568 goto cleanup_and_fail;
2571 dllname_uq = unquote (dllname);
2572 version_uq = unquote (version);
2573 culture_uq = unquote (culture);
2574 token_uq = unquote (token);
2575 key_uq = unquote (key);
2577 res = build_assembly_name (
2578 dllname_uq == NULL ? dllname : dllname_uq,
2579 version_uq == NULL ? version : version_uq,
2580 culture_uq == NULL ? culture : culture_uq,
2581 token_uq == NULL ? token : token_uq,
2582 key_uq == NULL ? key : key_uq,
2583 flags, arch, aname, save_public_key);
2585 g_free (dllname_uq);
2586 g_free (version_uq);
2587 g_free (culture_uq);
2600 unquote (const char *str)
2608 slen = strlen (str);
2612 if (*str != '\'' && *str != '\"')
2615 end = str + slen - 1;
2619 return g_strndup (str + 1, slen - 2);
2623 * mono_assembly_name_parse:
2624 * \param name name to parse
2625 * \param aname the destination assembly name
2627 * Parses an assembly qualified type name and assigns the name,
2628 * version, culture and token to the provided assembly name object.
2630 * \returns TRUE if the name could be parsed.
2633 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2635 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2639 * mono_assembly_name_new:
2640 * \param name name to parse
2642 * Allocate a new \c MonoAssemblyName and fill its values from the
2645 * \returns a newly allocated structure or NULL if there was any failure.
2648 mono_assembly_name_new (const char *name)
2650 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2651 if (mono_assembly_name_parse (name, aname))
2658 * mono_assembly_name_get_name:
2661 mono_assembly_name_get_name (MonoAssemblyName *aname)
2667 * mono_assembly_name_get_culture:
2670 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2672 return aname->culture;
2676 * mono_assembly_name_get_pubkeytoken:
2679 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2681 if (aname->public_key_token [0])
2682 return aname->public_key_token;
2687 * mono_assembly_name_get_version:
2690 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2693 *minor = aname->minor;
2695 *build = aname->build;
2697 *revision = aname->revision;
2698 return aname->major;
2701 static MonoAssembly*
2702 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2704 gchar *fullpath = NULL;
2706 const char* direntry;
2707 MonoAssemblyName gac_aname;
2708 gint major=-1, minor=0, build=0, revision=0;
2709 gboolean exact_version;
2711 dirhandle = g_dir_open (basepath, 0, NULL);
2715 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2717 while ((direntry = g_dir_read_name (dirhandle))) {
2718 gboolean match = TRUE;
2720 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2723 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2726 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2727 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2731 if (exact_version) {
2732 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2733 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2735 else if (gac_aname.major < major)
2737 else if (gac_aname.major == major) {
2738 if (gac_aname.minor < minor)
2740 else if (gac_aname.minor == minor) {
2741 if (gac_aname.build < build)
2743 else if (gac_aname.build == build && gac_aname.revision <= revision)
2750 major = gac_aname.major;
2751 minor = gac_aname.minor;
2752 build = gac_aname.build;
2753 revision = gac_aname.revision;
2755 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2758 mono_assembly_name_free (&gac_aname);
2761 g_dir_close (dirhandle);
2763 if (fullpath == NULL)
2766 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2773 * mono_assembly_load_with_partial_name:
2774 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2775 * \param status return status code
2777 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2778 * so it might contain a qualified type name, version, culture and token.
2780 * This will load the assembly from the file whose name is derived from the assembly name
2781 * by appending the \c .dll extension.
2783 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2784 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2785 * if that fails from the GAC.
2787 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2790 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2794 MonoAssemblyName *aname, base_name;
2795 MonoAssemblyName mapped_aname;
2796 gchar *fullname, *gacpath;
2799 memset (&base_name, 0, sizeof (MonoAssemblyName));
2802 if (!mono_assembly_name_parse (name, aname))
2806 * If no specific version has been requested, make sure we load the
2807 * correct version for system assemblies.
2809 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2810 aname = mono_assembly_remap_version (aname, &mapped_aname);
2812 res = mono_assembly_loaded (aname);
2814 mono_assembly_name_free (aname);
2818 res = invoke_assembly_preload_hook (aname, assemblies_path);
2820 res->in_gac = FALSE;
2821 mono_assembly_name_free (aname);
2825 fullname = g_strdup_printf ("%s.dll", aname->name);
2827 if (extra_gac_paths) {
2828 paths = extra_gac_paths;
2829 while (!res && *paths) {
2830 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2831 res = probe_for_partial_name (gacpath, fullname, aname, status);
2840 mono_assembly_name_free (aname);
2844 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2845 res = probe_for_partial_name (gacpath, fullname, aname, status);
2849 mono_assembly_name_free (aname);
2854 MonoDomain *domain = mono_domain_get ();
2856 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2857 if (!is_ok (&error)) {
2858 mono_error_cleanup (&error);
2859 if (*status == MONO_IMAGE_OK)
2860 *status = MONO_IMAGE_IMAGE_INVALID;
2868 mono_assembly_is_in_gac (const gchar *filename)
2870 const gchar *rootdir;
2874 if (filename == NULL)
2877 for (paths = extra_gac_paths; paths && *paths; paths++) {
2878 if (strstr (*paths, filename) != *paths)
2881 gp = (gchar *) (filename + strlen (*paths));
2882 if (*gp != G_DIR_SEPARATOR)
2885 if (strncmp (gp, "lib", 3))
2888 if (*gp != G_DIR_SEPARATOR)
2891 if (strncmp (gp, "mono", 4))
2894 if (*gp != G_DIR_SEPARATOR)
2897 if (strncmp (gp, "gac", 3))
2900 if (*gp != G_DIR_SEPARATOR)
2906 rootdir = mono_assembly_getrootdir ();
2907 if (strstr (filename, rootdir) != filename)
2910 gp = (gchar *) (filename + strlen (rootdir));
2911 if (*gp != G_DIR_SEPARATOR)
2914 if (strncmp (gp, "mono", 4))
2917 if (*gp != G_DIR_SEPARATOR)
2920 if (strncmp (gp, "gac", 3))
2923 if (*gp != G_DIR_SEPARATOR)
2929 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2932 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2936 if (strstr (aname->name, ".dll")) {
2937 len = strlen (aname->name) - 4;
2938 name = (gchar *)g_malloc (len + 1);
2939 memcpy (name, aname->name, len);
2942 name = g_strdup (aname->name);
2945 culture = g_utf8_strdown (aname->culture, -1);
2947 culture = g_strdup ("");
2949 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2950 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2954 filename = g_strconcat (pname, ".dll", NULL);
2955 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2961 if (extra_gac_paths) {
2962 paths = extra_gac_paths;
2963 while (!image && *paths) {
2964 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2965 "lib", "mono", "gac", subpath, NULL);
2966 image = mono_image_open (fullpath, NULL);
2977 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2978 "mono", "gac", subpath, NULL);
2979 image = mono_image_open (fullpath, NULL);
2986 static MonoAssemblyName*
2987 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2989 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2990 dest_name->major = info->new_version.major;
2991 dest_name->minor = info->new_version.minor;
2992 dest_name->build = info->new_version.build;
2993 dest_name->revision = info->new_version.revision;
2998 /* LOCKING: assembly_binding lock must be held */
2999 static MonoAssemblyBindingInfo*
3000 search_binding_loaded (MonoAssemblyName *aname)
3004 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3005 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3006 if (assembly_binding_maps_name (info, aname))
3013 static inline gboolean
3014 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3016 if (left->major != right->major || left->minor != right->minor ||
3017 left->build != right->build || left->revision != right->revision)
3023 static inline gboolean
3024 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3026 if (left->has_old_version_bottom != right->has_old_version_bottom)
3029 if (left->has_old_version_top != right->has_old_version_top)
3032 if (left->has_new_version != right->has_new_version)
3035 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3038 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3041 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3047 /* LOCKING: assumes all the necessary locks are held */
3049 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3051 MonoAssemblyBindingInfo *info_copy;
3053 MonoAssemblyBindingInfo *info_tmp;
3054 MonoDomain *domain = (MonoDomain*)user_data;
3059 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)) {
3060 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3061 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3065 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3066 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3067 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3071 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3072 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3074 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3076 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3078 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3082 get_version_number (int major, int minor)
3084 return major * 256 + minor;
3087 static inline gboolean
3088 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3090 int aname_version_number = get_version_number (aname->major, aname->minor);
3091 if (!info->has_old_version_bottom)
3094 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3097 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3100 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3101 info->major = aname->major;
3102 info->minor = aname->minor;
3107 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3108 static MonoAssemblyBindingInfo*
3109 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3111 MonoAssemblyBindingInfo *info;
3114 if (!domain->assembly_bindings)
3118 for (list = domain->assembly_bindings; list; list = list->next) {
3119 info = (MonoAssemblyBindingInfo *)list->data;
3120 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3126 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3127 info->has_new_version && assembly_binding_maps_name (info, aname))
3128 info->is_valid = TRUE;
3130 info->is_valid = FALSE;
3136 static MonoAssemblyName*
3137 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3140 MonoAssemblyBindingInfo *info, *info2;
3144 if (aname->public_key_token [0] == 0)
3147 domain = mono_domain_get ();
3149 mono_assembly_binding_lock ();
3150 info = search_binding_loaded (aname);
3151 mono_assembly_binding_unlock ();
3154 mono_domain_lock (domain);
3155 info = get_per_domain_assembly_binding_info (domain, aname);
3156 mono_domain_unlock (domain);
3160 if (!check_policy_versions (info, aname))
3163 mono_assembly_bind_version (info, aname, dest_name);
3167 if (domain && domain->setup && domain->setup->configuration_file) {
3168 mono_domain_lock (domain);
3169 if (!domain->assembly_bindings_parsed) {
3170 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3171 /* expect this to succeed because mono_domain_set_options_from_config () did
3172 * the same thing when the domain was created. */
3173 mono_error_assert_ok (&error);
3175 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3177 if (!domain_config_file_path)
3178 domain_config_file_path = domain_config_file_name;
3180 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3181 domain->assembly_bindings_parsed = TRUE;
3182 if (domain_config_file_name != domain_config_file_path)
3183 g_free (domain_config_file_name);
3184 g_free (domain_config_file_path);
3187 info2 = get_per_domain_assembly_binding_info (domain, aname);
3190 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3191 info->name = g_strdup (info2->name);
3192 info->culture = g_strdup (info2->culture);
3193 info->domain_id = domain->domain_id;
3196 mono_domain_unlock (domain);
3200 info = g_new0 (MonoAssemblyBindingInfo, 1);
3201 info->major = aname->major;
3202 info->minor = aname->minor;
3205 if (!info->is_valid) {
3206 ppimage = mono_assembly_load_publisher_policy (aname);
3208 get_publisher_policy_info (ppimage, aname, info);
3209 mono_image_close (ppimage);
3213 /* Define default error value if needed */
3214 if (!info->is_valid) {
3215 info->name = g_strdup (aname->name);
3216 info->culture = g_strdup (aname->culture);
3217 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3220 mono_assembly_binding_lock ();
3221 info2 = search_binding_loaded (aname);
3223 /* This binding was added by another thread
3225 mono_assembly_binding_info_free (info);
3230 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3232 mono_assembly_binding_unlock ();
3234 if (!info->is_valid || !check_policy_versions (info, aname))
3237 mono_assembly_bind_version (info, aname, dest_name);
3242 * mono_assembly_load_from_gac
3244 * \param aname The assembly name object
3246 static MonoAssembly*
3247 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3249 MonoAssembly *result = NULL;
3250 gchar *name, *version, *culture, *fullpath, *subpath;
3255 if (aname->public_key_token [0] == 0) {
3259 if (strstr (aname->name, ".dll")) {
3260 len = strlen (filename) - 4;
3261 name = (gchar *)g_malloc (len + 1);
3262 memcpy (name, aname->name, len);
3265 name = g_strdup (aname->name);
3268 if (aname->culture) {
3269 culture = g_utf8_strdown (aname->culture, -1);
3271 culture = g_strdup ("");
3274 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3275 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3276 aname->minor, aname->build, aname->revision,
3280 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3285 if (extra_gac_paths) {
3286 paths = extra_gac_paths;
3287 while (!result && *paths) {
3288 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3289 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3296 result->in_gac = TRUE;
3301 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3302 "mono", "gac", subpath, NULL);
3303 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3307 result->in_gac = TRUE;
3315 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3318 MonoAssemblyName *aname;
3321 /* g_print ("corlib already loaded\n"); */
3325 // In native client, Corlib is embedded in the executable as static variable corlibData
3326 #if defined(__native_client__)
3327 if (corlibData != NULL && corlibSize != 0) {
3329 /* First "FALSE" instructs mono not to make a copy. */
3330 /* Second "FALSE" says this is not just a ref. */
3331 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3332 if (image == NULL || status != 0)
3333 g_print("mono_image_open_from_data_full failed: %d\n", status);
3334 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3335 if (corlib == NULL || status != 0)
3336 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3342 // A nonstandard preload hook may provide a special mscorlib assembly
3343 aname = mono_assembly_name_new ("mscorlib.dll");
3344 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3345 mono_assembly_name_free (aname);
3348 goto return_corlib_and_facades;
3350 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3351 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3352 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3354 goto return_corlib_and_facades;
3357 /* Normal case: Load corlib from mono/<version> */
3358 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3359 if (assemblies_path) { // Custom assemblies path
3360 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3362 g_free (corlib_file);
3363 goto return_corlib_and_facades;
3366 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3367 g_free (corlib_file);
3369 return_corlib_and_facades:
3370 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3371 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3376 static MonoAssembly*
3377 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3379 MonoError refasm_error;
3380 error_init (&refasm_error);
3381 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3384 mono_error_cleanup (&refasm_error);
3389 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3391 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3392 MonoAssemblyName *candidate_name = &candidate->aname;
3394 g_assert (wanted_name != NULL);
3395 g_assert (candidate_name != NULL);
3397 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3398 char * s = mono_stringify_assembly_name (wanted_name);
3399 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3401 s = mono_stringify_assembly_name (candidate_name);
3402 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3406 /* No wanted token, bail. */
3407 if (0 == wanted_name->public_key_token [0]) {
3408 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3412 if (0 == candidate_name->public_key_token [0]) {
3413 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3418 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3420 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3421 result ? "match, returning TRUE" : "don't match, returning FALSE");
3428 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3429 const char *basedir,
3430 MonoImageOpenStatus *status,
3433 MonoAssembly *result;
3434 char *fullpath, *filename;
3435 MonoAssemblyName maped_aname;
3436 MonoAssemblyName maped_name_pp;
3441 aname = mono_assembly_remap_version (aname, &maped_aname);
3443 /* Reflection only assemblies don't get assembly binding */
3445 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3447 result = mono_assembly_loaded_full (aname, refonly);
3451 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3453 result->in_gac = FALSE;
3457 /* Currently we retrieve the loaded corlib for reflection
3458 * only requests, like a common reflection only assembly
3460 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3461 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3464 len = strlen (aname->name);
3465 for (ext_index = 0; ext_index < 2; ext_index ++) {
3466 ext = ext_index == 0 ? ".dll" : ".exe";
3467 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3468 filename = g_strdup (aname->name);
3469 /* Don't try appending .dll/.exe if it already has one of those extensions */
3472 filename = g_strconcat (aname->name, ext, NULL);
3475 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3482 fullpath = g_build_filename (basedir, filename, NULL);
3483 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3486 result->in_gac = FALSE;
3492 result = load_in_path (filename, default_path, status, refonly, NULL, NULL);
3494 result->in_gac = FALSE;
3504 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3506 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3509 /* Try a postload search hook */
3510 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3511 result = prevent_reference_assembly_from_running (result, refonly);
3517 * mono_assembly_load_full:
3518 * \param aname A MonoAssemblyName with the assembly name to load.
3519 * \param basedir A directory to look up the assembly at.
3520 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3521 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3523 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3524 * attempts to load the assembly from that directory before probing the standard locations.
3526 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3527 * assembly binding takes place.
3529 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3530 * value pointed by \p status is updated with an error code.
3533 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3535 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3539 * mono_assembly_load:
3540 * \param aname A MonoAssemblyName with the assembly name to load.
3541 * \param basedir A directory to look up the assembly at.
3542 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3544 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3545 * attempts to load the assembly from that directory before probing the standard locations.
3547 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3548 * value pointed by \p status is updated with an error code.
3551 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3553 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3557 * mono_assembly_loaded_full:
3558 * \param aname an assembly to look for.
3559 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3561 * This is used to determine if the specified assembly has been loaded
3562 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3563 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3566 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3569 MonoAssemblyName maped_aname;
3571 aname = mono_assembly_remap_version (aname, &maped_aname);
3573 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3579 * mono_assembly_loaded:
3580 * \param aname an assembly to look for.
3582 * This is used to determine if the specified assembly has been loaded
3584 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3585 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3588 mono_assembly_loaded (MonoAssemblyName *aname)
3590 return mono_assembly_loaded_full (aname, FALSE);
3594 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3596 if (assembly == NULL || assembly == REFERENCE_MISSING)
3599 if (assembly_is_dynamic (assembly)) {
3601 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3602 for (i = 0; i < dynimg->image.module_count; ++i)
3603 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3604 mono_dynamic_image_release_gc_roots (dynimg);
3609 * Returns whether mono_assembly_close_finish() must be called as
3610 * well. See comment for mono_image_close_except_pools() for why we
3611 * unload in two steps.
3614 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3617 g_return_val_if_fail (assembly != NULL, FALSE);
3619 if (assembly == REFERENCE_MISSING)
3622 /* Might be 0 already */
3623 if (InterlockedDecrement (&assembly->ref_count) > 0)
3626 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3628 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3630 mono_debug_close_image (assembly->image);
3632 mono_assemblies_lock ();
3633 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3634 mono_assemblies_unlock ();
3636 assembly->image->assembly = NULL;
3638 if (!mono_image_close_except_pools (assembly->image))
3639 assembly->image = NULL;
3641 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3642 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3643 mono_assembly_name_free (fname);
3646 g_slist_free (assembly->friend_assembly_names);
3647 g_free (assembly->basedir);
3649 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3655 mono_assembly_close_finish (MonoAssembly *assembly)
3657 g_assert (assembly && assembly != REFERENCE_MISSING);
3659 if (assembly->image)
3660 mono_image_close_finish (assembly->image);
3662 if (assembly_is_dynamic (assembly)) {
3663 g_free ((char*)assembly->aname.culture);
3670 * mono_assembly_close:
3671 * \param assembly the assembly to release.
3673 * This method releases a reference to the \p assembly. The assembly is
3674 * only released when all the outstanding references to it are released.
3677 mono_assembly_close (MonoAssembly *assembly)
3679 if (mono_assembly_close_except_image_pools (assembly))
3680 mono_assembly_close_finish (assembly);
3684 * mono_assembly_load_module:
3687 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3690 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3691 mono_error_assert_ok (&error);
3696 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3698 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3703 * mono_assembly_foreach:
3704 * \param func function to invoke for each assembly loaded
3705 * \param user_data data passed to the callback
3707 * Invokes the provided \p func callback for each assembly loaded into
3708 * the runtime. The first parameter passed to the callback is the
3709 * \c MonoAssembly*, and the second parameter is the \p user_data.
3711 * This is done for all assemblies loaded in the runtime, not just
3712 * those loaded in the current application domain.
3715 mono_assembly_foreach (GFunc func, gpointer user_data)
3720 * We make a copy of the list to avoid calling the callback inside the
3721 * lock, which could lead to deadlocks.
3723 mono_assemblies_lock ();
3724 copy = g_list_copy (loaded_assemblies);
3725 mono_assemblies_unlock ();
3727 g_list_foreach (loaded_assemblies, func, user_data);
3733 * mono_assemblies_cleanup:
3735 * Free all resources used by this module.
3738 mono_assemblies_cleanup (void)
3742 mono_os_mutex_destroy (&assemblies_mutex);
3743 mono_os_mutex_destroy (&assembly_binding_mutex);
3745 for (l = loaded_assembly_bindings; l; l = l->next) {
3746 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3748 mono_assembly_binding_info_free (info);
3751 g_slist_free (loaded_assembly_bindings);
3753 free_assembly_load_hooks ();
3754 free_assembly_search_hooks ();
3755 free_assembly_preload_hooks ();
3758 /*LOCKING takes the assembly_binding lock*/
3760 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3764 mono_assembly_binding_lock ();
3765 iter = &loaded_assembly_bindings;
3768 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3770 if (info->domain_id == domain_id) {
3772 mono_assembly_binding_info_free (info);
3779 mono_assembly_binding_unlock ();
3783 * Holds the assembly of the application, for
3784 * System.Diagnostics.Process::MainModule
3786 static MonoAssembly *main_assembly=NULL;
3789 * mono_assembly_set_main:
3792 mono_assembly_set_main (MonoAssembly *assembly)
3794 main_assembly = assembly;
3798 * mono_assembly_get_main:
3800 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3803 mono_assembly_get_main (void)
3805 return (main_assembly);
3809 * mono_assembly_get_image:
3810 * \param assembly The assembly to retrieve the image from
3812 * \returns the \c MonoImage associated with this assembly.
3815 mono_assembly_get_image (MonoAssembly *assembly)
3817 return assembly->image;
3821 * mono_assembly_get_name:
3822 * \param assembly The assembly to retrieve the name from
3824 * The returned name's lifetime is the same as \p assembly's.
3826 * \returns the \c MonoAssemblyName associated with this assembly.
3829 mono_assembly_get_name (MonoAssembly *assembly)
3831 return &assembly->aname;
3835 * mono_register_bundled_assemblies:
3838 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3840 bundles = assemblies;
3843 #define MONO_DECLSEC_FORMAT_10 0x3C
3844 #define MONO_DECLSEC_FORMAT_20 0x2E
3845 #define MONO_DECLSEC_FIELD 0x53
3846 #define MONO_DECLSEC_PROPERTY 0x54
3848 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3849 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3850 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3851 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3852 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3855 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3859 case MONO_DECLSEC_PROPERTY:
3861 case MONO_DECLSEC_FIELD:
3863 *abort_decoding = TRUE;
3868 if (*p++ != MONO_TYPE_BOOLEAN) {
3869 *abort_decoding = TRUE;
3873 /* property name length */
3874 len = mono_metadata_decode_value (p, &p);
3876 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3887 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3889 int i, j, num, len, params_len;
3891 if (*p == MONO_DECLSEC_FORMAT_10) {
3892 gsize read, written;
3893 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3895 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3901 if (*p++ != MONO_DECLSEC_FORMAT_20)
3904 /* number of encoded permission attributes */
3905 num = mono_metadata_decode_value (p, &p);
3906 for (i = 0; i < num; ++i) {
3907 gboolean is_valid = FALSE;
3908 gboolean abort_decoding = FALSE;
3910 /* attribute name length */
3911 len = mono_metadata_decode_value (p, &p);
3913 /* We don't really need to fully decode the type. Comparing the name is enough */
3914 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3918 /*size of the params table*/
3919 params_len = mono_metadata_decode_value (p, &p);
3921 const char *params_end = p + params_len;
3923 /* number of parameters */
3924 len = mono_metadata_decode_value (p, &p);
3926 for (j = 0; j < len; ++j) {
3927 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3943 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3946 guint32 cols [MONO_DECL_SECURITY_SIZE];
3950 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3951 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3953 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3955 for (i = 0; i < t->rows; ++i) {
3956 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3957 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3959 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3962 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3963 len = mono_metadata_decode_blob_size (blob, &blob);
3967 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3968 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3973 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);