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.
20 #include "object-internals.h"
21 #include <mono/metadata/loader.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/metadata-internals.h>
24 #include <mono/metadata/profiler-private.h>
25 #include <mono/metadata/class-internals.h>
26 #include <mono/metadata/domain-internals.h>
27 #include <mono/metadata/reflection-internals.h>
28 #include <mono/metadata/mono-endian.h>
29 #include <mono/metadata/mono-debug.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/utils/mono-uri.h>
32 #include <mono/metadata/mono-config.h>
33 #include <mono/metadata/mono-config-dirs.h>
34 #include <mono/utils/mono-digest.h>
35 #include <mono/utils/mono-logger-internals.h>
36 #include <mono/utils/mono-path.h>
37 #include <mono/metadata/reflection.h>
38 #include <mono/metadata/coree.h>
39 #include <mono/metadata/cil-coff.h>
40 #include <mono/utils/mono-io-portability.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-os-mutex.h>
45 #include <sys/types.h>
50 #ifdef PLATFORM_MACOSX
51 #include <mach-o/dyld.h>
54 /* 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 */
56 const char* assembly_name;
57 guint8 version_set_index;
58 const char* new_assembly_name;
59 gboolean only_lower_versions;
62 /* the default search path is empty, the first slot is replaced with the computed value */
70 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
71 static char **assemblies_path = NULL;
73 /* Contains the list of directories that point to auxiliary GACs */
74 static char **extra_gac_paths = NULL;
76 #ifndef DISABLE_ASSEMBLY_REMAPPING
77 /* The list of system assemblies what will be remapped to the running
78 * runtime version. WARNING: this list must be sorted.
79 * The integer number is an index in the MonoRuntimeInfo structure, whose
80 * values can be found in domain.c - supported_runtimes. Look there
81 * to understand what remapping will be made.
83 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
86 static const AssemblyVersionMap framework_assemblies [] = {
88 {"Commons.Xml.Relaxng", 0},
95 {"Microsoft.Build.Engine", 2, NULL, TRUE},
96 {"Microsoft.Build.Framework", 2, NULL, TRUE},
97 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
98 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
99 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
100 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
101 {"Microsoft.VisualBasic", 1},
102 {"Microsoft.VisualC", 1},
104 {"Mono.CompilerServices.SymbolWriter", 0},
106 {"Mono.Data.SybaseClient", 0},
107 {"Mono.Data.Tds", 0},
108 {"Mono.Data.TdsClient", 0},
109 {"Mono.GetOptions", 0},
112 {"Mono.Security", 0},
113 {"Mono.Security.Win32", 0},
115 {"Novell.Directory.Ldap", 0},
118 {"System.ComponentModel.Composition", 2},
119 {"System.ComponentModel.DataAnnotations", 2},
120 {"System.Configuration", 0},
121 {"System.Configuration.Install", 0},
124 {"System.Data.Linq", 2},
125 {"System.Data.OracleClient", 0},
126 {"System.Data.Services", 2},
127 {"System.Data.Services.Client", 2},
128 {"System.Data.SqlXml", 0},
129 {"System.Design", 0},
130 {"System.DirectoryServices", 0},
131 {"System.Drawing", 0},
132 {"System.Drawing.Design", 0},
133 {"System.EnterpriseServices", 0},
134 {"System.IdentityModel", 3},
135 {"System.IdentityModel.Selectors", 3},
136 {"System.Management", 0},
137 {"System.Messaging", 0},
139 {"System.Runtime.Remoting", 0},
140 {"System.Runtime.Serialization", 3},
141 {"System.Runtime.Serialization.Formatters.Soap", 0},
142 {"System.Security", 0},
143 {"System.ServiceModel", 3},
144 {"System.ServiceModel.Web", 2},
145 {"System.ServiceProcess", 0},
146 {"System.Transactions", 0},
148 {"System.Web.Abstractions", 2},
149 {"System.Web.DynamicData", 2},
150 {"System.Web.Extensions", 2},
151 {"System.Web.Mobile", 0},
152 {"System.Web.Routing", 2},
153 {"System.Web.Services", 0},
154 {"System.Windows.Forms", 0},
156 {"System.Xml.Linq", 2},
163 * keeps track of loaded assemblies
165 static GList *loaded_assemblies = NULL;
166 static MonoAssembly *corlib;
168 #if defined(__native_client__)
170 /* On Native Client, allow mscorlib to be loaded from memory */
171 /* instead of loaded off disk. If these are not set, default */
172 /* mscorlib loading will take place */
174 /* NOTE: If mscorlib data is passed to mono in this way then */
175 /* it needs to remain allocated during the use of mono. */
177 static void *corlibData = NULL;
178 static size_t corlibSize = 0;
181 mono_set_corlib_data (void *data, size_t size)
189 static char* unquote (const char *str);
191 /* This protects loaded_assemblies and image->references */
192 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
193 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
194 static mono_mutex_t assemblies_mutex;
196 /* If defined, points to the bundled assembly information */
197 const MonoBundledAssembly **bundles;
199 static mono_mutex_t assembly_binding_mutex;
201 /* Loaded assembly binding info */
202 static GSList *loaded_assembly_bindings = NULL;
204 /* Class lazy loading functions */
205 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
208 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
210 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
212 mono_assembly_is_in_gac (const gchar *filanem);
215 encode_public_tok (const guchar *token, gint32 len)
217 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
221 res = (gchar *)g_malloc (len * 2 + 1);
222 for (i = 0; i < len; i++) {
223 res [i * 2] = allowed [token [i] >> 4];
224 res [i * 2 + 1] = allowed [token [i] & 0xF];
231 * mono_public_tokens_are_equal:
232 * @pubt1: first public key token
233 * @pubt2: second public key token
235 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
239 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
241 return memcmp (pubt1, pubt2, 16) == 0;
245 * mono_set_assemblies_path:
246 * @path: list of paths that contain directories where Mono will look for assemblies
248 * Use this method to override the standard assembly lookup system and
249 * override any assemblies coming from the GAC. This is the method
250 * that supports the MONO_PATH variable.
252 * Notice that MONO_PATH and this method are really a very bad idea as
253 * it prevents the GAC from working and it prevents the standard
254 * resolution mechanisms from working. Nonetheless, for some debugging
255 * situations and bootstrapping setups, this is useful to have.
258 mono_set_assemblies_path (const char* path)
260 char **splitted, **dest;
262 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
264 g_strfreev (assemblies_path);
265 assemblies_path = dest = splitted;
267 char *tmp = *splitted;
269 *dest++ = mono_path_canonicalize (tmp);
275 if (g_getenv ("MONO_DEBUG") == NULL)
278 splitted = assemblies_path;
280 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
281 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
287 /* Native Client can't get this info from an environment variable so */
288 /* it's passed in to the runtime, or set manually by embedding code. */
289 #ifdef __native_client__
290 char* nacl_mono_path = NULL;
294 check_path_env (void)
297 path = g_getenv ("MONO_PATH");
298 #ifdef __native_client__
300 path = nacl_mono_path;
302 if (!path || assemblies_path != NULL)
305 mono_set_assemblies_path(path);
309 check_extra_gac_path_env (void) {
311 char **splitted, **dest;
313 path = g_getenv ("MONO_GAC_PREFIX");
317 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
319 g_strfreev (extra_gac_paths);
320 extra_gac_paths = dest = splitted;
328 if (g_getenv ("MONO_DEBUG") == NULL)
332 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
333 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
340 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
342 if (!info || !info->name)
345 if (strcmp (info->name, aname->name))
348 if (info->major != aname->major || info->minor != aname->minor)
351 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
354 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
357 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
364 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
370 g_free (info->culture);
374 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
377 guint32 cols [MONO_MANIFEST_SIZE];
378 const gchar *filename;
379 gchar *subpath, *fullpath;
381 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
382 /* MS Impl. accepts policy assemblies with more than
383 * one manifest resource, and only takes the first one */
385 binding_info->is_valid = FALSE;
389 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
390 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
391 binding_info->is_valid = FALSE;
395 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
396 g_assert (filename != NULL);
398 subpath = g_path_get_dirname (image->name);
399 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
400 mono_config_parse_publisher_policy (fullpath, binding_info);
404 /* Define the optional elements/attributes before checking */
405 if (!binding_info->culture)
406 binding_info->culture = g_strdup ("");
408 /* Check that the most important elements/attributes exist */
409 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
410 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
411 mono_assembly_binding_info_free (binding_info);
412 binding_info->is_valid = FALSE;
416 binding_info->is_valid = TRUE;
420 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
422 if (v->major > aname->major)
424 else if (v->major < aname->major)
427 if (v->minor > aname->minor)
429 else if (v->minor < aname->minor)
432 if (v->build > aname->build)
434 else if (v->build < aname->build)
437 if (v->revision > aname->revision)
439 else if (v->revision < aname->revision)
446 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
451 /* If has_old_version_top doesn't exist, we don't have an interval */
452 if (!info->has_old_version_top) {
453 if (compare_versions (&info->old_version_bottom, name) == 0)
459 /* Check that the version defined by name is valid for the interval */
460 if (compare_versions (&info->old_version_top, name) < 0)
463 /* We should be greater or equal than the small version */
464 if (compare_versions (&info->old_version_bottom, name) > 0)
471 * mono_assembly_names_equal:
473 * @r: second assembly.
475 * Compares two MonoAssemblyNames and returns whether they are equal.
477 * This compares the names, the cultures, the release version and their
480 * Returns: TRUE if both assembly names are equal.
483 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
485 if (!l->name || !r->name)
488 if (strcmp (l->name, r->name))
491 if (l->culture && r->culture && strcmp (l->culture, r->culture))
494 if (l->major != r->major || l->minor != r->minor ||
495 l->build != r->build || l->revision != r->revision)
496 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)))
499 if (!l->public_key_token [0] || !r->public_key_token [0])
502 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
508 static MonoAssembly *
509 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
513 MonoAssembly *result;
515 for (i = 0; search_path [i]; ++i) {
516 fullpath = g_build_filename (search_path [i], basename, NULL);
517 result = mono_assembly_open_full (fullpath, status, refonly);
526 * mono_assembly_setrootdir:
527 * @root_dir: The pathname of the root directory where we will locate assemblies
529 * This routine sets the internal default root directory for looking up
532 * This is used by Windows installations to compute dynamically the
533 * place where the Mono assemblies are located.
537 mono_assembly_setrootdir (const char *root_dir)
540 * Override the MONO_ASSEMBLIES directory configured at compile time.
542 /* Leak if called more than once */
543 default_path [0] = g_strdup (root_dir);
547 * mono_assembly_getrootdir:
549 * Obtains the root directory used for looking up assemblies.
551 * Returns: a string with the directory, this string should not be freed.
553 G_CONST_RETURN gchar *
554 mono_assembly_getrootdir (void)
556 return default_path [0];
561 * @assembly_dir: the base directory for assemblies
562 * @config_dir: the base directory for configuration files
564 * This routine is used internally and by developers embedding
565 * the runtime into their own applications.
567 * There are a number of cases to consider: Mono as a system-installed
568 * package that is available on the location preconfigured or Mono in
569 * a relocated location.
571 * If you are using a system-installed Mono, you can pass NULL
572 * to both parameters. If you are not, you should compute both
573 * directory values and call this routine.
575 * The values for a given PREFIX are:
577 * assembly_dir: PREFIX/lib
578 * config_dir: PREFIX/etc
580 * Notice that embedders that use Mono in a relocated way must
581 * compute the location at runtime, as they will be in control
582 * of where Mono is installed.
585 mono_set_dirs (const char *assembly_dir, const char *config_dir)
587 if (assembly_dir == NULL)
588 assembly_dir = mono_config_get_assemblies_dir ();
589 if (config_dir == NULL)
590 config_dir = mono_config_get_cfg_dir ();
591 mono_assembly_setrootdir (assembly_dir);
592 mono_set_config_dir (config_dir);
598 compute_base (char *path)
600 char *p = strrchr (path, '/');
604 /* Not a well known Mono executable, we are embedded, cant guess the base */
605 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
609 p = strrchr (path, '/');
613 if (strcmp (p, "/bin") != 0)
622 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
625 static G_GNUC_UNUSED void
629 char *config, *lib, *mono;
634 * Only /usr prefix is treated specially
636 bindir = mono_config_get_bin_dir ();
638 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
643 config = g_build_filename (base, "etc", NULL);
644 lib = g_build_filename (base, "lib", NULL);
645 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
646 if (stat (mono, &buf) == -1)
649 mono_set_dirs (lib, config);
657 #endif /* HOST_WIN32 */
662 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
663 * this auto-detects the prefix where Mono was installed.
666 mono_set_rootdir (void)
668 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
669 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
672 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
676 * _NSGetExecutablePath may return -1 to indicate buf is not large
677 * enough, but we ignore that case to avoid having to do extra dynamic
678 * allocation for the path and hope that 4096 is enough - this is
679 * ok in the Linux/Solaris case below at least...
683 guint buf_size = sizeof (buf);
686 if (_NSGetExecutablePath (buf, &buf_size) == 0)
687 name = g_strdup (buf);
696 resolvedname = mono_path_resolve_symlinks (name);
698 bindir = g_path_get_dirname (resolvedname);
699 installdir = g_path_get_dirname (bindir);
700 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
702 config = g_build_filename (root, "..", "etc", NULL);
704 mono_set_dirs (root, config);
706 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
707 mono_set_dirs (root, config);
717 g_free (resolvedname);
718 #elif defined(DISABLE_MONO_AUTODETECTION)
726 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
734 /* Solaris 10 style */
735 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
736 s = readlink (str, buf, sizeof (buf)-1);
748 * mono_assemblies_init:
750 * Initialize global variables used by this module.
753 mono_assemblies_init (void)
756 * Initialize our internal paths if we have not been initialized yet.
757 * This happens when embedders use Mono.
759 if (mono_assembly_getrootdir () == NULL)
763 check_extra_gac_path_env ();
765 mono_os_mutex_init_recursive (&assemblies_mutex);
766 mono_os_mutex_init (&assembly_binding_mutex);
770 mono_assembly_binding_lock (void)
772 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
776 mono_assembly_binding_unlock (void)
778 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
782 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
784 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
785 guint32 cols [MONO_ASSEMBLY_SIZE];
786 gint32 machine, flags;
791 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
794 aname->hash_value = NULL;
795 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
796 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
797 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
798 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
799 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
800 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
801 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
802 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
803 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
804 guchar* token = (guchar *)g_malloc (8);
809 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
810 len = mono_metadata_decode_blob_size (pkey, &pkey);
811 aname->public_key = (guchar*)pkey;
813 mono_digest_get_public_token (token, aname->public_key, len);
814 encoded = encode_public_tok (token, 8);
815 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
821 aname->public_key = NULL;
822 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
825 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
826 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
829 aname->public_key = 0;
831 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
832 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
834 case COFF_MACHINE_I386:
835 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
836 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
837 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
838 else if ((flags & 0x70) == 0x70)
839 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
841 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
843 case COFF_MACHINE_IA64:
844 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
846 case COFF_MACHINE_AMD64:
847 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
849 case COFF_MACHINE_ARM:
850 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
860 * mono_stringify_assembly_name:
861 * @aname: the assembly name.
863 * Convert @aname into its string format. The returned string is dynamically
864 * allocated and should be freed by the caller.
866 * Returns: a newly allocated string with a string representation of
870 mono_stringify_assembly_name (MonoAssemblyName *aname)
872 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
874 return g_strdup_printf (
875 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
876 quote, aname->name, quote,
877 aname->major, aname->minor, aname->build, aname->revision,
878 aname->culture && *aname->culture? aname->culture: "neutral",
879 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
880 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
884 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
886 const gchar *public_tok;
889 public_tok = mono_metadata_blob_heap (image, key_index);
890 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
892 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
894 mono_digest_get_public_token (token, (guchar*)public_tok, len);
895 return encode_public_tok (token, 8);
898 return encode_public_tok ((guchar*)public_tok, len);
902 * mono_assembly_addref:
903 * @assemnly: the assembly to reference
905 * This routine increments the reference count on a MonoAssembly.
906 * The reference count is reduced every time the method mono_assembly_close() is
910 mono_assembly_addref (MonoAssembly *assembly)
912 InterlockedIncrement (&assembly->ref_count);
916 * CAUTION: This table must be kept in sync with
917 * ivkm/reflect/Fusion.cs
920 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
921 #define WINFX_KEY "31bf3856ad364e35"
922 #define ECMA_KEY "b77a5c561934e089"
923 #define MSFINAL_KEY "b03f5f7f11d50a3a"
924 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
932 static KeyRemapEntry key_remap_table[] = {
933 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
934 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
935 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
936 { "System", SILVERLIGHT_KEY, ECMA_KEY },
937 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
938 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
939 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
940 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
941 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
942 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
943 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
944 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
945 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
946 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
947 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
948 { "System.Numerics", WINFX_KEY, ECMA_KEY },
949 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
950 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
951 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
952 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
953 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
954 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
955 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
956 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
957 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
958 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
959 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
960 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
961 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
965 remap_keys (MonoAssemblyName *aname)
968 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
969 const KeyRemapEntry *entry = &key_remap_table [i];
971 if (strcmp (aname->name, entry->name) ||
972 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
975 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
977 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
978 "Remapped public key token of retargetable assembly %s from %s to %s",
979 aname->name, entry->from, entry->to);
984 static MonoAssemblyName *
985 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
987 const MonoRuntimeInfo *current_runtime;
988 int pos, first, last;
990 if (aname->name == NULL) return aname;
992 current_runtime = mono_get_runtime_info ();
994 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
995 const AssemblyVersionSet* vset;
997 /* Remap to current runtime */
998 vset = ¤t_runtime->version_sets [0];
1000 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1001 dest_aname->major = vset->major;
1002 dest_aname->minor = vset->minor;
1003 dest_aname->build = vset->build;
1004 dest_aname->revision = vset->revision;
1005 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1007 /* Remap assembly name */
1008 if (!strcmp (aname->name, "System.Net"))
1009 dest_aname->name = g_strdup ("System");
1011 remap_keys (dest_aname);
1013 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1014 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1016 aname->major, aname->minor, aname->build, aname->revision,
1018 vset->major, vset->minor, vset->build, vset->revision
1024 #ifndef DISABLE_ASSEMBLY_REMAPPING
1026 last = G_N_ELEMENTS (framework_assemblies) - 1;
1028 while (first <= last) {
1030 pos = first + (last - first) / 2;
1031 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1033 const AssemblyVersionSet* vset;
1034 int index = framework_assemblies[pos].version_set_index;
1035 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1036 vset = ¤t_runtime->version_sets [index];
1038 if (aname->major == vset->major && aname->minor == vset->minor &&
1039 aname->build == vset->build && aname->revision == vset->revision)
1042 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1045 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1046 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1047 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1049 aname->major, aname->minor, aname->build, aname->revision,
1050 vset->major, vset->minor, vset->build, vset->revision
1053 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1054 dest_aname->major = vset->major;
1055 dest_aname->minor = vset->minor;
1056 dest_aname->build = vset->build;
1057 dest_aname->revision = vset->revision;
1058 if (framework_assemblies[pos].new_assembly_name != NULL) {
1059 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1060 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1061 "The assembly name %s was remapped to %s",
1066 } else if (res < 0) {
1078 * mono_assembly_get_assemblyref:
1079 * @image: pointer to the MonoImage to extract the information from.
1080 * @index: index to the assembly reference in the image.
1081 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1083 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1086 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1089 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1092 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1094 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1096 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1097 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1098 aname->hash_value = hash;
1099 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1100 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1101 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1102 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1103 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1104 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1105 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1107 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1108 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1109 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1112 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1117 mono_assembly_load_reference (MonoImage *image, int index)
1119 MonoAssembly *reference;
1120 MonoAssemblyName aname;
1121 MonoImageOpenStatus status;
1124 * image->references is shared between threads, so we need to access
1125 * it inside a critical section.
1127 mono_assemblies_lock ();
1128 if (!image->references) {
1129 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1131 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1132 image->nreferences = t->rows;
1134 reference = image->references [index];
1135 mono_assemblies_unlock ();
1139 mono_assembly_get_assemblyref (image, index, &aname);
1141 if (image->assembly && image->assembly->ref_only) {
1142 /* We use the loaded corlib */
1143 if (!strcmp (aname.name, "mscorlib"))
1144 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1146 reference = mono_assembly_loaded_full (&aname, TRUE);
1148 /* Try a postload search hook */
1149 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1153 * Here we must advice that the error was due to
1154 * a non loaded reference using the ReflectionOnly api
1157 reference = (MonoAssembly *)REFERENCE_MISSING;
1159 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1160 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1161 * accordingly, it would fail on the MS runtime before).
1162 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1163 * example bug-349190.2.cs and who knows how much more code in the wild.
1165 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1166 if (!reference && image->assembly)
1167 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1170 if (reference == NULL){
1173 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1174 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 : "" );
1175 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1176 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1177 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1178 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1179 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1180 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1182 extra_msg = g_strdup ("");
1185 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1186 " Assembly: %s (assemblyref_index=%d)\n"
1187 " Version: %d.%d.%d.%d\n"
1188 " Public Key: %s\n%s",
1189 image->name, aname.name, index,
1190 aname.major, aname.minor, aname.build, aname.revision,
1191 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1195 mono_assemblies_lock ();
1196 if (reference == NULL) {
1197 /* Flag as not found */
1198 reference = (MonoAssembly *)REFERENCE_MISSING;
1201 if (!image->references [index]) {
1202 if (reference != REFERENCE_MISSING){
1203 mono_assembly_addref (reference);
1204 if (image->assembly)
1205 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1206 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1208 if (image->assembly)
1209 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1210 image->assembly->aname.name, image->assembly);
1213 image->references [index] = reference;
1215 mono_assemblies_unlock ();
1217 if (image->references [index] != reference) {
1218 /* Somebody loaded it before us */
1219 mono_assembly_close (reference);
1224 * mono_assembly_load_references:
1227 * @deprecated: There is no reason to use this method anymore, it does nothing
1229 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1232 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1234 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1235 *status = MONO_IMAGE_OK;
1238 typedef struct AssemblyLoadHook AssemblyLoadHook;
1239 struct AssemblyLoadHook {
1240 AssemblyLoadHook *next;
1241 MonoAssemblyLoadFunc func;
1245 AssemblyLoadHook *assembly_load_hook = NULL;
1248 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1250 AssemblyLoadHook *hook;
1252 for (hook = assembly_load_hook; hook; hook = hook->next) {
1253 hook->func (ass, hook->user_data);
1258 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1260 AssemblyLoadHook *hook;
1262 g_return_if_fail (func != NULL);
1264 hook = g_new0 (AssemblyLoadHook, 1);
1266 hook->user_data = user_data;
1267 hook->next = assembly_load_hook;
1268 assembly_load_hook = hook;
1272 free_assembly_load_hooks (void)
1274 AssemblyLoadHook *hook, *next;
1276 for (hook = assembly_load_hook; hook; hook = next) {
1282 typedef struct AssemblySearchHook AssemblySearchHook;
1283 struct AssemblySearchHook {
1284 AssemblySearchHook *next;
1285 MonoAssemblySearchFunc func;
1291 AssemblySearchHook *assembly_search_hook = NULL;
1293 static MonoAssembly*
1294 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1296 AssemblySearchHook *hook;
1298 for (hook = assembly_search_hook; hook; hook = hook->next) {
1299 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1302 * A little explanation is in order here.
1304 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1305 * The embedding API exposes a search hook that doesn't take such argument.
1307 * The original fix would call the default search hook before all the registered ones and pass
1308 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1309 * rely on. Which is the ordering between user hooks and the default runtime hook.
1311 * Registering the hook after mono_jit_init would let your hook run before the default one and
1312 * when using it to handle non standard app layouts this could save your app from a massive amount
1313 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1314 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1316 * So what's the fix? We register the default hook using regular means and special case it when iterating
1317 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1320 if (hook->func == (void*)mono_domain_assembly_postload_search)
1321 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1323 ass = hook->func (aname, hook->user_data);
1333 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1335 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1339 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1341 AssemblySearchHook *hook;
1343 g_return_if_fail (func != NULL);
1345 hook = g_new0 (AssemblySearchHook, 1);
1347 hook->user_data = user_data;
1348 hook->refonly = refonly;
1349 hook->postload = postload;
1350 hook->next = assembly_search_hook;
1351 assembly_search_hook = hook;
1355 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1357 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1361 free_assembly_search_hooks (void)
1363 AssemblySearchHook *hook, *next;
1365 for (hook = assembly_search_hook; hook; hook = next) {
1372 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1374 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1378 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1380 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1384 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1386 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1389 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1390 struct AssemblyPreLoadHook {
1391 AssemblyPreLoadHook *next;
1392 MonoAssemblyPreLoadFunc func;
1396 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1397 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1399 static MonoAssembly *
1400 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1402 AssemblyPreLoadHook *hook;
1403 MonoAssembly *assembly;
1405 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1406 assembly = hook->func (aname, assemblies_path, hook->user_data);
1407 if (assembly != NULL)
1414 static MonoAssembly *
1415 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1417 AssemblyPreLoadHook *hook;
1418 MonoAssembly *assembly;
1420 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1421 assembly = hook->func (aname, assemblies_path, hook->user_data);
1422 if (assembly != NULL)
1430 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1432 AssemblyPreLoadHook *hook;
1434 g_return_if_fail (func != NULL);
1436 hook = g_new0 (AssemblyPreLoadHook, 1);
1438 hook->user_data = user_data;
1439 hook->next = assembly_preload_hook;
1440 assembly_preload_hook = hook;
1444 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1446 AssemblyPreLoadHook *hook;
1448 g_return_if_fail (func != NULL);
1450 hook = g_new0 (AssemblyPreLoadHook, 1);
1452 hook->user_data = user_data;
1453 hook->next = assembly_refonly_preload_hook;
1454 assembly_refonly_preload_hook = hook;
1458 free_assembly_preload_hooks (void)
1460 AssemblyPreLoadHook *hook, *next;
1462 for (hook = assembly_preload_hook; hook; hook = next) {
1467 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1474 absolute_dir (const gchar *filename)
1485 if (g_path_is_absolute (filename)) {
1486 part = g_path_get_dirname (filename);
1487 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1492 cwd = g_get_current_dir ();
1493 mixed = g_build_filename (cwd, filename, NULL);
1494 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1499 for (i = 0; (part = parts [i]) != NULL; i++) {
1500 if (!strcmp (part, "."))
1503 if (!strcmp (part, "..")) {
1504 if (list && list->next) /* Don't remove root */
1505 list = g_list_delete_link (list, list);
1507 list = g_list_prepend (list, part);
1511 result = g_string_new ("");
1512 list = g_list_reverse (list);
1514 /* Ignores last data pointer, which should be the filename */
1515 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1517 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1522 g_string_free (result, FALSE);
1527 return g_strdup (".");
1534 * mono_assembly_open_from_bundle:
1535 * @filename: Filename requested
1536 * @status: return status code
1538 * This routine tries to open the assembly specified by `filename' from the
1539 * defined bundles, if found, returns the MonoImage for it, if not found
1543 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1547 MonoImage *image = NULL;
1550 * we do a very simple search for bundled assemblies: it's not a general
1551 * purpose assembly loading mechanism.
1557 name = g_path_get_basename (filename);
1559 mono_assemblies_lock ();
1560 for (i = 0; !image && bundles [i]; ++i) {
1561 if (strcmp (bundles [i]->name, name) == 0) {
1562 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1566 mono_assemblies_unlock ();
1568 mono_image_addref (image);
1569 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
1578 * mono_assemblies_open_full:
1579 * @filename: the file to load
1580 * @status: return status code
1581 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1583 * This loads an assembly from the specified @filename. The @filename allows
1584 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1585 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1586 * is treated as a local path.
1588 * First, an attempt is made to load the assembly from the bundled executable (for those
1589 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1590 * assembly has been registered as an embedded assembly). If this is not the case, then
1591 * the assembly is loaded from disk using `api:mono_image_open_full`.
1593 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1594 * the assembly is made.
1596 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1597 * the `System.Reflection` API.
1599 * Returns: NULL on error, with the @status set to an error code, or a pointer
1603 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1607 MonoImageOpenStatus def_status;
1610 gboolean loaded_from_bundle;
1612 g_return_val_if_fail (filename != NULL, NULL);
1615 status = &def_status;
1616 *status = MONO_IMAGE_OK;
1618 if (strncmp (filename, "file://", 7) == 0) {
1619 GError *error = NULL;
1620 gchar *uri = (gchar *) filename;
1624 * MS allows file://c:/... and fails on file://localhost/c:/...
1625 * They also throw an IndexOutOfRangeException if "file://"
1628 uri = g_strdup_printf ("file:///%s", uri + 7);
1631 uri = mono_escape_uri_string (tmpuri);
1632 fname = g_filename_from_uri (uri, NULL, &error);
1635 if (tmpuri != filename)
1638 if (error != NULL) {
1639 g_warning ("%s\n", error->message);
1640 g_error_free (error);
1641 fname = g_strdup (filename);
1644 fname = g_strdup (filename);
1647 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1648 "Assembly Loader probing location: '%s'.", fname);
1651 if (!mono_assembly_is_in_gac (fname)) {
1653 new_fname = mono_make_shadow_copy (fname, &error);
1654 if (!is_ok (&error)) {
1655 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1656 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1657 mono_error_cleanup (&error);
1658 *status = MONO_IMAGE_IMAGE_INVALID;
1663 if (new_fname && new_fname != fname) {
1666 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1667 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1672 // If VM built with mkbundle
1673 loaded_from_bundle = FALSE;
1674 if (bundles != NULL) {
1675 image = mono_assembly_open_from_bundle (fname, status, refonly);
1676 loaded_from_bundle = image != NULL;
1680 image = mono_image_open_full (fname, status, refonly);
1683 if (*status == MONO_IMAGE_OK)
1684 *status = MONO_IMAGE_ERROR_ERRNO;
1689 if (image->assembly) {
1690 /* Already loaded by another appdomain */
1691 mono_assembly_invoke_load_hook (image->assembly);
1692 mono_image_close (image);
1694 return image->assembly;
1697 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1700 if (!loaded_from_bundle)
1701 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1702 "Assembly Loader loaded assembly from location: '%s'.", filename);
1704 mono_config_for_assembly (ass->image);
1707 /* Clear the reference added by mono_image_open */
1708 mono_image_close (image);
1716 free_item (gpointer val, gpointer user_data)
1722 * mono_assembly_load_friends:
1725 * Load the list of friend assemblies that are allowed to access
1726 * the assembly's internal types and members. They are stored as assembly
1727 * names in custom attributes.
1729 * This is an internal method, we need this because when we load mscorlib
1730 * we do not have the internals visible cattr loaded yet,
1731 * so we need to load these after we initialize the runtime.
1733 * LOCKING: Acquires the assemblies lock plus the loader lock.
1736 mono_assembly_load_friends (MonoAssembly* ass)
1740 MonoCustomAttrInfo* attrs;
1743 if (ass->friend_assembly_names_inited)
1746 attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1747 mono_error_assert_ok (&error);
1749 mono_assemblies_lock ();
1750 ass->friend_assembly_names_inited = TRUE;
1751 mono_assemblies_unlock ();
1755 mono_assemblies_lock ();
1756 if (ass->friend_assembly_names_inited) {
1757 mono_assemblies_unlock ();
1760 mono_assemblies_unlock ();
1764 * We build the list outside the assemblies lock, the worse that can happen
1765 * is that we'll need to free the allocated list.
1767 for (i = 0; i < attrs->num_attrs; ++i) {
1768 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1769 MonoAssemblyName *aname;
1771 /* Do some sanity checking */
1772 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1774 if (attr->data_size < 4)
1776 data = (const char*)attr->data;
1777 /* 0xFF means null string, see custom attr format */
1778 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1780 mono_metadata_decode_value (data + 2, &data);
1781 aname = g_new0 (MonoAssemblyName, 1);
1782 /*g_print ("friend ass: %s\n", data);*/
1783 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1784 list = g_slist_prepend (list, aname);
1789 mono_custom_attrs_free (attrs);
1791 mono_assemblies_lock ();
1792 if (ass->friend_assembly_names_inited) {
1793 mono_assemblies_unlock ();
1794 g_slist_foreach (list, free_item, NULL);
1795 g_slist_free (list);
1798 ass->friend_assembly_names = list;
1800 /* Because of the double checked locking pattern above */
1801 mono_memory_barrier ();
1802 ass->friend_assembly_names_inited = TRUE;
1803 mono_assemblies_unlock ();
1807 * mono_assembly_open:
1808 * @filename: Opens the assembly pointed out by this name
1809 * @status: return status code
1811 * This loads an assembly from the specified @filename. The @filename allows
1812 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1813 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1814 * is treated as a local path.
1816 * First, an attempt is made to load the assembly from the bundled executable (for those
1817 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1818 * assembly has been registered as an embedded assembly). If this is not the case, then
1819 * the assembly is loaded from disk using `api:mono_image_open_full`.
1821 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1822 * the assembly is made.
1824 * Return: a pointer to the MonoAssembly if @filename contains a valid
1825 * assembly or NULL on error. Details about the error are stored in the
1829 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1831 return mono_assembly_open_full (filename, status, FALSE);
1835 * mono_assembly_load_from_full:
1836 * @image: Image to load the assembly from
1837 * @fname: assembly name to associate with the assembly
1838 * @status: returns the status condition
1839 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1841 * If the provided @image has an assembly reference, it will process the given
1842 * image as an assembly with the given name.
1844 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1846 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1847 * set to #MONO_IMAGE_OK; or NULL on error.
1849 * If there is an error loading the assembly the @status will indicate the
1850 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1851 * image did not contain an assembly reference table.
1854 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1855 MonoImageOpenStatus *status, gboolean refonly)
1857 MonoAssembly *ass, *ass2;
1860 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1861 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1862 *status = MONO_IMAGE_IMAGE_INVALID;
1866 #if defined (HOST_WIN32)
1871 tmp_fn = g_strdup (fname);
1872 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1873 if (tmp_fn [i] == '/')
1877 base_dir = absolute_dir (tmp_fn);
1881 base_dir = absolute_dir (fname);
1885 * Create assembly struct, and enter it into the assembly cache
1887 ass = g_new0 (MonoAssembly, 1);
1888 ass->basedir = base_dir;
1889 ass->ref_only = refonly;
1892 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1894 mono_assembly_fill_assembly_name (image, &ass->aname);
1896 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1897 // MS.NET doesn't support loading other mscorlibs
1900 mono_image_addref (mono_defaults.corlib);
1901 *status = MONO_IMAGE_OK;
1902 return mono_defaults.corlib->assembly;
1905 /* Add a non-temporary reference because of ass->image */
1906 mono_image_addref (image);
1908 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);
1911 * The load hooks might take locks so we can't call them while holding the
1914 if (ass->aname.name) {
1915 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1919 mono_image_close (image);
1920 *status = MONO_IMAGE_OK;
1925 mono_assemblies_lock ();
1927 if (image->assembly) {
1929 * This means another thread has already loaded the assembly, but not yet
1930 * called the load hooks so the search hook can't find the assembly.
1932 mono_assemblies_unlock ();
1933 ass2 = image->assembly;
1936 mono_image_close (image);
1937 *status = MONO_IMAGE_OK;
1941 image->assembly = ass;
1943 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1944 mono_assemblies_unlock ();
1947 if (image->is_module_handle)
1948 mono_image_fixup_vtable (image);
1951 mono_assembly_invoke_load_hook (ass);
1953 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1959 * mono_assembly_load_from:
1960 * @image: Image to load the assembly from
1961 * @fname: assembly name to associate with the assembly
1962 * @status: return status code
1964 * If the provided @image has an assembly reference, it will process the given
1965 * image as an assembly with the given name.
1967 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1969 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
1970 * @refonly parameter set to FALSE.
1971 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1972 * set to #MONO_IMAGE_OK; or NULL on error.
1974 * If there is an error loading the assembly the @status will indicate the
1975 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1976 * image did not contain an assembly reference table.
1980 mono_assembly_load_from (MonoImage *image, const char *fname,
1981 MonoImageOpenStatus *status)
1983 return mono_assembly_load_from_full (image, fname, status, FALSE);
1987 * mono_assembly_name_free:
1988 * @aname: assembly name to free
1990 * Frees the provided assembly name object.
1991 * (it does not frees the object itself, only the name members).
1994 mono_assembly_name_free (MonoAssemblyName *aname)
1999 g_free ((void *) aname->name);
2000 g_free ((void *) aname->culture);
2001 g_free ((void *) aname->hash_value);
2002 g_free ((guint8*) aname->public_key);
2006 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2009 gchar header [16], val, *arr;
2010 gint i, j, offset, bitlen, keylen, pkeylen;
2012 keylen = strlen (key) >> 1;
2016 /* allow the ECMA standard key */
2017 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2019 *pubkey = g_strdup (key);
2025 val = g_ascii_xdigit_value (key [0]) << 4;
2026 val |= g_ascii_xdigit_value (key [1]);
2031 val = g_ascii_xdigit_value (key [24]);
2032 val |= g_ascii_xdigit_value (key [25]);
2044 /* We need the first 16 bytes
2045 * to check whether this key is valid or not */
2046 pkeylen = strlen (pkey) >> 1;
2050 for (i = 0, j = 0; i < 16; i++) {
2051 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2052 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2055 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2056 header [1] != 0x02 || /* Version (0x02) */
2057 header [2] != 0x00 || /* Reserved (word) */
2058 header [3] != 0x00 ||
2059 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2062 /* Based on this length, we _should_ be able to know if the length is right */
2063 bitlen = read32 (header + 12) >> 3;
2064 if ((bitlen + 16 + 4) != pkeylen)
2067 /* parsing is OK and the public key itself is not requested back */
2071 /* Encode the size of the blob */
2073 if (keylen <= 127) {
2074 arr = (gchar *)g_malloc (keylen + 1);
2075 arr [offset++] = keylen;
2077 arr = (gchar *)g_malloc (keylen + 2);
2078 arr [offset++] = 0x80; /* 10bs */
2079 arr [offset++] = keylen;
2082 for (i = offset, j = 0; i < keylen + offset; i++) {
2083 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2084 arr [i] |= g_ascii_xdigit_value (key [j++]);
2093 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)
2095 gint major, minor, build, revision;
2098 gchar *pkey, *pkeyptr, *encoded, tok [8];
2100 memset (aname, 0, sizeof (MonoAssemblyName));
2103 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2104 if (version_parts < 2 || version_parts > 4)
2107 /* FIXME: we should set build & revision to -1 (instead of 0)
2108 if these are not set in the version string. That way, later on,
2109 we can still determine if these were specified. */
2110 aname->major = major;
2111 aname->minor = minor;
2112 if (version_parts >= 3)
2113 aname->build = build;
2116 if (version_parts == 4)
2117 aname->revision = revision;
2119 aname->revision = 0;
2122 aname->flags = flags;
2124 aname->name = g_strdup (name);
2127 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2128 aname->culture = g_strdup ("");
2130 aname->culture = g_strdup (culture);
2133 if (token && strncmp (token, "null", 4) != 0) {
2136 /* the constant includes the ending NULL, hence the -1 */
2137 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2138 mono_assembly_name_free (aname);
2141 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2142 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2148 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2149 mono_assembly_name_free (aname);
2154 if (save_public_key)
2155 aname->public_key = (guint8*)pkey;
2158 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2162 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2163 // We also need to generate the key token
2164 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2165 encoded = encode_public_tok ((guchar*) tok, 8);
2166 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2169 if (save_public_key)
2170 aname->public_key = (guint8*) pkey;
2179 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2184 parts = g_strsplit (dirname, "_", 3);
2185 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2190 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2196 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2198 char *eqsign = strchr (pair, '=');
2206 *key = (gchar*)pair;
2207 *keylen = eqsign - *key;
2208 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2210 *value = g_strstrip (eqsign + 1);
2215 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2219 gchar *version = NULL;
2221 gchar *culture = NULL;
2223 gchar *token = NULL;
2227 gchar *retargetable = NULL;
2228 gchar *retargetable_uq;
2232 gchar *value, *part_name;
2233 guint32 part_name_len;
2236 gboolean version_defined;
2237 gboolean token_defined;
2239 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2241 if (!is_version_defined)
2242 is_version_defined = &version_defined;
2243 *is_version_defined = FALSE;
2244 if (!is_token_defined)
2245 is_token_defined = &token_defined;
2246 *is_token_defined = FALSE;
2248 parts = tmp = g_strsplit (name, ",", 6);
2249 if (!tmp || !*tmp) {
2254 dllname = g_strstrip (*tmp);
2259 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2260 goto cleanup_and_fail;
2262 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2263 *is_version_defined = TRUE;
2265 if (strlen (version) == 0) {
2266 goto cleanup_and_fail;
2272 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2274 if (strlen (culture) == 0) {
2275 goto cleanup_and_fail;
2281 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2282 *is_token_defined = TRUE;
2284 if (strlen (token) == 0) {
2285 goto cleanup_and_fail;
2291 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2293 if (strlen (key) == 0) {
2294 goto cleanup_and_fail;
2300 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2301 retargetable = value;
2302 retargetable_uq = unquote (retargetable);
2303 if (retargetable_uq != NULL)
2304 retargetable = retargetable_uq;
2306 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2307 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2308 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2309 free (retargetable_uq);
2310 goto cleanup_and_fail;
2313 free (retargetable_uq);
2318 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2320 procarch_uq = unquote (procarch);
2321 if (procarch_uq != NULL)
2322 procarch = procarch_uq;
2324 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2325 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2326 else if (!g_ascii_strcasecmp (procarch, "X86"))
2327 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2328 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2329 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2330 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2331 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2334 goto cleanup_and_fail;
2346 /* if retargetable flag is set, then we must have a fully qualified name */
2347 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2348 goto cleanup_and_fail;
2351 dllname_uq = unquote (dllname);
2352 version_uq = unquote (version);
2353 culture_uq = unquote (culture);
2354 token_uq = unquote (token);
2355 key_uq = unquote (key);
2357 res = build_assembly_name (
2358 dllname_uq == NULL ? dllname : dllname_uq,
2359 version_uq == NULL ? version : version_uq,
2360 culture_uq == NULL ? culture : culture_uq,
2361 token_uq == NULL ? token : token_uq,
2362 key_uq == NULL ? key : key_uq,
2363 flags, arch, aname, save_public_key);
2380 unquote (const char *str)
2388 slen = strlen (str);
2392 if (*str != '\'' && *str != '\"')
2395 end = str + slen - 1;
2399 return g_strndup (str + 1, slen - 2);
2403 * mono_assembly_name_parse:
2404 * @name: name to parse
2405 * @aname: the destination assembly name
2407 * Parses an assembly qualified type name and assigns the name,
2408 * version, culture and token to the provided assembly name object.
2410 * Returns: TRUE if the name could be parsed.
2413 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2415 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2419 * mono_assembly_name_new:
2420 * @name: name to parse
2422 * Allocate a new MonoAssemblyName and fill its values from the
2425 * Returns: a newly allocated structure or NULL if there was any failure.
2428 mono_assembly_name_new (const char *name)
2430 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2431 if (mono_assembly_name_parse (name, aname))
2438 mono_assembly_name_get_name (MonoAssemblyName *aname)
2444 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2446 return aname->culture;
2450 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2452 if (aname->public_key_token [0])
2453 return aname->public_key_token;
2458 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2461 *minor = aname->minor;
2463 *build = aname->build;
2465 *revision = aname->revision;
2466 return aname->major;
2469 static MonoAssembly*
2470 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2472 gchar *fullpath = NULL;
2474 const char* direntry;
2475 MonoAssemblyName gac_aname;
2476 gint major=-1, minor=0, build=0, revision=0;
2477 gboolean exact_version;
2479 dirhandle = g_dir_open (basepath, 0, NULL);
2483 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2485 while ((direntry = g_dir_read_name (dirhandle))) {
2486 gboolean match = TRUE;
2488 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2491 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2494 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2495 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2499 if (exact_version) {
2500 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2501 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2503 else if (gac_aname.major < major)
2505 else if (gac_aname.major == major) {
2506 if (gac_aname.minor < minor)
2508 else if (gac_aname.minor == minor) {
2509 if (gac_aname.build < build)
2511 else if (gac_aname.build == build && gac_aname.revision <= revision)
2518 major = gac_aname.major;
2519 minor = gac_aname.minor;
2520 build = gac_aname.build;
2521 revision = gac_aname.revision;
2523 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2526 mono_assembly_name_free (&gac_aname);
2529 g_dir_close (dirhandle);
2531 if (fullpath == NULL)
2534 MonoAssembly *res = mono_assembly_open (fullpath, status);
2541 * mono_assembly_load_with_partial_name:
2542 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2543 * @status: return status code
2545 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2546 * so it might contain a qualified type name, version, culture and token.
2548 * This will load the assembly from the file whose name is derived from the assembly name
2549 * by appending the .dll extension.
2551 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2552 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2553 * if that fails from the GAC.
2555 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2558 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2562 MonoAssemblyName *aname, base_name;
2563 MonoAssemblyName mapped_aname;
2564 gchar *fullname, *gacpath;
2567 memset (&base_name, 0, sizeof (MonoAssemblyName));
2570 if (!mono_assembly_name_parse (name, aname))
2574 * If no specific version has been requested, make sure we load the
2575 * correct version for system assemblies.
2577 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2578 aname = mono_assembly_remap_version (aname, &mapped_aname);
2580 res = mono_assembly_loaded (aname);
2582 mono_assembly_name_free (aname);
2586 res = invoke_assembly_preload_hook (aname, assemblies_path);
2588 res->in_gac = FALSE;
2589 mono_assembly_name_free (aname);
2593 fullname = g_strdup_printf ("%s.dll", aname->name);
2595 if (extra_gac_paths) {
2596 paths = extra_gac_paths;
2597 while (!res && *paths) {
2598 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2599 res = probe_for_partial_name (gacpath, fullname, aname, status);
2608 mono_assembly_name_free (aname);
2612 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2613 res = probe_for_partial_name (gacpath, fullname, aname, status);
2619 MonoDomain *domain = mono_domain_get ();
2620 MonoReflectionAssembly *refasm;
2622 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2623 if (!is_ok (&error)) {
2625 mono_assembly_name_free (aname);
2626 mono_error_cleanup (&error);
2627 if (*status == MONO_IMAGE_OK)
2628 *status = MONO_IMAGE_IMAGE_INVALID;
2632 res = refasm->assembly;
2636 mono_assembly_name_free (aname);
2642 mono_assembly_is_in_gac (const gchar *filename)
2644 const gchar *rootdir;
2648 if (filename == NULL)
2651 for (paths = extra_gac_paths; paths && *paths; paths++) {
2652 if (strstr (*paths, filename) != *paths)
2655 gp = (gchar *) (filename + strlen (*paths));
2656 if (*gp != G_DIR_SEPARATOR)
2659 if (strncmp (gp, "lib", 3))
2662 if (*gp != G_DIR_SEPARATOR)
2665 if (strncmp (gp, "mono", 4))
2668 if (*gp != G_DIR_SEPARATOR)
2671 if (strncmp (gp, "gac", 3))
2674 if (*gp != G_DIR_SEPARATOR)
2680 rootdir = mono_assembly_getrootdir ();
2681 if (strstr (filename, rootdir) != filename)
2684 gp = (gchar *) (filename + strlen (rootdir));
2685 if (*gp != G_DIR_SEPARATOR)
2688 if (strncmp (gp, "mono", 4))
2691 if (*gp != G_DIR_SEPARATOR)
2694 if (strncmp (gp, "gac", 3))
2697 if (*gp != G_DIR_SEPARATOR)
2703 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2706 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2710 if (strstr (aname->name, ".dll")) {
2711 len = strlen (aname->name) - 4;
2712 name = (gchar *)g_malloc (len + 1);
2713 strncpy (name, aname->name, len);
2716 name = g_strdup (aname->name);
2719 culture = g_utf8_strdown (aname->culture, -1);
2721 culture = g_strdup ("");
2723 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2724 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2728 filename = g_strconcat (pname, ".dll", NULL);
2729 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2735 if (extra_gac_paths) {
2736 paths = extra_gac_paths;
2737 while (!image && *paths) {
2738 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2739 "lib", "mono", "gac", subpath, NULL);
2740 image = mono_image_open (fullpath, NULL);
2751 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2752 "mono", "gac", subpath, NULL);
2753 image = mono_image_open (fullpath, NULL);
2760 static MonoAssemblyName*
2761 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2763 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2764 dest_name->major = info->new_version.major;
2765 dest_name->minor = info->new_version.minor;
2766 dest_name->build = info->new_version.build;
2767 dest_name->revision = info->new_version.revision;
2772 /* LOCKING: assembly_binding lock must be held */
2773 static MonoAssemblyBindingInfo*
2774 search_binding_loaded (MonoAssemblyName *aname)
2778 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2779 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2780 if (assembly_binding_maps_name (info, aname))
2787 static inline gboolean
2788 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2790 if (left->major != right->major || left->minor != right->minor ||
2791 left->build != right->build || left->revision != right->revision)
2797 static inline gboolean
2798 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2800 if (left->has_old_version_bottom != right->has_old_version_bottom)
2803 if (left->has_old_version_top != right->has_old_version_top)
2806 if (left->has_new_version != right->has_new_version)
2809 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2812 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2815 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2821 /* LOCKING: assumes all the necessary locks are held */
2823 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2825 MonoAssemblyBindingInfo *info_copy;
2827 MonoAssemblyBindingInfo *info_tmp;
2828 MonoDomain *domain = (MonoDomain*)user_data;
2833 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2834 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2835 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2839 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2840 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2842 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2844 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2846 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2850 get_version_number (int major, int minor)
2852 return major * 256 + minor;
2855 static inline gboolean
2856 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2858 int aname_version_number = get_version_number (aname->major, aname->minor);
2859 if (!info->has_old_version_bottom)
2862 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2865 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2868 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2869 info->major = aname->major;
2870 info->minor = aname->minor;
2875 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2876 static MonoAssemblyBindingInfo*
2877 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2879 MonoAssemblyBindingInfo *info;
2882 if (!domain->assembly_bindings)
2886 for (list = domain->assembly_bindings; list; list = list->next) {
2887 info = (MonoAssemblyBindingInfo *)list->data;
2888 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2894 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2895 info->has_new_version && assembly_binding_maps_name (info, aname))
2896 info->is_valid = TRUE;
2898 info->is_valid = FALSE;
2904 static MonoAssemblyName*
2905 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2908 MonoAssemblyBindingInfo *info, *info2;
2912 if (aname->public_key_token [0] == 0)
2915 domain = mono_domain_get ();
2917 mono_assembly_binding_lock ();
2918 info = search_binding_loaded (aname);
2919 mono_assembly_binding_unlock ();
2922 mono_domain_lock (domain);
2923 info = get_per_domain_assembly_binding_info (domain, aname);
2924 mono_domain_unlock (domain);
2928 if (!check_policy_versions (info, aname))
2931 mono_assembly_bind_version (info, aname, dest_name);
2935 if (domain && domain->setup && domain->setup->configuration_file) {
2936 mono_domain_lock (domain);
2937 if (!domain->assembly_bindings_parsed) {
2938 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2939 /* expect this to succeed because mono_domain_set_options_from_config () did
2940 * the same thing when the domain was created. */
2941 mono_error_assert_ok (&error);
2943 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2945 if (!domain_config_file_path)
2946 domain_config_file_path = domain_config_file_name;
2948 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2949 domain->assembly_bindings_parsed = TRUE;
2950 if (domain_config_file_name != domain_config_file_path)
2951 g_free (domain_config_file_name);
2952 g_free (domain_config_file_path);
2955 info2 = get_per_domain_assembly_binding_info (domain, aname);
2958 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2959 info->name = g_strdup (info2->name);
2960 info->culture = g_strdup (info2->culture);
2961 info->domain_id = domain->domain_id;
2964 mono_domain_unlock (domain);
2968 info = g_new0 (MonoAssemblyBindingInfo, 1);
2969 info->major = aname->major;
2970 info->minor = aname->minor;
2973 if (!info->is_valid) {
2974 ppimage = mono_assembly_load_publisher_policy (aname);
2976 get_publisher_policy_info (ppimage, aname, info);
2977 mono_image_close (ppimage);
2981 /* Define default error value if needed */
2982 if (!info->is_valid) {
2983 info->name = g_strdup (aname->name);
2984 info->culture = g_strdup (aname->culture);
2985 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2988 mono_assembly_binding_lock ();
2989 info2 = search_binding_loaded (aname);
2991 /* This binding was added by another thread
2993 mono_assembly_binding_info_free (info);
2998 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3000 mono_assembly_binding_unlock ();
3002 if (!info->is_valid || !check_policy_versions (info, aname))
3005 mono_assembly_bind_version (info, aname, dest_name);
3010 * mono_assembly_load_from_gac
3012 * @aname: The assembly name object
3014 static MonoAssembly*
3015 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3017 MonoAssembly *result = NULL;
3018 gchar *name, *version, *culture, *fullpath, *subpath;
3023 if (aname->public_key_token [0] == 0) {
3027 if (strstr (aname->name, ".dll")) {
3028 len = strlen (filename) - 4;
3029 name = (gchar *)g_malloc (len + 1);
3030 strncpy (name, aname->name, len);
3033 name = g_strdup (aname->name);
3036 if (aname->culture) {
3037 culture = g_utf8_strdown (aname->culture, -1);
3039 culture = g_strdup ("");
3042 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3043 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3044 aname->minor, aname->build, aname->revision,
3048 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3053 if (extra_gac_paths) {
3054 paths = extra_gac_paths;
3055 while (!result && *paths) {
3056 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3057 result = mono_assembly_open_full (fullpath, status, refonly);
3064 result->in_gac = TRUE;
3069 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3070 "mono", "gac", subpath, NULL);
3071 result = mono_assembly_open_full (fullpath, status, refonly);
3075 result->in_gac = TRUE;
3083 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3086 MonoAssemblyName *aname;
3089 /* g_print ("corlib already loaded\n"); */
3093 // In native client, Corlib is embedded in the executable as static variable corlibData
3094 #if defined(__native_client__)
3095 if (corlibData != NULL && corlibSize != 0) {
3097 /* First "FALSE" instructs mono not to make a copy. */
3098 /* Second "FALSE" says this is not just a ref. */
3099 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3100 if (image == NULL || status != 0)
3101 g_print("mono_image_open_from_data_full failed: %d\n", status);
3102 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3103 if (corlib == NULL || status != 0)
3104 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3110 // A nonstandard preload hook may provide a special mscorlib assembly
3111 aname = mono_assembly_name_new ("mscorlib.dll");
3112 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3113 mono_assembly_name_free (aname);
3116 goto return_corlib_and_facades;
3118 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3119 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3120 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3122 goto return_corlib_and_facades;
3125 /* Normal case: Load corlib from mono/<version> */
3126 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3127 if (assemblies_path) { // Custom assemblies path
3128 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3130 g_free (corlib_file);
3131 goto return_corlib_and_facades;
3134 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3135 g_free (corlib_file);
3137 return_corlib_and_facades:
3138 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3139 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3145 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3146 const char *basedir,
3147 MonoImageOpenStatus *status,
3150 MonoAssembly *result;
3151 char *fullpath, *filename;
3152 MonoAssemblyName maped_aname;
3153 MonoAssemblyName maped_name_pp;
3158 aname = mono_assembly_remap_version (aname, &maped_aname);
3160 /* Reflection only assemblies don't get assembly binding */
3162 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3164 result = mono_assembly_loaded_full (aname, refonly);
3168 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3170 result->in_gac = FALSE;
3174 /* Currently we retrieve the loaded corlib for reflection
3175 * only requests, like a common reflection only assembly
3177 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3178 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3181 len = strlen (aname->name);
3182 for (ext_index = 0; ext_index < 2; ext_index ++) {
3183 ext = ext_index == 0 ? ".dll" : ".exe";
3184 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3185 filename = g_strdup (aname->name);
3186 /* Don't try appending .dll/.exe if it already has one of those extensions */
3189 filename = g_strconcat (aname->name, ext, NULL);
3192 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3199 fullpath = g_build_filename (basedir, filename, NULL);
3200 result = mono_assembly_open_full (fullpath, status, refonly);
3203 result->in_gac = FALSE;
3209 result = load_in_path (filename, default_path, status, refonly);
3211 result->in_gac = FALSE;
3221 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3223 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3226 /* Try a postload search hook */
3227 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3232 * mono_assembly_load_full:
3233 * @aname: A MonoAssemblyName with the assembly name to load.
3234 * @basedir: A directory to look up the assembly at.
3235 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3236 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3238 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3239 * attempts to load the assembly from that directory before probing the standard locations.
3241 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3242 * assembly binding takes place.
3244 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3245 * value pointed by status is updated with an error code.
3248 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3250 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3254 * mono_assembly_load:
3255 * @aname: A MonoAssemblyName with the assembly name to load.
3256 * @basedir: A directory to look up the assembly at.
3257 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3259 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3260 * attempts to load the assembly from that directory before probing the standard locations.
3262 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3263 * value pointed by status is updated with an error code.
3266 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3268 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3272 * mono_assembly_loaded_full:
3273 * @aname: an assembly to look for.
3274 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3276 * This is used to determine if the specified assembly has been loaded
3277 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3278 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3281 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3284 MonoAssemblyName maped_aname;
3286 aname = mono_assembly_remap_version (aname, &maped_aname);
3288 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3294 * mono_assembly_loaded:
3295 * @aname: an assembly to look for.
3297 * This is used to determine if the specified assembly has been loaded
3299 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3300 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3303 mono_assembly_loaded (MonoAssemblyName *aname)
3305 return mono_assembly_loaded_full (aname, FALSE);
3309 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3311 if (assembly == NULL || assembly == REFERENCE_MISSING)
3314 if (assembly_is_dynamic (assembly)) {
3316 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3317 for (i = 0; i < dynimg->image.module_count; ++i)
3318 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3319 mono_dynamic_image_release_gc_roots (dynimg);
3324 * Returns whether mono_assembly_close_finish() must be called as
3325 * well. See comment for mono_image_close_except_pools() for why we
3326 * unload in two steps.
3329 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3332 g_return_val_if_fail (assembly != NULL, FALSE);
3334 if (assembly == REFERENCE_MISSING)
3337 /* Might be 0 already */
3338 if (InterlockedDecrement (&assembly->ref_count) > 0)
3341 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3343 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3345 mono_debug_close_image (assembly->image);
3347 mono_assemblies_lock ();
3348 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3349 mono_assemblies_unlock ();
3351 assembly->image->assembly = NULL;
3353 if (!mono_image_close_except_pools (assembly->image))
3354 assembly->image = NULL;
3356 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3357 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3358 mono_assembly_name_free (fname);
3361 g_slist_free (assembly->friend_assembly_names);
3362 g_free (assembly->basedir);
3364 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3370 mono_assembly_close_finish (MonoAssembly *assembly)
3372 g_assert (assembly && assembly != REFERENCE_MISSING);
3374 if (assembly->image)
3375 mono_image_close_finish (assembly->image);
3377 if (assembly_is_dynamic (assembly)) {
3378 g_free ((char*)assembly->aname.culture);
3385 * mono_assembly_close:
3386 * @assembly: the assembly to release.
3388 * This method releases a reference to the @assembly. The assembly is
3389 * only released when all the outstanding references to it are released.
3392 mono_assembly_close (MonoAssembly *assembly)
3394 if (mono_assembly_close_except_image_pools (assembly))
3395 mono_assembly_close_finish (assembly);
3399 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3401 return mono_image_load_file_for_image (assembly->image, idx);
3405 * mono_assembly_foreach:
3406 * @func: function to invoke for each assembly loaded
3407 * @user_data: data passed to the callback
3409 * Invokes the provided @func callback for each assembly loaded into
3410 * the runtime. The first parameter passed to the callback is the
3411 * `MonoAssembly*`, and the second parameter is the @user_data.
3413 * This is done for all assemblies loaded in the runtime, not just
3414 * those loaded in the current application domain.
3417 mono_assembly_foreach (GFunc func, gpointer user_data)
3422 * We make a copy of the list to avoid calling the callback inside the
3423 * lock, which could lead to deadlocks.
3425 mono_assemblies_lock ();
3426 copy = g_list_copy (loaded_assemblies);
3427 mono_assemblies_unlock ();
3429 g_list_foreach (loaded_assemblies, func, user_data);
3435 * mono_assemblies_cleanup:
3437 * Free all resources used by this module.
3440 mono_assemblies_cleanup (void)
3444 mono_os_mutex_destroy (&assemblies_mutex);
3445 mono_os_mutex_destroy (&assembly_binding_mutex);
3447 for (l = loaded_assembly_bindings; l; l = l->next) {
3448 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3450 mono_assembly_binding_info_free (info);
3453 g_slist_free (loaded_assembly_bindings);
3455 free_assembly_load_hooks ();
3456 free_assembly_search_hooks ();
3457 free_assembly_preload_hooks ();
3460 /*LOCKING takes the assembly_binding lock*/
3462 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3466 mono_assembly_binding_lock ();
3467 iter = &loaded_assembly_bindings;
3470 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3472 if (info->domain_id == domain_id) {
3474 mono_assembly_binding_info_free (info);
3481 mono_assembly_binding_unlock ();
3485 * Holds the assembly of the application, for
3486 * System.Diagnostics.Process::MainModule
3488 static MonoAssembly *main_assembly=NULL;
3491 mono_assembly_set_main (MonoAssembly *assembly)
3493 main_assembly = assembly;
3497 * mono_assembly_get_main:
3499 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3502 mono_assembly_get_main (void)
3504 return (main_assembly);
3508 * mono_assembly_get_image:
3509 * @assembly: The assembly to retrieve the image from
3511 * Returns: the MonoImage associated with this assembly.
3514 mono_assembly_get_image (MonoAssembly *assembly)
3516 return assembly->image;
3520 * mono_assembly_get_name:
3521 * @assembly: The assembly to retrieve the name from
3523 * The returned name's lifetime is the same as @assembly's.
3525 * Returns: the MonoAssemblyName associated with this assembly.
3528 mono_assembly_get_name (MonoAssembly *assembly)
3530 return &assembly->aname;
3534 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3536 bundles = assemblies;
3539 #define MONO_DECLSEC_FORMAT_10 0x3C
3540 #define MONO_DECLSEC_FORMAT_20 0x2E
3541 #define MONO_DECLSEC_FIELD 0x53
3542 #define MONO_DECLSEC_PROPERTY 0x54
3544 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3545 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3546 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3547 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3548 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3551 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3555 case MONO_DECLSEC_PROPERTY:
3557 case MONO_DECLSEC_FIELD:
3559 *abort_decoding = TRUE;
3564 if (*p++ != MONO_TYPE_BOOLEAN) {
3565 *abort_decoding = TRUE;
3569 /* property name length */
3570 len = mono_metadata_decode_value (p, &p);
3572 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3583 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3585 int i, j, num, len, params_len;
3587 if (*p == MONO_DECLSEC_FORMAT_10) {
3588 gsize read, written;
3589 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3591 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3597 if (*p++ != MONO_DECLSEC_FORMAT_20)
3600 /* number of encoded permission attributes */
3601 num = mono_metadata_decode_value (p, &p);
3602 for (i = 0; i < num; ++i) {
3603 gboolean is_valid = FALSE;
3604 gboolean abort_decoding = FALSE;
3606 /* attribute name length */
3607 len = mono_metadata_decode_value (p, &p);
3609 /* We don't really need to fully decode the type. Comparing the name is enough */
3610 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3614 /*size of the params table*/
3615 params_len = mono_metadata_decode_value (p, &p);
3617 const char *params_end = p + params_len;
3619 /* number of parameters */
3620 len = mono_metadata_decode_value (p, &p);
3622 for (j = 0; j < len; ++j) {
3623 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3639 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3642 guint32 cols [MONO_DECL_SECURITY_SIZE];
3646 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3647 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3649 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3651 for (i = 0; i < t->rows; ++i) {
3652 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3653 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3655 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3658 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3659 len = mono_metadata_decode_blob_size (blob, &blob);
3663 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3664 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3669 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);