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/metadata-internals.h>
26 #include <mono/metadata/profiler-private.h>
27 #include <mono/metadata/class-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include <mono/metadata/reflection-internals.h>
30 #include <mono/metadata/mono-endian.h>
31 #include <mono/metadata/mono-debug.h>
32 #include <mono/io-layer/io-layer.h>
33 #include <mono/utils/mono-uri.h>
34 #include <mono/metadata/mono-config.h>
35 #include <mono/metadata/mono-config-dirs.h>
36 #include <mono/utils/mono-digest.h>
37 #include <mono/utils/mono-logger-internals.h>
38 #include <mono/utils/mono-path.h>
39 #include <mono/metadata/reflection.h>
40 #include <mono/metadata/coree.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/utils/mono-io-portability.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-os-mutex.h>
47 #include <sys/types.h>
52 #ifdef PLATFORM_MACOSX
53 #include <mach-o/dyld.h>
56 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
58 const char* assembly_name;
59 guint8 version_set_index;
60 const char* new_assembly_name;
61 gboolean only_lower_versions;
64 /* the default search path is empty, the first slot is replaced with the computed value */
72 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
73 static char **assemblies_path = NULL;
75 /* Contains the list of directories that point to auxiliary GACs */
76 static char **extra_gac_paths = NULL;
78 #ifndef DISABLE_ASSEMBLY_REMAPPING
79 /* The list of system assemblies what will be remapped to the running
80 * runtime version. WARNING: this list must be sorted.
81 * The integer number is an index in the MonoRuntimeInfo structure, whose
82 * values can be found in domain.c - supported_runtimes. Look there
83 * to understand what remapping will be made.
85 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
88 static const AssemblyVersionMap framework_assemblies [] = {
90 {"Commons.Xml.Relaxng", 0},
97 {"Microsoft.Build.Engine", 2, NULL, TRUE},
98 {"Microsoft.Build.Framework", 2, NULL, TRUE},
99 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
100 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
101 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
102 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
103 {"Microsoft.VisualBasic", 1},
104 {"Microsoft.VisualC", 1},
106 {"Mono.CompilerServices.SymbolWriter", 0},
108 {"Mono.Data.SybaseClient", 0},
109 {"Mono.Data.Tds", 0},
110 {"Mono.Data.TdsClient", 0},
111 {"Mono.GetOptions", 0},
114 {"Mono.Security", 0},
115 {"Mono.Security.Win32", 0},
117 {"Novell.Directory.Ldap", 0},
120 {"System.ComponentModel.Composition", 2},
121 {"System.ComponentModel.DataAnnotations", 2},
122 {"System.Configuration", 0},
123 {"System.Configuration.Install", 0},
126 {"System.Data.Linq", 2},
127 {"System.Data.OracleClient", 0},
128 {"System.Data.Services", 2},
129 {"System.Data.Services.Client", 2},
130 {"System.Data.SqlXml", 0},
131 {"System.Design", 0},
132 {"System.DirectoryServices", 0},
133 {"System.Drawing", 0},
134 {"System.Drawing.Design", 0},
135 {"System.EnterpriseServices", 0},
136 {"System.IdentityModel", 3},
137 {"System.IdentityModel.Selectors", 3},
138 {"System.Management", 0},
139 {"System.Messaging", 0},
141 {"System.Runtime.Remoting", 0},
142 {"System.Runtime.Serialization", 3},
143 {"System.Runtime.Serialization.Formatters.Soap", 0},
144 {"System.Security", 0},
145 {"System.ServiceModel", 3},
146 {"System.ServiceModel.Web", 2},
147 {"System.ServiceProcess", 0},
148 {"System.Transactions", 0},
150 {"System.Web.Abstractions", 2},
151 {"System.Web.DynamicData", 2},
152 {"System.Web.Extensions", 2},
153 {"System.Web.Mobile", 0},
154 {"System.Web.Routing", 2},
155 {"System.Web.Services", 0},
156 {"System.Windows.Forms", 0},
158 {"System.Xml.Linq", 2},
165 * keeps track of loaded assemblies
167 static GList *loaded_assemblies = NULL;
168 static MonoAssembly *corlib;
170 #if defined(__native_client__)
172 /* On Native Client, allow mscorlib to be loaded from memory */
173 /* instead of loaded off disk. If these are not set, default */
174 /* mscorlib loading will take place */
176 /* NOTE: If mscorlib data is passed to mono in this way then */
177 /* it needs to remain allocated during the use of mono. */
179 static void *corlibData = NULL;
180 static size_t corlibSize = 0;
183 mono_set_corlib_data (void *data, size_t size)
191 static char* unquote (const char *str);
193 /* This protects loaded_assemblies and image->references */
194 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
195 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
196 static mono_mutex_t assemblies_mutex;
198 /* If defined, points to the bundled assembly information */
199 const MonoBundledAssembly **bundles;
201 static mono_mutex_t assembly_binding_mutex;
203 /* Loaded assembly binding info */
204 static GSList *loaded_assembly_bindings = NULL;
206 /* Class lazy loading functions */
207 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
208 static GENERATE_TRY_GET_CLASS_WITH_CACHE (reference_assembly, System.Runtime.CompilerServices, ReferenceAssemblyAttribute)
211 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
213 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
215 mono_assembly_is_in_gac (const gchar *filanem);
218 encode_public_tok (const guchar *token, gint32 len)
220 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
224 res = (gchar *)g_malloc (len * 2 + 1);
225 for (i = 0; i < len; i++) {
226 res [i * 2] = allowed [token [i] >> 4];
227 res [i * 2 + 1] = allowed [token [i] & 0xF];
234 * mono_public_tokens_are_equal:
235 * @pubt1: first public key token
236 * @pubt2: second public key token
238 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
242 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
244 return memcmp (pubt1, pubt2, 16) == 0;
248 * mono_set_assemblies_path:
249 * @path: list of paths that contain directories where Mono will look for assemblies
251 * Use this method to override the standard assembly lookup system and
252 * override any assemblies coming from the GAC. This is the method
253 * that supports the MONO_PATH variable.
255 * Notice that MONO_PATH and this method are really a very bad idea as
256 * it prevents the GAC from working and it prevents the standard
257 * resolution mechanisms from working. Nonetheless, for some debugging
258 * situations and bootstrapping setups, this is useful to have.
261 mono_set_assemblies_path (const char* path)
263 char **splitted, **dest;
265 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
267 g_strfreev (assemblies_path);
268 assemblies_path = dest = splitted;
270 char *tmp = *splitted;
272 *dest++ = mono_path_canonicalize (tmp);
278 if (g_getenv ("MONO_DEBUG") == NULL)
281 splitted = assemblies_path;
283 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
284 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
290 /* Native Client can't get this info from an environment variable so */
291 /* it's passed in to the runtime, or set manually by embedding code. */
292 #ifdef __native_client__
293 char* nacl_mono_path = NULL;
297 check_path_env (void)
300 path = g_getenv ("MONO_PATH");
301 #ifdef __native_client__
303 path = nacl_mono_path;
305 if (!path || assemblies_path != NULL)
308 mono_set_assemblies_path(path);
312 check_extra_gac_path_env (void) {
314 char **splitted, **dest;
316 path = g_getenv ("MONO_GAC_PREFIX");
320 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
322 g_strfreev (extra_gac_paths);
323 extra_gac_paths = dest = splitted;
331 if (g_getenv ("MONO_DEBUG") == NULL)
335 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
336 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
343 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
345 if (!info || !info->name)
348 if (strcmp (info->name, aname->name))
351 if (info->major != aname->major || info->minor != aname->minor)
354 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
357 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
360 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
367 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
373 g_free (info->culture);
377 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
380 guint32 cols [MONO_MANIFEST_SIZE];
381 const gchar *filename;
382 gchar *subpath, *fullpath;
384 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
385 /* MS Impl. accepts policy assemblies with more than
386 * one manifest resource, and only takes the first one */
388 binding_info->is_valid = FALSE;
392 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
393 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
394 binding_info->is_valid = FALSE;
398 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
399 g_assert (filename != NULL);
401 subpath = g_path_get_dirname (image->name);
402 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
403 mono_config_parse_publisher_policy (fullpath, binding_info);
407 /* Define the optional elements/attributes before checking */
408 if (!binding_info->culture)
409 binding_info->culture = g_strdup ("");
411 /* Check that the most important elements/attributes exist */
412 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
413 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
414 mono_assembly_binding_info_free (binding_info);
415 binding_info->is_valid = FALSE;
419 binding_info->is_valid = TRUE;
423 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
425 if (v->major > aname->major)
427 else if (v->major < aname->major)
430 if (v->minor > aname->minor)
432 else if (v->minor < aname->minor)
435 if (v->build > aname->build)
437 else if (v->build < aname->build)
440 if (v->revision > aname->revision)
442 else if (v->revision < aname->revision)
449 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
454 /* If has_old_version_top doesn't exist, we don't have an interval */
455 if (!info->has_old_version_top) {
456 if (compare_versions (&info->old_version_bottom, name) == 0)
462 /* Check that the version defined by name is valid for the interval */
463 if (compare_versions (&info->old_version_top, name) < 0)
466 /* We should be greater or equal than the small version */
467 if (compare_versions (&info->old_version_bottom, name) > 0)
474 * mono_assembly_names_equal:
476 * @r: second assembly.
478 * Compares two MonoAssemblyNames and returns whether they are equal.
480 * This compares the names, the cultures, the release version and their
483 * Returns: TRUE if both assembly names are equal.
486 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
488 if (!l->name || !r->name)
491 if (strcmp (l->name, r->name))
494 if (l->culture && r->culture && strcmp (l->culture, r->culture))
497 if (l->major != r->major || l->minor != r->minor ||
498 l->build != r->build || l->revision != r->revision)
499 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)))
502 if (!l->public_key_token [0] || !r->public_key_token [0])
505 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
511 static MonoAssembly *
512 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
516 MonoAssembly *result;
518 for (i = 0; search_path [i]; ++i) {
519 fullpath = g_build_filename (search_path [i], basename, NULL);
520 result = mono_assembly_open_full (fullpath, status, refonly);
529 * mono_assembly_setrootdir:
530 * @root_dir: The pathname of the root directory where we will locate assemblies
532 * This routine sets the internal default root directory for looking up
535 * This is used by Windows installations to compute dynamically the
536 * place where the Mono assemblies are located.
540 mono_assembly_setrootdir (const char *root_dir)
543 * Override the MONO_ASSEMBLIES directory configured at compile time.
545 /* Leak if called more than once */
546 default_path [0] = g_strdup (root_dir);
550 * mono_assembly_getrootdir:
552 * Obtains the root directory used for looking up assemblies.
554 * Returns: a string with the directory, this string should not be freed.
556 G_CONST_RETURN gchar *
557 mono_assembly_getrootdir (void)
559 return default_path [0];
564 * @assembly_dir: the base directory for assemblies
565 * @config_dir: the base directory for configuration files
567 * This routine is used internally and by developers embedding
568 * the runtime into their own applications.
570 * There are a number of cases to consider: Mono as a system-installed
571 * package that is available on the location preconfigured or Mono in
572 * a relocated location.
574 * If you are using a system-installed Mono, you can pass NULL
575 * to both parameters. If you are not, you should compute both
576 * directory values and call this routine.
578 * The values for a given PREFIX are:
580 * assembly_dir: PREFIX/lib
581 * config_dir: PREFIX/etc
583 * Notice that embedders that use Mono in a relocated way must
584 * compute the location at runtime, as they will be in control
585 * of where Mono is installed.
588 mono_set_dirs (const char *assembly_dir, const char *config_dir)
590 if (assembly_dir == NULL)
591 assembly_dir = mono_config_get_assemblies_dir ();
592 if (config_dir == NULL)
593 config_dir = mono_config_get_cfg_dir ();
594 mono_assembly_setrootdir (assembly_dir);
595 mono_set_config_dir (config_dir);
601 compute_base (char *path)
603 char *p = strrchr (path, '/');
607 /* Not a well known Mono executable, we are embedded, cant guess the base */
608 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
612 p = strrchr (path, '/');
616 if (strcmp (p, "/bin") != 0)
625 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
628 static G_GNUC_UNUSED void
632 char *config, *lib, *mono;
637 * Only /usr prefix is treated specially
639 bindir = mono_config_get_bin_dir ();
641 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
646 config = g_build_filename (base, "etc", NULL);
647 lib = g_build_filename (base, "lib", NULL);
648 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
649 if (stat (mono, &buf) == -1)
652 mono_set_dirs (lib, config);
660 #endif /* HOST_WIN32 */
665 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
666 * this auto-detects the prefix where Mono was installed.
669 mono_set_rootdir (void)
671 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
672 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
675 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
679 * _NSGetExecutablePath may return -1 to indicate buf is not large
680 * enough, but we ignore that case to avoid having to do extra dynamic
681 * allocation for the path and hope that 4096 is enough - this is
682 * ok in the Linux/Solaris case below at least...
686 guint buf_size = sizeof (buf);
689 if (_NSGetExecutablePath (buf, &buf_size) == 0)
690 name = g_strdup (buf);
699 resolvedname = mono_path_resolve_symlinks (name);
701 bindir = g_path_get_dirname (resolvedname);
702 installdir = g_path_get_dirname (bindir);
703 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
705 config = g_build_filename (root, "..", "etc", NULL);
707 mono_set_dirs (root, config);
709 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
710 mono_set_dirs (root, config);
720 g_free (resolvedname);
721 #elif defined(DISABLE_MONO_AUTODETECTION)
729 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
737 /* Solaris 10 style */
738 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
739 s = readlink (str, buf, sizeof (buf)-1);
751 * mono_assemblies_init:
753 * Initialize global variables used by this module.
756 mono_assemblies_init (void)
759 * Initialize our internal paths if we have not been initialized yet.
760 * This happens when embedders use Mono.
762 if (mono_assembly_getrootdir () == NULL)
766 check_extra_gac_path_env ();
768 mono_os_mutex_init_recursive (&assemblies_mutex);
769 mono_os_mutex_init (&assembly_binding_mutex);
773 mono_assembly_binding_lock (void)
775 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
779 mono_assembly_binding_unlock (void)
781 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
785 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
787 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
788 guint32 cols [MONO_ASSEMBLY_SIZE];
789 gint32 machine, flags;
794 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
797 aname->hash_value = NULL;
798 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
799 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
800 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
801 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
802 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
803 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
804 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
805 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
806 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
807 guchar* token = (guchar *)g_malloc (8);
812 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
813 len = mono_metadata_decode_blob_size (pkey, &pkey);
814 aname->public_key = (guchar*)pkey;
816 mono_digest_get_public_token (token, aname->public_key, len);
817 encoded = encode_public_tok (token, 8);
818 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
824 aname->public_key = NULL;
825 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
828 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
829 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
832 aname->public_key = 0;
834 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
835 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
837 case COFF_MACHINE_I386:
838 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
839 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
840 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
841 else if ((flags & 0x70) == 0x70)
842 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
844 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
846 case COFF_MACHINE_IA64:
847 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
849 case COFF_MACHINE_AMD64:
850 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
852 case COFF_MACHINE_ARM:
853 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
863 * mono_stringify_assembly_name:
864 * @aname: the assembly name.
866 * Convert @aname into its string format. The returned string is dynamically
867 * allocated and should be freed by the caller.
869 * Returns: a newly allocated string with a string representation of
873 mono_stringify_assembly_name (MonoAssemblyName *aname)
875 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
877 return g_strdup_printf (
878 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
879 quote, aname->name, quote,
880 aname->major, aname->minor, aname->build, aname->revision,
881 aname->culture && *aname->culture? aname->culture: "neutral",
882 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
883 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
887 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
889 const gchar *public_tok;
892 public_tok = mono_metadata_blob_heap (image, key_index);
893 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
895 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
897 mono_digest_get_public_token (token, (guchar*)public_tok, len);
898 return encode_public_tok (token, 8);
901 return encode_public_tok ((guchar*)public_tok, len);
905 * mono_assembly_addref:
906 * @assemnly: the assembly to reference
908 * This routine increments the reference count on a MonoAssembly.
909 * The reference count is reduced every time the method mono_assembly_close() is
913 mono_assembly_addref (MonoAssembly *assembly)
915 InterlockedIncrement (&assembly->ref_count);
919 * CAUTION: This table must be kept in sync with
920 * ivkm/reflect/Fusion.cs
923 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
924 #define WINFX_KEY "31bf3856ad364e35"
925 #define ECMA_KEY "b77a5c561934e089"
926 #define MSFINAL_KEY "b03f5f7f11d50a3a"
927 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
935 static KeyRemapEntry key_remap_table[] = {
936 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
937 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
938 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
939 { "System", SILVERLIGHT_KEY, ECMA_KEY },
940 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
941 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
942 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
943 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
944 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
945 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
946 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
947 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
948 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
949 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
950 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
951 { "System.Numerics", WINFX_KEY, ECMA_KEY },
952 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
953 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
954 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
955 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
956 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
957 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
958 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
959 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
960 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
961 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
962 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
963 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
964 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
968 remap_keys (MonoAssemblyName *aname)
971 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
972 const KeyRemapEntry *entry = &key_remap_table [i];
974 if (strcmp (aname->name, entry->name) ||
975 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
978 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
980 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
981 "Remapped public key token of retargetable assembly %s from %s to %s",
982 aname->name, entry->from, entry->to);
987 static MonoAssemblyName *
988 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
990 const MonoRuntimeInfo *current_runtime;
991 int pos, first, last;
993 if (aname->name == NULL) return aname;
995 current_runtime = mono_get_runtime_info ();
997 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
998 const AssemblyVersionSet* vset;
1000 /* Remap to current runtime */
1001 vset = ¤t_runtime->version_sets [0];
1003 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1004 dest_aname->major = vset->major;
1005 dest_aname->minor = vset->minor;
1006 dest_aname->build = vset->build;
1007 dest_aname->revision = vset->revision;
1008 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1010 /* Remap assembly name */
1011 if (!strcmp (aname->name, "System.Net"))
1012 dest_aname->name = g_strdup ("System");
1014 remap_keys (dest_aname);
1016 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1017 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1019 aname->major, aname->minor, aname->build, aname->revision,
1021 vset->major, vset->minor, vset->build, vset->revision
1027 #ifndef DISABLE_ASSEMBLY_REMAPPING
1029 last = G_N_ELEMENTS (framework_assemblies) - 1;
1031 while (first <= last) {
1033 pos = first + (last - first) / 2;
1034 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1036 const AssemblyVersionSet* vset;
1037 int index = framework_assemblies[pos].version_set_index;
1038 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1039 vset = ¤t_runtime->version_sets [index];
1041 if (aname->major == vset->major && aname->minor == vset->minor &&
1042 aname->build == vset->build && aname->revision == vset->revision)
1045 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1048 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1049 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1050 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1052 aname->major, aname->minor, aname->build, aname->revision,
1053 vset->major, vset->minor, vset->build, vset->revision
1056 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1057 dest_aname->major = vset->major;
1058 dest_aname->minor = vset->minor;
1059 dest_aname->build = vset->build;
1060 dest_aname->revision = vset->revision;
1061 if (framework_assemblies[pos].new_assembly_name != NULL) {
1062 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1063 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1064 "The assembly name %s was remapped to %s",
1069 } else if (res < 0) {
1081 * mono_assembly_get_assemblyref:
1082 * @image: pointer to the MonoImage to extract the information from.
1083 * @index: index to the assembly reference in the image.
1084 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1086 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1089 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1092 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1095 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1097 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1099 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1100 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1101 aname->hash_value = hash;
1102 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1103 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1104 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1105 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1106 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1107 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1108 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1110 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1111 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1112 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1115 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1120 mono_assembly_load_reference (MonoImage *image, int index)
1122 MonoAssembly *reference;
1123 MonoAssemblyName aname;
1124 MonoImageOpenStatus status;
1127 * image->references is shared between threads, so we need to access
1128 * it inside a critical section.
1130 mono_assemblies_lock ();
1131 if (!image->references) {
1132 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1134 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1135 image->nreferences = t->rows;
1137 reference = image->references [index];
1138 mono_assemblies_unlock ();
1142 mono_assembly_get_assemblyref (image, index, &aname);
1144 if (image->assembly && image->assembly->ref_only) {
1145 /* We use the loaded corlib */
1146 if (!strcmp (aname.name, "mscorlib"))
1147 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1149 reference = mono_assembly_loaded_full (&aname, TRUE);
1151 /* Try a postload search hook */
1152 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1156 * Here we must advice that the error was due to
1157 * a non loaded reference using the ReflectionOnly api
1160 reference = (MonoAssembly *)REFERENCE_MISSING;
1162 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1163 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1164 * accordingly, it would fail on the MS runtime before).
1165 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1166 * example bug-349190.2.cs and who knows how much more code in the wild.
1168 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1169 if (!reference && image->assembly)
1170 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1173 if (reference == NULL){
1176 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1177 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 : "" );
1178 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1179 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1180 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1181 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1182 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1183 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1185 extra_msg = g_strdup ("");
1188 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1189 " Assembly: %s (assemblyref_index=%d)\n"
1190 " Version: %d.%d.%d.%d\n"
1191 " Public Key: %s\n%s",
1192 image->name, aname.name, index,
1193 aname.major, aname.minor, aname.build, aname.revision,
1194 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1198 mono_assemblies_lock ();
1199 if (reference == NULL) {
1200 /* Flag as not found */
1201 reference = (MonoAssembly *)REFERENCE_MISSING;
1204 if (!image->references [index]) {
1205 if (reference != REFERENCE_MISSING){
1206 mono_assembly_addref (reference);
1207 if (image->assembly)
1208 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1209 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1211 if (image->assembly)
1212 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1213 image->assembly->aname.name, image->assembly);
1216 image->references [index] = reference;
1218 mono_assemblies_unlock ();
1220 if (image->references [index] != reference) {
1221 /* Somebody loaded it before us */
1222 mono_assembly_close (reference);
1227 * mono_assembly_load_references:
1230 * @deprecated: There is no reason to use this method anymore, it does nothing
1232 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1235 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1237 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1238 *status = MONO_IMAGE_OK;
1241 typedef struct AssemblyLoadHook AssemblyLoadHook;
1242 struct AssemblyLoadHook {
1243 AssemblyLoadHook *next;
1244 MonoAssemblyLoadFunc func;
1248 AssemblyLoadHook *assembly_load_hook = NULL;
1251 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1253 AssemblyLoadHook *hook;
1255 for (hook = assembly_load_hook; hook; hook = hook->next) {
1256 hook->func (ass, hook->user_data);
1261 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1263 AssemblyLoadHook *hook;
1265 g_return_if_fail (func != NULL);
1267 hook = g_new0 (AssemblyLoadHook, 1);
1269 hook->user_data = user_data;
1270 hook->next = assembly_load_hook;
1271 assembly_load_hook = hook;
1275 free_assembly_load_hooks (void)
1277 AssemblyLoadHook *hook, *next;
1279 for (hook = assembly_load_hook; hook; hook = next) {
1285 typedef struct AssemblySearchHook AssemblySearchHook;
1286 struct AssemblySearchHook {
1287 AssemblySearchHook *next;
1288 MonoAssemblySearchFunc func;
1294 AssemblySearchHook *assembly_search_hook = NULL;
1296 static MonoAssembly*
1297 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1299 AssemblySearchHook *hook;
1301 for (hook = assembly_search_hook; hook; hook = hook->next) {
1302 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1305 * A little explanation is in order here.
1307 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1308 * The embedding API exposes a search hook that doesn't take such argument.
1310 * The original fix would call the default search hook before all the registered ones and pass
1311 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1312 * rely on. Which is the ordering between user hooks and the default runtime hook.
1314 * Registering the hook after mono_jit_init would let your hook run before the default one and
1315 * when using it to handle non standard app layouts this could save your app from a massive amount
1316 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1317 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1319 * So what's the fix? We register the default hook using regular means and special case it when iterating
1320 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1323 if (hook->func == (void*)mono_domain_assembly_postload_search)
1324 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1326 ass = hook->func (aname, hook->user_data);
1336 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1338 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1342 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1344 AssemblySearchHook *hook;
1346 g_return_if_fail (func != NULL);
1348 hook = g_new0 (AssemblySearchHook, 1);
1350 hook->user_data = user_data;
1351 hook->refonly = refonly;
1352 hook->postload = postload;
1353 hook->next = assembly_search_hook;
1354 assembly_search_hook = hook;
1358 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1360 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1364 free_assembly_search_hooks (void)
1366 AssemblySearchHook *hook, *next;
1368 for (hook = assembly_search_hook; hook; hook = next) {
1375 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1377 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1381 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1383 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1387 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1389 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1392 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1393 struct AssemblyPreLoadHook {
1394 AssemblyPreLoadHook *next;
1395 MonoAssemblyPreLoadFunc func;
1399 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1400 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1402 static MonoAssembly *
1403 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1405 AssemblyPreLoadHook *hook;
1406 MonoAssembly *assembly;
1408 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1409 assembly = hook->func (aname, assemblies_path, hook->user_data);
1410 if (assembly != NULL)
1417 static MonoAssembly *
1418 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1420 AssemblyPreLoadHook *hook;
1421 MonoAssembly *assembly;
1423 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1424 assembly = hook->func (aname, assemblies_path, hook->user_data);
1425 if (assembly != NULL)
1433 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1435 AssemblyPreLoadHook *hook;
1437 g_return_if_fail (func != NULL);
1439 hook = g_new0 (AssemblyPreLoadHook, 1);
1441 hook->user_data = user_data;
1442 hook->next = assembly_preload_hook;
1443 assembly_preload_hook = hook;
1447 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1449 AssemblyPreLoadHook *hook;
1451 g_return_if_fail (func != NULL);
1453 hook = g_new0 (AssemblyPreLoadHook, 1);
1455 hook->user_data = user_data;
1456 hook->next = assembly_refonly_preload_hook;
1457 assembly_refonly_preload_hook = hook;
1461 free_assembly_preload_hooks (void)
1463 AssemblyPreLoadHook *hook, *next;
1465 for (hook = assembly_preload_hook; hook; hook = next) {
1470 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1477 absolute_dir (const gchar *filename)
1488 if (g_path_is_absolute (filename)) {
1489 part = g_path_get_dirname (filename);
1490 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1495 cwd = g_get_current_dir ();
1496 mixed = g_build_filename (cwd, filename, NULL);
1497 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1502 for (i = 0; (part = parts [i]) != NULL; i++) {
1503 if (!strcmp (part, "."))
1506 if (!strcmp (part, "..")) {
1507 if (list && list->next) /* Don't remove root */
1508 list = g_list_delete_link (list, list);
1510 list = g_list_prepend (list, part);
1514 result = g_string_new ("");
1515 list = g_list_reverse (list);
1517 /* Ignores last data pointer, which should be the filename */
1518 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1520 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1525 g_string_free (result, FALSE);
1530 return g_strdup (".");
1537 * mono_assembly_open_from_bundle:
1538 * @filename: Filename requested
1539 * @status: return status code
1541 * This routine tries to open the assembly specified by `filename' from the
1542 * defined bundles, if found, returns the MonoImage for it, if not found
1546 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1550 gchar *lowercase_filename;
1551 MonoImage *image = NULL;
1552 gboolean is_satellite = FALSE;
1554 * we do a very simple search for bundled assemblies: it's not a general
1555 * purpose assembly loading mechanism.
1561 lowercase_filename = g_utf8_strdown (filename, -1);
1562 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1563 g_free (lowercase_filename);
1564 name = g_path_get_basename (filename);
1565 mono_assemblies_lock ();
1566 for (i = 0; !image && bundles [i]; ++i) {
1567 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1568 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1572 mono_assemblies_unlock ();
1574 mono_image_addref (image);
1575 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1584 * mono_assemblies_open_full:
1585 * @filename: the file to load
1586 * @status: return status code
1587 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1589 * This loads an assembly from the specified @filename. The @filename allows
1590 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1591 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1592 * is treated as a local path.
1594 * First, an attempt is made to load the assembly from the bundled executable (for those
1595 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1596 * assembly has been registered as an embedded assembly). If this is not the case, then
1597 * the assembly is loaded from disk using `api:mono_image_open_full`.
1599 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1600 * the assembly is made.
1602 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1603 * the `System.Reflection` API.
1605 * Returns: NULL on error, with the @status set to an error code, or a pointer
1609 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1613 MonoImageOpenStatus def_status;
1616 gboolean loaded_from_bundle;
1618 g_return_val_if_fail (filename != NULL, NULL);
1621 status = &def_status;
1622 *status = MONO_IMAGE_OK;
1624 if (strncmp (filename, "file://", 7) == 0) {
1625 GError *error = NULL;
1626 gchar *uri = (gchar *) filename;
1630 * MS allows file://c:/... and fails on file://localhost/c:/...
1631 * They also throw an IndexOutOfRangeException if "file://"
1634 uri = g_strdup_printf ("file:///%s", uri + 7);
1637 uri = mono_escape_uri_string (tmpuri);
1638 fname = g_filename_from_uri (uri, NULL, &error);
1641 if (tmpuri != filename)
1644 if (error != NULL) {
1645 g_warning ("%s\n", error->message);
1646 g_error_free (error);
1647 fname = g_strdup (filename);
1650 fname = g_strdup (filename);
1653 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1654 "Assembly Loader probing location: '%s'.", fname);
1657 if (!mono_assembly_is_in_gac (fname)) {
1659 new_fname = mono_make_shadow_copy (fname, &error);
1660 if (!is_ok (&error)) {
1661 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1662 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1663 mono_error_cleanup (&error);
1664 *status = MONO_IMAGE_IMAGE_INVALID;
1669 if (new_fname && new_fname != fname) {
1672 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1673 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1678 // If VM built with mkbundle
1679 loaded_from_bundle = FALSE;
1680 if (bundles != NULL) {
1681 image = mono_assembly_open_from_bundle (fname, status, refonly);
1682 loaded_from_bundle = image != NULL;
1686 image = mono_image_open_full (fname, status, refonly);
1689 if (*status == MONO_IMAGE_OK)
1690 *status = MONO_IMAGE_ERROR_ERRNO;
1695 if (image->assembly) {
1696 /* Already loaded by another appdomain */
1697 mono_assembly_invoke_load_hook (image->assembly);
1698 mono_image_close (image);
1700 return image->assembly;
1703 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1706 if (!loaded_from_bundle)
1707 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1708 "Assembly Loader loaded assembly from location: '%s'.", filename);
1710 mono_config_for_assembly (ass->image);
1713 /* Clear the reference added by mono_image_open */
1714 mono_image_close (image);
1722 free_item (gpointer val, gpointer user_data)
1728 * mono_assembly_load_friends:
1731 * Load the list of friend assemblies that are allowed to access
1732 * the assembly's internal types and members. They are stored as assembly
1733 * names in custom attributes.
1735 * This is an internal method, we need this because when we load mscorlib
1736 * we do not have the internals visible cattr loaded yet,
1737 * so we need to load these after we initialize the runtime.
1739 * LOCKING: Acquires the assemblies lock plus the loader lock.
1742 mono_assembly_load_friends (MonoAssembly* ass)
1746 MonoCustomAttrInfo* attrs;
1749 if (ass->friend_assembly_names_inited)
1752 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1753 mono_error_assert_ok (&error);
1755 mono_assemblies_lock ();
1756 ass->friend_assembly_names_inited = TRUE;
1757 mono_assemblies_unlock ();
1761 mono_assemblies_lock ();
1762 if (ass->friend_assembly_names_inited) {
1763 mono_assemblies_unlock ();
1766 mono_assemblies_unlock ();
1770 * We build the list outside the assemblies lock, the worse that can happen
1771 * is that we'll need to free the allocated list.
1773 for (i = 0; i < attrs->num_attrs; ++i) {
1774 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1775 MonoAssemblyName *aname;
1777 /* Do some sanity checking */
1778 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1780 if (attr->data_size < 4)
1782 data = (const char*)attr->data;
1783 /* 0xFF means null string, see custom attr format */
1784 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1786 mono_metadata_decode_value (data + 2, &data);
1787 aname = g_new0 (MonoAssemblyName, 1);
1788 /*g_print ("friend ass: %s\n", data);*/
1789 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1790 list = g_slist_prepend (list, aname);
1795 mono_custom_attrs_free (attrs);
1797 mono_assemblies_lock ();
1798 if (ass->friend_assembly_names_inited) {
1799 mono_assemblies_unlock ();
1800 g_slist_foreach (list, free_item, NULL);
1801 g_slist_free (list);
1804 ass->friend_assembly_names = list;
1806 /* Because of the double checked locking pattern above */
1807 mono_memory_barrier ();
1808 ass->friend_assembly_names_inited = TRUE;
1809 mono_assemblies_unlock ();
1814 * mono_assembly_get_reference_assembly_attribute:
1815 * @assembly: a MonoAssembly
1816 * @error: set on error.
1818 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1819 * On error returns FALSE and sets @error.
1822 mono_assembly_get_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1824 mono_error_init (error);
1826 MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
1827 return_val_if_nok (error, FALSE);
1830 MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
1831 gboolean result = FALSE;
1832 for (int i = 0; i < attrs->num_attrs; ++i) {
1833 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1834 if (attr->ctor && attr->ctor->klass && attr->ctor->klass == ref_asm_class) {
1839 mono_custom_attrs_free (attrs);
1844 * mono_assembly_open:
1845 * @filename: Opens the assembly pointed out by this name
1846 * @status: return status code
1848 * This loads an assembly from the specified @filename. The @filename allows
1849 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1850 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1851 * is treated as a local path.
1853 * First, an attempt is made to load the assembly from the bundled executable (for those
1854 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1855 * assembly has been registered as an embedded assembly). If this is not the case, then
1856 * the assembly is loaded from disk using `api:mono_image_open_full`.
1858 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1859 * the assembly is made.
1861 * Return: a pointer to the MonoAssembly if @filename contains a valid
1862 * assembly or NULL on error. Details about the error are stored in the
1866 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1868 return mono_assembly_open_full (filename, status, FALSE);
1872 * mono_assembly_load_from_full:
1873 * @image: Image to load the assembly from
1874 * @fname: assembly name to associate with the assembly
1875 * @status: returns the status condition
1876 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1878 * If the provided @image has an assembly reference, it will process the given
1879 * image as an assembly with the given name.
1881 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1883 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1884 * set to #MONO_IMAGE_OK; or NULL on error.
1886 * If there is an error loading the assembly the @status will indicate the
1887 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1888 * image did not contain an assembly reference table.
1891 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1892 MonoImageOpenStatus *status, gboolean refonly)
1894 MonoAssembly *ass, *ass2;
1897 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1898 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1899 *status = MONO_IMAGE_IMAGE_INVALID;
1903 #if defined (HOST_WIN32)
1908 tmp_fn = g_strdup (fname);
1909 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1910 if (tmp_fn [i] == '/')
1914 base_dir = absolute_dir (tmp_fn);
1918 base_dir = absolute_dir (fname);
1922 * Create assembly struct, and enter it into the assembly cache
1924 ass = g_new0 (MonoAssembly, 1);
1925 ass->basedir = base_dir;
1926 ass->ref_only = refonly;
1929 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1931 mono_assembly_fill_assembly_name (image, &ass->aname);
1933 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1934 // MS.NET doesn't support loading other mscorlibs
1937 mono_image_addref (mono_defaults.corlib);
1938 *status = MONO_IMAGE_OK;
1939 return mono_defaults.corlib->assembly;
1942 /* Add a non-temporary reference because of ass->image */
1943 mono_image_addref (image);
1945 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);
1948 * The load hooks might take locks so we can't call them while holding the
1951 if (ass->aname.name) {
1952 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1956 mono_image_close (image);
1957 *status = MONO_IMAGE_OK;
1962 mono_assemblies_lock ();
1964 if (image->assembly) {
1966 * This means another thread has already loaded the assembly, but not yet
1967 * called the load hooks so the search hook can't find the assembly.
1969 mono_assemblies_unlock ();
1970 ass2 = image->assembly;
1973 mono_image_close (image);
1974 *status = MONO_IMAGE_OK;
1978 image->assembly = ass;
1980 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1981 mono_assemblies_unlock ();
1984 if (image->is_module_handle)
1985 mono_image_fixup_vtable (image);
1988 mono_assembly_invoke_load_hook (ass);
1990 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1996 * mono_assembly_load_from:
1997 * @image: Image to load the assembly from
1998 * @fname: assembly name to associate with the assembly
1999 * @status: return status code
2001 * If the provided @image has an assembly reference, it will process the given
2002 * image as an assembly with the given name.
2004 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2006 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2007 * @refonly parameter set to FALSE.
2008 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2009 * set to #MONO_IMAGE_OK; or NULL on error.
2011 * If there is an error loading the assembly the @status will indicate the
2012 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2013 * image did not contain an assembly reference table.
2017 mono_assembly_load_from (MonoImage *image, const char *fname,
2018 MonoImageOpenStatus *status)
2020 return mono_assembly_load_from_full (image, fname, status, FALSE);
2024 * mono_assembly_name_free:
2025 * @aname: assembly name to free
2027 * Frees the provided assembly name object.
2028 * (it does not frees the object itself, only the name members).
2031 mono_assembly_name_free (MonoAssemblyName *aname)
2036 g_free ((void *) aname->name);
2037 g_free ((void *) aname->culture);
2038 g_free ((void *) aname->hash_value);
2039 g_free ((guint8*) aname->public_key);
2043 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2046 gchar header [16], val, *arr;
2047 gint i, j, offset, bitlen, keylen, pkeylen;
2049 keylen = strlen (key) >> 1;
2053 /* allow the ECMA standard key */
2054 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2056 *pubkey = g_strdup (key);
2062 val = g_ascii_xdigit_value (key [0]) << 4;
2063 val |= g_ascii_xdigit_value (key [1]);
2068 val = g_ascii_xdigit_value (key [24]);
2069 val |= g_ascii_xdigit_value (key [25]);
2081 /* We need the first 16 bytes
2082 * to check whether this key is valid or not */
2083 pkeylen = strlen (pkey) >> 1;
2087 for (i = 0, j = 0; i < 16; i++) {
2088 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2089 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2092 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2093 header [1] != 0x02 || /* Version (0x02) */
2094 header [2] != 0x00 || /* Reserved (word) */
2095 header [3] != 0x00 ||
2096 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2099 /* Based on this length, we _should_ be able to know if the length is right */
2100 bitlen = read32 (header + 12) >> 3;
2101 if ((bitlen + 16 + 4) != pkeylen)
2104 /* parsing is OK and the public key itself is not requested back */
2108 /* Encode the size of the blob */
2110 if (keylen <= 127) {
2111 arr = (gchar *)g_malloc (keylen + 1);
2112 arr [offset++] = keylen;
2114 arr = (gchar *)g_malloc (keylen + 2);
2115 arr [offset++] = 0x80; /* 10bs */
2116 arr [offset++] = keylen;
2119 for (i = offset, j = 0; i < keylen + offset; i++) {
2120 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2121 arr [i] |= g_ascii_xdigit_value (key [j++]);
2130 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)
2132 gint major, minor, build, revision;
2135 gchar *pkey, *pkeyptr, *encoded, tok [8];
2137 memset (aname, 0, sizeof (MonoAssemblyName));
2140 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2141 if (version_parts < 2 || version_parts > 4)
2144 /* FIXME: we should set build & revision to -1 (instead of 0)
2145 if these are not set in the version string. That way, later on,
2146 we can still determine if these were specified. */
2147 aname->major = major;
2148 aname->minor = minor;
2149 if (version_parts >= 3)
2150 aname->build = build;
2153 if (version_parts == 4)
2154 aname->revision = revision;
2156 aname->revision = 0;
2159 aname->flags = flags;
2161 aname->name = g_strdup (name);
2164 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2165 aname->culture = g_strdup ("");
2167 aname->culture = g_strdup (culture);
2170 if (token && strncmp (token, "null", 4) != 0) {
2173 /* the constant includes the ending NULL, hence the -1 */
2174 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2175 mono_assembly_name_free (aname);
2178 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2179 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2185 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2186 mono_assembly_name_free (aname);
2191 if (save_public_key)
2192 aname->public_key = (guint8*)pkey;
2195 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2199 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2200 // We also need to generate the key token
2201 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2202 encoded = encode_public_tok ((guchar*) tok, 8);
2203 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2206 if (save_public_key)
2207 aname->public_key = (guint8*) pkey;
2216 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2221 parts = g_strsplit (dirname, "_", 3);
2222 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2227 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2233 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2235 char *eqsign = strchr (pair, '=');
2243 *key = (gchar*)pair;
2244 *keylen = eqsign - *key;
2245 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2247 *value = g_strstrip (eqsign + 1);
2252 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2256 gchar *version = NULL;
2258 gchar *culture = NULL;
2260 gchar *token = NULL;
2264 gchar *retargetable = NULL;
2265 gchar *retargetable_uq;
2269 gchar *value, *part_name;
2270 guint32 part_name_len;
2273 gboolean version_defined;
2274 gboolean token_defined;
2276 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2278 if (!is_version_defined)
2279 is_version_defined = &version_defined;
2280 *is_version_defined = FALSE;
2281 if (!is_token_defined)
2282 is_token_defined = &token_defined;
2283 *is_token_defined = FALSE;
2285 parts = tmp = g_strsplit (name, ",", 6);
2286 if (!tmp || !*tmp) {
2291 dllname = g_strstrip (*tmp);
2296 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2297 goto cleanup_and_fail;
2299 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2300 *is_version_defined = TRUE;
2302 if (strlen (version) == 0) {
2303 goto cleanup_and_fail;
2309 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2311 if (strlen (culture) == 0) {
2312 goto cleanup_and_fail;
2318 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2319 *is_token_defined = TRUE;
2321 if (strlen (token) == 0) {
2322 goto cleanup_and_fail;
2328 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2330 if (strlen (key) == 0) {
2331 goto cleanup_and_fail;
2337 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2338 retargetable = value;
2339 retargetable_uq = unquote (retargetable);
2340 if (retargetable_uq != NULL)
2341 retargetable = retargetable_uq;
2343 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2344 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2345 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2346 g_free (retargetable_uq);
2347 goto cleanup_and_fail;
2350 g_free (retargetable_uq);
2355 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2357 procarch_uq = unquote (procarch);
2358 if (procarch_uq != NULL)
2359 procarch = procarch_uq;
2361 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2362 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2363 else if (!g_ascii_strcasecmp (procarch, "X86"))
2364 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2365 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2366 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2367 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2368 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2370 g_free (procarch_uq);
2371 goto cleanup_and_fail;
2374 g_free (procarch_uq);
2383 /* if retargetable flag is set, then we must have a fully qualified name */
2384 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2385 goto cleanup_and_fail;
2388 dllname_uq = unquote (dllname);
2389 version_uq = unquote (version);
2390 culture_uq = unquote (culture);
2391 token_uq = unquote (token);
2392 key_uq = unquote (key);
2394 res = build_assembly_name (
2395 dllname_uq == NULL ? dllname : dllname_uq,
2396 version_uq == NULL ? version : version_uq,
2397 culture_uq == NULL ? culture : culture_uq,
2398 token_uq == NULL ? token : token_uq,
2399 key_uq == NULL ? key : key_uq,
2400 flags, arch, aname, save_public_key);
2402 g_free (dllname_uq);
2403 g_free (version_uq);
2404 g_free (culture_uq);
2417 unquote (const char *str)
2425 slen = strlen (str);
2429 if (*str != '\'' && *str != '\"')
2432 end = str + slen - 1;
2436 return g_strndup (str + 1, slen - 2);
2440 * mono_assembly_name_parse:
2441 * @name: name to parse
2442 * @aname: the destination assembly name
2444 * Parses an assembly qualified type name and assigns the name,
2445 * version, culture and token to the provided assembly name object.
2447 * Returns: TRUE if the name could be parsed.
2450 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2452 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2456 * mono_assembly_name_new:
2457 * @name: name to parse
2459 * Allocate a new MonoAssemblyName and fill its values from the
2462 * Returns: a newly allocated structure or NULL if there was any failure.
2465 mono_assembly_name_new (const char *name)
2467 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2468 if (mono_assembly_name_parse (name, aname))
2475 mono_assembly_name_get_name (MonoAssemblyName *aname)
2481 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2483 return aname->culture;
2487 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2489 if (aname->public_key_token [0])
2490 return aname->public_key_token;
2495 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2498 *minor = aname->minor;
2500 *build = aname->build;
2502 *revision = aname->revision;
2503 return aname->major;
2506 static MonoAssembly*
2507 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2509 gchar *fullpath = NULL;
2511 const char* direntry;
2512 MonoAssemblyName gac_aname;
2513 gint major=-1, minor=0, build=0, revision=0;
2514 gboolean exact_version;
2516 dirhandle = g_dir_open (basepath, 0, NULL);
2520 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2522 while ((direntry = g_dir_read_name (dirhandle))) {
2523 gboolean match = TRUE;
2525 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2528 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2531 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2532 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2536 if (exact_version) {
2537 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2538 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2540 else if (gac_aname.major < major)
2542 else if (gac_aname.major == major) {
2543 if (gac_aname.minor < minor)
2545 else if (gac_aname.minor == minor) {
2546 if (gac_aname.build < build)
2548 else if (gac_aname.build == build && gac_aname.revision <= revision)
2555 major = gac_aname.major;
2556 minor = gac_aname.minor;
2557 build = gac_aname.build;
2558 revision = gac_aname.revision;
2560 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2563 mono_assembly_name_free (&gac_aname);
2566 g_dir_close (dirhandle);
2568 if (fullpath == NULL)
2571 MonoAssembly *res = mono_assembly_open (fullpath, status);
2578 * mono_assembly_load_with_partial_name:
2579 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2580 * @status: return status code
2582 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2583 * so it might contain a qualified type name, version, culture and token.
2585 * This will load the assembly from the file whose name is derived from the assembly name
2586 * by appending the .dll extension.
2588 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2589 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2590 * if that fails from the GAC.
2592 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2595 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2599 MonoAssemblyName *aname, base_name;
2600 MonoAssemblyName mapped_aname;
2601 gchar *fullname, *gacpath;
2604 memset (&base_name, 0, sizeof (MonoAssemblyName));
2607 if (!mono_assembly_name_parse (name, aname))
2611 * If no specific version has been requested, make sure we load the
2612 * correct version for system assemblies.
2614 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2615 aname = mono_assembly_remap_version (aname, &mapped_aname);
2617 res = mono_assembly_loaded (aname);
2619 mono_assembly_name_free (aname);
2623 res = invoke_assembly_preload_hook (aname, assemblies_path);
2625 res->in_gac = FALSE;
2626 mono_assembly_name_free (aname);
2630 fullname = g_strdup_printf ("%s.dll", aname->name);
2632 if (extra_gac_paths) {
2633 paths = extra_gac_paths;
2634 while (!res && *paths) {
2635 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2636 res = probe_for_partial_name (gacpath, fullname, aname, status);
2645 mono_assembly_name_free (aname);
2649 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2650 res = probe_for_partial_name (gacpath, fullname, aname, status);
2656 MonoDomain *domain = mono_domain_get ();
2657 MonoReflectionAssembly *refasm;
2659 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2660 if (!is_ok (&error)) {
2662 mono_assembly_name_free (aname);
2663 mono_error_cleanup (&error);
2664 if (*status == MONO_IMAGE_OK)
2665 *status = MONO_IMAGE_IMAGE_INVALID;
2669 res = refasm->assembly;
2673 mono_assembly_name_free (aname);
2679 mono_assembly_is_in_gac (const gchar *filename)
2681 const gchar *rootdir;
2685 if (filename == NULL)
2688 for (paths = extra_gac_paths; paths && *paths; paths++) {
2689 if (strstr (*paths, filename) != *paths)
2692 gp = (gchar *) (filename + strlen (*paths));
2693 if (*gp != G_DIR_SEPARATOR)
2696 if (strncmp (gp, "lib", 3))
2699 if (*gp != G_DIR_SEPARATOR)
2702 if (strncmp (gp, "mono", 4))
2705 if (*gp != G_DIR_SEPARATOR)
2708 if (strncmp (gp, "gac", 3))
2711 if (*gp != G_DIR_SEPARATOR)
2717 rootdir = mono_assembly_getrootdir ();
2718 if (strstr (filename, rootdir) != filename)
2721 gp = (gchar *) (filename + strlen (rootdir));
2722 if (*gp != G_DIR_SEPARATOR)
2725 if (strncmp (gp, "mono", 4))
2728 if (*gp != G_DIR_SEPARATOR)
2731 if (strncmp (gp, "gac", 3))
2734 if (*gp != G_DIR_SEPARATOR)
2740 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2743 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2747 if (strstr (aname->name, ".dll")) {
2748 len = strlen (aname->name) - 4;
2749 name = (gchar *)g_malloc (len + 1);
2750 strncpy (name, aname->name, len);
2753 name = g_strdup (aname->name);
2756 culture = g_utf8_strdown (aname->culture, -1);
2758 culture = g_strdup ("");
2760 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2761 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2765 filename = g_strconcat (pname, ".dll", NULL);
2766 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2772 if (extra_gac_paths) {
2773 paths = extra_gac_paths;
2774 while (!image && *paths) {
2775 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2776 "lib", "mono", "gac", subpath, NULL);
2777 image = mono_image_open (fullpath, NULL);
2788 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2789 "mono", "gac", subpath, NULL);
2790 image = mono_image_open (fullpath, NULL);
2797 static MonoAssemblyName*
2798 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2800 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2801 dest_name->major = info->new_version.major;
2802 dest_name->minor = info->new_version.minor;
2803 dest_name->build = info->new_version.build;
2804 dest_name->revision = info->new_version.revision;
2809 /* LOCKING: assembly_binding lock must be held */
2810 static MonoAssemblyBindingInfo*
2811 search_binding_loaded (MonoAssemblyName *aname)
2815 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2816 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2817 if (assembly_binding_maps_name (info, aname))
2824 static inline gboolean
2825 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2827 if (left->major != right->major || left->minor != right->minor ||
2828 left->build != right->build || left->revision != right->revision)
2834 static inline gboolean
2835 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2837 if (left->has_old_version_bottom != right->has_old_version_bottom)
2840 if (left->has_old_version_top != right->has_old_version_top)
2843 if (left->has_new_version != right->has_new_version)
2846 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2849 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2852 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2858 /* LOCKING: assumes all the necessary locks are held */
2860 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2862 MonoAssemblyBindingInfo *info_copy;
2864 MonoAssemblyBindingInfo *info_tmp;
2865 MonoDomain *domain = (MonoDomain*)user_data;
2870 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2871 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2872 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2876 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2877 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2879 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2881 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2883 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2887 get_version_number (int major, int minor)
2889 return major * 256 + minor;
2892 static inline gboolean
2893 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2895 int aname_version_number = get_version_number (aname->major, aname->minor);
2896 if (!info->has_old_version_bottom)
2899 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2902 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2905 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2906 info->major = aname->major;
2907 info->minor = aname->minor;
2912 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2913 static MonoAssemblyBindingInfo*
2914 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2916 MonoAssemblyBindingInfo *info;
2919 if (!domain->assembly_bindings)
2923 for (list = domain->assembly_bindings; list; list = list->next) {
2924 info = (MonoAssemblyBindingInfo *)list->data;
2925 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2931 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2932 info->has_new_version && assembly_binding_maps_name (info, aname))
2933 info->is_valid = TRUE;
2935 info->is_valid = FALSE;
2941 static MonoAssemblyName*
2942 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2945 MonoAssemblyBindingInfo *info, *info2;
2949 if (aname->public_key_token [0] == 0)
2952 domain = mono_domain_get ();
2954 mono_assembly_binding_lock ();
2955 info = search_binding_loaded (aname);
2956 mono_assembly_binding_unlock ();
2959 mono_domain_lock (domain);
2960 info = get_per_domain_assembly_binding_info (domain, aname);
2961 mono_domain_unlock (domain);
2965 if (!check_policy_versions (info, aname))
2968 mono_assembly_bind_version (info, aname, dest_name);
2972 if (domain && domain->setup && domain->setup->configuration_file) {
2973 mono_domain_lock (domain);
2974 if (!domain->assembly_bindings_parsed) {
2975 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2976 /* expect this to succeed because mono_domain_set_options_from_config () did
2977 * the same thing when the domain was created. */
2978 mono_error_assert_ok (&error);
2980 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2982 if (!domain_config_file_path)
2983 domain_config_file_path = domain_config_file_name;
2985 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2986 domain->assembly_bindings_parsed = TRUE;
2987 if (domain_config_file_name != domain_config_file_path)
2988 g_free (domain_config_file_name);
2989 g_free (domain_config_file_path);
2992 info2 = get_per_domain_assembly_binding_info (domain, aname);
2995 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2996 info->name = g_strdup (info2->name);
2997 info->culture = g_strdup (info2->culture);
2998 info->domain_id = domain->domain_id;
3001 mono_domain_unlock (domain);
3005 info = g_new0 (MonoAssemblyBindingInfo, 1);
3006 info->major = aname->major;
3007 info->minor = aname->minor;
3010 if (!info->is_valid) {
3011 ppimage = mono_assembly_load_publisher_policy (aname);
3013 get_publisher_policy_info (ppimage, aname, info);
3014 mono_image_close (ppimage);
3018 /* Define default error value if needed */
3019 if (!info->is_valid) {
3020 info->name = g_strdup (aname->name);
3021 info->culture = g_strdup (aname->culture);
3022 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3025 mono_assembly_binding_lock ();
3026 info2 = search_binding_loaded (aname);
3028 /* This binding was added by another thread
3030 mono_assembly_binding_info_free (info);
3035 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3037 mono_assembly_binding_unlock ();
3039 if (!info->is_valid || !check_policy_versions (info, aname))
3042 mono_assembly_bind_version (info, aname, dest_name);
3047 * mono_assembly_load_from_gac
3049 * @aname: The assembly name object
3051 static MonoAssembly*
3052 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3054 MonoAssembly *result = NULL;
3055 gchar *name, *version, *culture, *fullpath, *subpath;
3060 if (aname->public_key_token [0] == 0) {
3064 if (strstr (aname->name, ".dll")) {
3065 len = strlen (filename) - 4;
3066 name = (gchar *)g_malloc (len + 1);
3067 strncpy (name, aname->name, len);
3070 name = g_strdup (aname->name);
3073 if (aname->culture) {
3074 culture = g_utf8_strdown (aname->culture, -1);
3076 culture = g_strdup ("");
3079 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3080 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3081 aname->minor, aname->build, aname->revision,
3085 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3090 if (extra_gac_paths) {
3091 paths = extra_gac_paths;
3092 while (!result && *paths) {
3093 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3094 result = mono_assembly_open_full (fullpath, status, refonly);
3101 result->in_gac = TRUE;
3106 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3107 "mono", "gac", subpath, NULL);
3108 result = mono_assembly_open_full (fullpath, status, refonly);
3112 result->in_gac = TRUE;
3120 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3123 MonoAssemblyName *aname;
3126 /* g_print ("corlib already loaded\n"); */
3130 // In native client, Corlib is embedded in the executable as static variable corlibData
3131 #if defined(__native_client__)
3132 if (corlibData != NULL && corlibSize != 0) {
3134 /* First "FALSE" instructs mono not to make a copy. */
3135 /* Second "FALSE" says this is not just a ref. */
3136 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3137 if (image == NULL || status != 0)
3138 g_print("mono_image_open_from_data_full failed: %d\n", status);
3139 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3140 if (corlib == NULL || status != 0)
3141 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3147 // A nonstandard preload hook may provide a special mscorlib assembly
3148 aname = mono_assembly_name_new ("mscorlib.dll");
3149 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3150 mono_assembly_name_free (aname);
3153 goto return_corlib_and_facades;
3155 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3156 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3157 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3159 goto return_corlib_and_facades;
3162 /* Normal case: Load corlib from mono/<version> */
3163 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3164 if (assemblies_path) { // Custom assemblies path
3165 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3167 g_free (corlib_file);
3168 goto return_corlib_and_facades;
3171 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3172 g_free (corlib_file);
3174 return_corlib_and_facades:
3175 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3176 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3182 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3183 const char *basedir,
3184 MonoImageOpenStatus *status,
3187 MonoAssembly *result;
3188 char *fullpath, *filename;
3189 MonoAssemblyName maped_aname;
3190 MonoAssemblyName maped_name_pp;
3195 aname = mono_assembly_remap_version (aname, &maped_aname);
3197 /* Reflection only assemblies don't get assembly binding */
3199 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3201 result = mono_assembly_loaded_full (aname, refonly);
3205 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3207 result->in_gac = FALSE;
3211 /* Currently we retrieve the loaded corlib for reflection
3212 * only requests, like a common reflection only assembly
3214 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3215 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3218 len = strlen (aname->name);
3219 for (ext_index = 0; ext_index < 2; ext_index ++) {
3220 ext = ext_index == 0 ? ".dll" : ".exe";
3221 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3222 filename = g_strdup (aname->name);
3223 /* Don't try appending .dll/.exe if it already has one of those extensions */
3226 filename = g_strconcat (aname->name, ext, NULL);
3229 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3236 fullpath = g_build_filename (basedir, filename, NULL);
3237 result = mono_assembly_open_full (fullpath, status, refonly);
3240 result->in_gac = FALSE;
3246 result = load_in_path (filename, default_path, status, refonly);
3248 result->in_gac = FALSE;
3258 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3260 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3263 /* Try a postload search hook */
3264 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3269 * mono_assembly_load_full:
3270 * @aname: A MonoAssemblyName with the assembly name to load.
3271 * @basedir: A directory to look up the assembly at.
3272 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3273 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3275 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3276 * attempts to load the assembly from that directory before probing the standard locations.
3278 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3279 * assembly binding takes place.
3281 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3282 * value pointed by status is updated with an error code.
3285 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3287 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3291 * mono_assembly_load:
3292 * @aname: A MonoAssemblyName with the assembly name to load.
3293 * @basedir: A directory to look up the assembly at.
3294 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3296 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3297 * attempts to load the assembly from that directory before probing the standard locations.
3299 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3300 * value pointed by status is updated with an error code.
3303 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3305 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3309 * mono_assembly_loaded_full:
3310 * @aname: an assembly to look for.
3311 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3313 * This is used to determine if the specified assembly has been loaded
3314 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3315 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3318 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3321 MonoAssemblyName maped_aname;
3323 aname = mono_assembly_remap_version (aname, &maped_aname);
3325 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3331 * mono_assembly_loaded:
3332 * @aname: an assembly to look for.
3334 * This is used to determine if the specified assembly has been loaded
3336 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3337 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3340 mono_assembly_loaded (MonoAssemblyName *aname)
3342 return mono_assembly_loaded_full (aname, FALSE);
3346 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3348 if (assembly == NULL || assembly == REFERENCE_MISSING)
3351 if (assembly_is_dynamic (assembly)) {
3353 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3354 for (i = 0; i < dynimg->image.module_count; ++i)
3355 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3356 mono_dynamic_image_release_gc_roots (dynimg);
3361 * Returns whether mono_assembly_close_finish() must be called as
3362 * well. See comment for mono_image_close_except_pools() for why we
3363 * unload in two steps.
3366 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3369 g_return_val_if_fail (assembly != NULL, FALSE);
3371 if (assembly == REFERENCE_MISSING)
3374 /* Might be 0 already */
3375 if (InterlockedDecrement (&assembly->ref_count) > 0)
3378 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3380 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3382 mono_debug_close_image (assembly->image);
3384 mono_assemblies_lock ();
3385 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3386 mono_assemblies_unlock ();
3388 assembly->image->assembly = NULL;
3390 if (!mono_image_close_except_pools (assembly->image))
3391 assembly->image = NULL;
3393 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3394 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3395 mono_assembly_name_free (fname);
3398 g_slist_free (assembly->friend_assembly_names);
3399 g_free (assembly->basedir);
3401 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3407 mono_assembly_close_finish (MonoAssembly *assembly)
3409 g_assert (assembly && assembly != REFERENCE_MISSING);
3411 if (assembly->image)
3412 mono_image_close_finish (assembly->image);
3414 if (assembly_is_dynamic (assembly)) {
3415 g_free ((char*)assembly->aname.culture);
3422 * mono_assembly_close:
3423 * @assembly: the assembly to release.
3425 * This method releases a reference to the @assembly. The assembly is
3426 * only released when all the outstanding references to it are released.
3429 mono_assembly_close (MonoAssembly *assembly)
3431 if (mono_assembly_close_except_image_pools (assembly))
3432 mono_assembly_close_finish (assembly);
3436 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3439 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3440 mono_error_assert_ok (&error);
3445 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3447 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3452 * mono_assembly_foreach:
3453 * @func: function to invoke for each assembly loaded
3454 * @user_data: data passed to the callback
3456 * Invokes the provided @func callback for each assembly loaded into
3457 * the runtime. The first parameter passed to the callback is the
3458 * `MonoAssembly*`, and the second parameter is the @user_data.
3460 * This is done for all assemblies loaded in the runtime, not just
3461 * those loaded in the current application domain.
3464 mono_assembly_foreach (GFunc func, gpointer user_data)
3469 * We make a copy of the list to avoid calling the callback inside the
3470 * lock, which could lead to deadlocks.
3472 mono_assemblies_lock ();
3473 copy = g_list_copy (loaded_assemblies);
3474 mono_assemblies_unlock ();
3476 g_list_foreach (loaded_assemblies, func, user_data);
3482 * mono_assemblies_cleanup:
3484 * Free all resources used by this module.
3487 mono_assemblies_cleanup (void)
3491 mono_os_mutex_destroy (&assemblies_mutex);
3492 mono_os_mutex_destroy (&assembly_binding_mutex);
3494 for (l = loaded_assembly_bindings; l; l = l->next) {
3495 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3497 mono_assembly_binding_info_free (info);
3500 g_slist_free (loaded_assembly_bindings);
3502 free_assembly_load_hooks ();
3503 free_assembly_search_hooks ();
3504 free_assembly_preload_hooks ();
3507 /*LOCKING takes the assembly_binding lock*/
3509 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3513 mono_assembly_binding_lock ();
3514 iter = &loaded_assembly_bindings;
3517 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3519 if (info->domain_id == domain_id) {
3521 mono_assembly_binding_info_free (info);
3528 mono_assembly_binding_unlock ();
3532 * Holds the assembly of the application, for
3533 * System.Diagnostics.Process::MainModule
3535 static MonoAssembly *main_assembly=NULL;
3538 mono_assembly_set_main (MonoAssembly *assembly)
3540 main_assembly = assembly;
3544 * mono_assembly_get_main:
3546 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3549 mono_assembly_get_main (void)
3551 return (main_assembly);
3555 * mono_assembly_get_image:
3556 * @assembly: The assembly to retrieve the image from
3558 * Returns: the MonoImage associated with this assembly.
3561 mono_assembly_get_image (MonoAssembly *assembly)
3563 return assembly->image;
3567 * mono_assembly_get_name:
3568 * @assembly: The assembly to retrieve the name from
3570 * The returned name's lifetime is the same as @assembly's.
3572 * Returns: the MonoAssemblyName associated with this assembly.
3575 mono_assembly_get_name (MonoAssembly *assembly)
3577 return &assembly->aname;
3581 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3583 bundles = assemblies;
3586 #define MONO_DECLSEC_FORMAT_10 0x3C
3587 #define MONO_DECLSEC_FORMAT_20 0x2E
3588 #define MONO_DECLSEC_FIELD 0x53
3589 #define MONO_DECLSEC_PROPERTY 0x54
3591 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3592 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3593 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3594 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3595 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3598 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3602 case MONO_DECLSEC_PROPERTY:
3604 case MONO_DECLSEC_FIELD:
3606 *abort_decoding = TRUE;
3611 if (*p++ != MONO_TYPE_BOOLEAN) {
3612 *abort_decoding = TRUE;
3616 /* property name length */
3617 len = mono_metadata_decode_value (p, &p);
3619 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3630 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3632 int i, j, num, len, params_len;
3634 if (*p == MONO_DECLSEC_FORMAT_10) {
3635 gsize read, written;
3636 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3638 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3644 if (*p++ != MONO_DECLSEC_FORMAT_20)
3647 /* number of encoded permission attributes */
3648 num = mono_metadata_decode_value (p, &p);
3649 for (i = 0; i < num; ++i) {
3650 gboolean is_valid = FALSE;
3651 gboolean abort_decoding = FALSE;
3653 /* attribute name length */
3654 len = mono_metadata_decode_value (p, &p);
3656 /* We don't really need to fully decode the type. Comparing the name is enough */
3657 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3661 /*size of the params table*/
3662 params_len = mono_metadata_decode_value (p, &p);
3664 const char *params_end = p + params_len;
3666 /* number of parameters */
3667 len = mono_metadata_decode_value (p, &p);
3669 for (j = 0; j < len; ++j) {
3670 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3686 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3689 guint32 cols [MONO_DECL_SECURITY_SIZE];
3693 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3694 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3696 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3698 for (i = 0; i < t->rows; ++i) {
3699 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3700 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3702 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3705 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3706 len = mono_metadata_decode_blob_size (blob, &blob);
3710 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3711 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3716 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);