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);
2005 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2008 gchar header [16], val, *arr;
2009 gint i, j, offset, bitlen, keylen, pkeylen;
2011 keylen = strlen (key) >> 1;
2015 /* allow the ECMA standard key */
2016 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2018 *pubkey = g_strdup (key);
2024 val = g_ascii_xdigit_value (key [0]) << 4;
2025 val |= g_ascii_xdigit_value (key [1]);
2030 val = g_ascii_xdigit_value (key [24]);
2031 val |= g_ascii_xdigit_value (key [25]);
2043 /* We need the first 16 bytes
2044 * to check whether this key is valid or not */
2045 pkeylen = strlen (pkey) >> 1;
2049 for (i = 0, j = 0; i < 16; i++) {
2050 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2051 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2054 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2055 header [1] != 0x02 || /* Version (0x02) */
2056 header [2] != 0x00 || /* Reserved (word) */
2057 header [3] != 0x00 ||
2058 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2061 /* Based on this length, we _should_ be able to know if the length is right */
2062 bitlen = read32 (header + 12) >> 3;
2063 if ((bitlen + 16 + 4) != pkeylen)
2066 /* parsing is OK and the public key itself is not requested back */
2070 /* Encode the size of the blob */
2072 if (keylen <= 127) {
2073 arr = (gchar *)g_malloc (keylen + 1);
2074 arr [offset++] = keylen;
2076 arr = (gchar *)g_malloc (keylen + 2);
2077 arr [offset++] = 0x80; /* 10bs */
2078 arr [offset++] = keylen;
2081 for (i = offset, j = 0; i < keylen + offset; i++) {
2082 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2083 arr [i] |= g_ascii_xdigit_value (key [j++]);
2092 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)
2094 gint major, minor, build, revision;
2097 gchar *pkey, *pkeyptr, *encoded, tok [8];
2099 memset (aname, 0, sizeof (MonoAssemblyName));
2102 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2103 if (version_parts < 2 || version_parts > 4)
2106 /* FIXME: we should set build & revision to -1 (instead of 0)
2107 if these are not set in the version string. That way, later on,
2108 we can still determine if these were specified. */
2109 aname->major = major;
2110 aname->minor = minor;
2111 if (version_parts >= 3)
2112 aname->build = build;
2115 if (version_parts == 4)
2116 aname->revision = revision;
2118 aname->revision = 0;
2121 aname->flags = flags;
2123 aname->name = g_strdup (name);
2126 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2127 aname->culture = g_strdup ("");
2129 aname->culture = g_strdup (culture);
2132 if (token && strncmp (token, "null", 4) != 0) {
2135 /* the constant includes the ending NULL, hence the -1 */
2136 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2137 mono_assembly_name_free (aname);
2140 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2141 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2147 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2148 mono_assembly_name_free (aname);
2153 if (save_public_key)
2154 aname->public_key = (guint8*)pkey;
2157 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2161 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2162 // We also need to generate the key token
2163 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2164 encoded = encode_public_tok ((guchar*) tok, 8);
2165 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2168 if (save_public_key)
2169 aname->public_key = (guint8*) pkey;
2178 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2183 parts = g_strsplit (dirname, "_", 3);
2184 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2189 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2195 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2197 char *eqsign = strchr (pair, '=');
2205 *key = (gchar*)pair;
2206 *keylen = eqsign - *key;
2207 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2209 *value = g_strstrip (eqsign + 1);
2214 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2218 gchar *version = NULL;
2220 gchar *culture = NULL;
2222 gchar *token = NULL;
2226 gchar *retargetable = NULL;
2227 gchar *retargetable_uq;
2231 gchar *value, *part_name;
2232 guint32 part_name_len;
2235 gboolean version_defined;
2236 gboolean token_defined;
2238 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2240 if (!is_version_defined)
2241 is_version_defined = &version_defined;
2242 *is_version_defined = FALSE;
2243 if (!is_token_defined)
2244 is_token_defined = &token_defined;
2245 *is_token_defined = FALSE;
2247 parts = tmp = g_strsplit (name, ",", 6);
2248 if (!tmp || !*tmp) {
2253 dllname = g_strstrip (*tmp);
2258 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2259 goto cleanup_and_fail;
2261 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2262 *is_version_defined = TRUE;
2264 if (strlen (version) == 0) {
2265 goto cleanup_and_fail;
2271 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2273 if (strlen (culture) == 0) {
2274 goto cleanup_and_fail;
2280 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2281 *is_token_defined = TRUE;
2283 if (strlen (token) == 0) {
2284 goto cleanup_and_fail;
2290 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2292 if (strlen (key) == 0) {
2293 goto cleanup_and_fail;
2299 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2300 retargetable = value;
2301 retargetable_uq = unquote (retargetable);
2302 if (retargetable_uq != NULL)
2303 retargetable = retargetable_uq;
2305 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2306 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2307 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2308 free (retargetable_uq);
2309 goto cleanup_and_fail;
2312 free (retargetable_uq);
2317 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2319 procarch_uq = unquote (procarch);
2320 if (procarch_uq != NULL)
2321 procarch = procarch_uq;
2323 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2324 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2325 else if (!g_ascii_strcasecmp (procarch, "X86"))
2326 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2327 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2328 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2329 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2330 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2333 goto cleanup_and_fail;
2345 /* if retargetable flag is set, then we must have a fully qualified name */
2346 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2347 goto cleanup_and_fail;
2350 dllname_uq = unquote (dllname);
2351 version_uq = unquote (version);
2352 culture_uq = unquote (culture);
2353 token_uq = unquote (token);
2354 key_uq = unquote (key);
2356 res = build_assembly_name (
2357 dllname_uq == NULL ? dllname : dllname_uq,
2358 version_uq == NULL ? version : version_uq,
2359 culture_uq == NULL ? culture : culture_uq,
2360 token_uq == NULL ? token : token_uq,
2361 key_uq == NULL ? key : key_uq,
2362 flags, arch, aname, save_public_key);
2379 unquote (const char *str)
2387 slen = strlen (str);
2391 if (*str != '\'' && *str != '\"')
2394 end = str + slen - 1;
2398 return g_strndup (str + 1, slen - 2);
2402 * mono_assembly_name_parse:
2403 * @name: name to parse
2404 * @aname: the destination assembly name
2406 * Parses an assembly qualified type name and assigns the name,
2407 * version, culture and token to the provided assembly name object.
2409 * Returns: TRUE if the name could be parsed.
2412 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2414 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2418 * mono_assembly_name_new:
2419 * @name: name to parse
2421 * Allocate a new MonoAssemblyName and fill its values from the
2424 * Returns: a newly allocated structure or NULL if there was any failure.
2427 mono_assembly_name_new (const char *name)
2429 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2430 if (mono_assembly_name_parse (name, aname))
2437 mono_assembly_name_get_name (MonoAssemblyName *aname)
2443 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2445 return aname->culture;
2449 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2451 if (aname->public_key_token [0])
2452 return aname->public_key_token;
2457 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2460 *minor = aname->minor;
2462 *build = aname->build;
2464 *revision = aname->revision;
2465 return aname->major;
2468 static MonoAssembly*
2469 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2471 gchar *fullpath = NULL;
2473 const char* direntry;
2474 MonoAssemblyName gac_aname;
2475 gint major=-1, minor=0, build=0, revision=0;
2476 gboolean exact_version;
2478 dirhandle = g_dir_open (basepath, 0, NULL);
2482 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2484 while ((direntry = g_dir_read_name (dirhandle))) {
2485 gboolean match = TRUE;
2487 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2490 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2493 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2494 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2498 if (exact_version) {
2499 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2500 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2502 else if (gac_aname.major < major)
2504 else if (gac_aname.major == major) {
2505 if (gac_aname.minor < minor)
2507 else if (gac_aname.minor == minor) {
2508 if (gac_aname.build < build)
2510 else if (gac_aname.build == build && gac_aname.revision <= revision)
2517 major = gac_aname.major;
2518 minor = gac_aname.minor;
2519 build = gac_aname.build;
2520 revision = gac_aname.revision;
2522 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2525 mono_assembly_name_free (&gac_aname);
2528 g_dir_close (dirhandle);
2530 if (fullpath == NULL)
2533 MonoAssembly *res = mono_assembly_open (fullpath, status);
2540 * mono_assembly_load_with_partial_name:
2541 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2542 * @status: return status code
2544 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2545 * so it might contain a qualified type name, version, culture and token.
2547 * This will load the assembly from the file whose name is derived from the assembly name
2548 * by appending the .dll extension.
2550 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2551 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2552 * if that fails from the GAC.
2554 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2557 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2561 MonoAssemblyName *aname, base_name;
2562 MonoAssemblyName mapped_aname;
2563 gchar *fullname, *gacpath;
2566 memset (&base_name, 0, sizeof (MonoAssemblyName));
2569 if (!mono_assembly_name_parse (name, aname))
2573 * If no specific version has been requested, make sure we load the
2574 * correct version for system assemblies.
2576 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2577 aname = mono_assembly_remap_version (aname, &mapped_aname);
2579 res = mono_assembly_loaded (aname);
2581 mono_assembly_name_free (aname);
2585 res = invoke_assembly_preload_hook (aname, assemblies_path);
2587 res->in_gac = FALSE;
2588 mono_assembly_name_free (aname);
2592 fullname = g_strdup_printf ("%s.dll", aname->name);
2594 if (extra_gac_paths) {
2595 paths = extra_gac_paths;
2596 while (!res && *paths) {
2597 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2598 res = probe_for_partial_name (gacpath, fullname, aname, status);
2607 mono_assembly_name_free (aname);
2611 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2612 res = probe_for_partial_name (gacpath, fullname, aname, status);
2618 MonoDomain *domain = mono_domain_get ();
2619 MonoReflectionAssembly *refasm;
2621 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2622 if (!is_ok (&error)) {
2624 mono_assembly_name_free (aname);
2625 mono_error_cleanup (&error);
2626 if (*status == MONO_IMAGE_OK)
2627 *status = MONO_IMAGE_IMAGE_INVALID;
2631 res = refasm->assembly;
2635 mono_assembly_name_free (aname);
2641 mono_assembly_is_in_gac (const gchar *filename)
2643 const gchar *rootdir;
2647 if (filename == NULL)
2650 for (paths = extra_gac_paths; paths && *paths; paths++) {
2651 if (strstr (*paths, filename) != *paths)
2654 gp = (gchar *) (filename + strlen (*paths));
2655 if (*gp != G_DIR_SEPARATOR)
2658 if (strncmp (gp, "lib", 3))
2661 if (*gp != G_DIR_SEPARATOR)
2664 if (strncmp (gp, "mono", 4))
2667 if (*gp != G_DIR_SEPARATOR)
2670 if (strncmp (gp, "gac", 3))
2673 if (*gp != G_DIR_SEPARATOR)
2679 rootdir = mono_assembly_getrootdir ();
2680 if (strstr (filename, rootdir) != filename)
2683 gp = (gchar *) (filename + strlen (rootdir));
2684 if (*gp != G_DIR_SEPARATOR)
2687 if (strncmp (gp, "mono", 4))
2690 if (*gp != G_DIR_SEPARATOR)
2693 if (strncmp (gp, "gac", 3))
2696 if (*gp != G_DIR_SEPARATOR)
2702 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2705 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2709 if (strstr (aname->name, ".dll")) {
2710 len = strlen (aname->name) - 4;
2711 name = (gchar *)g_malloc (len + 1);
2712 strncpy (name, aname->name, len);
2715 name = g_strdup (aname->name);
2718 culture = g_utf8_strdown (aname->culture, -1);
2720 culture = g_strdup ("");
2722 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2723 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2727 filename = g_strconcat (pname, ".dll", NULL);
2728 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2734 if (extra_gac_paths) {
2735 paths = extra_gac_paths;
2736 while (!image && *paths) {
2737 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2738 "lib", "mono", "gac", subpath, NULL);
2739 image = mono_image_open (fullpath, NULL);
2750 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2751 "mono", "gac", subpath, NULL);
2752 image = mono_image_open (fullpath, NULL);
2759 static MonoAssemblyName*
2760 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2762 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2763 dest_name->major = info->new_version.major;
2764 dest_name->minor = info->new_version.minor;
2765 dest_name->build = info->new_version.build;
2766 dest_name->revision = info->new_version.revision;
2771 /* LOCKING: assembly_binding lock must be held */
2772 static MonoAssemblyBindingInfo*
2773 search_binding_loaded (MonoAssemblyName *aname)
2777 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2778 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2779 if (assembly_binding_maps_name (info, aname))
2786 static inline gboolean
2787 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2789 if (left->major != right->major || left->minor != right->minor ||
2790 left->build != right->build || left->revision != right->revision)
2796 static inline gboolean
2797 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2799 if (left->has_old_version_bottom != right->has_old_version_bottom)
2802 if (left->has_old_version_top != right->has_old_version_top)
2805 if (left->has_new_version != right->has_new_version)
2808 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2811 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2814 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2820 /* LOCKING: assumes all the necessary locks are held */
2822 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2824 MonoAssemblyBindingInfo *info_copy;
2826 MonoAssemblyBindingInfo *info_tmp;
2827 MonoDomain *domain = (MonoDomain*)user_data;
2832 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2833 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2834 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2838 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2839 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2841 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2843 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2845 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2849 get_version_number (int major, int minor)
2851 return major * 256 + minor;
2854 static inline gboolean
2855 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2857 int aname_version_number = get_version_number (aname->major, aname->minor);
2858 if (!info->has_old_version_bottom)
2861 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2864 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2867 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2868 info->major = aname->major;
2869 info->minor = aname->minor;
2874 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2875 static MonoAssemblyBindingInfo*
2876 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2878 MonoAssemblyBindingInfo *info;
2881 if (!domain->assembly_bindings)
2885 for (list = domain->assembly_bindings; list; list = list->next) {
2886 info = (MonoAssemblyBindingInfo *)list->data;
2887 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2893 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2894 info->has_new_version && assembly_binding_maps_name (info, aname))
2895 info->is_valid = TRUE;
2897 info->is_valid = FALSE;
2903 static MonoAssemblyName*
2904 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2907 MonoAssemblyBindingInfo *info, *info2;
2911 if (aname->public_key_token [0] == 0)
2914 domain = mono_domain_get ();
2916 mono_assembly_binding_lock ();
2917 info = search_binding_loaded (aname);
2918 mono_assembly_binding_unlock ();
2921 mono_domain_lock (domain);
2922 info = get_per_domain_assembly_binding_info (domain, aname);
2923 mono_domain_unlock (domain);
2927 if (!check_policy_versions (info, aname))
2930 mono_assembly_bind_version (info, aname, dest_name);
2934 if (domain && domain->setup && domain->setup->configuration_file) {
2935 mono_domain_lock (domain);
2936 if (!domain->assembly_bindings_parsed) {
2937 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2938 /* expect this to succeed because mono_domain_set_options_from_config () did
2939 * the same thing when the domain was created. */
2940 mono_error_assert_ok (&error);
2942 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2944 if (!domain_config_file_path)
2945 domain_config_file_path = domain_config_file_name;
2947 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2948 domain->assembly_bindings_parsed = TRUE;
2949 if (domain_config_file_name != domain_config_file_path)
2950 g_free (domain_config_file_name);
2951 g_free (domain_config_file_path);
2954 info2 = get_per_domain_assembly_binding_info (domain, aname);
2957 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2958 info->name = g_strdup (info2->name);
2959 info->culture = g_strdup (info2->culture);
2960 info->domain_id = domain->domain_id;
2963 mono_domain_unlock (domain);
2967 info = g_new0 (MonoAssemblyBindingInfo, 1);
2968 info->major = aname->major;
2969 info->minor = aname->minor;
2972 if (!info->is_valid) {
2973 ppimage = mono_assembly_load_publisher_policy (aname);
2975 get_publisher_policy_info (ppimage, aname, info);
2976 mono_image_close (ppimage);
2980 /* Define default error value if needed */
2981 if (!info->is_valid) {
2982 info->name = g_strdup (aname->name);
2983 info->culture = g_strdup (aname->culture);
2984 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2987 mono_assembly_binding_lock ();
2988 info2 = search_binding_loaded (aname);
2990 /* This binding was added by another thread
2992 mono_assembly_binding_info_free (info);
2997 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2999 mono_assembly_binding_unlock ();
3001 if (!info->is_valid || !check_policy_versions (info, aname))
3004 mono_assembly_bind_version (info, aname, dest_name);
3009 * mono_assembly_load_from_gac
3011 * @aname: The assembly name object
3013 static MonoAssembly*
3014 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3016 MonoAssembly *result = NULL;
3017 gchar *name, *version, *culture, *fullpath, *subpath;
3022 if (aname->public_key_token [0] == 0) {
3026 if (strstr (aname->name, ".dll")) {
3027 len = strlen (filename) - 4;
3028 name = (gchar *)g_malloc (len + 1);
3029 strncpy (name, aname->name, len);
3032 name = g_strdup (aname->name);
3035 if (aname->culture) {
3036 culture = g_utf8_strdown (aname->culture, -1);
3038 culture = g_strdup ("");
3041 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3042 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3043 aname->minor, aname->build, aname->revision,
3047 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3052 if (extra_gac_paths) {
3053 paths = extra_gac_paths;
3054 while (!result && *paths) {
3055 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3056 result = mono_assembly_open_full (fullpath, status, refonly);
3063 result->in_gac = TRUE;
3068 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3069 "mono", "gac", subpath, NULL);
3070 result = mono_assembly_open_full (fullpath, status, refonly);
3074 result->in_gac = TRUE;
3082 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3085 MonoAssemblyName *aname;
3088 /* g_print ("corlib already loaded\n"); */
3092 // In native client, Corlib is embedded in the executable as static variable corlibData
3093 #if defined(__native_client__)
3094 if (corlibData != NULL && corlibSize != 0) {
3096 /* First "FALSE" instructs mono not to make a copy. */
3097 /* Second "FALSE" says this is not just a ref. */
3098 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3099 if (image == NULL || status != 0)
3100 g_print("mono_image_open_from_data_full failed: %d\n", status);
3101 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3102 if (corlib == NULL || status != 0)
3103 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3109 // A nonstandard preload hook may provide a special mscorlib assembly
3110 aname = mono_assembly_name_new ("mscorlib.dll");
3111 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3112 mono_assembly_name_free (aname);
3115 goto return_corlib_and_facades;
3117 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3118 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3119 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3121 goto return_corlib_and_facades;
3124 /* Normal case: Load corlib from mono/<version> */
3125 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3126 if (assemblies_path) { // Custom assemblies path
3127 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3129 g_free (corlib_file);
3130 goto return_corlib_and_facades;
3133 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3134 g_free (corlib_file);
3136 return_corlib_and_facades:
3137 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3138 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3144 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3145 const char *basedir,
3146 MonoImageOpenStatus *status,
3149 MonoAssembly *result;
3150 char *fullpath, *filename;
3151 MonoAssemblyName maped_aname;
3152 MonoAssemblyName maped_name_pp;
3157 aname = mono_assembly_remap_version (aname, &maped_aname);
3159 /* Reflection only assemblies don't get assembly binding */
3161 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3163 result = mono_assembly_loaded_full (aname, refonly);
3167 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3169 result->in_gac = FALSE;
3173 /* Currently we retrieve the loaded corlib for reflection
3174 * only requests, like a common reflection only assembly
3176 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3177 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3180 len = strlen (aname->name);
3181 for (ext_index = 0; ext_index < 2; ext_index ++) {
3182 ext = ext_index == 0 ? ".dll" : ".exe";
3183 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3184 filename = g_strdup (aname->name);
3185 /* Don't try appending .dll/.exe if it already has one of those extensions */
3188 filename = g_strconcat (aname->name, ext, NULL);
3191 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3198 fullpath = g_build_filename (basedir, filename, NULL);
3199 result = mono_assembly_open_full (fullpath, status, refonly);
3202 result->in_gac = FALSE;
3208 result = load_in_path (filename, default_path, status, refonly);
3210 result->in_gac = FALSE;
3220 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3222 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3225 /* Try a postload search hook */
3226 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3231 * mono_assembly_load_full:
3232 * @aname: A MonoAssemblyName with the assembly name to load.
3233 * @basedir: A directory to look up the assembly at.
3234 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3235 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3237 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3238 * attempts to load the assembly from that directory before probing the standard locations.
3240 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3241 * assembly binding takes place.
3243 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3244 * value pointed by status is updated with an error code.
3247 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3249 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3253 * mono_assembly_load:
3254 * @aname: A MonoAssemblyName with the assembly name to load.
3255 * @basedir: A directory to look up the assembly at.
3256 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3258 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3259 * attempts to load the assembly from that directory before probing the standard locations.
3261 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3262 * value pointed by status is updated with an error code.
3265 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3267 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3271 * mono_assembly_loaded_full:
3272 * @aname: an assembly to look for.
3273 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3275 * This is used to determine if the specified assembly has been loaded
3276 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3277 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3280 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3283 MonoAssemblyName maped_aname;
3285 aname = mono_assembly_remap_version (aname, &maped_aname);
3287 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3293 * mono_assembly_loaded:
3294 * @aname: an assembly to look for.
3296 * This is used to determine if the specified assembly has been loaded
3298 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3299 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3302 mono_assembly_loaded (MonoAssemblyName *aname)
3304 return mono_assembly_loaded_full (aname, FALSE);
3308 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3310 if (assembly == NULL || assembly == REFERENCE_MISSING)
3313 if (assembly_is_dynamic (assembly)) {
3315 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3316 for (i = 0; i < dynimg->image.module_count; ++i)
3317 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3318 mono_dynamic_image_release_gc_roots (dynimg);
3323 * Returns whether mono_assembly_close_finish() must be called as
3324 * well. See comment for mono_image_close_except_pools() for why we
3325 * unload in two steps.
3328 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3331 g_return_val_if_fail (assembly != NULL, FALSE);
3333 if (assembly == REFERENCE_MISSING)
3336 /* Might be 0 already */
3337 if (InterlockedDecrement (&assembly->ref_count) > 0)
3340 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3342 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3344 mono_debug_close_image (assembly->image);
3346 mono_assemblies_lock ();
3347 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3348 mono_assemblies_unlock ();
3350 assembly->image->assembly = NULL;
3352 if (!mono_image_close_except_pools (assembly->image))
3353 assembly->image = NULL;
3355 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3356 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3357 mono_assembly_name_free (fname);
3360 g_slist_free (assembly->friend_assembly_names);
3361 g_free (assembly->basedir);
3363 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3369 mono_assembly_close_finish (MonoAssembly *assembly)
3371 g_assert (assembly && assembly != REFERENCE_MISSING);
3373 if (assembly->image)
3374 mono_image_close_finish (assembly->image);
3376 if (assembly_is_dynamic (assembly)) {
3377 g_free ((char*)assembly->aname.culture);
3384 * mono_assembly_close:
3385 * @assembly: the assembly to release.
3387 * This method releases a reference to the @assembly. The assembly is
3388 * only released when all the outstanding references to it are released.
3391 mono_assembly_close (MonoAssembly *assembly)
3393 if (mono_assembly_close_except_image_pools (assembly))
3394 mono_assembly_close_finish (assembly);
3398 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3400 return mono_image_load_file_for_image (assembly->image, idx);
3404 * mono_assembly_foreach:
3405 * @func: function to invoke for each assembly loaded
3406 * @user_data: data passed to the callback
3408 * Invokes the provided @func callback for each assembly loaded into
3409 * the runtime. The first parameter passed to the callback is the
3410 * `MonoAssembly*`, and the second parameter is the @user_data.
3412 * This is done for all assemblies loaded in the runtime, not just
3413 * those loaded in the current application domain.
3416 mono_assembly_foreach (GFunc func, gpointer user_data)
3421 * We make a copy of the list to avoid calling the callback inside the
3422 * lock, which could lead to deadlocks.
3424 mono_assemblies_lock ();
3425 copy = g_list_copy (loaded_assemblies);
3426 mono_assemblies_unlock ();
3428 g_list_foreach (loaded_assemblies, func, user_data);
3434 * mono_assemblies_cleanup:
3436 * Free all resources used by this module.
3439 mono_assemblies_cleanup (void)
3443 mono_os_mutex_destroy (&assemblies_mutex);
3444 mono_os_mutex_destroy (&assembly_binding_mutex);
3446 for (l = loaded_assembly_bindings; l; l = l->next) {
3447 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3449 mono_assembly_binding_info_free (info);
3452 g_slist_free (loaded_assembly_bindings);
3454 free_assembly_load_hooks ();
3455 free_assembly_search_hooks ();
3456 free_assembly_preload_hooks ();
3459 /*LOCKING takes the assembly_binding lock*/
3461 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3465 mono_assembly_binding_lock ();
3466 iter = &loaded_assembly_bindings;
3469 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3471 if (info->domain_id == domain_id) {
3473 mono_assembly_binding_info_free (info);
3480 mono_assembly_binding_unlock ();
3484 * Holds the assembly of the application, for
3485 * System.Diagnostics.Process::MainModule
3487 static MonoAssembly *main_assembly=NULL;
3490 mono_assembly_set_main (MonoAssembly *assembly)
3492 main_assembly = assembly;
3496 * mono_assembly_get_main:
3498 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3501 mono_assembly_get_main (void)
3503 return (main_assembly);
3507 * mono_assembly_get_image:
3508 * @assembly: The assembly to retrieve the image from
3510 * Returns: the MonoImage associated with this assembly.
3513 mono_assembly_get_image (MonoAssembly *assembly)
3515 return assembly->image;
3519 * mono_assembly_get_name:
3520 * @assembly: The assembly to retrieve the name from
3522 * The returned name's lifetime is the same as @assembly's.
3524 * Returns: the MonoAssemblyName associated with this assembly.
3527 mono_assembly_get_name (MonoAssembly *assembly)
3529 return &assembly->aname;
3533 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3535 bundles = assemblies;
3538 #define MONO_DECLSEC_FORMAT_10 0x3C
3539 #define MONO_DECLSEC_FORMAT_20 0x2E
3540 #define MONO_DECLSEC_FIELD 0x53
3541 #define MONO_DECLSEC_PROPERTY 0x54
3543 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3544 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3545 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3546 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3547 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3550 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3554 case MONO_DECLSEC_PROPERTY:
3556 case MONO_DECLSEC_FIELD:
3558 *abort_decoding = TRUE;
3563 if (*p++ != MONO_TYPE_BOOLEAN) {
3564 *abort_decoding = TRUE;
3568 /* property name length */
3569 len = mono_metadata_decode_value (p, &p);
3571 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3582 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3584 int i, j, num, len, params_len;
3586 if (*p == MONO_DECLSEC_FORMAT_10) {
3587 gsize read, written;
3588 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3590 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3596 if (*p++ != MONO_DECLSEC_FORMAT_20)
3599 /* number of encoded permission attributes */
3600 num = mono_metadata_decode_value (p, &p);
3601 for (i = 0; i < num; ++i) {
3602 gboolean is_valid = FALSE;
3603 gboolean abort_decoding = FALSE;
3605 /* attribute name length */
3606 len = mono_metadata_decode_value (p, &p);
3608 /* We don't really need to fully decode the type. Comparing the name is enough */
3609 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3613 /*size of the params table*/
3614 params_len = mono_metadata_decode_value (p, &p);
3616 const char *params_end = p + params_len;
3618 /* number of parameters */
3619 len = mono_metadata_decode_value (p, &p);
3621 for (j = 0; j < len; ++j) {
3622 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3638 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3641 guint32 cols [MONO_DECL_SECURITY_SIZE];
3645 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3646 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3648 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3650 for (i = 0; i < t->rows; ++i) {
3651 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3652 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3654 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3657 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3658 len = mono_metadata_decode_blob_size (blob, &blob);
3662 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3663 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3668 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);