2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include "assembly-internals.h"
21 #include "image-internals.h"
22 #include "object-internals.h"
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/custom-attrs-internals.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/class-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include <mono/metadata/reflection-internals.h>
31 #include <mono/metadata/mono-endian.h>
32 #include <mono/metadata/mono-debug.h>
33 #include <mono/io-layer/io-layer.h>
34 #include <mono/utils/mono-uri.h>
35 #include <mono/metadata/mono-config.h>
36 #include <mono/metadata/mono-config-dirs.h>
37 #include <mono/utils/mono-digest.h>
38 #include <mono/utils/mono-logger-internals.h>
39 #include <mono/utils/mono-path.h>
40 #include <mono/metadata/reflection.h>
41 #include <mono/metadata/coree.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/utils/mono-io-portability.h>
44 #include <mono/utils/atomic.h>
45 #include <mono/utils/mono-os-mutex.h>
48 #include <sys/types.h>
53 #ifdef PLATFORM_MACOSX
54 #include <mach-o/dyld.h>
57 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
59 const char* assembly_name;
60 guint8 version_set_index;
61 const char* new_assembly_name;
62 gboolean only_lower_versions;
65 /* the default search path is empty, the first slot is replaced with the computed value */
73 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
74 static char **assemblies_path = NULL;
76 /* Contains the list of directories that point to auxiliary GACs */
77 static char **extra_gac_paths = NULL;
79 #ifndef DISABLE_ASSEMBLY_REMAPPING
80 /* The list of system assemblies what will be remapped to the running
81 * runtime version. WARNING: this list must be sorted.
82 * The integer number is an index in the MonoRuntimeInfo structure, whose
83 * values can be found in domain.c - supported_runtimes. Look there
84 * to understand what remapping will be made.
86 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
89 static const AssemblyVersionMap framework_assemblies [] = {
91 {"Commons.Xml.Relaxng", 0},
98 {"Microsoft.Build.Engine", 2, NULL, TRUE},
99 {"Microsoft.Build.Framework", 2, NULL, TRUE},
100 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
101 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
102 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
103 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
104 {"Microsoft.VisualBasic", 1},
105 {"Microsoft.VisualC", 1},
107 {"Mono.CompilerServices.SymbolWriter", 0},
109 {"Mono.Data.SybaseClient", 0},
110 {"Mono.Data.Tds", 0},
111 {"Mono.Data.TdsClient", 0},
112 {"Mono.GetOptions", 0},
115 {"Mono.Security", 0},
116 {"Mono.Security.Win32", 0},
118 {"Novell.Directory.Ldap", 0},
121 {"System.ComponentModel.Composition", 2},
122 {"System.ComponentModel.DataAnnotations", 2},
123 {"System.Configuration", 0},
124 {"System.Configuration.Install", 0},
127 {"System.Data.Linq", 2},
128 {"System.Data.OracleClient", 0},
129 {"System.Data.Services", 2},
130 {"System.Data.Services.Client", 2},
131 {"System.Data.SqlXml", 0},
132 {"System.Design", 0},
133 {"System.DirectoryServices", 0},
134 {"System.Drawing", 0},
135 {"System.Drawing.Design", 0},
136 {"System.EnterpriseServices", 0},
137 {"System.IdentityModel", 3},
138 {"System.IdentityModel.Selectors", 3},
139 {"System.Management", 0},
140 {"System.Messaging", 0},
142 {"System.Runtime.Remoting", 0},
143 {"System.Runtime.Serialization", 3},
144 {"System.Runtime.Serialization.Formatters.Soap", 0},
145 {"System.Security", 0},
146 {"System.ServiceModel", 3},
147 {"System.ServiceModel.Web", 2},
148 {"System.ServiceProcess", 0},
149 {"System.Transactions", 0},
151 {"System.Web.Abstractions", 2},
152 {"System.Web.DynamicData", 2},
153 {"System.Web.Extensions", 2},
154 {"System.Web.Mobile", 0},
155 {"System.Web.Routing", 2},
156 {"System.Web.Services", 0},
157 {"System.Windows.Forms", 0},
159 {"System.Xml.Linq", 2},
166 * keeps track of loaded assemblies
168 static GList *loaded_assemblies = NULL;
169 static MonoAssembly *corlib;
171 #if defined(__native_client__)
173 /* On Native Client, allow mscorlib to be loaded from memory */
174 /* instead of loaded off disk. If these are not set, default */
175 /* mscorlib loading will take place */
177 /* NOTE: If mscorlib data is passed to mono in this way then */
178 /* it needs to remain allocated during the use of mono. */
180 static void *corlibData = NULL;
181 static size_t corlibSize = 0;
184 mono_set_corlib_data (void *data, size_t size)
192 static char* unquote (const char *str);
194 /* This protects loaded_assemblies and image->references */
195 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
196 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
197 static mono_mutex_t assemblies_mutex;
199 /* If defined, points to the bundled assembly information */
200 const MonoBundledAssembly **bundles;
202 static mono_mutex_t assembly_binding_mutex;
204 /* Loaded assembly binding info */
205 static GSList *loaded_assembly_bindings = NULL;
207 /* Class lazy loading functions */
208 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
210 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
212 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
214 mono_assembly_is_in_gac (const gchar *filanem);
217 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
220 encode_public_tok (const guchar *token, gint32 len)
222 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
226 res = (gchar *)g_malloc (len * 2 + 1);
227 for (i = 0; i < len; i++) {
228 res [i * 2] = allowed [token [i] >> 4];
229 res [i * 2 + 1] = allowed [token [i] & 0xF];
236 * mono_public_tokens_are_equal:
237 * @pubt1: first public key token
238 * @pubt2: second public key token
240 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
244 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
246 return memcmp (pubt1, pubt2, 16) == 0;
250 * mono_set_assemblies_path:
251 * @path: list of paths that contain directories where Mono will look for assemblies
253 * Use this method to override the standard assembly lookup system and
254 * override any assemblies coming from the GAC. This is the method
255 * that supports the MONO_PATH variable.
257 * Notice that MONO_PATH and this method are really a very bad idea as
258 * it prevents the GAC from working and it prevents the standard
259 * resolution mechanisms from working. Nonetheless, for some debugging
260 * situations and bootstrapping setups, this is useful to have.
263 mono_set_assemblies_path (const char* path)
265 char **splitted, **dest;
267 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
269 g_strfreev (assemblies_path);
270 assemblies_path = dest = splitted;
272 char *tmp = *splitted;
274 *dest++ = mono_path_canonicalize (tmp);
280 if (g_getenv ("MONO_DEBUG") == NULL)
283 splitted = assemblies_path;
285 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
286 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
292 /* Native Client can't get this info from an environment variable so */
293 /* it's passed in to the runtime, or set manually by embedding code. */
294 #ifdef __native_client__
295 char* nacl_mono_path = NULL;
299 check_path_env (void)
302 path = g_getenv ("MONO_PATH");
303 #ifdef __native_client__
305 path = nacl_mono_path;
307 if (!path || assemblies_path != NULL)
310 mono_set_assemblies_path(path);
314 check_extra_gac_path_env (void) {
316 char **splitted, **dest;
318 path = g_getenv ("MONO_GAC_PREFIX");
322 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
324 g_strfreev (extra_gac_paths);
325 extra_gac_paths = dest = splitted;
333 if (g_getenv ("MONO_DEBUG") == NULL)
337 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
338 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
345 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
347 if (!info || !info->name)
350 if (strcmp (info->name, aname->name))
353 if (info->major != aname->major || info->minor != aname->minor)
356 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
359 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
362 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
369 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
375 g_free (info->culture);
379 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
382 guint32 cols [MONO_MANIFEST_SIZE];
383 const gchar *filename;
384 gchar *subpath, *fullpath;
386 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
387 /* MS Impl. accepts policy assemblies with more than
388 * one manifest resource, and only takes the first one */
390 binding_info->is_valid = FALSE;
394 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
395 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
396 binding_info->is_valid = FALSE;
400 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
401 g_assert (filename != NULL);
403 subpath = g_path_get_dirname (image->name);
404 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
405 mono_config_parse_publisher_policy (fullpath, binding_info);
409 /* Define the optional elements/attributes before checking */
410 if (!binding_info->culture)
411 binding_info->culture = g_strdup ("");
413 /* Check that the most important elements/attributes exist */
414 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
415 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
416 mono_assembly_binding_info_free (binding_info);
417 binding_info->is_valid = FALSE;
421 binding_info->is_valid = TRUE;
425 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
427 if (v->major > aname->major)
429 else if (v->major < aname->major)
432 if (v->minor > aname->minor)
434 else if (v->minor < aname->minor)
437 if (v->build > aname->build)
439 else if (v->build < aname->build)
442 if (v->revision > aname->revision)
444 else if (v->revision < aname->revision)
451 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
456 /* If has_old_version_top doesn't exist, we don't have an interval */
457 if (!info->has_old_version_top) {
458 if (compare_versions (&info->old_version_bottom, name) == 0)
464 /* Check that the version defined by name is valid for the interval */
465 if (compare_versions (&info->old_version_top, name) < 0)
468 /* We should be greater or equal than the small version */
469 if (compare_versions (&info->old_version_bottom, name) > 0)
476 * mono_assembly_names_equal:
478 * @r: second assembly.
480 * Compares two MonoAssemblyNames and returns whether they are equal.
482 * This compares the names, the cultures, the release version and their
485 * Returns: TRUE if both assembly names are equal.
488 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
490 if (!l->name || !r->name)
493 if (strcmp (l->name, r->name))
496 if (l->culture && r->culture && strcmp (l->culture, r->culture))
499 if (l->major != r->major || l->minor != r->minor ||
500 l->build != r->build || l->revision != r->revision)
501 if (! ((l->major == 0 && l->minor == 0 && l->build == 0 && l->revision == 0) || (r->major == 0 && r->minor == 0 && r->build == 0 && r->revision == 0)))
504 if (!l->public_key_token [0] || !r->public_key_token [0])
507 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
513 static MonoAssembly *
514 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
518 MonoAssembly *result;
520 for (i = 0; search_path [i]; ++i) {
521 fullpath = g_build_filename (search_path [i], basename, NULL);
522 result = mono_assembly_open_full (fullpath, status, refonly);
531 * mono_assembly_setrootdir:
532 * @root_dir: The pathname of the root directory where we will locate assemblies
534 * This routine sets the internal default root directory for looking up
537 * This is used by Windows installations to compute dynamically the
538 * place where the Mono assemblies are located.
542 mono_assembly_setrootdir (const char *root_dir)
545 * Override the MONO_ASSEMBLIES directory configured at compile time.
547 /* Leak if called more than once */
548 default_path [0] = g_strdup (root_dir);
552 * mono_assembly_getrootdir:
554 * Obtains the root directory used for looking up assemblies.
556 * Returns: a string with the directory, this string should not be freed.
558 G_CONST_RETURN gchar *
559 mono_assembly_getrootdir (void)
561 return default_path [0];
565 * mono_native_getrootdir:
567 * Obtains the root directory used for looking up native libs (.so, .dylib).
569 * Returns: a string with the directory, this string should be freed by
573 mono_native_getrootdir (void)
575 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
581 * @assembly_dir: the base directory for assemblies
582 * @config_dir: the base directory for configuration files
584 * This routine is used internally and by developers embedding
585 * the runtime into their own applications.
587 * There are a number of cases to consider: Mono as a system-installed
588 * package that is available on the location preconfigured or Mono in
589 * a relocated location.
591 * If you are using a system-installed Mono, you can pass NULL
592 * to both parameters. If you are not, you should compute both
593 * directory values and call this routine.
595 * The values for a given PREFIX are:
597 * assembly_dir: PREFIX/lib
598 * config_dir: PREFIX/etc
600 * Notice that embedders that use Mono in a relocated way must
601 * compute the location at runtime, as they will be in control
602 * of where Mono is installed.
605 mono_set_dirs (const char *assembly_dir, const char *config_dir)
607 if (assembly_dir == NULL)
608 assembly_dir = mono_config_get_assemblies_dir ();
609 if (config_dir == NULL)
610 config_dir = mono_config_get_cfg_dir ();
611 mono_assembly_setrootdir (assembly_dir);
612 mono_set_config_dir (config_dir);
618 compute_base (char *path)
620 char *p = strrchr (path, '/');
624 /* Not a well known Mono executable, we are embedded, cant guess the base */
625 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
629 p = strrchr (path, '/');
633 if (strcmp (p, "/bin") != 0)
642 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
645 static G_GNUC_UNUSED void
649 char *config, *lib, *mono;
654 * Only /usr prefix is treated specially
656 bindir = mono_config_get_bin_dir ();
658 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
663 config = g_build_filename (base, "etc", NULL);
664 lib = g_build_filename (base, "lib", NULL);
665 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
666 if (stat (mono, &buf) == -1)
669 mono_set_dirs (lib, config);
677 #endif /* HOST_WIN32 */
682 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
683 * this auto-detects the prefix where Mono was installed.
686 mono_set_rootdir (void)
688 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
689 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
692 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
696 * _NSGetExecutablePath may return -1 to indicate buf is not large
697 * enough, but we ignore that case to avoid having to do extra dynamic
698 * allocation for the path and hope that 4096 is enough - this is
699 * ok in the Linux/Solaris case below at least...
703 guint buf_size = sizeof (buf);
706 if (_NSGetExecutablePath (buf, &buf_size) == 0)
707 name = g_strdup (buf);
716 resolvedname = mono_path_resolve_symlinks (name);
718 bindir = g_path_get_dirname (resolvedname);
719 installdir = g_path_get_dirname (bindir);
720 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
722 config = g_build_filename (root, "..", "etc", NULL);
724 mono_set_dirs (root, config);
726 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
727 mono_set_dirs (root, config);
737 g_free (resolvedname);
738 #elif defined(DISABLE_MONO_AUTODETECTION)
746 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
754 /* Solaris 10 style */
755 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
756 s = readlink (str, buf, sizeof (buf)-1);
768 * mono_assemblies_init:
770 * Initialize global variables used by this module.
773 mono_assemblies_init (void)
776 * Initialize our internal paths if we have not been initialized yet.
777 * This happens when embedders use Mono.
779 if (mono_assembly_getrootdir () == NULL)
783 check_extra_gac_path_env ();
785 mono_os_mutex_init_recursive (&assemblies_mutex);
786 mono_os_mutex_init (&assembly_binding_mutex);
790 mono_assembly_binding_lock (void)
792 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
796 mono_assembly_binding_unlock (void)
798 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
802 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
804 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
805 guint32 cols [MONO_ASSEMBLY_SIZE];
806 gint32 machine, flags;
811 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
814 aname->hash_value = NULL;
815 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
817 aname->name = g_strdup (aname->name);
818 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
820 aname->culture = g_strdup (aname->culture);
821 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
822 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
823 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
824 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
825 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
826 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
827 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
828 guchar* token = (guchar *)g_malloc (8);
833 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
834 len = mono_metadata_decode_blob_size (pkey, &pkey);
835 aname->public_key = (guchar*)pkey;
837 mono_digest_get_public_token (token, aname->public_key, len);
838 encoded = encode_public_tok (token, 8);
839 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
845 aname->public_key = NULL;
846 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
849 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
850 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
852 const gchar *pkey_end;
853 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
854 pkey_end += len; /* move to end */
855 size_t size = pkey_end - (const gchar*)aname->public_key;
856 guchar *tmp = g_new (guchar, size);
857 memcpy (tmp, aname->public_key, size);
858 aname->public_key = tmp;
863 aname->public_key = 0;
865 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
866 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
868 case COFF_MACHINE_I386:
869 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
870 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
871 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
872 else if ((flags & 0x70) == 0x70)
873 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
875 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
877 case COFF_MACHINE_IA64:
878 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
880 case COFF_MACHINE_AMD64:
881 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
883 case COFF_MACHINE_ARM:
884 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
894 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
896 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
900 * mono_stringify_assembly_name:
901 * @aname: the assembly name.
903 * Convert @aname into its string format. The returned string is dynamically
904 * allocated and should be freed by the caller.
906 * Returns: a newly allocated string with a string representation of
910 mono_stringify_assembly_name (MonoAssemblyName *aname)
912 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
914 return g_strdup_printf (
915 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
916 quote, aname->name, quote,
917 aname->major, aname->minor, aname->build, aname->revision,
918 aname->culture && *aname->culture? aname->culture: "neutral",
919 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
920 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
924 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
926 const gchar *public_tok;
929 public_tok = mono_metadata_blob_heap (image, key_index);
930 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
932 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
934 mono_digest_get_public_token (token, (guchar*)public_tok, len);
935 return encode_public_tok (token, 8);
938 return encode_public_tok ((guchar*)public_tok, len);
942 * mono_assembly_addref:
943 * @assemnly: the assembly to reference
945 * This routine increments the reference count on a MonoAssembly.
946 * The reference count is reduced every time the method mono_assembly_close() is
950 mono_assembly_addref (MonoAssembly *assembly)
952 InterlockedIncrement (&assembly->ref_count);
956 * CAUTION: This table must be kept in sync with
957 * ivkm/reflect/Fusion.cs
960 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
961 #define WINFX_KEY "31bf3856ad364e35"
962 #define ECMA_KEY "b77a5c561934e089"
963 #define MSFINAL_KEY "b03f5f7f11d50a3a"
964 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
972 static KeyRemapEntry key_remap_table[] = {
973 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
974 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
975 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
976 { "System", SILVERLIGHT_KEY, ECMA_KEY },
977 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
978 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
979 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
980 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
981 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
982 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
983 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
984 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
985 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
986 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
987 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
988 { "System.Numerics", WINFX_KEY, ECMA_KEY },
989 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
990 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
991 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
992 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
993 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
994 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
995 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
996 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
997 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
998 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
999 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1000 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1001 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1005 remap_keys (MonoAssemblyName *aname)
1008 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1009 const KeyRemapEntry *entry = &key_remap_table [i];
1011 if (strcmp (aname->name, entry->name) ||
1012 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1015 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1017 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1018 "Remapped public key token of retargetable assembly %s from %s to %s",
1019 aname->name, entry->from, entry->to);
1024 static MonoAssemblyName *
1025 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1027 const MonoRuntimeInfo *current_runtime;
1028 int pos, first, last;
1030 if (aname->name == NULL) return aname;
1032 current_runtime = mono_get_runtime_info ();
1034 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1035 const AssemblyVersionSet* vset;
1037 /* Remap to current runtime */
1038 vset = ¤t_runtime->version_sets [0];
1040 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1041 dest_aname->major = vset->major;
1042 dest_aname->minor = vset->minor;
1043 dest_aname->build = vset->build;
1044 dest_aname->revision = vset->revision;
1045 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1047 /* Remap assembly name */
1048 if (!strcmp (aname->name, "System.Net"))
1049 dest_aname->name = g_strdup ("System");
1051 remap_keys (dest_aname);
1053 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1054 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1056 aname->major, aname->minor, aname->build, aname->revision,
1058 vset->major, vset->minor, vset->build, vset->revision
1064 #ifndef DISABLE_ASSEMBLY_REMAPPING
1066 last = G_N_ELEMENTS (framework_assemblies) - 1;
1068 while (first <= last) {
1070 pos = first + (last - first) / 2;
1071 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1073 const AssemblyVersionSet* vset;
1074 int index = framework_assemblies[pos].version_set_index;
1075 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1076 vset = ¤t_runtime->version_sets [index];
1078 if (aname->major == vset->major && aname->minor == vset->minor &&
1079 aname->build == vset->build && aname->revision == vset->revision)
1082 if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1085 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1086 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1087 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1089 aname->major, aname->minor, aname->build, aname->revision,
1090 vset->major, vset->minor, vset->build, vset->revision
1093 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1094 dest_aname->major = vset->major;
1095 dest_aname->minor = vset->minor;
1096 dest_aname->build = vset->build;
1097 dest_aname->revision = vset->revision;
1098 if (framework_assemblies[pos].new_assembly_name != NULL) {
1099 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1100 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1101 "The assembly name %s was remapped to %s",
1106 } else if (res < 0) {
1118 * mono_assembly_get_assemblyref:
1119 * @image: pointer to the MonoImage to extract the information from.
1120 * @index: index to the assembly reference in the image.
1121 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1123 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1126 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1129 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1132 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1134 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1136 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1137 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1138 aname->hash_value = hash;
1139 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1140 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1141 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1142 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1143 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1144 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1145 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1147 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1148 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1149 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1152 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1157 mono_assembly_load_reference (MonoImage *image, int index)
1159 MonoAssembly *reference;
1160 MonoAssemblyName aname;
1161 MonoImageOpenStatus status;
1164 * image->references is shared between threads, so we need to access
1165 * it inside a critical section.
1167 mono_assemblies_lock ();
1168 if (!image->references) {
1169 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1171 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1172 image->nreferences = t->rows;
1174 reference = image->references [index];
1175 mono_assemblies_unlock ();
1179 mono_assembly_get_assemblyref (image, index, &aname);
1181 if (image->assembly && image->assembly->ref_only) {
1182 /* We use the loaded corlib */
1183 if (!strcmp (aname.name, "mscorlib"))
1184 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1186 reference = mono_assembly_loaded_full (&aname, TRUE);
1188 /* Try a postload search hook */
1189 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1193 * Here we must advice that the error was due to
1194 * a non loaded reference using the ReflectionOnly api
1197 reference = (MonoAssembly *)REFERENCE_MISSING;
1199 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1200 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1201 * accordingly, it would fail on the MS runtime before).
1202 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1203 * example bug-349190.2.cs and who knows how much more code in the wild.
1205 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1206 if (!reference && image->assembly)
1207 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1210 if (reference == NULL){
1213 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1214 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 : "" );
1215 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1216 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1217 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1218 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1219 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1220 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1222 extra_msg = g_strdup ("");
1225 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1226 " Assembly: %s (assemblyref_index=%d)\n"
1227 " Version: %d.%d.%d.%d\n"
1228 " Public Key: %s\n%s",
1229 image->name, aname.name, index,
1230 aname.major, aname.minor, aname.build, aname.revision,
1231 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1236 mono_assemblies_lock ();
1237 if (reference == NULL) {
1238 /* Flag as not found */
1239 reference = (MonoAssembly *)REFERENCE_MISSING;
1242 if (!image->references [index]) {
1243 if (reference != REFERENCE_MISSING){
1244 mono_assembly_addref (reference);
1245 if (image->assembly)
1246 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1247 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1249 if (image->assembly)
1250 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1251 image->assembly->aname.name, image->assembly);
1254 image->references [index] = reference;
1256 mono_assemblies_unlock ();
1258 if (image->references [index] != reference) {
1259 /* Somebody loaded it before us */
1260 mono_assembly_close (reference);
1265 * mono_assembly_load_references:
1268 * @deprecated: There is no reason to use this method anymore, it does nothing
1270 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1273 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1275 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1276 *status = MONO_IMAGE_OK;
1279 typedef struct AssemblyLoadHook AssemblyLoadHook;
1280 struct AssemblyLoadHook {
1281 AssemblyLoadHook *next;
1282 MonoAssemblyLoadFunc func;
1286 AssemblyLoadHook *assembly_load_hook = NULL;
1289 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1291 AssemblyLoadHook *hook;
1293 for (hook = assembly_load_hook; hook; hook = hook->next) {
1294 hook->func (ass, hook->user_data);
1299 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1301 AssemblyLoadHook *hook;
1303 g_return_if_fail (func != NULL);
1305 hook = g_new0 (AssemblyLoadHook, 1);
1307 hook->user_data = user_data;
1308 hook->next = assembly_load_hook;
1309 assembly_load_hook = hook;
1313 free_assembly_load_hooks (void)
1315 AssemblyLoadHook *hook, *next;
1317 for (hook = assembly_load_hook; hook; hook = next) {
1323 typedef struct AssemblySearchHook AssemblySearchHook;
1324 struct AssemblySearchHook {
1325 AssemblySearchHook *next;
1326 MonoAssemblySearchFunc func;
1332 AssemblySearchHook *assembly_search_hook = NULL;
1334 static MonoAssembly*
1335 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1337 AssemblySearchHook *hook;
1339 for (hook = assembly_search_hook; hook; hook = hook->next) {
1340 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1343 * A little explanation is in order here.
1345 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1346 * The embedding API exposes a search hook that doesn't take such argument.
1348 * The original fix would call the default search hook before all the registered ones and pass
1349 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1350 * rely on. Which is the ordering between user hooks and the default runtime hook.
1352 * Registering the hook after mono_jit_init would let your hook run before the default one and
1353 * when using it to handle non standard app layouts this could save your app from a massive amount
1354 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1355 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1357 * So what's the fix? We register the default hook using regular means and special case it when iterating
1358 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1361 if (hook->func == (void*)mono_domain_assembly_postload_search)
1362 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1364 ass = hook->func (aname, hook->user_data);
1374 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1376 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1380 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1382 AssemblySearchHook *hook;
1384 g_return_if_fail (func != NULL);
1386 hook = g_new0 (AssemblySearchHook, 1);
1388 hook->user_data = user_data;
1389 hook->refonly = refonly;
1390 hook->postload = postload;
1391 hook->next = assembly_search_hook;
1392 assembly_search_hook = hook;
1396 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1398 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1402 free_assembly_search_hooks (void)
1404 AssemblySearchHook *hook, *next;
1406 for (hook = assembly_search_hook; hook; hook = next) {
1413 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1415 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1419 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1421 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1425 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1427 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1430 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1431 struct AssemblyPreLoadHook {
1432 AssemblyPreLoadHook *next;
1433 MonoAssemblyPreLoadFunc func;
1437 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1438 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1440 static MonoAssembly *
1441 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1443 AssemblyPreLoadHook *hook;
1444 MonoAssembly *assembly;
1446 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1447 assembly = hook->func (aname, assemblies_path, hook->user_data);
1448 if (assembly != NULL)
1455 static MonoAssembly *
1456 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1458 AssemblyPreLoadHook *hook;
1459 MonoAssembly *assembly;
1461 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1462 assembly = hook->func (aname, assemblies_path, hook->user_data);
1463 if (assembly != NULL)
1471 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1473 AssemblyPreLoadHook *hook;
1475 g_return_if_fail (func != NULL);
1477 hook = g_new0 (AssemblyPreLoadHook, 1);
1479 hook->user_data = user_data;
1480 hook->next = assembly_preload_hook;
1481 assembly_preload_hook = hook;
1485 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1487 AssemblyPreLoadHook *hook;
1489 g_return_if_fail (func != NULL);
1491 hook = g_new0 (AssemblyPreLoadHook, 1);
1493 hook->user_data = user_data;
1494 hook->next = assembly_refonly_preload_hook;
1495 assembly_refonly_preload_hook = hook;
1499 free_assembly_preload_hooks (void)
1501 AssemblyPreLoadHook *hook, *next;
1503 for (hook = assembly_preload_hook; hook; hook = next) {
1508 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1515 absolute_dir (const gchar *filename)
1526 if (g_path_is_absolute (filename)) {
1527 part = g_path_get_dirname (filename);
1528 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1533 cwd = g_get_current_dir ();
1534 mixed = g_build_filename (cwd, filename, NULL);
1535 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1540 for (i = 0; (part = parts [i]) != NULL; i++) {
1541 if (!strcmp (part, "."))
1544 if (!strcmp (part, "..")) {
1545 if (list && list->next) /* Don't remove root */
1546 list = g_list_delete_link (list, list);
1548 list = g_list_prepend (list, part);
1552 result = g_string_new ("");
1553 list = g_list_reverse (list);
1555 /* Ignores last data pointer, which should be the filename */
1556 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1558 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1563 g_string_free (result, FALSE);
1568 return g_strdup (".");
1575 * mono_assembly_open_from_bundle:
1576 * @filename: Filename requested
1577 * @status: return status code
1579 * This routine tries to open the assembly specified by `filename' from the
1580 * defined bundles, if found, returns the MonoImage for it, if not found
1584 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1588 gchar *lowercase_filename;
1589 MonoImage *image = NULL;
1590 gboolean is_satellite = FALSE;
1592 * we do a very simple search for bundled assemblies: it's not a general
1593 * purpose assembly loading mechanism.
1599 lowercase_filename = g_utf8_strdown (filename, -1);
1600 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1601 g_free (lowercase_filename);
1602 name = g_path_get_basename (filename);
1603 mono_assemblies_lock ();
1604 for (i = 0; !image && bundles [i]; ++i) {
1605 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1606 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1610 mono_assemblies_unlock ();
1612 mono_image_addref (image);
1613 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1622 * mono_assemblies_open_full:
1623 * @filename: the file to load
1624 * @status: return status code
1625 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1627 * This loads an assembly from the specified @filename. The @filename allows
1628 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1629 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1630 * is treated as a local path.
1632 * First, an attempt is made to load the assembly from the bundled executable (for those
1633 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1634 * assembly has been registered as an embedded assembly). If this is not the case, then
1635 * the assembly is loaded from disk using `api:mono_image_open_full`.
1637 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1638 * the assembly is made.
1640 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1641 * the `System.Reflection` API.
1643 * Returns: NULL on error, with the @status set to an error code, or a pointer
1647 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1651 MonoImageOpenStatus def_status;
1654 gboolean loaded_from_bundle;
1656 g_return_val_if_fail (filename != NULL, NULL);
1659 status = &def_status;
1660 *status = MONO_IMAGE_OK;
1662 if (strncmp (filename, "file://", 7) == 0) {
1663 GError *error = NULL;
1664 gchar *uri = (gchar *) filename;
1668 * MS allows file://c:/... and fails on file://localhost/c:/...
1669 * They also throw an IndexOutOfRangeException if "file://"
1672 uri = g_strdup_printf ("file:///%s", uri + 7);
1675 uri = mono_escape_uri_string (tmpuri);
1676 fname = g_filename_from_uri (uri, NULL, &error);
1679 if (tmpuri != filename)
1682 if (error != NULL) {
1683 g_warning ("%s\n", error->message);
1684 g_error_free (error);
1685 fname = g_strdup (filename);
1688 fname = g_strdup (filename);
1691 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1692 "Assembly Loader probing location: '%s'.", fname);
1695 if (!mono_assembly_is_in_gac (fname)) {
1697 new_fname = mono_make_shadow_copy (fname, &error);
1698 if (!is_ok (&error)) {
1699 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1700 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1701 mono_error_cleanup (&error);
1702 *status = MONO_IMAGE_IMAGE_INVALID;
1707 if (new_fname && new_fname != fname) {
1710 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1711 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1716 // If VM built with mkbundle
1717 loaded_from_bundle = FALSE;
1718 if (bundles != NULL) {
1719 image = mono_assembly_open_from_bundle (fname, status, refonly);
1720 loaded_from_bundle = image != NULL;
1724 image = mono_image_open_full (fname, status, refonly);
1727 if (*status == MONO_IMAGE_OK)
1728 *status = MONO_IMAGE_ERROR_ERRNO;
1733 if (image->assembly) {
1734 /* Already loaded by another appdomain */
1735 mono_assembly_invoke_load_hook (image->assembly);
1736 mono_image_close (image);
1738 return image->assembly;
1741 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1744 if (!loaded_from_bundle)
1745 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1746 "Assembly Loader loaded assembly from location: '%s'.", filename);
1748 mono_config_for_assembly (ass->image);
1751 /* Clear the reference added by mono_image_open */
1752 mono_image_close (image);
1760 free_item (gpointer val, gpointer user_data)
1766 * mono_assembly_load_friends:
1769 * Load the list of friend assemblies that are allowed to access
1770 * the assembly's internal types and members. They are stored as assembly
1771 * names in custom attributes.
1773 * This is an internal method, we need this because when we load mscorlib
1774 * we do not have the internals visible cattr loaded yet,
1775 * so we need to load these after we initialize the runtime.
1777 * LOCKING: Acquires the assemblies lock plus the loader lock.
1780 mono_assembly_load_friends (MonoAssembly* ass)
1784 MonoCustomAttrInfo* attrs;
1787 if (ass->friend_assembly_names_inited)
1790 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1791 mono_error_assert_ok (&error);
1793 mono_assemblies_lock ();
1794 ass->friend_assembly_names_inited = TRUE;
1795 mono_assemblies_unlock ();
1799 mono_assemblies_lock ();
1800 if (ass->friend_assembly_names_inited) {
1801 mono_assemblies_unlock ();
1804 mono_assemblies_unlock ();
1808 * We build the list outside the assemblies lock, the worse that can happen
1809 * is that we'll need to free the allocated list.
1811 for (i = 0; i < attrs->num_attrs; ++i) {
1812 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1813 MonoAssemblyName *aname;
1815 /* Do some sanity checking */
1816 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1818 if (attr->data_size < 4)
1820 data = (const char*)attr->data;
1821 /* 0xFF means null string, see custom attr format */
1822 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1824 mono_metadata_decode_value (data + 2, &data);
1825 aname = g_new0 (MonoAssemblyName, 1);
1826 /*g_print ("friend ass: %s\n", data);*/
1827 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1828 list = g_slist_prepend (list, aname);
1833 mono_custom_attrs_free (attrs);
1835 mono_assemblies_lock ();
1836 if (ass->friend_assembly_names_inited) {
1837 mono_assemblies_unlock ();
1838 g_slist_foreach (list, free_item, NULL);
1839 g_slist_free (list);
1842 ass->friend_assembly_names = list;
1844 /* Because of the double checked locking pattern above */
1845 mono_memory_barrier ();
1846 ass->friend_assembly_names_inited = TRUE;
1847 mono_assemblies_unlock ();
1850 struct HasReferenceAssemblyAttributeIterData {
1855 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1857 gboolean stop_scanning = FALSE;
1858 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1860 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1861 /* Note we don't check the assembly name, same as coreCLR. */
1862 iter_data->has_attr = TRUE;
1863 stop_scanning = TRUE;
1866 return stop_scanning;
1870 * mono_assembly_has_reference_assembly_attribute:
1871 * @assembly: a MonoAssembly
1872 * @error: set on error.
1874 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1875 * On error returns FALSE and sets @error.
1878 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1880 mono_error_init (error);
1883 * This might be called during assembly loading, so do everything using the low-level
1887 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1889 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1891 return iter_data.has_attr;
1895 * mono_assembly_open:
1896 * @filename: Opens the assembly pointed out by this name
1897 * @status: return status code
1899 * This loads an assembly from the specified @filename. The @filename allows
1900 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1901 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1902 * is treated as a local path.
1904 * First, an attempt is made to load the assembly from the bundled executable (for those
1905 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1906 * assembly has been registered as an embedded assembly). If this is not the case, then
1907 * the assembly is loaded from disk using `api:mono_image_open_full`.
1909 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1910 * the assembly is made.
1912 * Return: a pointer to the MonoAssembly if @filename contains a valid
1913 * assembly or NULL on error. Details about the error are stored in the
1917 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1919 return mono_assembly_open_full (filename, status, FALSE);
1923 * mono_assembly_load_from_full:
1924 * @image: Image to load the assembly from
1925 * @fname: assembly name to associate with the assembly
1926 * @status: returns the status condition
1927 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1929 * If the provided @image has an assembly reference, it will process the given
1930 * image as an assembly with the given name.
1932 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1934 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1935 * set to #MONO_IMAGE_OK; or NULL on error.
1937 * If there is an error loading the assembly the @status will indicate the
1938 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1939 * image did not contain an assembly reference table.
1942 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1943 MonoImageOpenStatus *status, gboolean refonly)
1945 MonoAssembly *ass, *ass2;
1948 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1949 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1950 *status = MONO_IMAGE_IMAGE_INVALID;
1954 #if defined (HOST_WIN32)
1959 tmp_fn = g_strdup (fname);
1960 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1961 if (tmp_fn [i] == '/')
1965 base_dir = absolute_dir (tmp_fn);
1969 base_dir = absolute_dir (fname);
1973 * Create assembly struct, and enter it into the assembly cache
1975 ass = g_new0 (MonoAssembly, 1);
1976 ass->basedir = base_dir;
1977 ass->ref_only = refonly;
1980 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1982 mono_assembly_fill_assembly_name (image, &ass->aname);
1984 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1985 // MS.NET doesn't support loading other mscorlibs
1988 mono_image_addref (mono_defaults.corlib);
1989 *status = MONO_IMAGE_OK;
1990 return mono_defaults.corlib->assembly;
1993 /* Add a non-temporary reference because of ass->image */
1994 mono_image_addref (image);
1996 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);
1999 * The load hooks might take locks so we can't call them while holding the
2002 if (ass->aname.name) {
2003 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2007 mono_image_close (image);
2008 *status = MONO_IMAGE_OK;
2013 /* We need to check for ReferenceAssmeblyAttribute before we
2014 * mark the assembly as loaded and before we fire the load
2015 * hook. Otherwise mono_domain_fire_assembly_load () in
2016 * appdomain.c will cache a mapping from the assembly name to
2017 * this image and we won't be able to look for a different
2021 MonoError refasm_error;
2022 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2023 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2026 mono_image_close (image);
2027 *status = MONO_IMAGE_IMAGE_INVALID;
2030 mono_error_cleanup (&refasm_error);
2033 mono_assemblies_lock ();
2035 if (image->assembly) {
2037 * This means another thread has already loaded the assembly, but not yet
2038 * called the load hooks so the search hook can't find the assembly.
2040 mono_assemblies_unlock ();
2041 ass2 = image->assembly;
2044 mono_image_close (image);
2045 *status = MONO_IMAGE_OK;
2049 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2051 image->assembly = ass;
2053 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2054 mono_assemblies_unlock ();
2057 if (image->is_module_handle)
2058 mono_image_fixup_vtable (image);
2061 mono_assembly_invoke_load_hook (ass);
2063 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2069 * mono_assembly_load_from:
2070 * @image: Image to load the assembly from
2071 * @fname: assembly name to associate with the assembly
2072 * @status: return status code
2074 * If the provided @image has an assembly reference, it will process the given
2075 * image as an assembly with the given name.
2077 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2079 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2080 * @refonly parameter set to FALSE.
2081 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2082 * set to #MONO_IMAGE_OK; or NULL on error.
2084 * If there is an error loading the assembly the @status will indicate the
2085 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2086 * image did not contain an assembly reference table.
2090 mono_assembly_load_from (MonoImage *image, const char *fname,
2091 MonoImageOpenStatus *status)
2093 return mono_assembly_load_from_full (image, fname, status, FALSE);
2097 * mono_assembly_name_free:
2098 * @aname: assembly name to free
2100 * Frees the provided assembly name object.
2101 * (it does not frees the object itself, only the name members).
2104 mono_assembly_name_free (MonoAssemblyName *aname)
2109 g_free ((void *) aname->name);
2110 g_free ((void *) aname->culture);
2111 g_free ((void *) aname->hash_value);
2112 g_free ((guint8*) aname->public_key);
2116 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2119 gchar header [16], val, *arr;
2120 gint i, j, offset, bitlen, keylen, pkeylen;
2122 keylen = strlen (key) >> 1;
2126 /* allow the ECMA standard key */
2127 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2129 *pubkey = g_strdup (key);
2135 val = g_ascii_xdigit_value (key [0]) << 4;
2136 val |= g_ascii_xdigit_value (key [1]);
2141 val = g_ascii_xdigit_value (key [24]);
2142 val |= g_ascii_xdigit_value (key [25]);
2154 /* We need the first 16 bytes
2155 * to check whether this key is valid or not */
2156 pkeylen = strlen (pkey) >> 1;
2160 for (i = 0, j = 0; i < 16; i++) {
2161 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2162 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2165 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2166 header [1] != 0x02 || /* Version (0x02) */
2167 header [2] != 0x00 || /* Reserved (word) */
2168 header [3] != 0x00 ||
2169 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2172 /* Based on this length, we _should_ be able to know if the length is right */
2173 bitlen = read32 (header + 12) >> 3;
2174 if ((bitlen + 16 + 4) != pkeylen)
2177 /* parsing is OK and the public key itself is not requested back */
2181 /* Encode the size of the blob */
2183 if (keylen <= 127) {
2184 arr = (gchar *)g_malloc (keylen + 1);
2185 arr [offset++] = keylen;
2187 arr = (gchar *)g_malloc (keylen + 2);
2188 arr [offset++] = 0x80; /* 10bs */
2189 arr [offset++] = keylen;
2192 for (i = offset, j = 0; i < keylen + offset; i++) {
2193 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2194 arr [i] |= g_ascii_xdigit_value (key [j++]);
2203 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)
2205 gint major, minor, build, revision;
2208 gchar *pkey, *pkeyptr, *encoded, tok [8];
2210 memset (aname, 0, sizeof (MonoAssemblyName));
2213 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2214 if (version_parts < 2 || version_parts > 4)
2217 /* FIXME: we should set build & revision to -1 (instead of 0)
2218 if these are not set in the version string. That way, later on,
2219 we can still determine if these were specified. */
2220 aname->major = major;
2221 aname->minor = minor;
2222 if (version_parts >= 3)
2223 aname->build = build;
2226 if (version_parts == 4)
2227 aname->revision = revision;
2229 aname->revision = 0;
2232 aname->flags = flags;
2234 aname->name = g_strdup (name);
2237 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2238 aname->culture = g_strdup ("");
2240 aname->culture = g_strdup (culture);
2243 if (token && strncmp (token, "null", 4) != 0) {
2246 /* the constant includes the ending NULL, hence the -1 */
2247 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2248 mono_assembly_name_free (aname);
2251 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2252 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2258 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2259 mono_assembly_name_free (aname);
2264 if (save_public_key)
2265 aname->public_key = (guint8*)pkey;
2268 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2272 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2273 // We also need to generate the key token
2274 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2275 encoded = encode_public_tok ((guchar*) tok, 8);
2276 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2279 if (save_public_key)
2280 aname->public_key = (guint8*) pkey;
2289 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2294 parts = g_strsplit (dirname, "_", 3);
2295 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2300 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2306 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2308 char *eqsign = strchr (pair, '=');
2316 *key = (gchar*)pair;
2317 *keylen = eqsign - *key;
2318 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2320 *value = g_strstrip (eqsign + 1);
2325 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2329 gchar *version = NULL;
2331 gchar *culture = NULL;
2333 gchar *token = NULL;
2337 gchar *retargetable = NULL;
2338 gchar *retargetable_uq;
2342 gchar *value, *part_name;
2343 guint32 part_name_len;
2346 gboolean version_defined;
2347 gboolean token_defined;
2349 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2351 if (!is_version_defined)
2352 is_version_defined = &version_defined;
2353 *is_version_defined = FALSE;
2354 if (!is_token_defined)
2355 is_token_defined = &token_defined;
2356 *is_token_defined = FALSE;
2358 parts = tmp = g_strsplit (name, ",", 6);
2359 if (!tmp || !*tmp) {
2364 dllname = g_strstrip (*tmp);
2369 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2370 goto cleanup_and_fail;
2372 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2373 *is_version_defined = TRUE;
2375 if (strlen (version) == 0) {
2376 goto cleanup_and_fail;
2382 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2384 if (strlen (culture) == 0) {
2385 goto cleanup_and_fail;
2391 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2392 *is_token_defined = TRUE;
2394 if (strlen (token) == 0) {
2395 goto cleanup_and_fail;
2401 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2403 if (strlen (key) == 0) {
2404 goto cleanup_and_fail;
2410 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2411 retargetable = value;
2412 retargetable_uq = unquote (retargetable);
2413 if (retargetable_uq != NULL)
2414 retargetable = retargetable_uq;
2416 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2417 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2418 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2419 g_free (retargetable_uq);
2420 goto cleanup_and_fail;
2423 g_free (retargetable_uq);
2428 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2430 procarch_uq = unquote (procarch);
2431 if (procarch_uq != NULL)
2432 procarch = procarch_uq;
2434 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2435 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2436 else if (!g_ascii_strcasecmp (procarch, "X86"))
2437 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2438 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2439 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2440 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2441 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2443 g_free (procarch_uq);
2444 goto cleanup_and_fail;
2447 g_free (procarch_uq);
2456 /* if retargetable flag is set, then we must have a fully qualified name */
2457 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2458 goto cleanup_and_fail;
2461 dllname_uq = unquote (dllname);
2462 version_uq = unquote (version);
2463 culture_uq = unquote (culture);
2464 token_uq = unquote (token);
2465 key_uq = unquote (key);
2467 res = build_assembly_name (
2468 dllname_uq == NULL ? dllname : dllname_uq,
2469 version_uq == NULL ? version : version_uq,
2470 culture_uq == NULL ? culture : culture_uq,
2471 token_uq == NULL ? token : token_uq,
2472 key_uq == NULL ? key : key_uq,
2473 flags, arch, aname, save_public_key);
2475 g_free (dllname_uq);
2476 g_free (version_uq);
2477 g_free (culture_uq);
2490 unquote (const char *str)
2498 slen = strlen (str);
2502 if (*str != '\'' && *str != '\"')
2505 end = str + slen - 1;
2509 return g_strndup (str + 1, slen - 2);
2513 * mono_assembly_name_parse:
2514 * @name: name to parse
2515 * @aname: the destination assembly name
2517 * Parses an assembly qualified type name and assigns the name,
2518 * version, culture and token to the provided assembly name object.
2520 * Returns: TRUE if the name could be parsed.
2523 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2525 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2529 * mono_assembly_name_new:
2530 * @name: name to parse
2532 * Allocate a new MonoAssemblyName and fill its values from the
2535 * Returns: a newly allocated structure or NULL if there was any failure.
2538 mono_assembly_name_new (const char *name)
2540 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2541 if (mono_assembly_name_parse (name, aname))
2548 mono_assembly_name_get_name (MonoAssemblyName *aname)
2554 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2556 return aname->culture;
2560 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2562 if (aname->public_key_token [0])
2563 return aname->public_key_token;
2568 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2571 *minor = aname->minor;
2573 *build = aname->build;
2575 *revision = aname->revision;
2576 return aname->major;
2579 static MonoAssembly*
2580 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2582 gchar *fullpath = NULL;
2584 const char* direntry;
2585 MonoAssemblyName gac_aname;
2586 gint major=-1, minor=0, build=0, revision=0;
2587 gboolean exact_version;
2589 dirhandle = g_dir_open (basepath, 0, NULL);
2593 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2595 while ((direntry = g_dir_read_name (dirhandle))) {
2596 gboolean match = TRUE;
2598 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2601 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2604 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2605 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2609 if (exact_version) {
2610 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2611 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2613 else if (gac_aname.major < major)
2615 else if (gac_aname.major == major) {
2616 if (gac_aname.minor < minor)
2618 else if (gac_aname.minor == minor) {
2619 if (gac_aname.build < build)
2621 else if (gac_aname.build == build && gac_aname.revision <= revision)
2628 major = gac_aname.major;
2629 minor = gac_aname.minor;
2630 build = gac_aname.build;
2631 revision = gac_aname.revision;
2633 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2636 mono_assembly_name_free (&gac_aname);
2639 g_dir_close (dirhandle);
2641 if (fullpath == NULL)
2644 MonoAssembly *res = mono_assembly_open (fullpath, status);
2651 * mono_assembly_load_with_partial_name:
2652 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2653 * @status: return status code
2655 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2656 * so it might contain a qualified type name, version, culture and token.
2658 * This will load the assembly from the file whose name is derived from the assembly name
2659 * by appending the .dll extension.
2661 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2662 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2663 * if that fails from the GAC.
2665 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2668 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2672 MonoAssemblyName *aname, base_name;
2673 MonoAssemblyName mapped_aname;
2674 gchar *fullname, *gacpath;
2677 memset (&base_name, 0, sizeof (MonoAssemblyName));
2680 if (!mono_assembly_name_parse (name, aname))
2684 * If no specific version has been requested, make sure we load the
2685 * correct version for system assemblies.
2687 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2688 aname = mono_assembly_remap_version (aname, &mapped_aname);
2690 res = mono_assembly_loaded (aname);
2692 mono_assembly_name_free (aname);
2696 res = invoke_assembly_preload_hook (aname, assemblies_path);
2698 res->in_gac = FALSE;
2699 mono_assembly_name_free (aname);
2703 fullname = g_strdup_printf ("%s.dll", aname->name);
2705 if (extra_gac_paths) {
2706 paths = extra_gac_paths;
2707 while (!res && *paths) {
2708 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2709 res = probe_for_partial_name (gacpath, fullname, aname, status);
2718 mono_assembly_name_free (aname);
2722 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2723 res = probe_for_partial_name (gacpath, fullname, aname, status);
2727 mono_assembly_name_free (aname);
2732 MonoDomain *domain = mono_domain_get ();
2734 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2735 if (!is_ok (&error)) {
2736 mono_error_cleanup (&error);
2737 if (*status == MONO_IMAGE_OK)
2738 *status = MONO_IMAGE_IMAGE_INVALID;
2746 mono_assembly_is_in_gac (const gchar *filename)
2748 const gchar *rootdir;
2752 if (filename == NULL)
2755 for (paths = extra_gac_paths; paths && *paths; paths++) {
2756 if (strstr (*paths, filename) != *paths)
2759 gp = (gchar *) (filename + strlen (*paths));
2760 if (*gp != G_DIR_SEPARATOR)
2763 if (strncmp (gp, "lib", 3))
2766 if (*gp != G_DIR_SEPARATOR)
2769 if (strncmp (gp, "mono", 4))
2772 if (*gp != G_DIR_SEPARATOR)
2775 if (strncmp (gp, "gac", 3))
2778 if (*gp != G_DIR_SEPARATOR)
2784 rootdir = mono_assembly_getrootdir ();
2785 if (strstr (filename, rootdir) != filename)
2788 gp = (gchar *) (filename + strlen (rootdir));
2789 if (*gp != G_DIR_SEPARATOR)
2792 if (strncmp (gp, "mono", 4))
2795 if (*gp != G_DIR_SEPARATOR)
2798 if (strncmp (gp, "gac", 3))
2801 if (*gp != G_DIR_SEPARATOR)
2807 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2810 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2814 if (strstr (aname->name, ".dll")) {
2815 len = strlen (aname->name) - 4;
2816 name = (gchar *)g_malloc (len + 1);
2817 strncpy (name, aname->name, len);
2820 name = g_strdup (aname->name);
2823 culture = g_utf8_strdown (aname->culture, -1);
2825 culture = g_strdup ("");
2827 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2828 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2832 filename = g_strconcat (pname, ".dll", NULL);
2833 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2839 if (extra_gac_paths) {
2840 paths = extra_gac_paths;
2841 while (!image && *paths) {
2842 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2843 "lib", "mono", "gac", subpath, NULL);
2844 image = mono_image_open (fullpath, NULL);
2855 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2856 "mono", "gac", subpath, NULL);
2857 image = mono_image_open (fullpath, NULL);
2864 static MonoAssemblyName*
2865 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2867 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2868 dest_name->major = info->new_version.major;
2869 dest_name->minor = info->new_version.minor;
2870 dest_name->build = info->new_version.build;
2871 dest_name->revision = info->new_version.revision;
2876 /* LOCKING: assembly_binding lock must be held */
2877 static MonoAssemblyBindingInfo*
2878 search_binding_loaded (MonoAssemblyName *aname)
2882 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2883 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2884 if (assembly_binding_maps_name (info, aname))
2891 static inline gboolean
2892 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2894 if (left->major != right->major || left->minor != right->minor ||
2895 left->build != right->build || left->revision != right->revision)
2901 static inline gboolean
2902 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2904 if (left->has_old_version_bottom != right->has_old_version_bottom)
2907 if (left->has_old_version_top != right->has_old_version_top)
2910 if (left->has_new_version != right->has_new_version)
2913 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2916 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2919 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2925 /* LOCKING: assumes all the necessary locks are held */
2927 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2929 MonoAssemblyBindingInfo *info_copy;
2931 MonoAssemblyBindingInfo *info_tmp;
2932 MonoDomain *domain = (MonoDomain*)user_data;
2937 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2938 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2939 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2943 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2944 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2946 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2948 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2950 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2954 get_version_number (int major, int minor)
2956 return major * 256 + minor;
2959 static inline gboolean
2960 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2962 int aname_version_number = get_version_number (aname->major, aname->minor);
2963 if (!info->has_old_version_bottom)
2966 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2969 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2972 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2973 info->major = aname->major;
2974 info->minor = aname->minor;
2979 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2980 static MonoAssemblyBindingInfo*
2981 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2983 MonoAssemblyBindingInfo *info;
2986 if (!domain->assembly_bindings)
2990 for (list = domain->assembly_bindings; list; list = list->next) {
2991 info = (MonoAssemblyBindingInfo *)list->data;
2992 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2998 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2999 info->has_new_version && assembly_binding_maps_name (info, aname))
3000 info->is_valid = TRUE;
3002 info->is_valid = FALSE;
3008 static MonoAssemblyName*
3009 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3012 MonoAssemblyBindingInfo *info, *info2;
3016 if (aname->public_key_token [0] == 0)
3019 domain = mono_domain_get ();
3021 mono_assembly_binding_lock ();
3022 info = search_binding_loaded (aname);
3023 mono_assembly_binding_unlock ();
3026 mono_domain_lock (domain);
3027 info = get_per_domain_assembly_binding_info (domain, aname);
3028 mono_domain_unlock (domain);
3032 if (!check_policy_versions (info, aname))
3035 mono_assembly_bind_version (info, aname, dest_name);
3039 if (domain && domain->setup && domain->setup->configuration_file) {
3040 mono_domain_lock (domain);
3041 if (!domain->assembly_bindings_parsed) {
3042 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3043 /* expect this to succeed because mono_domain_set_options_from_config () did
3044 * the same thing when the domain was created. */
3045 mono_error_assert_ok (&error);
3047 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3049 if (!domain_config_file_path)
3050 domain_config_file_path = domain_config_file_name;
3052 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3053 domain->assembly_bindings_parsed = TRUE;
3054 if (domain_config_file_name != domain_config_file_path)
3055 g_free (domain_config_file_name);
3056 g_free (domain_config_file_path);
3059 info2 = get_per_domain_assembly_binding_info (domain, aname);
3062 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3063 info->name = g_strdup (info2->name);
3064 info->culture = g_strdup (info2->culture);
3065 info->domain_id = domain->domain_id;
3068 mono_domain_unlock (domain);
3072 info = g_new0 (MonoAssemblyBindingInfo, 1);
3073 info->major = aname->major;
3074 info->minor = aname->minor;
3077 if (!info->is_valid) {
3078 ppimage = mono_assembly_load_publisher_policy (aname);
3080 get_publisher_policy_info (ppimage, aname, info);
3081 mono_image_close (ppimage);
3085 /* Define default error value if needed */
3086 if (!info->is_valid) {
3087 info->name = g_strdup (aname->name);
3088 info->culture = g_strdup (aname->culture);
3089 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3092 mono_assembly_binding_lock ();
3093 info2 = search_binding_loaded (aname);
3095 /* This binding was added by another thread
3097 mono_assembly_binding_info_free (info);
3102 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3104 mono_assembly_binding_unlock ();
3106 if (!info->is_valid || !check_policy_versions (info, aname))
3109 mono_assembly_bind_version (info, aname, dest_name);
3114 * mono_assembly_load_from_gac
3116 * @aname: The assembly name object
3118 static MonoAssembly*
3119 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3121 MonoAssembly *result = NULL;
3122 gchar *name, *version, *culture, *fullpath, *subpath;
3127 if (aname->public_key_token [0] == 0) {
3131 if (strstr (aname->name, ".dll")) {
3132 len = strlen (filename) - 4;
3133 name = (gchar *)g_malloc (len + 1);
3134 strncpy (name, aname->name, len);
3137 name = g_strdup (aname->name);
3140 if (aname->culture) {
3141 culture = g_utf8_strdown (aname->culture, -1);
3143 culture = g_strdup ("");
3146 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3147 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3148 aname->minor, aname->build, aname->revision,
3152 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3157 if (extra_gac_paths) {
3158 paths = extra_gac_paths;
3159 while (!result && *paths) {
3160 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3161 result = mono_assembly_open_full (fullpath, status, refonly);
3168 result->in_gac = TRUE;
3173 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3174 "mono", "gac", subpath, NULL);
3175 result = mono_assembly_open_full (fullpath, status, refonly);
3179 result->in_gac = TRUE;
3187 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3190 MonoAssemblyName *aname;
3193 /* g_print ("corlib already loaded\n"); */
3197 // In native client, Corlib is embedded in the executable as static variable corlibData
3198 #if defined(__native_client__)
3199 if (corlibData != NULL && corlibSize != 0) {
3201 /* First "FALSE" instructs mono not to make a copy. */
3202 /* Second "FALSE" says this is not just a ref. */
3203 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3204 if (image == NULL || status != 0)
3205 g_print("mono_image_open_from_data_full failed: %d\n", status);
3206 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3207 if (corlib == NULL || status != 0)
3208 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3214 // A nonstandard preload hook may provide a special mscorlib assembly
3215 aname = mono_assembly_name_new ("mscorlib.dll");
3216 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3217 mono_assembly_name_free (aname);
3220 goto return_corlib_and_facades;
3222 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3223 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3224 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3226 goto return_corlib_and_facades;
3229 /* Normal case: Load corlib from mono/<version> */
3230 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3231 if (assemblies_path) { // Custom assemblies path
3232 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3234 g_free (corlib_file);
3235 goto return_corlib_and_facades;
3238 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3239 g_free (corlib_file);
3241 return_corlib_and_facades:
3242 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3243 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3248 static MonoAssembly*
3249 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3251 MonoError refasm_error;
3252 mono_error_init (&refasm_error);
3253 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3256 mono_error_cleanup (&refasm_error);
3262 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3263 const char *basedir,
3264 MonoImageOpenStatus *status,
3267 MonoAssembly *result;
3268 char *fullpath, *filename;
3269 MonoAssemblyName maped_aname;
3270 MonoAssemblyName maped_name_pp;
3275 aname = mono_assembly_remap_version (aname, &maped_aname);
3277 /* Reflection only assemblies don't get assembly binding */
3279 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3281 result = mono_assembly_loaded_full (aname, refonly);
3285 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3287 result->in_gac = FALSE;
3291 /* Currently we retrieve the loaded corlib for reflection
3292 * only requests, like a common reflection only assembly
3294 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3295 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3298 len = strlen (aname->name);
3299 for (ext_index = 0; ext_index < 2; ext_index ++) {
3300 ext = ext_index == 0 ? ".dll" : ".exe";
3301 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3302 filename = g_strdup (aname->name);
3303 /* Don't try appending .dll/.exe if it already has one of those extensions */
3306 filename = g_strconcat (aname->name, ext, NULL);
3309 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3316 fullpath = g_build_filename (basedir, filename, NULL);
3317 result = mono_assembly_open_full (fullpath, status, refonly);
3320 result->in_gac = FALSE;
3326 result = load_in_path (filename, default_path, status, refonly);
3328 result->in_gac = FALSE;
3338 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3340 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3343 /* Try a postload search hook */
3344 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3345 result = prevent_reference_assembly_from_running (result, refonly);
3351 * mono_assembly_load_full:
3352 * @aname: A MonoAssemblyName with the assembly name to load.
3353 * @basedir: A directory to look up the assembly at.
3354 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3355 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3357 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3358 * attempts to load the assembly from that directory before probing the standard locations.
3360 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3361 * assembly binding takes place.
3363 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3364 * value pointed by status is updated with an error code.
3367 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3369 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3373 * mono_assembly_load:
3374 * @aname: A MonoAssemblyName with the assembly name to load.
3375 * @basedir: A directory to look up the assembly at.
3376 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3378 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3379 * attempts to load the assembly from that directory before probing the standard locations.
3381 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3382 * value pointed by status is updated with an error code.
3385 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3387 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3391 * mono_assembly_loaded_full:
3392 * @aname: an assembly to look for.
3393 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3395 * This is used to determine if the specified assembly has been loaded
3396 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3397 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3400 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3403 MonoAssemblyName maped_aname;
3405 aname = mono_assembly_remap_version (aname, &maped_aname);
3407 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3413 * mono_assembly_loaded:
3414 * @aname: an assembly to look for.
3416 * This is used to determine if the specified assembly has been loaded
3418 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3419 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3422 mono_assembly_loaded (MonoAssemblyName *aname)
3424 return mono_assembly_loaded_full (aname, FALSE);
3428 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3430 if (assembly == NULL || assembly == REFERENCE_MISSING)
3433 if (assembly_is_dynamic (assembly)) {
3435 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3436 for (i = 0; i < dynimg->image.module_count; ++i)
3437 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3438 mono_dynamic_image_release_gc_roots (dynimg);
3443 * Returns whether mono_assembly_close_finish() must be called as
3444 * well. See comment for mono_image_close_except_pools() for why we
3445 * unload in two steps.
3448 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3451 g_return_val_if_fail (assembly != NULL, FALSE);
3453 if (assembly == REFERENCE_MISSING)
3456 /* Might be 0 already */
3457 if (InterlockedDecrement (&assembly->ref_count) > 0)
3460 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3462 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3464 mono_debug_close_image (assembly->image);
3466 mono_assemblies_lock ();
3467 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3468 mono_assemblies_unlock ();
3470 assembly->image->assembly = NULL;
3472 if (!mono_image_close_except_pools (assembly->image))
3473 assembly->image = NULL;
3475 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3476 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3477 mono_assembly_name_free (fname);
3480 g_slist_free (assembly->friend_assembly_names);
3481 g_free (assembly->basedir);
3483 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3489 mono_assembly_close_finish (MonoAssembly *assembly)
3491 g_assert (assembly && assembly != REFERENCE_MISSING);
3493 if (assembly->image)
3494 mono_image_close_finish (assembly->image);
3496 if (assembly_is_dynamic (assembly)) {
3497 g_free ((char*)assembly->aname.culture);
3504 * mono_assembly_close:
3505 * @assembly: the assembly to release.
3507 * This method releases a reference to the @assembly. The assembly is
3508 * only released when all the outstanding references to it are released.
3511 mono_assembly_close (MonoAssembly *assembly)
3513 if (mono_assembly_close_except_image_pools (assembly))
3514 mono_assembly_close_finish (assembly);
3518 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3521 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3522 mono_error_assert_ok (&error);
3527 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3529 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3534 * mono_assembly_foreach:
3535 * @func: function to invoke for each assembly loaded
3536 * @user_data: data passed to the callback
3538 * Invokes the provided @func callback for each assembly loaded into
3539 * the runtime. The first parameter passed to the callback is the
3540 * `MonoAssembly*`, and the second parameter is the @user_data.
3542 * This is done for all assemblies loaded in the runtime, not just
3543 * those loaded in the current application domain.
3546 mono_assembly_foreach (GFunc func, gpointer user_data)
3551 * We make a copy of the list to avoid calling the callback inside the
3552 * lock, which could lead to deadlocks.
3554 mono_assemblies_lock ();
3555 copy = g_list_copy (loaded_assemblies);
3556 mono_assemblies_unlock ();
3558 g_list_foreach (loaded_assemblies, func, user_data);
3564 * mono_assemblies_cleanup:
3566 * Free all resources used by this module.
3569 mono_assemblies_cleanup (void)
3573 mono_os_mutex_destroy (&assemblies_mutex);
3574 mono_os_mutex_destroy (&assembly_binding_mutex);
3576 for (l = loaded_assembly_bindings; l; l = l->next) {
3577 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3579 mono_assembly_binding_info_free (info);
3582 g_slist_free (loaded_assembly_bindings);
3584 free_assembly_load_hooks ();
3585 free_assembly_search_hooks ();
3586 free_assembly_preload_hooks ();
3589 /*LOCKING takes the assembly_binding lock*/
3591 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3595 mono_assembly_binding_lock ();
3596 iter = &loaded_assembly_bindings;
3599 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3601 if (info->domain_id == domain_id) {
3603 mono_assembly_binding_info_free (info);
3610 mono_assembly_binding_unlock ();
3614 * Holds the assembly of the application, for
3615 * System.Diagnostics.Process::MainModule
3617 static MonoAssembly *main_assembly=NULL;
3620 mono_assembly_set_main (MonoAssembly *assembly)
3622 main_assembly = assembly;
3626 * mono_assembly_get_main:
3628 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3631 mono_assembly_get_main (void)
3633 return (main_assembly);
3637 * mono_assembly_get_image:
3638 * @assembly: The assembly to retrieve the image from
3640 * Returns: the MonoImage associated with this assembly.
3643 mono_assembly_get_image (MonoAssembly *assembly)
3645 return assembly->image;
3649 * mono_assembly_get_name:
3650 * @assembly: The assembly to retrieve the name from
3652 * The returned name's lifetime is the same as @assembly's.
3654 * Returns: the MonoAssemblyName associated with this assembly.
3657 mono_assembly_get_name (MonoAssembly *assembly)
3659 return &assembly->aname;
3663 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3665 bundles = assemblies;
3668 #define MONO_DECLSEC_FORMAT_10 0x3C
3669 #define MONO_DECLSEC_FORMAT_20 0x2E
3670 #define MONO_DECLSEC_FIELD 0x53
3671 #define MONO_DECLSEC_PROPERTY 0x54
3673 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3674 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3675 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3676 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3677 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3680 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3684 case MONO_DECLSEC_PROPERTY:
3686 case MONO_DECLSEC_FIELD:
3688 *abort_decoding = TRUE;
3693 if (*p++ != MONO_TYPE_BOOLEAN) {
3694 *abort_decoding = TRUE;
3698 /* property name length */
3699 len = mono_metadata_decode_value (p, &p);
3701 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3712 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3714 int i, j, num, len, params_len;
3716 if (*p == MONO_DECLSEC_FORMAT_10) {
3717 gsize read, written;
3718 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3720 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3726 if (*p++ != MONO_DECLSEC_FORMAT_20)
3729 /* number of encoded permission attributes */
3730 num = mono_metadata_decode_value (p, &p);
3731 for (i = 0; i < num; ++i) {
3732 gboolean is_valid = FALSE;
3733 gboolean abort_decoding = FALSE;
3735 /* attribute name length */
3736 len = mono_metadata_decode_value (p, &p);
3738 /* We don't really need to fully decode the type. Comparing the name is enough */
3739 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3743 /*size of the params table*/
3744 params_len = mono_metadata_decode_value (p, &p);
3746 const char *params_end = p + params_len;
3748 /* number of parameters */
3749 len = mono_metadata_decode_value (p, &p);
3751 for (j = 0; j < len; ++j) {
3752 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3768 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3771 guint32 cols [MONO_DECL_SECURITY_SIZE];
3775 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3776 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3778 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3780 for (i = 0; i < t->rows; ++i) {
3781 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3782 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3784 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3787 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3788 len = mono_metadata_decode_blob_size (blob, &blob);
3792 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3793 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3798 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);