2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include "assembly-internals.h"
21 #include "image-internals.h"
22 #include "object-internals.h"
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/custom-attrs-internals.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/class-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include <mono/metadata/reflection-internals.h>
31 #include <mono/metadata/mono-endian.h>
32 #include <mono/metadata/mono-debug.h>
33 #include <mono/io-layer/io-layer.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
80 /* The list of system assemblies what will be remapped to the running
81 * runtime version. WARNING: this list must be sorted.
82 * The integer number is an index in the MonoRuntimeInfo structure, whose
83 * values can be found in domain.c - supported_runtimes. Look there
84 * to understand what remapping will be made.
86 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
89 static const AssemblyVersionMap framework_assemblies [] = {
91 {"Commons.Xml.Relaxng", 0},
98 {"Microsoft.Build.Engine", 2, NULL, TRUE},
99 {"Microsoft.Build.Framework", 2, NULL, TRUE},
100 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
101 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
102 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
103 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
104 {"Microsoft.VisualBasic", 1},
105 {"Microsoft.VisualC", 1},
107 {"Mono.CompilerServices.SymbolWriter", 0},
109 {"Mono.Data.SybaseClient", 0},
110 {"Mono.Data.Tds", 0},
111 {"Mono.Data.TdsClient", 0},
112 {"Mono.GetOptions", 0},
115 {"Mono.Security", 0},
116 {"Mono.Security.Win32", 0},
118 {"Novell.Directory.Ldap", 0},
121 {"System.ComponentModel.Composition", 2},
122 {"System.ComponentModel.DataAnnotations", 2},
123 {"System.Configuration", 0},
124 {"System.Configuration.Install", 0},
127 {"System.Data.Linq", 2},
128 {"System.Data.OracleClient", 0},
129 {"System.Data.Services", 2},
130 {"System.Data.Services.Client", 2},
131 {"System.Data.SqlXml", 0},
132 {"System.Design", 0},
133 {"System.DirectoryServices", 0},
134 {"System.Drawing", 0},
135 {"System.Drawing.Design", 0},
136 {"System.EnterpriseServices", 0},
137 {"System.IdentityModel", 3},
138 {"System.IdentityModel.Selectors", 3},
139 {"System.Management", 0},
140 {"System.Messaging", 0},
142 {"System.Runtime.Remoting", 0},
143 {"System.Runtime.Serialization", 3},
144 {"System.Runtime.Serialization.Formatters.Soap", 0},
145 {"System.Security", 0},
146 {"System.ServiceModel", 3},
147 {"System.ServiceModel.Web", 2},
148 {"System.ServiceProcess", 0},
149 {"System.Transactions", 0},
151 {"System.Web.Abstractions", 2},
152 {"System.Web.DynamicData", 2},
153 {"System.Web.Extensions", 2},
154 {"System.Web.Mobile", 0},
155 {"System.Web.Routing", 2},
156 {"System.Web.Services", 0},
157 {"System.Windows.Forms", 0},
159 {"System.Xml.Linq", 2},
166 * keeps track of loaded assemblies
168 static GList *loaded_assemblies = NULL;
169 static MonoAssembly *corlib;
171 #if defined(__native_client__)
173 /* On Native Client, allow mscorlib to be loaded from memory */
174 /* instead of loaded off disk. If these are not set, default */
175 /* mscorlib loading will take place */
177 /* NOTE: If mscorlib data is passed to mono in this way then */
178 /* it needs to remain allocated during the use of mono. */
180 static void *corlibData = NULL;
181 static size_t corlibSize = 0;
184 mono_set_corlib_data (void *data, size_t size)
192 static char* unquote (const char *str);
194 /* This protects loaded_assemblies and image->references */
195 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
196 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
197 static mono_mutex_t assemblies_mutex;
199 /* If defined, points to the bundled assembly information */
200 const MonoBundledAssembly **bundles;
202 static mono_mutex_t assembly_binding_mutex;
204 /* Loaded assembly binding info */
205 static GSList *loaded_assembly_bindings = NULL;
207 /* Class lazy loading functions */
208 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
210 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
212 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
214 mono_assembly_is_in_gac (const gchar *filanem);
217 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
220 encode_public_tok (const guchar *token, gint32 len)
222 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
226 res = (gchar *)g_malloc (len * 2 + 1);
227 for (i = 0; i < len; i++) {
228 res [i * 2] = allowed [token [i] >> 4];
229 res [i * 2 + 1] = allowed [token [i] & 0xF];
236 * mono_public_tokens_are_equal:
237 * @pubt1: first public key token
238 * @pubt2: second public key token
240 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
244 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
246 return memcmp (pubt1, pubt2, 16) == 0;
250 * mono_set_assemblies_path:
251 * @path: list of paths that contain directories where Mono will look for assemblies
253 * Use this method to override the standard assembly lookup system and
254 * override any assemblies coming from the GAC. This is the method
255 * that supports the MONO_PATH variable.
257 * Notice that MONO_PATH and this method are really a very bad idea as
258 * it prevents the GAC from working and it prevents the standard
259 * resolution mechanisms from working. Nonetheless, for some debugging
260 * situations and bootstrapping setups, this is useful to have.
263 mono_set_assemblies_path (const char* path)
265 char **splitted, **dest;
267 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
269 g_strfreev (assemblies_path);
270 assemblies_path = dest = splitted;
272 char *tmp = *splitted;
274 *dest++ = mono_path_canonicalize (tmp);
280 if (g_getenv ("MONO_DEBUG") == NULL)
283 splitted = assemblies_path;
285 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
286 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
292 /* Native Client can't get this info from an environment variable so */
293 /* it's passed in to the runtime, or set manually by embedding code. */
294 #ifdef __native_client__
295 char* nacl_mono_path = NULL;
299 check_path_env (void)
302 path = g_getenv ("MONO_PATH");
303 #ifdef __native_client__
305 path = nacl_mono_path;
307 if (!path || assemblies_path != NULL)
310 mono_set_assemblies_path(path);
314 check_extra_gac_path_env (void) {
316 char **splitted, **dest;
318 path = g_getenv ("MONO_GAC_PREFIX");
322 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
324 g_strfreev (extra_gac_paths);
325 extra_gac_paths = dest = splitted;
333 if (g_getenv ("MONO_DEBUG") == NULL)
337 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
338 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
345 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
347 if (!info || !info->name)
350 if (strcmp (info->name, aname->name))
353 if (info->major != aname->major || info->minor != aname->minor)
356 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
359 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
362 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
369 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
375 g_free (info->culture);
379 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
382 guint32 cols [MONO_MANIFEST_SIZE];
383 const gchar *filename;
384 gchar *subpath, *fullpath;
386 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
387 /* MS Impl. accepts policy assemblies with more than
388 * one manifest resource, and only takes the first one */
390 binding_info->is_valid = FALSE;
394 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
395 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
396 binding_info->is_valid = FALSE;
400 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
401 g_assert (filename != NULL);
403 subpath = g_path_get_dirname (image->name);
404 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
405 mono_config_parse_publisher_policy (fullpath, binding_info);
409 /* Define the optional elements/attributes before checking */
410 if (!binding_info->culture)
411 binding_info->culture = g_strdup ("");
413 /* Check that the most important elements/attributes exist */
414 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
415 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
416 mono_assembly_binding_info_free (binding_info);
417 binding_info->is_valid = FALSE;
421 binding_info->is_valid = TRUE;
425 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
427 if (v->major > aname->major)
429 else if (v->major < aname->major)
432 if (v->minor > aname->minor)
434 else if (v->minor < aname->minor)
437 if (v->build > aname->build)
439 else if (v->build < aname->build)
442 if (v->revision > aname->revision)
444 else if (v->revision < aname->revision)
451 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
456 /* If has_old_version_top doesn't exist, we don't have an interval */
457 if (!info->has_old_version_top) {
458 if (compare_versions (&info->old_version_bottom, name) == 0)
464 /* Check that the version defined by name is valid for the interval */
465 if (compare_versions (&info->old_version_top, name) < 0)
468 /* We should be greater or equal than the small version */
469 if (compare_versions (&info->old_version_bottom, name) > 0)
476 * mono_assembly_names_equal:
478 * @r: second assembly.
480 * Compares two MonoAssemblyNames and returns whether they are equal.
482 * This compares the names, the cultures, the release version and their
485 * Returns: TRUE if both assembly names are equal.
488 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
490 if (!l->name || !r->name)
493 if (strcmp (l->name, r->name))
496 if (l->culture && r->culture && strcmp (l->culture, r->culture))
499 if (l->major != r->major || l->minor != r->minor ||
500 l->build != r->build || l->revision != r->revision)
501 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)))
504 if (!l->public_key_token [0] || !r->public_key_token [0])
507 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
513 static MonoAssembly *
514 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
518 MonoAssembly *result;
520 for (i = 0; search_path [i]; ++i) {
521 fullpath = g_build_filename (search_path [i], basename, NULL);
522 result = mono_assembly_open_full (fullpath, status, refonly);
531 * mono_assembly_setrootdir:
532 * @root_dir: The pathname of the root directory where we will locate assemblies
534 * This routine sets the internal default root directory for looking up
537 * This is used by Windows installations to compute dynamically the
538 * place where the Mono assemblies are located.
542 mono_assembly_setrootdir (const char *root_dir)
545 * Override the MONO_ASSEMBLIES directory configured at compile time.
547 /* Leak if called more than once */
548 default_path [0] = g_strdup (root_dir);
552 * mono_assembly_getrootdir:
554 * Obtains the root directory used for looking up assemblies.
556 * Returns: a string with the directory, this string should not be freed.
558 G_CONST_RETURN gchar *
559 mono_assembly_getrootdir (void)
561 return default_path [0];
565 * mono_native_getrootdir:
567 * Obtains the root directory used for looking up native libs (.so, .dylib).
569 * Returns: a string with the directory, this string should be freed by
573 mono_native_getrootdir (void)
575 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
581 * @assembly_dir: the base directory for assemblies
582 * @config_dir: the base directory for configuration files
584 * This routine is used internally and by developers embedding
585 * the runtime into their own applications.
587 * There are a number of cases to consider: Mono as a system-installed
588 * package that is available on the location preconfigured or Mono in
589 * a relocated location.
591 * If you are using a system-installed Mono, you can pass NULL
592 * to both parameters. If you are not, you should compute both
593 * directory values and call this routine.
595 * The values for a given PREFIX are:
597 * assembly_dir: PREFIX/lib
598 * config_dir: PREFIX/etc
600 * Notice that embedders that use Mono in a relocated way must
601 * compute the location at runtime, as they will be in control
602 * of where Mono is installed.
605 mono_set_dirs (const char *assembly_dir, const char *config_dir)
607 if (assembly_dir == NULL)
608 assembly_dir = mono_config_get_assemblies_dir ();
609 if (config_dir == NULL)
610 config_dir = mono_config_get_cfg_dir ();
611 mono_assembly_setrootdir (assembly_dir);
612 mono_set_config_dir (config_dir);
618 compute_base (char *path)
620 char *p = strrchr (path, '/');
624 /* Not a well known Mono executable, we are embedded, cant guess the base */
625 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
629 p = strrchr (path, '/');
633 if (strcmp (p, "/bin") != 0)
642 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
645 static G_GNUC_UNUSED void
649 char *config, *lib, *mono;
654 * Only /usr prefix is treated specially
656 bindir = mono_config_get_bin_dir ();
658 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
663 config = g_build_filename (base, "etc", NULL);
664 lib = g_build_filename (base, "lib", NULL);
665 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
666 if (stat (mono, &buf) == -1)
669 mono_set_dirs (lib, config);
677 #endif /* HOST_WIN32 */
682 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
683 * this auto-detects the prefix where Mono was installed.
686 mono_set_rootdir (void)
688 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
689 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
692 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
696 * _NSGetExecutablePath may return -1 to indicate buf is not large
697 * enough, but we ignore that case to avoid having to do extra dynamic
698 * allocation for the path and hope that 4096 is enough - this is
699 * ok in the Linux/Solaris case below at least...
703 guint buf_size = sizeof (buf);
706 if (_NSGetExecutablePath (buf, &buf_size) == 0)
707 name = g_strdup (buf);
716 resolvedname = mono_path_resolve_symlinks (name);
718 bindir = g_path_get_dirname (resolvedname);
719 installdir = g_path_get_dirname (bindir);
720 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
722 config = g_build_filename (root, "..", "etc", NULL);
724 mono_set_dirs (root, config);
726 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
727 mono_set_dirs (root, config);
737 g_free (resolvedname);
738 #elif defined(DISABLE_MONO_AUTODETECTION)
746 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
754 /* Solaris 10 style */
755 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
756 s = readlink (str, buf, sizeof (buf)-1);
768 * mono_assemblies_init:
770 * Initialize global variables used by this module.
773 mono_assemblies_init (void)
776 * Initialize our internal paths if we have not been initialized yet.
777 * This happens when embedders use Mono.
779 if (mono_assembly_getrootdir () == NULL)
783 check_extra_gac_path_env ();
785 mono_os_mutex_init_recursive (&assemblies_mutex);
786 mono_os_mutex_init (&assembly_binding_mutex);
790 mono_assembly_binding_lock (void)
792 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
796 mono_assembly_binding_unlock (void)
798 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
802 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
804 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
805 guint32 cols [MONO_ASSEMBLY_SIZE];
806 gint32 machine, flags;
811 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
814 aname->hash_value = NULL;
815 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
816 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
817 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
818 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
819 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
820 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
821 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
822 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
823 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
824 guchar* token = (guchar *)g_malloc (8);
829 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
830 len = mono_metadata_decode_blob_size (pkey, &pkey);
831 aname->public_key = (guchar*)pkey;
833 mono_digest_get_public_token (token, aname->public_key, len);
834 encoded = encode_public_tok (token, 8);
835 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
841 aname->public_key = NULL;
842 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
845 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
846 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
849 aname->public_key = 0;
851 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
852 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
854 case COFF_MACHINE_I386:
855 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
856 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
857 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
858 else if ((flags & 0x70) == 0x70)
859 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
861 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
863 case COFF_MACHINE_IA64:
864 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
866 case COFF_MACHINE_AMD64:
867 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
869 case COFF_MACHINE_ARM:
870 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
880 * mono_stringify_assembly_name:
881 * @aname: the assembly name.
883 * Convert @aname into its string format. The returned string is dynamically
884 * allocated and should be freed by the caller.
886 * Returns: a newly allocated string with a string representation of
890 mono_stringify_assembly_name (MonoAssemblyName *aname)
892 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
894 return g_strdup_printf (
895 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
896 quote, aname->name, quote,
897 aname->major, aname->minor, aname->build, aname->revision,
898 aname->culture && *aname->culture? aname->culture: "neutral",
899 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
900 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
904 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
906 const gchar *public_tok;
909 public_tok = mono_metadata_blob_heap (image, key_index);
910 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
912 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
914 mono_digest_get_public_token (token, (guchar*)public_tok, len);
915 return encode_public_tok (token, 8);
918 return encode_public_tok ((guchar*)public_tok, len);
922 * mono_assembly_addref:
923 * @assemnly: the assembly to reference
925 * This routine increments the reference count on a MonoAssembly.
926 * The reference count is reduced every time the method mono_assembly_close() is
930 mono_assembly_addref (MonoAssembly *assembly)
932 InterlockedIncrement (&assembly->ref_count);
936 * CAUTION: This table must be kept in sync with
937 * ivkm/reflect/Fusion.cs
940 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
941 #define WINFX_KEY "31bf3856ad364e35"
942 #define ECMA_KEY "b77a5c561934e089"
943 #define MSFINAL_KEY "b03f5f7f11d50a3a"
944 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
952 static KeyRemapEntry key_remap_table[] = {
953 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
954 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
955 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
956 { "System", SILVERLIGHT_KEY, ECMA_KEY },
957 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
958 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
959 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
960 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
961 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
962 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
963 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
964 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
965 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
966 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
967 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
968 { "System.Numerics", WINFX_KEY, ECMA_KEY },
969 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
970 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
971 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
972 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
973 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
974 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
975 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
976 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
977 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
978 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
979 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
980 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
981 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
985 remap_keys (MonoAssemblyName *aname)
988 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
989 const KeyRemapEntry *entry = &key_remap_table [i];
991 if (strcmp (aname->name, entry->name) ||
992 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
995 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
997 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
998 "Remapped public key token of retargetable assembly %s from %s to %s",
999 aname->name, entry->from, entry->to);
1004 static MonoAssemblyName *
1005 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1007 const MonoRuntimeInfo *current_runtime;
1008 int pos, first, last;
1010 if (aname->name == NULL) return aname;
1012 current_runtime = mono_get_runtime_info ();
1014 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1015 const AssemblyVersionSet* vset;
1017 /* Remap to current runtime */
1018 vset = ¤t_runtime->version_sets [0];
1020 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1021 dest_aname->major = vset->major;
1022 dest_aname->minor = vset->minor;
1023 dest_aname->build = vset->build;
1024 dest_aname->revision = vset->revision;
1025 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1027 /* Remap assembly name */
1028 if (!strcmp (aname->name, "System.Net"))
1029 dest_aname->name = g_strdup ("System");
1031 remap_keys (dest_aname);
1033 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1034 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1036 aname->major, aname->minor, aname->build, aname->revision,
1038 vset->major, vset->minor, vset->build, vset->revision
1044 #ifndef DISABLE_ASSEMBLY_REMAPPING
1046 last = G_N_ELEMENTS (framework_assemblies) - 1;
1048 while (first <= last) {
1050 pos = first + (last - first) / 2;
1051 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1053 const AssemblyVersionSet* vset;
1054 int index = framework_assemblies[pos].version_set_index;
1055 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1056 vset = ¤t_runtime->version_sets [index];
1058 if (aname->major == vset->major && aname->minor == vset->minor &&
1059 aname->build == vset->build && aname->revision == vset->revision)
1062 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1065 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1066 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1067 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1069 aname->major, aname->minor, aname->build, aname->revision,
1070 vset->major, vset->minor, vset->build, vset->revision
1073 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1074 dest_aname->major = vset->major;
1075 dest_aname->minor = vset->minor;
1076 dest_aname->build = vset->build;
1077 dest_aname->revision = vset->revision;
1078 if (framework_assemblies[pos].new_assembly_name != NULL) {
1079 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1080 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1081 "The assembly name %s was remapped to %s",
1086 } else if (res < 0) {
1098 * mono_assembly_get_assemblyref:
1099 * @image: pointer to the MonoImage to extract the information from.
1100 * @index: index to the assembly reference in the image.
1101 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1103 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1106 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1109 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1112 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1114 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1116 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1117 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1118 aname->hash_value = hash;
1119 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1120 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1121 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1122 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1123 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1124 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1125 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1127 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1128 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1129 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1132 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1137 mono_assembly_load_reference (MonoImage *image, int index)
1139 MonoAssembly *reference;
1140 MonoAssemblyName aname;
1141 MonoImageOpenStatus status;
1144 * image->references is shared between threads, so we need to access
1145 * it inside a critical section.
1147 mono_assemblies_lock ();
1148 if (!image->references) {
1149 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1151 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1152 image->nreferences = t->rows;
1154 reference = image->references [index];
1155 mono_assemblies_unlock ();
1159 mono_assembly_get_assemblyref (image, index, &aname);
1161 if (image->assembly && image->assembly->ref_only) {
1162 /* We use the loaded corlib */
1163 if (!strcmp (aname.name, "mscorlib"))
1164 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1166 reference = mono_assembly_loaded_full (&aname, TRUE);
1168 /* Try a postload search hook */
1169 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1173 * Here we must advice that the error was due to
1174 * a non loaded reference using the ReflectionOnly api
1177 reference = (MonoAssembly *)REFERENCE_MISSING;
1179 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1180 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1181 * accordingly, it would fail on the MS runtime before).
1182 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1183 * example bug-349190.2.cs and who knows how much more code in the wild.
1185 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1186 if (!reference && image->assembly)
1187 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1190 if (reference == NULL){
1193 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1194 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 : "" );
1195 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1196 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1197 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1198 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1199 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1200 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1202 extra_msg = g_strdup ("");
1205 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1206 " Assembly: %s (assemblyref_index=%d)\n"
1207 " Version: %d.%d.%d.%d\n"
1208 " Public Key: %s\n%s",
1209 image->name, aname.name, index,
1210 aname.major, aname.minor, aname.build, aname.revision,
1211 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1216 mono_assemblies_lock ();
1217 if (reference == NULL) {
1218 /* Flag as not found */
1219 reference = (MonoAssembly *)REFERENCE_MISSING;
1222 if (!image->references [index]) {
1223 if (reference != REFERENCE_MISSING){
1224 mono_assembly_addref (reference);
1225 if (image->assembly)
1226 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1227 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1229 if (image->assembly)
1230 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1231 image->assembly->aname.name, image->assembly);
1234 image->references [index] = reference;
1236 mono_assemblies_unlock ();
1238 if (image->references [index] != reference) {
1239 /* Somebody loaded it before us */
1240 mono_assembly_close (reference);
1245 * mono_assembly_load_references:
1248 * @deprecated: There is no reason to use this method anymore, it does nothing
1250 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1253 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1255 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1256 *status = MONO_IMAGE_OK;
1259 typedef struct AssemblyLoadHook AssemblyLoadHook;
1260 struct AssemblyLoadHook {
1261 AssemblyLoadHook *next;
1262 MonoAssemblyLoadFunc func;
1266 AssemblyLoadHook *assembly_load_hook = NULL;
1269 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1271 AssemblyLoadHook *hook;
1273 for (hook = assembly_load_hook; hook; hook = hook->next) {
1274 hook->func (ass, hook->user_data);
1279 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1281 AssemblyLoadHook *hook;
1283 g_return_if_fail (func != NULL);
1285 hook = g_new0 (AssemblyLoadHook, 1);
1287 hook->user_data = user_data;
1288 hook->next = assembly_load_hook;
1289 assembly_load_hook = hook;
1293 free_assembly_load_hooks (void)
1295 AssemblyLoadHook *hook, *next;
1297 for (hook = assembly_load_hook; hook; hook = next) {
1303 typedef struct AssemblySearchHook AssemblySearchHook;
1304 struct AssemblySearchHook {
1305 AssemblySearchHook *next;
1306 MonoAssemblySearchFunc func;
1312 AssemblySearchHook *assembly_search_hook = NULL;
1314 static MonoAssembly*
1315 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1317 AssemblySearchHook *hook;
1319 for (hook = assembly_search_hook; hook; hook = hook->next) {
1320 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1323 * A little explanation is in order here.
1325 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1326 * The embedding API exposes a search hook that doesn't take such argument.
1328 * The original fix would call the default search hook before all the registered ones and pass
1329 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1330 * rely on. Which is the ordering between user hooks and the default runtime hook.
1332 * Registering the hook after mono_jit_init would let your hook run before the default one and
1333 * when using it to handle non standard app layouts this could save your app from a massive amount
1334 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1335 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1337 * So what's the fix? We register the default hook using regular means and special case it when iterating
1338 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1341 if (hook->func == (void*)mono_domain_assembly_postload_search)
1342 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1344 ass = hook->func (aname, hook->user_data);
1354 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1356 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1360 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1362 AssemblySearchHook *hook;
1364 g_return_if_fail (func != NULL);
1366 hook = g_new0 (AssemblySearchHook, 1);
1368 hook->user_data = user_data;
1369 hook->refonly = refonly;
1370 hook->postload = postload;
1371 hook->next = assembly_search_hook;
1372 assembly_search_hook = hook;
1376 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1378 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1382 free_assembly_search_hooks (void)
1384 AssemblySearchHook *hook, *next;
1386 for (hook = assembly_search_hook; hook; hook = next) {
1393 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1395 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1399 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1401 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1405 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1407 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1410 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1411 struct AssemblyPreLoadHook {
1412 AssemblyPreLoadHook *next;
1413 MonoAssemblyPreLoadFunc func;
1417 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1418 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1420 static MonoAssembly *
1421 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1423 AssemblyPreLoadHook *hook;
1424 MonoAssembly *assembly;
1426 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1427 assembly = hook->func (aname, assemblies_path, hook->user_data);
1428 if (assembly != NULL)
1435 static MonoAssembly *
1436 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1438 AssemblyPreLoadHook *hook;
1439 MonoAssembly *assembly;
1441 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1442 assembly = hook->func (aname, assemblies_path, hook->user_data);
1443 if (assembly != NULL)
1451 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1453 AssemblyPreLoadHook *hook;
1455 g_return_if_fail (func != NULL);
1457 hook = g_new0 (AssemblyPreLoadHook, 1);
1459 hook->user_data = user_data;
1460 hook->next = assembly_preload_hook;
1461 assembly_preload_hook = hook;
1465 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1467 AssemblyPreLoadHook *hook;
1469 g_return_if_fail (func != NULL);
1471 hook = g_new0 (AssemblyPreLoadHook, 1);
1473 hook->user_data = user_data;
1474 hook->next = assembly_refonly_preload_hook;
1475 assembly_refonly_preload_hook = hook;
1479 free_assembly_preload_hooks (void)
1481 AssemblyPreLoadHook *hook, *next;
1483 for (hook = assembly_preload_hook; hook; hook = next) {
1488 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1495 absolute_dir (const gchar *filename)
1506 if (g_path_is_absolute (filename)) {
1507 part = g_path_get_dirname (filename);
1508 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1513 cwd = g_get_current_dir ();
1514 mixed = g_build_filename (cwd, filename, NULL);
1515 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1520 for (i = 0; (part = parts [i]) != NULL; i++) {
1521 if (!strcmp (part, "."))
1524 if (!strcmp (part, "..")) {
1525 if (list && list->next) /* Don't remove root */
1526 list = g_list_delete_link (list, list);
1528 list = g_list_prepend (list, part);
1532 result = g_string_new ("");
1533 list = g_list_reverse (list);
1535 /* Ignores last data pointer, which should be the filename */
1536 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1538 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1543 g_string_free (result, FALSE);
1548 return g_strdup (".");
1555 * mono_assembly_open_from_bundle:
1556 * @filename: Filename requested
1557 * @status: return status code
1559 * This routine tries to open the assembly specified by `filename' from the
1560 * defined bundles, if found, returns the MonoImage for it, if not found
1564 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1568 gchar *lowercase_filename;
1569 MonoImage *image = NULL;
1570 gboolean is_satellite = FALSE;
1572 * we do a very simple search for bundled assemblies: it's not a general
1573 * purpose assembly loading mechanism.
1579 lowercase_filename = g_utf8_strdown (filename, -1);
1580 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1581 g_free (lowercase_filename);
1582 name = g_path_get_basename (filename);
1583 mono_assemblies_lock ();
1584 for (i = 0; !image && bundles [i]; ++i) {
1585 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1586 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1590 mono_assemblies_unlock ();
1592 mono_image_addref (image);
1593 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1602 * mono_assemblies_open_full:
1603 * @filename: the file to load
1604 * @status: return status code
1605 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1607 * This loads an assembly from the specified @filename. The @filename allows
1608 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1609 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1610 * is treated as a local path.
1612 * First, an attempt is made to load the assembly from the bundled executable (for those
1613 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1614 * assembly has been registered as an embedded assembly). If this is not the case, then
1615 * the assembly is loaded from disk using `api:mono_image_open_full`.
1617 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1618 * the assembly is made.
1620 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1621 * the `System.Reflection` API.
1623 * Returns: NULL on error, with the @status set to an error code, or a pointer
1627 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1631 MonoImageOpenStatus def_status;
1634 gboolean loaded_from_bundle;
1636 g_return_val_if_fail (filename != NULL, NULL);
1639 status = &def_status;
1640 *status = MONO_IMAGE_OK;
1642 if (strncmp (filename, "file://", 7) == 0) {
1643 GError *error = NULL;
1644 gchar *uri = (gchar *) filename;
1648 * MS allows file://c:/... and fails on file://localhost/c:/...
1649 * They also throw an IndexOutOfRangeException if "file://"
1652 uri = g_strdup_printf ("file:///%s", uri + 7);
1655 uri = mono_escape_uri_string (tmpuri);
1656 fname = g_filename_from_uri (uri, NULL, &error);
1659 if (tmpuri != filename)
1662 if (error != NULL) {
1663 g_warning ("%s\n", error->message);
1664 g_error_free (error);
1665 fname = g_strdup (filename);
1668 fname = g_strdup (filename);
1671 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1672 "Assembly Loader probing location: '%s'.", fname);
1675 if (!mono_assembly_is_in_gac (fname)) {
1677 new_fname = mono_make_shadow_copy (fname, &error);
1678 if (!is_ok (&error)) {
1679 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1680 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1681 mono_error_cleanup (&error);
1682 *status = MONO_IMAGE_IMAGE_INVALID;
1687 if (new_fname && new_fname != fname) {
1690 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1691 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1696 // If VM built with mkbundle
1697 loaded_from_bundle = FALSE;
1698 if (bundles != NULL) {
1699 image = mono_assembly_open_from_bundle (fname, status, refonly);
1700 loaded_from_bundle = image != NULL;
1704 image = mono_image_open_full (fname, status, refonly);
1707 if (*status == MONO_IMAGE_OK)
1708 *status = MONO_IMAGE_ERROR_ERRNO;
1713 if (image->assembly) {
1714 /* Already loaded by another appdomain */
1715 mono_assembly_invoke_load_hook (image->assembly);
1716 mono_image_close (image);
1718 return image->assembly;
1721 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1724 if (!loaded_from_bundle)
1725 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1726 "Assembly Loader loaded assembly from location: '%s'.", filename);
1728 mono_config_for_assembly (ass->image);
1731 /* Clear the reference added by mono_image_open */
1732 mono_image_close (image);
1740 free_item (gpointer val, gpointer user_data)
1746 * mono_assembly_load_friends:
1749 * Load the list of friend assemblies that are allowed to access
1750 * the assembly's internal types and members. They are stored as assembly
1751 * names in custom attributes.
1753 * This is an internal method, we need this because when we load mscorlib
1754 * we do not have the internals visible cattr loaded yet,
1755 * so we need to load these after we initialize the runtime.
1757 * LOCKING: Acquires the assemblies lock plus the loader lock.
1760 mono_assembly_load_friends (MonoAssembly* ass)
1764 MonoCustomAttrInfo* attrs;
1767 if (ass->friend_assembly_names_inited)
1770 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1771 mono_error_assert_ok (&error);
1773 mono_assemblies_lock ();
1774 ass->friend_assembly_names_inited = TRUE;
1775 mono_assemblies_unlock ();
1779 mono_assemblies_lock ();
1780 if (ass->friend_assembly_names_inited) {
1781 mono_assemblies_unlock ();
1784 mono_assemblies_unlock ();
1788 * We build the list outside the assemblies lock, the worse that can happen
1789 * is that we'll need to free the allocated list.
1791 for (i = 0; i < attrs->num_attrs; ++i) {
1792 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1793 MonoAssemblyName *aname;
1795 /* Do some sanity checking */
1796 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1798 if (attr->data_size < 4)
1800 data = (const char*)attr->data;
1801 /* 0xFF means null string, see custom attr format */
1802 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1804 mono_metadata_decode_value (data + 2, &data);
1805 aname = g_new0 (MonoAssemblyName, 1);
1806 /*g_print ("friend ass: %s\n", data);*/
1807 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1808 list = g_slist_prepend (list, aname);
1813 mono_custom_attrs_free (attrs);
1815 mono_assemblies_lock ();
1816 if (ass->friend_assembly_names_inited) {
1817 mono_assemblies_unlock ();
1818 g_slist_foreach (list, free_item, NULL);
1819 g_slist_free (list);
1822 ass->friend_assembly_names = list;
1824 /* Because of the double checked locking pattern above */
1825 mono_memory_barrier ();
1826 ass->friend_assembly_names_inited = TRUE;
1827 mono_assemblies_unlock ();
1830 struct HasReferenceAssemblyAttributeIterData {
1835 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1837 gboolean stop_scanning = FALSE;
1838 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1840 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1841 /* Note we don't check the assembly name, same as coreCLR. */
1842 iter_data->has_attr = TRUE;
1843 stop_scanning = TRUE;
1846 return stop_scanning;
1850 * mono_assembly_has_reference_assembly_attribute:
1851 * @assembly: a MonoAssembly
1852 * @error: set on error.
1854 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1855 * On error returns FALSE and sets @error.
1858 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1860 mono_error_init (error);
1863 * This might be called during assembly loading, so do everything using the low-level
1867 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1869 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1871 return iter_data.has_attr;
1875 * mono_assembly_open:
1876 * @filename: Opens the assembly pointed out by this name
1877 * @status: return status code
1879 * This loads an assembly from the specified @filename. The @filename allows
1880 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1881 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1882 * is treated as a local path.
1884 * First, an attempt is made to load the assembly from the bundled executable (for those
1885 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1886 * assembly has been registered as an embedded assembly). If this is not the case, then
1887 * the assembly is loaded from disk using `api:mono_image_open_full`.
1889 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1890 * the assembly is made.
1892 * Return: a pointer to the MonoAssembly if @filename contains a valid
1893 * assembly or NULL on error. Details about the error are stored in the
1897 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1899 return mono_assembly_open_full (filename, status, FALSE);
1903 * mono_assembly_load_from_full:
1904 * @image: Image to load the assembly from
1905 * @fname: assembly name to associate with the assembly
1906 * @status: returns the status condition
1907 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1909 * If the provided @image has an assembly reference, it will process the given
1910 * image as an assembly with the given name.
1912 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1914 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1915 * set to #MONO_IMAGE_OK; or NULL on error.
1917 * If there is an error loading the assembly the @status will indicate the
1918 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1919 * image did not contain an assembly reference table.
1922 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1923 MonoImageOpenStatus *status, gboolean refonly)
1925 MonoAssembly *ass, *ass2;
1928 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1929 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1930 *status = MONO_IMAGE_IMAGE_INVALID;
1934 #if defined (HOST_WIN32)
1939 tmp_fn = g_strdup (fname);
1940 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1941 if (tmp_fn [i] == '/')
1945 base_dir = absolute_dir (tmp_fn);
1949 base_dir = absolute_dir (fname);
1953 * Create assembly struct, and enter it into the assembly cache
1955 ass = g_new0 (MonoAssembly, 1);
1956 ass->basedir = base_dir;
1957 ass->ref_only = refonly;
1960 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1962 mono_assembly_fill_assembly_name (image, &ass->aname);
1964 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1965 // MS.NET doesn't support loading other mscorlibs
1968 mono_image_addref (mono_defaults.corlib);
1969 *status = MONO_IMAGE_OK;
1970 return mono_defaults.corlib->assembly;
1973 /* Add a non-temporary reference because of ass->image */
1974 mono_image_addref (image);
1976 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);
1979 * The load hooks might take locks so we can't call them while holding the
1982 if (ass->aname.name) {
1983 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1987 mono_image_close (image);
1988 *status = MONO_IMAGE_OK;
1993 /* We need to check for ReferenceAssmeblyAttribute before we
1994 * mark the assembly as loaded and before we fire the load
1995 * hook. Otherwise mono_domain_fire_assembly_load () in
1996 * appdomain.c will cache a mapping from the assembly name to
1997 * this image and we won't be able to look for a different
2001 MonoError refasm_error;
2002 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2003 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2006 mono_image_close (image);
2007 *status = MONO_IMAGE_IMAGE_INVALID;
2010 mono_error_cleanup (&refasm_error);
2013 mono_assemblies_lock ();
2015 if (image->assembly) {
2017 * This means another thread has already loaded the assembly, but not yet
2018 * called the load hooks so the search hook can't find the assembly.
2020 mono_assemblies_unlock ();
2021 ass2 = image->assembly;
2024 mono_image_close (image);
2025 *status = MONO_IMAGE_OK;
2029 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2031 image->assembly = ass;
2033 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2034 mono_assemblies_unlock ();
2037 if (image->is_module_handle)
2038 mono_image_fixup_vtable (image);
2041 mono_assembly_invoke_load_hook (ass);
2043 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2049 * mono_assembly_load_from:
2050 * @image: Image to load the assembly from
2051 * @fname: assembly name to associate with the assembly
2052 * @status: return status code
2054 * If the provided @image has an assembly reference, it will process the given
2055 * image as an assembly with the given name.
2057 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2059 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2060 * @refonly parameter set to FALSE.
2061 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2062 * set to #MONO_IMAGE_OK; or NULL on error.
2064 * If there is an error loading the assembly the @status will indicate the
2065 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2066 * image did not contain an assembly reference table.
2070 mono_assembly_load_from (MonoImage *image, const char *fname,
2071 MonoImageOpenStatus *status)
2073 return mono_assembly_load_from_full (image, fname, status, FALSE);
2077 * mono_assembly_name_free:
2078 * @aname: assembly name to free
2080 * Frees the provided assembly name object.
2081 * (it does not frees the object itself, only the name members).
2084 mono_assembly_name_free (MonoAssemblyName *aname)
2089 g_free ((void *) aname->name);
2090 g_free ((void *) aname->culture);
2091 g_free ((void *) aname->hash_value);
2092 g_free ((guint8*) aname->public_key);
2096 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2099 gchar header [16], val, *arr;
2100 gint i, j, offset, bitlen, keylen, pkeylen;
2102 keylen = strlen (key) >> 1;
2106 /* allow the ECMA standard key */
2107 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2109 *pubkey = g_strdup (key);
2115 val = g_ascii_xdigit_value (key [0]) << 4;
2116 val |= g_ascii_xdigit_value (key [1]);
2121 val = g_ascii_xdigit_value (key [24]);
2122 val |= g_ascii_xdigit_value (key [25]);
2134 /* We need the first 16 bytes
2135 * to check whether this key is valid or not */
2136 pkeylen = strlen (pkey) >> 1;
2140 for (i = 0, j = 0; i < 16; i++) {
2141 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2142 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2145 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2146 header [1] != 0x02 || /* Version (0x02) */
2147 header [2] != 0x00 || /* Reserved (word) */
2148 header [3] != 0x00 ||
2149 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2152 /* Based on this length, we _should_ be able to know if the length is right */
2153 bitlen = read32 (header + 12) >> 3;
2154 if ((bitlen + 16 + 4) != pkeylen)
2157 /* parsing is OK and the public key itself is not requested back */
2161 /* Encode the size of the blob */
2163 if (keylen <= 127) {
2164 arr = (gchar *)g_malloc (keylen + 1);
2165 arr [offset++] = keylen;
2167 arr = (gchar *)g_malloc (keylen + 2);
2168 arr [offset++] = 0x80; /* 10bs */
2169 arr [offset++] = keylen;
2172 for (i = offset, j = 0; i < keylen + offset; i++) {
2173 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2174 arr [i] |= g_ascii_xdigit_value (key [j++]);
2183 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)
2185 gint major, minor, build, revision;
2188 gchar *pkey, *pkeyptr, *encoded, tok [8];
2190 memset (aname, 0, sizeof (MonoAssemblyName));
2193 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2194 if (version_parts < 2 || version_parts > 4)
2197 /* FIXME: we should set build & revision to -1 (instead of 0)
2198 if these are not set in the version string. That way, later on,
2199 we can still determine if these were specified. */
2200 aname->major = major;
2201 aname->minor = minor;
2202 if (version_parts >= 3)
2203 aname->build = build;
2206 if (version_parts == 4)
2207 aname->revision = revision;
2209 aname->revision = 0;
2212 aname->flags = flags;
2214 aname->name = g_strdup (name);
2217 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2218 aname->culture = g_strdup ("");
2220 aname->culture = g_strdup (culture);
2223 if (token && strncmp (token, "null", 4) != 0) {
2226 /* the constant includes the ending NULL, hence the -1 */
2227 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2228 mono_assembly_name_free (aname);
2231 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2232 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2238 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2239 mono_assembly_name_free (aname);
2244 if (save_public_key)
2245 aname->public_key = (guint8*)pkey;
2248 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2252 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2253 // We also need to generate the key token
2254 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2255 encoded = encode_public_tok ((guchar*) tok, 8);
2256 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2259 if (save_public_key)
2260 aname->public_key = (guint8*) pkey;
2269 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2274 parts = g_strsplit (dirname, "_", 3);
2275 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2280 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2286 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2288 char *eqsign = strchr (pair, '=');
2296 *key = (gchar*)pair;
2297 *keylen = eqsign - *key;
2298 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2300 *value = g_strstrip (eqsign + 1);
2305 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2309 gchar *version = NULL;
2311 gchar *culture = NULL;
2313 gchar *token = NULL;
2317 gchar *retargetable = NULL;
2318 gchar *retargetable_uq;
2322 gchar *value, *part_name;
2323 guint32 part_name_len;
2326 gboolean version_defined;
2327 gboolean token_defined;
2329 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2331 if (!is_version_defined)
2332 is_version_defined = &version_defined;
2333 *is_version_defined = FALSE;
2334 if (!is_token_defined)
2335 is_token_defined = &token_defined;
2336 *is_token_defined = FALSE;
2338 parts = tmp = g_strsplit (name, ",", 6);
2339 if (!tmp || !*tmp) {
2344 dllname = g_strstrip (*tmp);
2349 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2350 goto cleanup_and_fail;
2352 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2353 *is_version_defined = TRUE;
2355 if (strlen (version) == 0) {
2356 goto cleanup_and_fail;
2362 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2364 if (strlen (culture) == 0) {
2365 goto cleanup_and_fail;
2371 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2372 *is_token_defined = TRUE;
2374 if (strlen (token) == 0) {
2375 goto cleanup_and_fail;
2381 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2383 if (strlen (key) == 0) {
2384 goto cleanup_and_fail;
2390 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2391 retargetable = value;
2392 retargetable_uq = unquote (retargetable);
2393 if (retargetable_uq != NULL)
2394 retargetable = retargetable_uq;
2396 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2397 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2398 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2399 g_free (retargetable_uq);
2400 goto cleanup_and_fail;
2403 g_free (retargetable_uq);
2408 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2410 procarch_uq = unquote (procarch);
2411 if (procarch_uq != NULL)
2412 procarch = procarch_uq;
2414 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2415 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2416 else if (!g_ascii_strcasecmp (procarch, "X86"))
2417 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2418 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2419 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2420 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2421 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2423 g_free (procarch_uq);
2424 goto cleanup_and_fail;
2427 g_free (procarch_uq);
2436 /* if retargetable flag is set, then we must have a fully qualified name */
2437 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2438 goto cleanup_and_fail;
2441 dllname_uq = unquote (dllname);
2442 version_uq = unquote (version);
2443 culture_uq = unquote (culture);
2444 token_uq = unquote (token);
2445 key_uq = unquote (key);
2447 res = build_assembly_name (
2448 dllname_uq == NULL ? dllname : dllname_uq,
2449 version_uq == NULL ? version : version_uq,
2450 culture_uq == NULL ? culture : culture_uq,
2451 token_uq == NULL ? token : token_uq,
2452 key_uq == NULL ? key : key_uq,
2453 flags, arch, aname, save_public_key);
2455 g_free (dllname_uq);
2456 g_free (version_uq);
2457 g_free (culture_uq);
2470 unquote (const char *str)
2478 slen = strlen (str);
2482 if (*str != '\'' && *str != '\"')
2485 end = str + slen - 1;
2489 return g_strndup (str + 1, slen - 2);
2493 * mono_assembly_name_parse:
2494 * @name: name to parse
2495 * @aname: the destination assembly name
2497 * Parses an assembly qualified type name and assigns the name,
2498 * version, culture and token to the provided assembly name object.
2500 * Returns: TRUE if the name could be parsed.
2503 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2505 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2509 * mono_assembly_name_new:
2510 * @name: name to parse
2512 * Allocate a new MonoAssemblyName and fill its values from the
2515 * Returns: a newly allocated structure or NULL if there was any failure.
2518 mono_assembly_name_new (const char *name)
2520 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2521 if (mono_assembly_name_parse (name, aname))
2528 mono_assembly_name_get_name (MonoAssemblyName *aname)
2534 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2536 return aname->culture;
2540 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2542 if (aname->public_key_token [0])
2543 return aname->public_key_token;
2548 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2551 *minor = aname->minor;
2553 *build = aname->build;
2555 *revision = aname->revision;
2556 return aname->major;
2559 static MonoAssembly*
2560 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2562 gchar *fullpath = NULL;
2564 const char* direntry;
2565 MonoAssemblyName gac_aname;
2566 gint major=-1, minor=0, build=0, revision=0;
2567 gboolean exact_version;
2569 dirhandle = g_dir_open (basepath, 0, NULL);
2573 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2575 while ((direntry = g_dir_read_name (dirhandle))) {
2576 gboolean match = TRUE;
2578 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2581 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2584 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2585 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2589 if (exact_version) {
2590 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2591 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2593 else if (gac_aname.major < major)
2595 else if (gac_aname.major == major) {
2596 if (gac_aname.minor < minor)
2598 else if (gac_aname.minor == minor) {
2599 if (gac_aname.build < build)
2601 else if (gac_aname.build == build && gac_aname.revision <= revision)
2608 major = gac_aname.major;
2609 minor = gac_aname.minor;
2610 build = gac_aname.build;
2611 revision = gac_aname.revision;
2613 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2616 mono_assembly_name_free (&gac_aname);
2619 g_dir_close (dirhandle);
2621 if (fullpath == NULL)
2624 MonoAssembly *res = mono_assembly_open (fullpath, status);
2631 * mono_assembly_load_with_partial_name:
2632 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2633 * @status: return status code
2635 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2636 * so it might contain a qualified type name, version, culture and token.
2638 * This will load the assembly from the file whose name is derived from the assembly name
2639 * by appending the .dll extension.
2641 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2642 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2643 * if that fails from the GAC.
2645 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2648 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2652 MonoAssemblyName *aname, base_name;
2653 MonoAssemblyName mapped_aname;
2654 gchar *fullname, *gacpath;
2657 memset (&base_name, 0, sizeof (MonoAssemblyName));
2660 if (!mono_assembly_name_parse (name, aname))
2664 * If no specific version has been requested, make sure we load the
2665 * correct version for system assemblies.
2667 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2668 aname = mono_assembly_remap_version (aname, &mapped_aname);
2670 res = mono_assembly_loaded (aname);
2672 mono_assembly_name_free (aname);
2676 res = invoke_assembly_preload_hook (aname, assemblies_path);
2678 res->in_gac = FALSE;
2679 mono_assembly_name_free (aname);
2683 fullname = g_strdup_printf ("%s.dll", aname->name);
2685 if (extra_gac_paths) {
2686 paths = extra_gac_paths;
2687 while (!res && *paths) {
2688 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2689 res = probe_for_partial_name (gacpath, fullname, aname, status);
2698 mono_assembly_name_free (aname);
2702 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2703 res = probe_for_partial_name (gacpath, fullname, aname, status);
2709 MonoDomain *domain = mono_domain_get ();
2710 MonoReflectionAssembly *refasm;
2712 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2713 if (!is_ok (&error)) {
2715 mono_assembly_name_free (aname);
2716 mono_error_cleanup (&error);
2717 if (*status == MONO_IMAGE_OK)
2718 *status = MONO_IMAGE_IMAGE_INVALID;
2722 res = refasm->assembly;
2726 mono_assembly_name_free (aname);
2732 mono_assembly_is_in_gac (const gchar *filename)
2734 const gchar *rootdir;
2738 if (filename == NULL)
2741 for (paths = extra_gac_paths; paths && *paths; paths++) {
2742 if (strstr (*paths, filename) != *paths)
2745 gp = (gchar *) (filename + strlen (*paths));
2746 if (*gp != G_DIR_SEPARATOR)
2749 if (strncmp (gp, "lib", 3))
2752 if (*gp != G_DIR_SEPARATOR)
2755 if (strncmp (gp, "mono", 4))
2758 if (*gp != G_DIR_SEPARATOR)
2761 if (strncmp (gp, "gac", 3))
2764 if (*gp != G_DIR_SEPARATOR)
2770 rootdir = mono_assembly_getrootdir ();
2771 if (strstr (filename, rootdir) != filename)
2774 gp = (gchar *) (filename + strlen (rootdir));
2775 if (*gp != G_DIR_SEPARATOR)
2778 if (strncmp (gp, "mono", 4))
2781 if (*gp != G_DIR_SEPARATOR)
2784 if (strncmp (gp, "gac", 3))
2787 if (*gp != G_DIR_SEPARATOR)
2793 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2796 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2800 if (strstr (aname->name, ".dll")) {
2801 len = strlen (aname->name) - 4;
2802 name = (gchar *)g_malloc (len + 1);
2803 strncpy (name, aname->name, len);
2806 name = g_strdup (aname->name);
2809 culture = g_utf8_strdown (aname->culture, -1);
2811 culture = g_strdup ("");
2813 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2814 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2818 filename = g_strconcat (pname, ".dll", NULL);
2819 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2825 if (extra_gac_paths) {
2826 paths = extra_gac_paths;
2827 while (!image && *paths) {
2828 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2829 "lib", "mono", "gac", subpath, NULL);
2830 image = mono_image_open (fullpath, NULL);
2841 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2842 "mono", "gac", subpath, NULL);
2843 image = mono_image_open (fullpath, NULL);
2850 static MonoAssemblyName*
2851 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2853 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2854 dest_name->major = info->new_version.major;
2855 dest_name->minor = info->new_version.minor;
2856 dest_name->build = info->new_version.build;
2857 dest_name->revision = info->new_version.revision;
2862 /* LOCKING: assembly_binding lock must be held */
2863 static MonoAssemblyBindingInfo*
2864 search_binding_loaded (MonoAssemblyName *aname)
2868 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2869 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2870 if (assembly_binding_maps_name (info, aname))
2877 static inline gboolean
2878 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2880 if (left->major != right->major || left->minor != right->minor ||
2881 left->build != right->build || left->revision != right->revision)
2887 static inline gboolean
2888 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2890 if (left->has_old_version_bottom != right->has_old_version_bottom)
2893 if (left->has_old_version_top != right->has_old_version_top)
2896 if (left->has_new_version != right->has_new_version)
2899 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2902 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2905 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2911 /* LOCKING: assumes all the necessary locks are held */
2913 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2915 MonoAssemblyBindingInfo *info_copy;
2917 MonoAssemblyBindingInfo *info_tmp;
2918 MonoDomain *domain = (MonoDomain*)user_data;
2923 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2924 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2925 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2929 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2930 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2932 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2934 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2936 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2940 get_version_number (int major, int minor)
2942 return major * 256 + minor;
2945 static inline gboolean
2946 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2948 int aname_version_number = get_version_number (aname->major, aname->minor);
2949 if (!info->has_old_version_bottom)
2952 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2955 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2958 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2959 info->major = aname->major;
2960 info->minor = aname->minor;
2965 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2966 static MonoAssemblyBindingInfo*
2967 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2969 MonoAssemblyBindingInfo *info;
2972 if (!domain->assembly_bindings)
2976 for (list = domain->assembly_bindings; list; list = list->next) {
2977 info = (MonoAssemblyBindingInfo *)list->data;
2978 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2984 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2985 info->has_new_version && assembly_binding_maps_name (info, aname))
2986 info->is_valid = TRUE;
2988 info->is_valid = FALSE;
2994 static MonoAssemblyName*
2995 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2998 MonoAssemblyBindingInfo *info, *info2;
3002 if (aname->public_key_token [0] == 0)
3005 domain = mono_domain_get ();
3007 mono_assembly_binding_lock ();
3008 info = search_binding_loaded (aname);
3009 mono_assembly_binding_unlock ();
3012 mono_domain_lock (domain);
3013 info = get_per_domain_assembly_binding_info (domain, aname);
3014 mono_domain_unlock (domain);
3018 if (!check_policy_versions (info, aname))
3021 mono_assembly_bind_version (info, aname, dest_name);
3025 if (domain && domain->setup && domain->setup->configuration_file) {
3026 mono_domain_lock (domain);
3027 if (!domain->assembly_bindings_parsed) {
3028 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3029 /* expect this to succeed because mono_domain_set_options_from_config () did
3030 * the same thing when the domain was created. */
3031 mono_error_assert_ok (&error);
3033 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3035 if (!domain_config_file_path)
3036 domain_config_file_path = domain_config_file_name;
3038 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3039 domain->assembly_bindings_parsed = TRUE;
3040 if (domain_config_file_name != domain_config_file_path)
3041 g_free (domain_config_file_name);
3042 g_free (domain_config_file_path);
3045 info2 = get_per_domain_assembly_binding_info (domain, aname);
3048 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3049 info->name = g_strdup (info2->name);
3050 info->culture = g_strdup (info2->culture);
3051 info->domain_id = domain->domain_id;
3054 mono_domain_unlock (domain);
3058 info = g_new0 (MonoAssemblyBindingInfo, 1);
3059 info->major = aname->major;
3060 info->minor = aname->minor;
3063 if (!info->is_valid) {
3064 ppimage = mono_assembly_load_publisher_policy (aname);
3066 get_publisher_policy_info (ppimage, aname, info);
3067 mono_image_close (ppimage);
3071 /* Define default error value if needed */
3072 if (!info->is_valid) {
3073 info->name = g_strdup (aname->name);
3074 info->culture = g_strdup (aname->culture);
3075 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3078 mono_assembly_binding_lock ();
3079 info2 = search_binding_loaded (aname);
3081 /* This binding was added by another thread
3083 mono_assembly_binding_info_free (info);
3088 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3090 mono_assembly_binding_unlock ();
3092 if (!info->is_valid || !check_policy_versions (info, aname))
3095 mono_assembly_bind_version (info, aname, dest_name);
3100 * mono_assembly_load_from_gac
3102 * @aname: The assembly name object
3104 static MonoAssembly*
3105 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3107 MonoAssembly *result = NULL;
3108 gchar *name, *version, *culture, *fullpath, *subpath;
3113 if (aname->public_key_token [0] == 0) {
3117 if (strstr (aname->name, ".dll")) {
3118 len = strlen (filename) - 4;
3119 name = (gchar *)g_malloc (len + 1);
3120 strncpy (name, aname->name, len);
3123 name = g_strdup (aname->name);
3126 if (aname->culture) {
3127 culture = g_utf8_strdown (aname->culture, -1);
3129 culture = g_strdup ("");
3132 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3133 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3134 aname->minor, aname->build, aname->revision,
3138 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3143 if (extra_gac_paths) {
3144 paths = extra_gac_paths;
3145 while (!result && *paths) {
3146 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3147 result = mono_assembly_open_full (fullpath, status, refonly);
3154 result->in_gac = TRUE;
3159 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3160 "mono", "gac", subpath, NULL);
3161 result = mono_assembly_open_full (fullpath, status, refonly);
3165 result->in_gac = TRUE;
3173 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3176 MonoAssemblyName *aname;
3179 /* g_print ("corlib already loaded\n"); */
3183 // In native client, Corlib is embedded in the executable as static variable corlibData
3184 #if defined(__native_client__)
3185 if (corlibData != NULL && corlibSize != 0) {
3187 /* First "FALSE" instructs mono not to make a copy. */
3188 /* Second "FALSE" says this is not just a ref. */
3189 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3190 if (image == NULL || status != 0)
3191 g_print("mono_image_open_from_data_full failed: %d\n", status);
3192 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3193 if (corlib == NULL || status != 0)
3194 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3200 // A nonstandard preload hook may provide a special mscorlib assembly
3201 aname = mono_assembly_name_new ("mscorlib.dll");
3202 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3203 mono_assembly_name_free (aname);
3206 goto return_corlib_and_facades;
3208 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3209 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3210 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3212 goto return_corlib_and_facades;
3215 /* Normal case: Load corlib from mono/<version> */
3216 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3217 if (assemblies_path) { // Custom assemblies path
3218 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3220 g_free (corlib_file);
3221 goto return_corlib_and_facades;
3224 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3225 g_free (corlib_file);
3227 return_corlib_and_facades:
3228 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3229 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3234 static MonoAssembly*
3235 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3237 MonoError refasm_error;
3238 mono_error_init (&refasm_error);
3239 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3242 mono_error_cleanup (&refasm_error);
3248 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3249 const char *basedir,
3250 MonoImageOpenStatus *status,
3253 MonoAssembly *result;
3254 char *fullpath, *filename;
3255 MonoAssemblyName maped_aname;
3256 MonoAssemblyName maped_name_pp;
3261 aname = mono_assembly_remap_version (aname, &maped_aname);
3263 /* Reflection only assemblies don't get assembly binding */
3265 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3267 result = mono_assembly_loaded_full (aname, refonly);
3271 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3273 result->in_gac = FALSE;
3277 /* Currently we retrieve the loaded corlib for reflection
3278 * only requests, like a common reflection only assembly
3280 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3281 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3284 len = strlen (aname->name);
3285 for (ext_index = 0; ext_index < 2; ext_index ++) {
3286 ext = ext_index == 0 ? ".dll" : ".exe";
3287 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3288 filename = g_strdup (aname->name);
3289 /* Don't try appending .dll/.exe if it already has one of those extensions */
3292 filename = g_strconcat (aname->name, ext, NULL);
3295 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3302 fullpath = g_build_filename (basedir, filename, NULL);
3303 result = mono_assembly_open_full (fullpath, status, refonly);
3306 result->in_gac = FALSE;
3312 result = load_in_path (filename, default_path, status, refonly);
3314 result->in_gac = FALSE;
3324 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3326 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3329 /* Try a postload search hook */
3330 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3331 result = prevent_reference_assembly_from_running (result, refonly);
3337 * mono_assembly_load_full:
3338 * @aname: A MonoAssemblyName with the assembly name to load.
3339 * @basedir: A directory to look up the assembly at.
3340 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3341 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3343 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3344 * attempts to load the assembly from that directory before probing the standard locations.
3346 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3347 * assembly binding takes place.
3349 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3350 * value pointed by status is updated with an error code.
3353 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3355 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3359 * mono_assembly_load:
3360 * @aname: A MonoAssemblyName with the assembly name to load.
3361 * @basedir: A directory to look up the assembly at.
3362 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3364 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3365 * attempts to load the assembly from that directory before probing the standard locations.
3367 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3368 * value pointed by status is updated with an error code.
3371 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3373 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3377 * mono_assembly_loaded_full:
3378 * @aname: an assembly to look for.
3379 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3381 * This is used to determine if the specified assembly has been loaded
3382 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3383 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3386 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3389 MonoAssemblyName maped_aname;
3391 aname = mono_assembly_remap_version (aname, &maped_aname);
3393 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3399 * mono_assembly_loaded:
3400 * @aname: an assembly to look for.
3402 * This is used to determine if the specified assembly has been loaded
3404 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3405 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3408 mono_assembly_loaded (MonoAssemblyName *aname)
3410 return mono_assembly_loaded_full (aname, FALSE);
3414 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3416 if (assembly == NULL || assembly == REFERENCE_MISSING)
3419 if (assembly_is_dynamic (assembly)) {
3421 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3422 for (i = 0; i < dynimg->image.module_count; ++i)
3423 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3424 mono_dynamic_image_release_gc_roots (dynimg);
3429 * Returns whether mono_assembly_close_finish() must be called as
3430 * well. See comment for mono_image_close_except_pools() for why we
3431 * unload in two steps.
3434 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3437 g_return_val_if_fail (assembly != NULL, FALSE);
3439 if (assembly == REFERENCE_MISSING)
3442 /* Might be 0 already */
3443 if (InterlockedDecrement (&assembly->ref_count) > 0)
3446 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3448 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3450 mono_debug_close_image (assembly->image);
3452 mono_assemblies_lock ();
3453 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3454 mono_assemblies_unlock ();
3456 assembly->image->assembly = NULL;
3458 if (!mono_image_close_except_pools (assembly->image))
3459 assembly->image = NULL;
3461 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3462 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3463 mono_assembly_name_free (fname);
3466 g_slist_free (assembly->friend_assembly_names);
3467 g_free (assembly->basedir);
3469 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3475 mono_assembly_close_finish (MonoAssembly *assembly)
3477 g_assert (assembly && assembly != REFERENCE_MISSING);
3479 if (assembly->image)
3480 mono_image_close_finish (assembly->image);
3482 if (assembly_is_dynamic (assembly)) {
3483 g_free ((char*)assembly->aname.culture);
3490 * mono_assembly_close:
3491 * @assembly: the assembly to release.
3493 * This method releases a reference to the @assembly. The assembly is
3494 * only released when all the outstanding references to it are released.
3497 mono_assembly_close (MonoAssembly *assembly)
3499 if (mono_assembly_close_except_image_pools (assembly))
3500 mono_assembly_close_finish (assembly);
3504 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3507 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3508 mono_error_assert_ok (&error);
3513 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3515 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3520 * mono_assembly_foreach:
3521 * @func: function to invoke for each assembly loaded
3522 * @user_data: data passed to the callback
3524 * Invokes the provided @func callback for each assembly loaded into
3525 * the runtime. The first parameter passed to the callback is the
3526 * `MonoAssembly*`, and the second parameter is the @user_data.
3528 * This is done for all assemblies loaded in the runtime, not just
3529 * those loaded in the current application domain.
3532 mono_assembly_foreach (GFunc func, gpointer user_data)
3537 * We make a copy of the list to avoid calling the callback inside the
3538 * lock, which could lead to deadlocks.
3540 mono_assemblies_lock ();
3541 copy = g_list_copy (loaded_assemblies);
3542 mono_assemblies_unlock ();
3544 g_list_foreach (loaded_assemblies, func, user_data);
3550 * mono_assemblies_cleanup:
3552 * Free all resources used by this module.
3555 mono_assemblies_cleanup (void)
3559 mono_os_mutex_destroy (&assemblies_mutex);
3560 mono_os_mutex_destroy (&assembly_binding_mutex);
3562 for (l = loaded_assembly_bindings; l; l = l->next) {
3563 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3565 mono_assembly_binding_info_free (info);
3568 g_slist_free (loaded_assembly_bindings);
3570 free_assembly_load_hooks ();
3571 free_assembly_search_hooks ();
3572 free_assembly_preload_hooks ();
3575 /*LOCKING takes the assembly_binding lock*/
3577 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3581 mono_assembly_binding_lock ();
3582 iter = &loaded_assembly_bindings;
3585 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3587 if (info->domain_id == domain_id) {
3589 mono_assembly_binding_info_free (info);
3596 mono_assembly_binding_unlock ();
3600 * Holds the assembly of the application, for
3601 * System.Diagnostics.Process::MainModule
3603 static MonoAssembly *main_assembly=NULL;
3606 mono_assembly_set_main (MonoAssembly *assembly)
3608 main_assembly = assembly;
3612 * mono_assembly_get_main:
3614 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3617 mono_assembly_get_main (void)
3619 return (main_assembly);
3623 * mono_assembly_get_image:
3624 * @assembly: The assembly to retrieve the image from
3626 * Returns: the MonoImage associated with this assembly.
3629 mono_assembly_get_image (MonoAssembly *assembly)
3631 return assembly->image;
3635 * mono_assembly_get_name:
3636 * @assembly: The assembly to retrieve the name from
3638 * The returned name's lifetime is the same as @assembly's.
3640 * Returns: the MonoAssemblyName associated with this assembly.
3643 mono_assembly_get_name (MonoAssembly *assembly)
3645 return &assembly->aname;
3649 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3651 bundles = assemblies;
3654 #define MONO_DECLSEC_FORMAT_10 0x3C
3655 #define MONO_DECLSEC_FORMAT_20 0x2E
3656 #define MONO_DECLSEC_FIELD 0x53
3657 #define MONO_DECLSEC_PROPERTY 0x54
3659 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3660 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3661 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3662 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3663 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3666 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3670 case MONO_DECLSEC_PROPERTY:
3672 case MONO_DECLSEC_FIELD:
3674 *abort_decoding = TRUE;
3679 if (*p++ != MONO_TYPE_BOOLEAN) {
3680 *abort_decoding = TRUE;
3684 /* property name length */
3685 len = mono_metadata_decode_value (p, &p);
3687 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3698 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3700 int i, j, num, len, params_len;
3702 if (*p == MONO_DECLSEC_FORMAT_10) {
3703 gsize read, written;
3704 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3706 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3712 if (*p++ != MONO_DECLSEC_FORMAT_20)
3715 /* number of encoded permission attributes */
3716 num = mono_metadata_decode_value (p, &p);
3717 for (i = 0; i < num; ++i) {
3718 gboolean is_valid = FALSE;
3719 gboolean abort_decoding = FALSE;
3721 /* attribute name length */
3722 len = mono_metadata_decode_value (p, &p);
3724 /* We don't really need to fully decode the type. Comparing the name is enough */
3725 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3729 /*size of the params table*/
3730 params_len = mono_metadata_decode_value (p, &p);
3732 const char *params_end = p + params_len;
3734 /* number of parameters */
3735 len = mono_metadata_decode_value (p, &p);
3737 for (j = 0; j < len; ++j) {
3738 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3754 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3757 guint32 cols [MONO_DECL_SECURITY_SIZE];
3761 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3762 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3764 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3766 for (i = 0; i < t->rows; ++i) {
3767 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3768 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3770 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3773 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3774 len = mono_metadata_decode_blob_size (blob, &blob);
3778 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3779 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3784 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);