2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include "assembly-internals.h"
21 #include "image-internals.h"
22 #include "object-internals.h"
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/custom-attrs-internals.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/class-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include <mono/metadata/reflection-internals.h>
31 #include <mono/metadata/mono-endian.h>
32 #include <mono/metadata/mono-debug.h>
33 #include <mono/utils/mono-uri.h>
34 #include <mono/metadata/mono-config.h>
35 #include <mono/metadata/mono-config-dirs.h>
36 #include <mono/utils/mono-digest.h>
37 #include <mono/utils/mono-logger-internals.h>
38 #include <mono/utils/mono-path.h>
39 #include <mono/metadata/reflection.h>
40 #include <mono/metadata/coree.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/utils/mono-io-portability.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-os-mutex.h>
47 #include <sys/types.h>
52 #ifdef PLATFORM_MACOSX
53 #include <mach-o/dyld.h>
56 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
58 const char* assembly_name;
59 guint8 version_set_index;
60 const char* new_assembly_name;
61 gboolean only_lower_versions;
64 /* the default search path is empty, the first slot is replaced with the computed value */
72 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
73 static char **assemblies_path = NULL;
75 /* Contains the list of directories that point to auxiliary GACs */
76 static char **extra_gac_paths = NULL;
78 #ifndef DISABLE_ASSEMBLY_REMAPPING
79 /* The list of system assemblies what will be remapped to the running
80 * runtime version. WARNING: this list must be sorted.
81 * The integer number is an index in the MonoRuntimeInfo structure, whose
82 * values can be found in domain.c - supported_runtimes. Look there
83 * to understand what remapping will be made.
85 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
88 static const AssemblyVersionMap framework_assemblies [] = {
90 {"Commons.Xml.Relaxng", 0},
97 {"Microsoft.Build.Engine", 2, NULL, TRUE},
98 {"Microsoft.Build.Framework", 2, NULL, TRUE},
99 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
100 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
101 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
102 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
103 {"Microsoft.VisualBasic", 1},
104 {"Microsoft.VisualC", 1},
106 {"Mono.CompilerServices.SymbolWriter", 0},
108 {"Mono.Data.SybaseClient", 0},
109 {"Mono.Data.Tds", 0},
110 {"Mono.Data.TdsClient", 0},
111 {"Mono.GetOptions", 0},
114 {"Mono.Security", 0},
115 {"Mono.Security.Win32", 0},
117 {"Novell.Directory.Ldap", 0},
120 {"System.ComponentModel.Composition", 2},
121 {"System.ComponentModel.DataAnnotations", 2},
122 {"System.Configuration", 0},
123 {"System.Configuration.Install", 0},
126 {"System.Data.Linq", 2},
127 {"System.Data.OracleClient", 0},
128 {"System.Data.Services", 2},
129 {"System.Data.Services.Client", 2},
130 {"System.Data.SqlXml", 0},
131 {"System.Design", 0},
132 {"System.DirectoryServices", 0},
133 {"System.Drawing", 0},
134 {"System.Drawing.Design", 0},
135 {"System.EnterpriseServices", 0},
136 {"System.IdentityModel", 3},
137 {"System.IdentityModel.Selectors", 3},
138 {"System.Management", 0},
139 {"System.Messaging", 0},
141 {"System.Runtime.Remoting", 0},
142 {"System.Runtime.Serialization", 3},
143 {"System.Runtime.Serialization.Formatters.Soap", 0},
144 {"System.Security", 0},
145 {"System.ServiceModel", 3},
146 {"System.ServiceModel.Web", 2},
147 {"System.ServiceProcess", 0},
148 {"System.Transactions", 0},
150 {"System.Web.Abstractions", 2},
151 {"System.Web.DynamicData", 2},
152 {"System.Web.Extensions", 2},
153 {"System.Web.Mobile", 0},
154 {"System.Web.Routing", 2},
155 {"System.Web.Services", 0},
156 {"System.Windows.Forms", 0},
158 {"System.Xml.Linq", 2},
165 * keeps track of loaded assemblies
167 static GList *loaded_assemblies = NULL;
168 static MonoAssembly *corlib;
170 #if defined(__native_client__)
172 /* On Native Client, allow mscorlib to be loaded from memory */
173 /* instead of loaded off disk. If these are not set, default */
174 /* mscorlib loading will take place */
176 /* NOTE: If mscorlib data is passed to mono in this way then */
177 /* it needs to remain allocated during the use of mono. */
179 static void *corlibData = NULL;
180 static size_t corlibSize = 0;
183 mono_set_corlib_data (void *data, size_t size)
191 static char* unquote (const char *str);
193 /* This protects loaded_assemblies and image->references */
194 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
195 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
196 static mono_mutex_t assemblies_mutex;
198 /* If defined, points to the bundled assembly information */
199 const MonoBundledAssembly **bundles;
201 static mono_mutex_t assembly_binding_mutex;
203 /* Loaded assembly binding info */
204 static GSList *loaded_assembly_bindings = NULL;
206 /* Class lazy loading functions */
207 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
209 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
211 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
213 mono_assembly_is_in_gac (const gchar *filanem);
216 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
219 encode_public_tok (const guchar *token, gint32 len)
221 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
225 res = (gchar *)g_malloc (len * 2 + 1);
226 for (i = 0; i < len; i++) {
227 res [i * 2] = allowed [token [i] >> 4];
228 res [i * 2 + 1] = allowed [token [i] & 0xF];
235 * mono_public_tokens_are_equal:
236 * @pubt1: first public key token
237 * @pubt2: second public key token
239 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
243 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
245 return memcmp (pubt1, pubt2, 16) == 0;
249 * mono_set_assemblies_path:
250 * @path: list of paths that contain directories where Mono will look for assemblies
252 * Use this method to override the standard assembly lookup system and
253 * override any assemblies coming from the GAC. This is the method
254 * that supports the MONO_PATH variable.
256 * Notice that MONO_PATH and this method are really a very bad idea as
257 * it prevents the GAC from working and it prevents the standard
258 * resolution mechanisms from working. Nonetheless, for some debugging
259 * situations and bootstrapping setups, this is useful to have.
262 mono_set_assemblies_path (const char* path)
264 char **splitted, **dest;
266 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
268 g_strfreev (assemblies_path);
269 assemblies_path = dest = splitted;
271 char *tmp = *splitted;
273 *dest++ = mono_path_canonicalize (tmp);
279 if (g_getenv ("MONO_DEBUG") == NULL)
282 splitted = assemblies_path;
284 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
285 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
291 /* Native Client can't get this info from an environment variable so */
292 /* it's passed in to the runtime, or set manually by embedding code. */
293 #ifdef __native_client__
294 char* nacl_mono_path = NULL;
298 check_path_env (void)
301 path = g_getenv ("MONO_PATH");
302 #ifdef __native_client__
304 path = nacl_mono_path;
306 if (!path || assemblies_path != NULL)
309 mono_set_assemblies_path(path);
313 check_extra_gac_path_env (void) {
315 char **splitted, **dest;
317 path = g_getenv ("MONO_GAC_PREFIX");
321 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
323 g_strfreev (extra_gac_paths);
324 extra_gac_paths = dest = splitted;
332 if (g_getenv ("MONO_DEBUG") == NULL)
336 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
337 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
344 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
346 if (!info || !info->name)
349 if (strcmp (info->name, aname->name))
352 if (info->major != aname->major || info->minor != aname->minor)
355 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
358 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
361 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
368 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
374 g_free (info->culture);
378 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
381 guint32 cols [MONO_MANIFEST_SIZE];
382 const gchar *filename;
383 gchar *subpath, *fullpath;
385 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
386 /* MS Impl. accepts policy assemblies with more than
387 * one manifest resource, and only takes the first one */
389 binding_info->is_valid = FALSE;
393 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
394 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
395 binding_info->is_valid = FALSE;
399 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
400 g_assert (filename != NULL);
402 subpath = g_path_get_dirname (image->name);
403 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
404 mono_config_parse_publisher_policy (fullpath, binding_info);
408 /* Define the optional elements/attributes before checking */
409 if (!binding_info->culture)
410 binding_info->culture = g_strdup ("");
412 /* Check that the most important elements/attributes exist */
413 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
414 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
415 mono_assembly_binding_info_free (binding_info);
416 binding_info->is_valid = FALSE;
420 binding_info->is_valid = TRUE;
424 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
426 if (v->major > aname->major)
428 else if (v->major < aname->major)
431 if (v->minor > aname->minor)
433 else if (v->minor < aname->minor)
436 if (v->build > aname->build)
438 else if (v->build < aname->build)
441 if (v->revision > aname->revision)
443 else if (v->revision < aname->revision)
450 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
455 /* If has_old_version_top doesn't exist, we don't have an interval */
456 if (!info->has_old_version_top) {
457 if (compare_versions (&info->old_version_bottom, name) == 0)
463 /* Check that the version defined by name is valid for the interval */
464 if (compare_versions (&info->old_version_top, name) < 0)
467 /* We should be greater or equal than the small version */
468 if (compare_versions (&info->old_version_bottom, name) > 0)
475 * mono_assembly_names_equal:
477 * @r: second assembly.
479 * Compares two MonoAssemblyNames and returns whether they are equal.
481 * This compares the names, the cultures, the release version and their
484 * Returns: TRUE if both assembly names are equal.
487 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
489 if (!l->name || !r->name)
492 if (strcmp (l->name, r->name))
495 if (l->culture && r->culture && strcmp (l->culture, r->culture))
498 if (l->major != r->major || l->minor != r->minor ||
499 l->build != r->build || l->revision != r->revision)
500 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)))
503 if (!l->public_key_token [0] || !r->public_key_token [0])
506 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
512 static MonoAssembly *
513 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
517 MonoAssembly *result;
519 for (i = 0; search_path [i]; ++i) {
520 fullpath = g_build_filename (search_path [i], basename, NULL);
521 result = mono_assembly_open_full (fullpath, status, refonly);
530 * mono_assembly_setrootdir:
531 * @root_dir: The pathname of the root directory where we will locate assemblies
533 * This routine sets the internal default root directory for looking up
536 * This is used by Windows installations to compute dynamically the
537 * place where the Mono assemblies are located.
541 mono_assembly_setrootdir (const char *root_dir)
544 * Override the MONO_ASSEMBLIES directory configured at compile time.
546 /* Leak if called more than once */
547 default_path [0] = g_strdup (root_dir);
551 * mono_assembly_getrootdir:
553 * Obtains the root directory used for looking up assemblies.
555 * Returns: a string with the directory, this string should not be freed.
557 G_CONST_RETURN gchar *
558 mono_assembly_getrootdir (void)
560 return default_path [0];
564 * mono_native_getrootdir:
566 * Obtains the root directory used for looking up native libs (.so, .dylib).
568 * Returns: a string with the directory, this string should be freed by
572 mono_native_getrootdir (void)
574 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
580 * @assembly_dir: the base directory for assemblies
581 * @config_dir: the base directory for configuration files
583 * This routine is used internally and by developers embedding
584 * the runtime into their own applications.
586 * There are a number of cases to consider: Mono as a system-installed
587 * package that is available on the location preconfigured or Mono in
588 * a relocated location.
590 * If you are using a system-installed Mono, you can pass NULL
591 * to both parameters. If you are not, you should compute both
592 * directory values and call this routine.
594 * The values for a given PREFIX are:
596 * assembly_dir: PREFIX/lib
597 * config_dir: PREFIX/etc
599 * Notice that embedders that use Mono in a relocated way must
600 * compute the location at runtime, as they will be in control
601 * of where Mono is installed.
604 mono_set_dirs (const char *assembly_dir, const char *config_dir)
606 if (assembly_dir == NULL)
607 assembly_dir = mono_config_get_assemblies_dir ();
608 if (config_dir == NULL)
609 config_dir = mono_config_get_cfg_dir ();
610 mono_assembly_setrootdir (assembly_dir);
611 mono_set_config_dir (config_dir);
617 compute_base (char *path)
619 char *p = strrchr (path, '/');
623 /* Not a well known Mono executable, we are embedded, cant guess the base */
624 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
628 p = strrchr (path, '/');
632 if (strcmp (p, "/bin") != 0)
641 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
644 static G_GNUC_UNUSED void
648 char *config, *lib, *mono;
653 * Only /usr prefix is treated specially
655 bindir = mono_config_get_bin_dir ();
657 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
662 config = g_build_filename (base, "etc", NULL);
663 lib = g_build_filename (base, "lib", NULL);
664 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
665 if (stat (mono, &buf) == -1)
668 mono_set_dirs (lib, config);
676 #endif /* HOST_WIN32 */
681 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
682 * this auto-detects the prefix where Mono was installed.
685 mono_set_rootdir (void)
687 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
688 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
691 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
695 * _NSGetExecutablePath may return -1 to indicate buf is not large
696 * enough, but we ignore that case to avoid having to do extra dynamic
697 * allocation for the path and hope that 4096 is enough - this is
698 * ok in the Linux/Solaris case below at least...
702 guint buf_size = sizeof (buf);
705 if (_NSGetExecutablePath (buf, &buf_size) == 0)
706 name = g_strdup (buf);
715 resolvedname = mono_path_resolve_symlinks (name);
717 bindir = g_path_get_dirname (resolvedname);
718 installdir = g_path_get_dirname (bindir);
719 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
721 config = g_build_filename (root, "..", "etc", NULL);
723 mono_set_dirs (root, config);
725 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
726 mono_set_dirs (root, config);
736 g_free (resolvedname);
737 #elif defined(DISABLE_MONO_AUTODETECTION)
745 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
753 /* Solaris 10 style */
754 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
755 s = readlink (str, buf, sizeof (buf)-1);
767 * mono_assemblies_init:
769 * Initialize global variables used by this module.
772 mono_assemblies_init (void)
775 * Initialize our internal paths if we have not been initialized yet.
776 * This happens when embedders use Mono.
778 if (mono_assembly_getrootdir () == NULL)
782 check_extra_gac_path_env ();
784 mono_os_mutex_init_recursive (&assemblies_mutex);
785 mono_os_mutex_init (&assembly_binding_mutex);
789 mono_assembly_binding_lock (void)
791 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
795 mono_assembly_binding_unlock (void)
797 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
801 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
803 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
804 guint32 cols [MONO_ASSEMBLY_SIZE];
805 gint32 machine, flags;
810 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
813 aname->hash_value = NULL;
814 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
816 aname->name = g_strdup (aname->name);
817 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
819 aname->culture = g_strdup (aname->culture);
820 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
821 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
822 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
823 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
824 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
825 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
826 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
827 guchar* token = (guchar *)g_malloc (8);
832 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
833 len = mono_metadata_decode_blob_size (pkey, &pkey);
834 aname->public_key = (guchar*)pkey;
836 mono_digest_get_public_token (token, aname->public_key, len);
837 encoded = encode_public_tok (token, 8);
838 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
844 aname->public_key = NULL;
845 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
848 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
849 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
851 const gchar *pkey_end;
852 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
853 pkey_end += len; /* move to end */
854 size_t size = pkey_end - (const gchar*)aname->public_key;
855 guchar *tmp = g_new (guchar, size);
856 memcpy (tmp, aname->public_key, size);
857 aname->public_key = tmp;
862 aname->public_key = 0;
864 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
865 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
867 case COFF_MACHINE_I386:
868 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
869 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
870 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
871 else if ((flags & 0x70) == 0x70)
872 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
874 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
876 case COFF_MACHINE_IA64:
877 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
879 case COFF_MACHINE_AMD64:
880 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
882 case COFF_MACHINE_ARM:
883 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
893 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
895 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
899 * mono_stringify_assembly_name:
900 * @aname: the assembly name.
902 * Convert @aname into its string format. The returned string is dynamically
903 * allocated and should be freed by the caller.
905 * Returns: a newly allocated string with a string representation of
909 mono_stringify_assembly_name (MonoAssemblyName *aname)
911 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
913 return g_strdup_printf (
914 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
915 quote, aname->name, quote,
916 aname->major, aname->minor, aname->build, aname->revision,
917 aname->culture && *aname->culture? aname->culture: "neutral",
918 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
919 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
923 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
925 const gchar *public_tok;
928 public_tok = mono_metadata_blob_heap (image, key_index);
929 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
931 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
933 mono_digest_get_public_token (token, (guchar*)public_tok, len);
934 return encode_public_tok (token, 8);
937 return encode_public_tok ((guchar*)public_tok, len);
941 * mono_assembly_addref:
942 * @assemnly: the assembly to reference
944 * This routine increments the reference count on a MonoAssembly.
945 * The reference count is reduced every time the method mono_assembly_close() is
949 mono_assembly_addref (MonoAssembly *assembly)
951 InterlockedIncrement (&assembly->ref_count);
955 * CAUTION: This table must be kept in sync with
956 * ivkm/reflect/Fusion.cs
959 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
960 #define WINFX_KEY "31bf3856ad364e35"
961 #define ECMA_KEY "b77a5c561934e089"
962 #define MSFINAL_KEY "b03f5f7f11d50a3a"
963 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
971 static KeyRemapEntry key_remap_table[] = {
972 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
973 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
974 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
975 { "System", SILVERLIGHT_KEY, ECMA_KEY },
976 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
977 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
978 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
979 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
980 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
981 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
982 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
983 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
984 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
985 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
986 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
987 { "System.Numerics", WINFX_KEY, ECMA_KEY },
988 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
989 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
990 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
991 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
992 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
993 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
994 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
995 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
996 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
997 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
998 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
999 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1000 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1004 remap_keys (MonoAssemblyName *aname)
1007 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1008 const KeyRemapEntry *entry = &key_remap_table [i];
1010 if (strcmp (aname->name, entry->name) ||
1011 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1014 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1016 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1017 "Remapped public key token of retargetable assembly %s from %s to %s",
1018 aname->name, entry->from, entry->to);
1023 static MonoAssemblyName *
1024 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1026 const MonoRuntimeInfo *current_runtime;
1027 int pos, first, last;
1029 if (aname->name == NULL) return aname;
1031 current_runtime = mono_get_runtime_info ();
1033 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1034 const AssemblyVersionSet* vset;
1036 /* Remap to current runtime */
1037 vset = ¤t_runtime->version_sets [0];
1039 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1040 dest_aname->major = vset->major;
1041 dest_aname->minor = vset->minor;
1042 dest_aname->build = vset->build;
1043 dest_aname->revision = vset->revision;
1044 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1046 /* Remap assembly name */
1047 if (!strcmp (aname->name, "System.Net"))
1048 dest_aname->name = g_strdup ("System");
1050 remap_keys (dest_aname);
1052 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1053 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1055 aname->major, aname->minor, aname->build, aname->revision,
1057 vset->major, vset->minor, vset->build, vset->revision
1063 #ifndef DISABLE_ASSEMBLY_REMAPPING
1065 last = G_N_ELEMENTS (framework_assemblies) - 1;
1067 while (first <= last) {
1069 pos = first + (last - first) / 2;
1070 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1072 const AssemblyVersionSet* vset;
1073 int index = framework_assemblies[pos].version_set_index;
1074 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1075 vset = ¤t_runtime->version_sets [index];
1077 if (aname->major == vset->major && aname->minor == vset->minor &&
1078 aname->build == vset->build && aname->revision == vset->revision)
1081 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1084 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1085 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1086 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1088 aname->major, aname->minor, aname->build, aname->revision,
1089 vset->major, vset->minor, vset->build, vset->revision
1092 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1093 dest_aname->major = vset->major;
1094 dest_aname->minor = vset->minor;
1095 dest_aname->build = vset->build;
1096 dest_aname->revision = vset->revision;
1097 if (framework_assemblies[pos].new_assembly_name != NULL) {
1098 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1099 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1100 "The assembly name %s was remapped to %s",
1105 } else if (res < 0) {
1117 * mono_assembly_get_assemblyref:
1118 * @image: pointer to the MonoImage to extract the information from.
1119 * @index: index to the assembly reference in the image.
1120 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1122 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1125 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1128 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1131 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1133 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1135 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1136 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1137 aname->hash_value = hash;
1138 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1139 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1140 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1141 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1142 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1143 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1144 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1146 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1147 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1148 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1151 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1156 mono_assembly_load_reference (MonoImage *image, int index)
1158 MonoAssembly *reference;
1159 MonoAssemblyName aname;
1160 MonoImageOpenStatus status;
1163 * image->references is shared between threads, so we need to access
1164 * it inside a critical section.
1166 mono_assemblies_lock ();
1167 if (!image->references) {
1168 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1170 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1171 image->nreferences = t->rows;
1173 reference = image->references [index];
1174 mono_assemblies_unlock ();
1178 mono_assembly_get_assemblyref (image, index, &aname);
1180 if (image->assembly && image->assembly->ref_only) {
1181 /* We use the loaded corlib */
1182 if (!strcmp (aname.name, "mscorlib"))
1183 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1185 reference = mono_assembly_loaded_full (&aname, TRUE);
1187 /* Try a postload search hook */
1188 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1192 * Here we must advice that the error was due to
1193 * a non loaded reference using the ReflectionOnly api
1196 reference = (MonoAssembly *)REFERENCE_MISSING;
1198 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1199 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1200 * accordingly, it would fail on the MS runtime before).
1201 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1202 * example bug-349190.2.cs and who knows how much more code in the wild.
1204 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1205 if (!reference && image->assembly)
1206 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1209 if (reference == NULL){
1212 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1213 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 : "" );
1214 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1215 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1216 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1217 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1218 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1219 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1221 extra_msg = g_strdup ("");
1224 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1225 " Assembly: %s (assemblyref_index=%d)\n"
1226 " Version: %d.%d.%d.%d\n"
1227 " Public Key: %s\n%s",
1228 image->name, aname.name, index,
1229 aname.major, aname.minor, aname.build, aname.revision,
1230 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1235 mono_assemblies_lock ();
1236 if (reference == NULL) {
1237 /* Flag as not found */
1238 reference = (MonoAssembly *)REFERENCE_MISSING;
1241 if (!image->references [index]) {
1242 if (reference != REFERENCE_MISSING){
1243 mono_assembly_addref (reference);
1244 if (image->assembly)
1245 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1246 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1248 if (image->assembly)
1249 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1250 image->assembly->aname.name, image->assembly);
1253 image->references [index] = reference;
1255 mono_assemblies_unlock ();
1257 if (image->references [index] != reference) {
1258 /* Somebody loaded it before us */
1259 mono_assembly_close (reference);
1264 * mono_assembly_load_references:
1267 * @deprecated: There is no reason to use this method anymore, it does nothing
1269 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1272 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1274 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1275 *status = MONO_IMAGE_OK;
1278 typedef struct AssemblyLoadHook AssemblyLoadHook;
1279 struct AssemblyLoadHook {
1280 AssemblyLoadHook *next;
1281 MonoAssemblyLoadFunc func;
1285 AssemblyLoadHook *assembly_load_hook = NULL;
1288 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1290 AssemblyLoadHook *hook;
1292 for (hook = assembly_load_hook; hook; hook = hook->next) {
1293 hook->func (ass, hook->user_data);
1298 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1300 AssemblyLoadHook *hook;
1302 g_return_if_fail (func != NULL);
1304 hook = g_new0 (AssemblyLoadHook, 1);
1306 hook->user_data = user_data;
1307 hook->next = assembly_load_hook;
1308 assembly_load_hook = hook;
1312 free_assembly_load_hooks (void)
1314 AssemblyLoadHook *hook, *next;
1316 for (hook = assembly_load_hook; hook; hook = next) {
1322 typedef struct AssemblySearchHook AssemblySearchHook;
1323 struct AssemblySearchHook {
1324 AssemblySearchHook *next;
1325 MonoAssemblySearchFunc func;
1331 AssemblySearchHook *assembly_search_hook = NULL;
1333 static MonoAssembly*
1334 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1336 AssemblySearchHook *hook;
1338 for (hook = assembly_search_hook; hook; hook = hook->next) {
1339 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1342 * A little explanation is in order here.
1344 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1345 * The embedding API exposes a search hook that doesn't take such argument.
1347 * The original fix would call the default search hook before all the registered ones and pass
1348 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1349 * rely on. Which is the ordering between user hooks and the default runtime hook.
1351 * Registering the hook after mono_jit_init would let your hook run before the default one and
1352 * when using it to handle non standard app layouts this could save your app from a massive amount
1353 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1354 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1356 * So what's the fix? We register the default hook using regular means and special case it when iterating
1357 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1360 if (hook->func == (void*)mono_domain_assembly_postload_search)
1361 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1363 ass = hook->func (aname, hook->user_data);
1373 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1375 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1379 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1381 AssemblySearchHook *hook;
1383 g_return_if_fail (func != NULL);
1385 hook = g_new0 (AssemblySearchHook, 1);
1387 hook->user_data = user_data;
1388 hook->refonly = refonly;
1389 hook->postload = postload;
1390 hook->next = assembly_search_hook;
1391 assembly_search_hook = hook;
1395 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1397 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1401 free_assembly_search_hooks (void)
1403 AssemblySearchHook *hook, *next;
1405 for (hook = assembly_search_hook; hook; hook = next) {
1412 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1414 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1418 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1420 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1424 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1426 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1429 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1430 struct AssemblyPreLoadHook {
1431 AssemblyPreLoadHook *next;
1432 MonoAssemblyPreLoadFunc func;
1436 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1437 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1439 static MonoAssembly *
1440 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1442 AssemblyPreLoadHook *hook;
1443 MonoAssembly *assembly;
1445 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1446 assembly = hook->func (aname, assemblies_path, hook->user_data);
1447 if (assembly != NULL)
1454 static MonoAssembly *
1455 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1457 AssemblyPreLoadHook *hook;
1458 MonoAssembly *assembly;
1460 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1461 assembly = hook->func (aname, assemblies_path, hook->user_data);
1462 if (assembly != NULL)
1470 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1472 AssemblyPreLoadHook *hook;
1474 g_return_if_fail (func != NULL);
1476 hook = g_new0 (AssemblyPreLoadHook, 1);
1478 hook->user_data = user_data;
1479 hook->next = assembly_preload_hook;
1480 assembly_preload_hook = hook;
1484 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1486 AssemblyPreLoadHook *hook;
1488 g_return_if_fail (func != NULL);
1490 hook = g_new0 (AssemblyPreLoadHook, 1);
1492 hook->user_data = user_data;
1493 hook->next = assembly_refonly_preload_hook;
1494 assembly_refonly_preload_hook = hook;
1498 free_assembly_preload_hooks (void)
1500 AssemblyPreLoadHook *hook, *next;
1502 for (hook = assembly_preload_hook; hook; hook = next) {
1507 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1514 absolute_dir (const gchar *filename)
1525 if (g_path_is_absolute (filename)) {
1526 part = g_path_get_dirname (filename);
1527 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1532 cwd = g_get_current_dir ();
1533 mixed = g_build_filename (cwd, filename, NULL);
1534 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1539 for (i = 0; (part = parts [i]) != NULL; i++) {
1540 if (!strcmp (part, "."))
1543 if (!strcmp (part, "..")) {
1544 if (list && list->next) /* Don't remove root */
1545 list = g_list_delete_link (list, list);
1547 list = g_list_prepend (list, part);
1551 result = g_string_new ("");
1552 list = g_list_reverse (list);
1554 /* Ignores last data pointer, which should be the filename */
1555 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1557 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1562 g_string_free (result, FALSE);
1567 return g_strdup (".");
1574 * mono_assembly_open_from_bundle:
1575 * @filename: Filename requested
1576 * @status: return status code
1578 * This routine tries to open the assembly specified by `filename' from the
1579 * defined bundles, if found, returns the MonoImage for it, if not found
1583 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1587 gchar *lowercase_filename;
1588 MonoImage *image = NULL;
1589 gboolean is_satellite = FALSE;
1591 * we do a very simple search for bundled assemblies: it's not a general
1592 * purpose assembly loading mechanism.
1598 lowercase_filename = g_utf8_strdown (filename, -1);
1599 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1600 g_free (lowercase_filename);
1601 name = g_path_get_basename (filename);
1602 mono_assemblies_lock ();
1603 for (i = 0; !image && bundles [i]; ++i) {
1604 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1605 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1609 mono_assemblies_unlock ();
1611 mono_image_addref (image);
1612 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1621 * mono_assemblies_open_full:
1622 * @filename: the file to load
1623 * @status: return status code
1624 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1626 * This loads an assembly from the specified @filename. The @filename allows
1627 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1628 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1629 * is treated as a local path.
1631 * First, an attempt is made to load the assembly from the bundled executable (for those
1632 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1633 * assembly has been registered as an embedded assembly). If this is not the case, then
1634 * the assembly is loaded from disk using `api:mono_image_open_full`.
1636 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1637 * the assembly is made.
1639 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1640 * the `System.Reflection` API.
1642 * Returns: NULL on error, with the @status set to an error code, or a pointer
1646 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1650 MonoImageOpenStatus def_status;
1653 gboolean loaded_from_bundle;
1655 g_return_val_if_fail (filename != NULL, NULL);
1658 status = &def_status;
1659 *status = MONO_IMAGE_OK;
1661 if (strncmp (filename, "file://", 7) == 0) {
1662 GError *error = NULL;
1663 gchar *uri = (gchar *) filename;
1667 * MS allows file://c:/... and fails on file://localhost/c:/...
1668 * They also throw an IndexOutOfRangeException if "file://"
1671 uri = g_strdup_printf ("file:///%s", uri + 7);
1674 uri = mono_escape_uri_string (tmpuri);
1675 fname = g_filename_from_uri (uri, NULL, &error);
1678 if (tmpuri != filename)
1681 if (error != NULL) {
1682 g_warning ("%s\n", error->message);
1683 g_error_free (error);
1684 fname = g_strdup (filename);
1687 fname = g_strdup (filename);
1690 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1691 "Assembly Loader probing location: '%s'.", fname);
1694 if (!mono_assembly_is_in_gac (fname)) {
1696 new_fname = mono_make_shadow_copy (fname, &error);
1697 if (!is_ok (&error)) {
1698 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1699 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1700 mono_error_cleanup (&error);
1701 *status = MONO_IMAGE_IMAGE_INVALID;
1706 if (new_fname && new_fname != fname) {
1709 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1710 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1715 // If VM built with mkbundle
1716 loaded_from_bundle = FALSE;
1717 if (bundles != NULL) {
1718 image = mono_assembly_open_from_bundle (fname, status, refonly);
1719 loaded_from_bundle = image != NULL;
1723 image = mono_image_open_full (fname, status, refonly);
1726 if (*status == MONO_IMAGE_OK)
1727 *status = MONO_IMAGE_ERROR_ERRNO;
1732 if (image->assembly) {
1733 /* Already loaded by another appdomain */
1734 mono_assembly_invoke_load_hook (image->assembly);
1735 mono_image_close (image);
1737 return image->assembly;
1740 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1743 if (!loaded_from_bundle)
1744 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1745 "Assembly Loader loaded assembly from location: '%s'.", filename);
1747 mono_config_for_assembly (ass->image);
1750 /* Clear the reference added by mono_image_open */
1751 mono_image_close (image);
1759 free_item (gpointer val, gpointer user_data)
1765 * mono_assembly_load_friends:
1768 * Load the list of friend assemblies that are allowed to access
1769 * the assembly's internal types and members. They are stored as assembly
1770 * names in custom attributes.
1772 * This is an internal method, we need this because when we load mscorlib
1773 * we do not have the internals visible cattr loaded yet,
1774 * so we need to load these after we initialize the runtime.
1776 * LOCKING: Acquires the assemblies lock plus the loader lock.
1779 mono_assembly_load_friends (MonoAssembly* ass)
1783 MonoCustomAttrInfo* attrs;
1786 if (ass->friend_assembly_names_inited)
1789 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1790 mono_error_assert_ok (&error);
1792 mono_assemblies_lock ();
1793 ass->friend_assembly_names_inited = TRUE;
1794 mono_assemblies_unlock ();
1798 mono_assemblies_lock ();
1799 if (ass->friend_assembly_names_inited) {
1800 mono_assemblies_unlock ();
1803 mono_assemblies_unlock ();
1807 * We build the list outside the assemblies lock, the worse that can happen
1808 * is that we'll need to free the allocated list.
1810 for (i = 0; i < attrs->num_attrs; ++i) {
1811 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1812 MonoAssemblyName *aname;
1814 /* Do some sanity checking */
1815 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1817 if (attr->data_size < 4)
1819 data = (const char*)attr->data;
1820 /* 0xFF means null string, see custom attr format */
1821 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1823 mono_metadata_decode_value (data + 2, &data);
1824 aname = g_new0 (MonoAssemblyName, 1);
1825 /*g_print ("friend ass: %s\n", data);*/
1826 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1827 list = g_slist_prepend (list, aname);
1832 mono_custom_attrs_free (attrs);
1834 mono_assemblies_lock ();
1835 if (ass->friend_assembly_names_inited) {
1836 mono_assemblies_unlock ();
1837 g_slist_foreach (list, free_item, NULL);
1838 g_slist_free (list);
1841 ass->friend_assembly_names = list;
1843 /* Because of the double checked locking pattern above */
1844 mono_memory_barrier ();
1845 ass->friend_assembly_names_inited = TRUE;
1846 mono_assemblies_unlock ();
1849 struct HasReferenceAssemblyAttributeIterData {
1854 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1856 gboolean stop_scanning = FALSE;
1857 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1859 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1860 /* Note we don't check the assembly name, same as coreCLR. */
1861 iter_data->has_attr = TRUE;
1862 stop_scanning = TRUE;
1865 return stop_scanning;
1869 * mono_assembly_has_reference_assembly_attribute:
1870 * @assembly: a MonoAssembly
1871 * @error: set on error.
1873 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1874 * On error returns FALSE and sets @error.
1877 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1879 mono_error_init (error);
1882 * This might be called during assembly loading, so do everything using the low-level
1886 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1888 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1890 return iter_data.has_attr;
1894 * mono_assembly_open:
1895 * @filename: Opens the assembly pointed out by this name
1896 * @status: return status code
1898 * This loads an assembly from the specified @filename. The @filename allows
1899 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1900 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1901 * is treated as a local path.
1903 * First, an attempt is made to load the assembly from the bundled executable (for those
1904 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1905 * assembly has been registered as an embedded assembly). If this is not the case, then
1906 * the assembly is loaded from disk using `api:mono_image_open_full`.
1908 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1909 * the assembly is made.
1911 * Return: a pointer to the MonoAssembly if @filename contains a valid
1912 * assembly or NULL on error. Details about the error are stored in the
1916 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1918 return mono_assembly_open_full (filename, status, FALSE);
1922 * mono_assembly_load_from_full:
1923 * @image: Image to load the assembly from
1924 * @fname: assembly name to associate with the assembly
1925 * @status: returns the status condition
1926 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1928 * If the provided @image has an assembly reference, it will process the given
1929 * image as an assembly with the given name.
1931 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1933 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1934 * set to #MONO_IMAGE_OK; or NULL on error.
1936 * If there is an error loading the assembly the @status will indicate the
1937 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1938 * image did not contain an assembly reference table.
1941 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1942 MonoImageOpenStatus *status, gboolean refonly)
1944 MonoAssembly *ass, *ass2;
1947 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1948 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1949 *status = MONO_IMAGE_IMAGE_INVALID;
1953 #if defined (HOST_WIN32)
1958 tmp_fn = g_strdup (fname);
1959 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1960 if (tmp_fn [i] == '/')
1964 base_dir = absolute_dir (tmp_fn);
1968 base_dir = absolute_dir (fname);
1972 * Create assembly struct, and enter it into the assembly cache
1974 ass = g_new0 (MonoAssembly, 1);
1975 ass->basedir = base_dir;
1976 ass->ref_only = refonly;
1979 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1981 mono_assembly_fill_assembly_name (image, &ass->aname);
1983 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1984 // MS.NET doesn't support loading other mscorlibs
1987 mono_image_addref (mono_defaults.corlib);
1988 *status = MONO_IMAGE_OK;
1989 return mono_defaults.corlib->assembly;
1992 /* Add a non-temporary reference because of ass->image */
1993 mono_image_addref (image);
1995 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);
1998 * The load hooks might take locks so we can't call them while holding the
2001 if (ass->aname.name) {
2002 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2006 mono_image_close (image);
2007 *status = MONO_IMAGE_OK;
2012 /* We need to check for ReferenceAssmeblyAttribute before we
2013 * mark the assembly as loaded and before we fire the load
2014 * hook. Otherwise mono_domain_fire_assembly_load () in
2015 * appdomain.c will cache a mapping from the assembly name to
2016 * this image and we won't be able to look for a different
2020 MonoError refasm_error;
2021 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2022 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2025 mono_image_close (image);
2026 *status = MONO_IMAGE_IMAGE_INVALID;
2029 mono_error_cleanup (&refasm_error);
2032 mono_assemblies_lock ();
2034 if (image->assembly) {
2036 * This means another thread has already loaded the assembly, but not yet
2037 * called the load hooks so the search hook can't find the assembly.
2039 mono_assemblies_unlock ();
2040 ass2 = image->assembly;
2043 mono_image_close (image);
2044 *status = MONO_IMAGE_OK;
2048 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2050 image->assembly = ass;
2052 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2053 mono_assemblies_unlock ();
2056 if (image->is_module_handle)
2057 mono_image_fixup_vtable (image);
2060 mono_assembly_invoke_load_hook (ass);
2062 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2068 * mono_assembly_load_from:
2069 * @image: Image to load the assembly from
2070 * @fname: assembly name to associate with the assembly
2071 * @status: return status code
2073 * If the provided @image has an assembly reference, it will process the given
2074 * image as an assembly with the given name.
2076 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2078 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2079 * @refonly parameter set to FALSE.
2080 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2081 * set to #MONO_IMAGE_OK; or NULL on error.
2083 * If there is an error loading the assembly the @status will indicate the
2084 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2085 * image did not contain an assembly reference table.
2089 mono_assembly_load_from (MonoImage *image, const char *fname,
2090 MonoImageOpenStatus *status)
2092 return mono_assembly_load_from_full (image, fname, status, FALSE);
2096 * mono_assembly_name_free:
2097 * @aname: assembly name to free
2099 * Frees the provided assembly name object.
2100 * (it does not frees the object itself, only the name members).
2103 mono_assembly_name_free (MonoAssemblyName *aname)
2108 g_free ((void *) aname->name);
2109 g_free ((void *) aname->culture);
2110 g_free ((void *) aname->hash_value);
2111 g_free ((guint8*) aname->public_key);
2115 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2118 gchar header [16], val, *arr;
2119 gint i, j, offset, bitlen, keylen, pkeylen;
2121 keylen = strlen (key) >> 1;
2125 /* allow the ECMA standard key */
2126 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2128 *pubkey = g_strdup (key);
2134 val = g_ascii_xdigit_value (key [0]) << 4;
2135 val |= g_ascii_xdigit_value (key [1]);
2140 val = g_ascii_xdigit_value (key [24]);
2141 val |= g_ascii_xdigit_value (key [25]);
2153 /* We need the first 16 bytes
2154 * to check whether this key is valid or not */
2155 pkeylen = strlen (pkey) >> 1;
2159 for (i = 0, j = 0; i < 16; i++) {
2160 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2161 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2164 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2165 header [1] != 0x02 || /* Version (0x02) */
2166 header [2] != 0x00 || /* Reserved (word) */
2167 header [3] != 0x00 ||
2168 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2171 /* Based on this length, we _should_ be able to know if the length is right */
2172 bitlen = read32 (header + 12) >> 3;
2173 if ((bitlen + 16 + 4) != pkeylen)
2176 /* parsing is OK and the public key itself is not requested back */
2180 /* Encode the size of the blob */
2182 if (keylen <= 127) {
2183 arr = (gchar *)g_malloc (keylen + 1);
2184 arr [offset++] = keylen;
2186 arr = (gchar *)g_malloc (keylen + 2);
2187 arr [offset++] = 0x80; /* 10bs */
2188 arr [offset++] = keylen;
2191 for (i = offset, j = 0; i < keylen + offset; i++) {
2192 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2193 arr [i] |= g_ascii_xdigit_value (key [j++]);
2202 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)
2204 gint major, minor, build, revision;
2207 gchar *pkey, *pkeyptr, *encoded, tok [8];
2209 memset (aname, 0, sizeof (MonoAssemblyName));
2212 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2213 if (version_parts < 2 || version_parts > 4)
2216 /* FIXME: we should set build & revision to -1 (instead of 0)
2217 if these are not set in the version string. That way, later on,
2218 we can still determine if these were specified. */
2219 aname->major = major;
2220 aname->minor = minor;
2221 if (version_parts >= 3)
2222 aname->build = build;
2225 if (version_parts == 4)
2226 aname->revision = revision;
2228 aname->revision = 0;
2231 aname->flags = flags;
2233 aname->name = g_strdup (name);
2236 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2237 aname->culture = g_strdup ("");
2239 aname->culture = g_strdup (culture);
2242 if (token && strncmp (token, "null", 4) != 0) {
2245 /* the constant includes the ending NULL, hence the -1 */
2246 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2247 mono_assembly_name_free (aname);
2250 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2251 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2257 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2258 mono_assembly_name_free (aname);
2263 if (save_public_key)
2264 aname->public_key = (guint8*)pkey;
2267 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2271 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2272 // We also need to generate the key token
2273 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2274 encoded = encode_public_tok ((guchar*) tok, 8);
2275 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2278 if (save_public_key)
2279 aname->public_key = (guint8*) pkey;
2288 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2293 parts = g_strsplit (dirname, "_", 3);
2294 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2299 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2305 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2307 char *eqsign = strchr (pair, '=');
2315 *key = (gchar*)pair;
2316 *keylen = eqsign - *key;
2317 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2319 *value = g_strstrip (eqsign + 1);
2324 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2328 gchar *version = NULL;
2330 gchar *culture = NULL;
2332 gchar *token = NULL;
2336 gchar *retargetable = NULL;
2337 gchar *retargetable_uq;
2341 gchar *value, *part_name;
2342 guint32 part_name_len;
2345 gboolean version_defined;
2346 gboolean token_defined;
2348 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2350 if (!is_version_defined)
2351 is_version_defined = &version_defined;
2352 *is_version_defined = FALSE;
2353 if (!is_token_defined)
2354 is_token_defined = &token_defined;
2355 *is_token_defined = FALSE;
2357 parts = tmp = g_strsplit (name, ",", 6);
2358 if (!tmp || !*tmp) {
2363 dllname = g_strstrip (*tmp);
2368 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2369 goto cleanup_and_fail;
2371 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2372 *is_version_defined = TRUE;
2374 if (strlen (version) == 0) {
2375 goto cleanup_and_fail;
2381 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2383 if (strlen (culture) == 0) {
2384 goto cleanup_and_fail;
2390 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2391 *is_token_defined = TRUE;
2393 if (strlen (token) == 0) {
2394 goto cleanup_and_fail;
2400 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2402 if (strlen (key) == 0) {
2403 goto cleanup_and_fail;
2409 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2410 retargetable = value;
2411 retargetable_uq = unquote (retargetable);
2412 if (retargetable_uq != NULL)
2413 retargetable = retargetable_uq;
2415 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2416 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2417 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2418 g_free (retargetable_uq);
2419 goto cleanup_and_fail;
2422 g_free (retargetable_uq);
2427 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2429 procarch_uq = unquote (procarch);
2430 if (procarch_uq != NULL)
2431 procarch = procarch_uq;
2433 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2434 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2435 else if (!g_ascii_strcasecmp (procarch, "X86"))
2436 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2437 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2438 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2439 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2440 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2442 g_free (procarch_uq);
2443 goto cleanup_and_fail;
2446 g_free (procarch_uq);
2455 /* if retargetable flag is set, then we must have a fully qualified name */
2456 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2457 goto cleanup_and_fail;
2460 dllname_uq = unquote (dllname);
2461 version_uq = unquote (version);
2462 culture_uq = unquote (culture);
2463 token_uq = unquote (token);
2464 key_uq = unquote (key);
2466 res = build_assembly_name (
2467 dllname_uq == NULL ? dllname : dllname_uq,
2468 version_uq == NULL ? version : version_uq,
2469 culture_uq == NULL ? culture : culture_uq,
2470 token_uq == NULL ? token : token_uq,
2471 key_uq == NULL ? key : key_uq,
2472 flags, arch, aname, save_public_key);
2474 g_free (dllname_uq);
2475 g_free (version_uq);
2476 g_free (culture_uq);
2489 unquote (const char *str)
2497 slen = strlen (str);
2501 if (*str != '\'' && *str != '\"')
2504 end = str + slen - 1;
2508 return g_strndup (str + 1, slen - 2);
2512 * mono_assembly_name_parse:
2513 * @name: name to parse
2514 * @aname: the destination assembly name
2516 * Parses an assembly qualified type name and assigns the name,
2517 * version, culture and token to the provided assembly name object.
2519 * Returns: TRUE if the name could be parsed.
2522 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2524 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2528 * mono_assembly_name_new:
2529 * @name: name to parse
2531 * Allocate a new MonoAssemblyName and fill its values from the
2534 * Returns: a newly allocated structure or NULL if there was any failure.
2537 mono_assembly_name_new (const char *name)
2539 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2540 if (mono_assembly_name_parse (name, aname))
2547 mono_assembly_name_get_name (MonoAssemblyName *aname)
2553 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2555 return aname->culture;
2559 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2561 if (aname->public_key_token [0])
2562 return aname->public_key_token;
2567 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2570 *minor = aname->minor;
2572 *build = aname->build;
2574 *revision = aname->revision;
2575 return aname->major;
2578 static MonoAssembly*
2579 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2581 gchar *fullpath = NULL;
2583 const char* direntry;
2584 MonoAssemblyName gac_aname;
2585 gint major=-1, minor=0, build=0, revision=0;
2586 gboolean exact_version;
2588 dirhandle = g_dir_open (basepath, 0, NULL);
2592 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2594 while ((direntry = g_dir_read_name (dirhandle))) {
2595 gboolean match = TRUE;
2597 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2600 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2603 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2604 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2608 if (exact_version) {
2609 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2610 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2612 else if (gac_aname.major < major)
2614 else if (gac_aname.major == major) {
2615 if (gac_aname.minor < minor)
2617 else if (gac_aname.minor == minor) {
2618 if (gac_aname.build < build)
2620 else if (gac_aname.build == build && gac_aname.revision <= revision)
2627 major = gac_aname.major;
2628 minor = gac_aname.minor;
2629 build = gac_aname.build;
2630 revision = gac_aname.revision;
2632 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2635 mono_assembly_name_free (&gac_aname);
2638 g_dir_close (dirhandle);
2640 if (fullpath == NULL)
2643 MonoAssembly *res = mono_assembly_open (fullpath, status);
2650 * mono_assembly_load_with_partial_name:
2651 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2652 * @status: return status code
2654 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2655 * so it might contain a qualified type name, version, culture and token.
2657 * This will load the assembly from the file whose name is derived from the assembly name
2658 * by appending the .dll extension.
2660 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2661 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2662 * if that fails from the GAC.
2664 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2667 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2671 MonoAssemblyName *aname, base_name;
2672 MonoAssemblyName mapped_aname;
2673 gchar *fullname, *gacpath;
2676 memset (&base_name, 0, sizeof (MonoAssemblyName));
2679 if (!mono_assembly_name_parse (name, aname))
2683 * If no specific version has been requested, make sure we load the
2684 * correct version for system assemblies.
2686 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2687 aname = mono_assembly_remap_version (aname, &mapped_aname);
2689 res = mono_assembly_loaded (aname);
2691 mono_assembly_name_free (aname);
2695 res = invoke_assembly_preload_hook (aname, assemblies_path);
2697 res->in_gac = FALSE;
2698 mono_assembly_name_free (aname);
2702 fullname = g_strdup_printf ("%s.dll", aname->name);
2704 if (extra_gac_paths) {
2705 paths = extra_gac_paths;
2706 while (!res && *paths) {
2707 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2708 res = probe_for_partial_name (gacpath, fullname, aname, status);
2717 mono_assembly_name_free (aname);
2721 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2722 res = probe_for_partial_name (gacpath, fullname, aname, status);
2726 mono_assembly_name_free (aname);
2731 MonoDomain *domain = mono_domain_get ();
2733 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2734 if (!is_ok (&error)) {
2735 mono_error_cleanup (&error);
2736 if (*status == MONO_IMAGE_OK)
2737 *status = MONO_IMAGE_IMAGE_INVALID;
2745 mono_assembly_is_in_gac (const gchar *filename)
2747 const gchar *rootdir;
2751 if (filename == NULL)
2754 for (paths = extra_gac_paths; paths && *paths; paths++) {
2755 if (strstr (*paths, filename) != *paths)
2758 gp = (gchar *) (filename + strlen (*paths));
2759 if (*gp != G_DIR_SEPARATOR)
2762 if (strncmp (gp, "lib", 3))
2765 if (*gp != G_DIR_SEPARATOR)
2768 if (strncmp (gp, "mono", 4))
2771 if (*gp != G_DIR_SEPARATOR)
2774 if (strncmp (gp, "gac", 3))
2777 if (*gp != G_DIR_SEPARATOR)
2783 rootdir = mono_assembly_getrootdir ();
2784 if (strstr (filename, rootdir) != filename)
2787 gp = (gchar *) (filename + strlen (rootdir));
2788 if (*gp != G_DIR_SEPARATOR)
2791 if (strncmp (gp, "mono", 4))
2794 if (*gp != G_DIR_SEPARATOR)
2797 if (strncmp (gp, "gac", 3))
2800 if (*gp != G_DIR_SEPARATOR)
2806 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2809 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2813 if (strstr (aname->name, ".dll")) {
2814 len = strlen (aname->name) - 4;
2815 name = (gchar *)g_malloc (len + 1);
2816 strncpy (name, aname->name, len);
2819 name = g_strdup (aname->name);
2822 culture = g_utf8_strdown (aname->culture, -1);
2824 culture = g_strdup ("");
2826 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2827 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2831 filename = g_strconcat (pname, ".dll", NULL);
2832 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2838 if (extra_gac_paths) {
2839 paths = extra_gac_paths;
2840 while (!image && *paths) {
2841 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2842 "lib", "mono", "gac", subpath, NULL);
2843 image = mono_image_open (fullpath, NULL);
2854 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2855 "mono", "gac", subpath, NULL);
2856 image = mono_image_open (fullpath, NULL);
2863 static MonoAssemblyName*
2864 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2866 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2867 dest_name->major = info->new_version.major;
2868 dest_name->minor = info->new_version.minor;
2869 dest_name->build = info->new_version.build;
2870 dest_name->revision = info->new_version.revision;
2875 /* LOCKING: assembly_binding lock must be held */
2876 static MonoAssemblyBindingInfo*
2877 search_binding_loaded (MonoAssemblyName *aname)
2881 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2882 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2883 if (assembly_binding_maps_name (info, aname))
2890 static inline gboolean
2891 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2893 if (left->major != right->major || left->minor != right->minor ||
2894 left->build != right->build || left->revision != right->revision)
2900 static inline gboolean
2901 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2903 if (left->has_old_version_bottom != right->has_old_version_bottom)
2906 if (left->has_old_version_top != right->has_old_version_top)
2909 if (left->has_new_version != right->has_new_version)
2912 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2915 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2918 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2924 /* LOCKING: assumes all the necessary locks are held */
2926 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2928 MonoAssemblyBindingInfo *info_copy;
2930 MonoAssemblyBindingInfo *info_tmp;
2931 MonoDomain *domain = (MonoDomain*)user_data;
2936 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2937 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2938 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2942 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2943 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2945 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2947 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2949 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2953 get_version_number (int major, int minor)
2955 return major * 256 + minor;
2958 static inline gboolean
2959 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2961 int aname_version_number = get_version_number (aname->major, aname->minor);
2962 if (!info->has_old_version_bottom)
2965 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2968 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2971 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2972 info->major = aname->major;
2973 info->minor = aname->minor;
2978 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2979 static MonoAssemblyBindingInfo*
2980 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2982 MonoAssemblyBindingInfo *info;
2985 if (!domain->assembly_bindings)
2989 for (list = domain->assembly_bindings; list; list = list->next) {
2990 info = (MonoAssemblyBindingInfo *)list->data;
2991 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2997 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2998 info->has_new_version && assembly_binding_maps_name (info, aname))
2999 info->is_valid = TRUE;
3001 info->is_valid = FALSE;
3007 static MonoAssemblyName*
3008 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3011 MonoAssemblyBindingInfo *info, *info2;
3015 if (aname->public_key_token [0] == 0)
3018 domain = mono_domain_get ();
3020 mono_assembly_binding_lock ();
3021 info = search_binding_loaded (aname);
3022 mono_assembly_binding_unlock ();
3025 mono_domain_lock (domain);
3026 info = get_per_domain_assembly_binding_info (domain, aname);
3027 mono_domain_unlock (domain);
3031 if (!check_policy_versions (info, aname))
3034 mono_assembly_bind_version (info, aname, dest_name);
3038 if (domain && domain->setup && domain->setup->configuration_file) {
3039 mono_domain_lock (domain);
3040 if (!domain->assembly_bindings_parsed) {
3041 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3042 /* expect this to succeed because mono_domain_set_options_from_config () did
3043 * the same thing when the domain was created. */
3044 mono_error_assert_ok (&error);
3046 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3048 if (!domain_config_file_path)
3049 domain_config_file_path = domain_config_file_name;
3051 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3052 domain->assembly_bindings_parsed = TRUE;
3053 if (domain_config_file_name != domain_config_file_path)
3054 g_free (domain_config_file_name);
3055 g_free (domain_config_file_path);
3058 info2 = get_per_domain_assembly_binding_info (domain, aname);
3061 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3062 info->name = g_strdup (info2->name);
3063 info->culture = g_strdup (info2->culture);
3064 info->domain_id = domain->domain_id;
3067 mono_domain_unlock (domain);
3071 info = g_new0 (MonoAssemblyBindingInfo, 1);
3072 info->major = aname->major;
3073 info->minor = aname->minor;
3076 if (!info->is_valid) {
3077 ppimage = mono_assembly_load_publisher_policy (aname);
3079 get_publisher_policy_info (ppimage, aname, info);
3080 mono_image_close (ppimage);
3084 /* Define default error value if needed */
3085 if (!info->is_valid) {
3086 info->name = g_strdup (aname->name);
3087 info->culture = g_strdup (aname->culture);
3088 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3091 mono_assembly_binding_lock ();
3092 info2 = search_binding_loaded (aname);
3094 /* This binding was added by another thread
3096 mono_assembly_binding_info_free (info);
3101 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3103 mono_assembly_binding_unlock ();
3105 if (!info->is_valid || !check_policy_versions (info, aname))
3108 mono_assembly_bind_version (info, aname, dest_name);
3113 * mono_assembly_load_from_gac
3115 * @aname: The assembly name object
3117 static MonoAssembly*
3118 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3120 MonoAssembly *result = NULL;
3121 gchar *name, *version, *culture, *fullpath, *subpath;
3126 if (aname->public_key_token [0] == 0) {
3130 if (strstr (aname->name, ".dll")) {
3131 len = strlen (filename) - 4;
3132 name = (gchar *)g_malloc (len + 1);
3133 strncpy (name, aname->name, len);
3136 name = g_strdup (aname->name);
3139 if (aname->culture) {
3140 culture = g_utf8_strdown (aname->culture, -1);
3142 culture = g_strdup ("");
3145 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3146 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3147 aname->minor, aname->build, aname->revision,
3151 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3156 if (extra_gac_paths) {
3157 paths = extra_gac_paths;
3158 while (!result && *paths) {
3159 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3160 result = mono_assembly_open_full (fullpath, status, refonly);
3167 result->in_gac = TRUE;
3172 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3173 "mono", "gac", subpath, NULL);
3174 result = mono_assembly_open_full (fullpath, status, refonly);
3178 result->in_gac = TRUE;
3186 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3189 MonoAssemblyName *aname;
3192 /* g_print ("corlib already loaded\n"); */
3196 // In native client, Corlib is embedded in the executable as static variable corlibData
3197 #if defined(__native_client__)
3198 if (corlibData != NULL && corlibSize != 0) {
3200 /* First "FALSE" instructs mono not to make a copy. */
3201 /* Second "FALSE" says this is not just a ref. */
3202 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3203 if (image == NULL || status != 0)
3204 g_print("mono_image_open_from_data_full failed: %d\n", status);
3205 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3206 if (corlib == NULL || status != 0)
3207 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3213 // A nonstandard preload hook may provide a special mscorlib assembly
3214 aname = mono_assembly_name_new ("mscorlib.dll");
3215 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3216 mono_assembly_name_free (aname);
3219 goto return_corlib_and_facades;
3221 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3222 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3223 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3225 goto return_corlib_and_facades;
3228 /* Normal case: Load corlib from mono/<version> */
3229 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3230 if (assemblies_path) { // Custom assemblies path
3231 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3233 g_free (corlib_file);
3234 goto return_corlib_and_facades;
3237 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3238 g_free (corlib_file);
3240 return_corlib_and_facades:
3241 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3242 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3247 static MonoAssembly*
3248 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3250 MonoError refasm_error;
3251 mono_error_init (&refasm_error);
3252 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3255 mono_error_cleanup (&refasm_error);
3261 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3262 const char *basedir,
3263 MonoImageOpenStatus *status,
3266 MonoAssembly *result;
3267 char *fullpath, *filename;
3268 MonoAssemblyName maped_aname;
3269 MonoAssemblyName maped_name_pp;
3274 aname = mono_assembly_remap_version (aname, &maped_aname);
3276 /* Reflection only assemblies don't get assembly binding */
3278 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3280 result = mono_assembly_loaded_full (aname, refonly);
3284 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3286 result->in_gac = FALSE;
3290 /* Currently we retrieve the loaded corlib for reflection
3291 * only requests, like a common reflection only assembly
3293 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3294 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3297 len = strlen (aname->name);
3298 for (ext_index = 0; ext_index < 2; ext_index ++) {
3299 ext = ext_index == 0 ? ".dll" : ".exe";
3300 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3301 filename = g_strdup (aname->name);
3302 /* Don't try appending .dll/.exe if it already has one of those extensions */
3305 filename = g_strconcat (aname->name, ext, NULL);
3308 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3315 fullpath = g_build_filename (basedir, filename, NULL);
3316 result = mono_assembly_open_full (fullpath, status, refonly);
3319 result->in_gac = FALSE;
3325 result = load_in_path (filename, default_path, status, refonly);
3327 result->in_gac = FALSE;
3337 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3339 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3342 /* Try a postload search hook */
3343 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3344 result = prevent_reference_assembly_from_running (result, refonly);
3350 * mono_assembly_load_full:
3351 * @aname: A MonoAssemblyName with the assembly name to load.
3352 * @basedir: A directory to look up the assembly at.
3353 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3354 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3356 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3357 * attempts to load the assembly from that directory before probing the standard locations.
3359 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3360 * assembly binding takes place.
3362 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3363 * value pointed by status is updated with an error code.
3366 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3368 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3372 * mono_assembly_load:
3373 * @aname: A MonoAssemblyName with the assembly name to load.
3374 * @basedir: A directory to look up the assembly at.
3375 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3377 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3378 * attempts to load the assembly from that directory before probing the standard locations.
3380 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3381 * value pointed by status is updated with an error code.
3384 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3386 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3390 * mono_assembly_loaded_full:
3391 * @aname: an assembly to look for.
3392 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3394 * This is used to determine if the specified assembly has been loaded
3395 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3396 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3399 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3402 MonoAssemblyName maped_aname;
3404 aname = mono_assembly_remap_version (aname, &maped_aname);
3406 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3412 * mono_assembly_loaded:
3413 * @aname: an assembly to look for.
3415 * This is used to determine if the specified assembly has been loaded
3417 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3418 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3421 mono_assembly_loaded (MonoAssemblyName *aname)
3423 return mono_assembly_loaded_full (aname, FALSE);
3427 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3429 if (assembly == NULL || assembly == REFERENCE_MISSING)
3432 if (assembly_is_dynamic (assembly)) {
3434 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3435 for (i = 0; i < dynimg->image.module_count; ++i)
3436 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3437 mono_dynamic_image_release_gc_roots (dynimg);
3442 * Returns whether mono_assembly_close_finish() must be called as
3443 * well. See comment for mono_image_close_except_pools() for why we
3444 * unload in two steps.
3447 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3450 g_return_val_if_fail (assembly != NULL, FALSE);
3452 if (assembly == REFERENCE_MISSING)
3455 /* Might be 0 already */
3456 if (InterlockedDecrement (&assembly->ref_count) > 0)
3459 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3461 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3463 mono_debug_close_image (assembly->image);
3465 mono_assemblies_lock ();
3466 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3467 mono_assemblies_unlock ();
3469 assembly->image->assembly = NULL;
3471 if (!mono_image_close_except_pools (assembly->image))
3472 assembly->image = NULL;
3474 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3475 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3476 mono_assembly_name_free (fname);
3479 g_slist_free (assembly->friend_assembly_names);
3480 g_free (assembly->basedir);
3482 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3488 mono_assembly_close_finish (MonoAssembly *assembly)
3490 g_assert (assembly && assembly != REFERENCE_MISSING);
3492 if (assembly->image)
3493 mono_image_close_finish (assembly->image);
3495 if (assembly_is_dynamic (assembly)) {
3496 g_free ((char*)assembly->aname.culture);
3503 * mono_assembly_close:
3504 * @assembly: the assembly to release.
3506 * This method releases a reference to the @assembly. The assembly is
3507 * only released when all the outstanding references to it are released.
3510 mono_assembly_close (MonoAssembly *assembly)
3512 if (mono_assembly_close_except_image_pools (assembly))
3513 mono_assembly_close_finish (assembly);
3517 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3520 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3521 mono_error_assert_ok (&error);
3526 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3528 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3533 * mono_assembly_foreach:
3534 * @func: function to invoke for each assembly loaded
3535 * @user_data: data passed to the callback
3537 * Invokes the provided @func callback for each assembly loaded into
3538 * the runtime. The first parameter passed to the callback is the
3539 * `MonoAssembly*`, and the second parameter is the @user_data.
3541 * This is done for all assemblies loaded in the runtime, not just
3542 * those loaded in the current application domain.
3545 mono_assembly_foreach (GFunc func, gpointer user_data)
3550 * We make a copy of the list to avoid calling the callback inside the
3551 * lock, which could lead to deadlocks.
3553 mono_assemblies_lock ();
3554 copy = g_list_copy (loaded_assemblies);
3555 mono_assemblies_unlock ();
3557 g_list_foreach (loaded_assemblies, func, user_data);
3563 * mono_assemblies_cleanup:
3565 * Free all resources used by this module.
3568 mono_assemblies_cleanup (void)
3572 mono_os_mutex_destroy (&assemblies_mutex);
3573 mono_os_mutex_destroy (&assembly_binding_mutex);
3575 for (l = loaded_assembly_bindings; l; l = l->next) {
3576 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3578 mono_assembly_binding_info_free (info);
3581 g_slist_free (loaded_assembly_bindings);
3583 free_assembly_load_hooks ();
3584 free_assembly_search_hooks ();
3585 free_assembly_preload_hooks ();
3588 /*LOCKING takes the assembly_binding lock*/
3590 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3594 mono_assembly_binding_lock ();
3595 iter = &loaded_assembly_bindings;
3598 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3600 if (info->domain_id == domain_id) {
3602 mono_assembly_binding_info_free (info);
3609 mono_assembly_binding_unlock ();
3613 * Holds the assembly of the application, for
3614 * System.Diagnostics.Process::MainModule
3616 static MonoAssembly *main_assembly=NULL;
3619 mono_assembly_set_main (MonoAssembly *assembly)
3621 main_assembly = assembly;
3625 * mono_assembly_get_main:
3627 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3630 mono_assembly_get_main (void)
3632 return (main_assembly);
3636 * mono_assembly_get_image:
3637 * @assembly: The assembly to retrieve the image from
3639 * Returns: the MonoImage associated with this assembly.
3642 mono_assembly_get_image (MonoAssembly *assembly)
3644 return assembly->image;
3648 * mono_assembly_get_name:
3649 * @assembly: The assembly to retrieve the name from
3651 * The returned name's lifetime is the same as @assembly's.
3653 * Returns: the MonoAssemblyName associated with this assembly.
3656 mono_assembly_get_name (MonoAssembly *assembly)
3658 return &assembly->aname;
3662 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3664 bundles = assemblies;
3667 #define MONO_DECLSEC_FORMAT_10 0x3C
3668 #define MONO_DECLSEC_FORMAT_20 0x2E
3669 #define MONO_DECLSEC_FIELD 0x53
3670 #define MONO_DECLSEC_PROPERTY 0x54
3672 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3673 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3674 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3675 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3676 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3679 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3683 case MONO_DECLSEC_PROPERTY:
3685 case MONO_DECLSEC_FIELD:
3687 *abort_decoding = TRUE;
3692 if (*p++ != MONO_TYPE_BOOLEAN) {
3693 *abort_decoding = TRUE;
3697 /* property name length */
3698 len = mono_metadata_decode_value (p, &p);
3700 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3711 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3713 int i, j, num, len, params_len;
3715 if (*p == MONO_DECLSEC_FORMAT_10) {
3716 gsize read, written;
3717 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3719 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3725 if (*p++ != MONO_DECLSEC_FORMAT_20)
3728 /* number of encoded permission attributes */
3729 num = mono_metadata_decode_value (p, &p);
3730 for (i = 0; i < num; ++i) {
3731 gboolean is_valid = FALSE;
3732 gboolean abort_decoding = FALSE;
3734 /* attribute name length */
3735 len = mono_metadata_decode_value (p, &p);
3737 /* We don't really need to fully decode the type. Comparing the name is enough */
3738 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3742 /*size of the params table*/
3743 params_len = mono_metadata_decode_value (p, &p);
3745 const char *params_end = p + params_len;
3747 /* number of parameters */
3748 len = mono_metadata_decode_value (p, &p);
3750 for (j = 0; j < len; ++j) {
3751 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3767 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3770 guint32 cols [MONO_DECL_SECURITY_SIZE];
3774 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3775 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3777 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3779 for (i = 0; i < t->rows; ++i) {
3780 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3781 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3783 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3786 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3787 len = mono_metadata_decode_blob_size (blob, &blob);
3791 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3792 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3797 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);