2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include "assembly-internals.h"
21 #include "image-internals.h"
22 #include "object-internals.h"
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/metadata/custom-attrs-internals.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/class-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include <mono/metadata/reflection-internals.h>
31 #include <mono/metadata/mono-endian.h>
32 #include <mono/metadata/mono-debug.h>
33 #include <mono/utils/mono-uri.h>
34 #include <mono/metadata/mono-config.h>
35 #include <mono/metadata/mono-config-dirs.h>
36 #include <mono/utils/mono-digest.h>
37 #include <mono/utils/mono-logger-internals.h>
38 #include <mono/utils/mono-path.h>
39 #include <mono/metadata/reflection.h>
40 #include <mono/metadata/coree.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/utils/mono-io-portability.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-os-mutex.h>
47 #include <sys/types.h>
52 #ifdef PLATFORM_MACOSX
53 #include <mach-o/dyld.h>
56 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
58 const char* assembly_name;
59 guint8 version_set_index;
60 const char* new_assembly_name;
61 gboolean only_lower_versions;
64 /* the default search path is empty, the first slot is replaced with the computed value */
72 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
73 static char **assemblies_path = NULL;
75 /* Contains the list of directories that point to auxiliary GACs */
76 static char **extra_gac_paths = NULL;
78 #ifndef DISABLE_ASSEMBLY_REMAPPING
80 static GHashTable* assembly_remapping_table;
81 /* The list of system assemblies what will be remapped to the running
83 * This list is stored in @assembly_remapping_table during initialization.
84 * Keep it sorted just to make maintenance easier.
86 * The integer number is an index in the MonoRuntimeInfo structure, whose
87 * values can be found in domain.c - supported_runtimes. Look there
88 * to understand what remapping will be made.
90 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
93 static const AssemblyVersionMap framework_assemblies [] = {
95 {"Commons.Xml.Relaxng", 0},
102 {"Microsoft.Build.Engine", 2, NULL, TRUE},
103 {"Microsoft.Build.Framework", 2, NULL, TRUE},
104 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
105 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
106 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
107 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
108 {"Microsoft.VisualBasic", 1},
109 {"Microsoft.VisualC", 1},
111 {"Mono.CompilerServices.SymbolWriter", 0},
113 {"Mono.Data.SybaseClient", 0},
114 {"Mono.Data.Tds", 0},
115 {"Mono.Data.TdsClient", 0},
116 {"Mono.GetOptions", 0},
119 {"Mono.Security", 0},
120 {"Mono.Security.Win32", 0},
122 {"Novell.Directory.Ldap", 0},
125 {"System.ComponentModel.Composition", 2},
126 {"System.ComponentModel.DataAnnotations", 2},
127 {"System.Configuration", 0},
128 {"System.Configuration.Install", 0},
131 {"System.Data.Linq", 2},
132 {"System.Data.OracleClient", 0},
133 {"System.Data.Services", 2},
134 {"System.Data.Services.Client", 2},
135 {"System.Data.SqlXml", 0},
136 {"System.Design", 0},
137 {"System.DirectoryServices", 0},
138 {"System.Drawing", 0},
139 {"System.Drawing.Design", 0},
140 {"System.EnterpriseServices", 0},
141 {"System.IO.Compression", 2},
142 {"System.IdentityModel", 3},
143 {"System.IdentityModel.Selectors", 3},
144 {"System.Management", 0},
145 {"System.Messaging", 0},
147 {"System.Net.Http", 4},
148 {"System.Numerics.Vectors", 3},
149 {"System.Runtime.InteropServices.RuntimeInformation", 2},
150 {"System.Runtime.Remoting", 0},
151 {"System.Runtime.Serialization", 3},
152 {"System.Runtime.Serialization.Formatters", 3},
153 {"System.Runtime.Serialization.Formatters.Soap", 0},
154 {"System.Security", 0},
155 {"System.ServiceModel", 3},
156 {"System.ServiceModel.Duplex", 3},
157 {"System.ServiceModel.Http", 3},
158 {"System.ServiceModel.NetTcp", 3},
159 {"System.ServiceModel.Primitives", 3},
160 {"System.ServiceModel.Security", 3},
161 {"System.ServiceModel.Web", 2},
162 {"System.ServiceProcess", 0},
163 {"System.Text.Encoding.CodePages", 3},
164 {"System.Transactions", 0},
166 {"System.Web.Abstractions", 2},
167 {"System.Web.DynamicData", 2},
168 {"System.Web.Extensions", 2},
169 {"System.Web.Mobile", 0},
170 {"System.Web.Routing", 2},
171 {"System.Web.Services", 0},
172 {"System.Windows.Forms", 0},
174 {"System.Xml.Linq", 2},
175 {"System.Xml.ReaderWriter", 3},
176 {"System.Xml.XPath.XmlDocument", 3},
183 * keeps track of loaded assemblies
185 static GList *loaded_assemblies = NULL;
186 static MonoAssembly *corlib;
188 #if defined(__native_client__)
190 /* On Native Client, allow mscorlib to be loaded from memory */
191 /* instead of loaded off disk. If these are not set, default */
192 /* mscorlib loading will take place */
194 /* NOTE: If mscorlib data is passed to mono in this way then */
195 /* it needs to remain allocated during the use of mono. */
197 static void *corlibData = NULL;
198 static size_t corlibSize = 0;
201 mono_set_corlib_data (void *data, size_t size)
209 static char* unquote (const char *str);
211 /* This protects loaded_assemblies and image->references */
212 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
213 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
214 static mono_mutex_t assemblies_mutex;
216 /* If defined, points to the bundled assembly information */
217 const MonoBundledAssembly **bundles;
219 static mono_mutex_t assembly_binding_mutex;
221 /* Loaded assembly binding info */
222 static GSList *loaded_assembly_bindings = NULL;
224 /* Class lazy loading functions */
225 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
227 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
229 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
231 mono_assembly_is_in_gac (const gchar *filanem);
234 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
237 encode_public_tok (const guchar *token, gint32 len)
239 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
243 res = (gchar *)g_malloc (len * 2 + 1);
244 for (i = 0; i < len; i++) {
245 res [i * 2] = allowed [token [i] >> 4];
246 res [i * 2 + 1] = allowed [token [i] & 0xF];
253 * mono_public_tokens_are_equal:
254 * @pubt1: first public key token
255 * @pubt2: second public key token
257 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
261 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
263 return memcmp (pubt1, pubt2, 16) == 0;
267 * mono_set_assemblies_path:
268 * @path: list of paths that contain directories where Mono will look for assemblies
270 * Use this method to override the standard assembly lookup system and
271 * override any assemblies coming from the GAC. This is the method
272 * that supports the MONO_PATH variable.
274 * Notice that MONO_PATH and this method are really a very bad idea as
275 * it prevents the GAC from working and it prevents the standard
276 * resolution mechanisms from working. Nonetheless, for some debugging
277 * situations and bootstrapping setups, this is useful to have.
280 mono_set_assemblies_path (const char* path)
282 char **splitted, **dest;
284 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
286 g_strfreev (assemblies_path);
287 assemblies_path = dest = splitted;
289 char *tmp = *splitted;
291 *dest++ = mono_path_canonicalize (tmp);
297 if (g_hasenv ("MONO_DEBUG"))
300 splitted = assemblies_path;
302 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
303 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
309 /* Native Client can't get this info from an environment variable so */
310 /* it's passed in to the runtime, or set manually by embedding code. */
311 #ifdef __native_client__
312 char* nacl_mono_path = NULL;
316 check_path_env (void)
318 if (assemblies_path != NULL)
321 char* path = g_getenv ("MONO_PATH");
322 #ifdef __native_client__
324 path = strdup (nacl_mono_path);
329 mono_set_assemblies_path(path);
334 check_extra_gac_path_env (void)
337 char **splitted, **dest;
339 path = g_getenv ("MONO_GAC_PREFIX");
343 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
347 g_strfreev (extra_gac_paths);
348 extra_gac_paths = dest = splitted;
356 if (!g_hasenv ("MONO_DEBUG"))
360 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
361 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
368 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
370 if (!info || !info->name)
373 if (strcmp (info->name, aname->name))
376 if (info->major != aname->major || info->minor != aname->minor)
379 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
382 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
385 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
392 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
398 g_free (info->culture);
402 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
405 guint32 cols [MONO_MANIFEST_SIZE];
406 const gchar *filename;
407 gchar *subpath, *fullpath;
409 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
410 /* MS Impl. accepts policy assemblies with more than
411 * one manifest resource, and only takes the first one */
413 binding_info->is_valid = FALSE;
417 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
418 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
419 binding_info->is_valid = FALSE;
423 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
424 g_assert (filename != NULL);
426 subpath = g_path_get_dirname (image->name);
427 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
428 mono_config_parse_publisher_policy (fullpath, binding_info);
432 /* Define the optional elements/attributes before checking */
433 if (!binding_info->culture)
434 binding_info->culture = g_strdup ("");
436 /* Check that the most important elements/attributes exist */
437 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
438 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
439 mono_assembly_binding_info_free (binding_info);
440 binding_info->is_valid = FALSE;
444 binding_info->is_valid = TRUE;
448 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
450 if (v->major > aname->major)
452 else if (v->major < aname->major)
455 if (v->minor > aname->minor)
457 else if (v->minor < aname->minor)
460 if (v->build > aname->build)
462 else if (v->build < aname->build)
465 if (v->revision > aname->revision)
467 else if (v->revision < aname->revision)
474 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
479 /* If has_old_version_top doesn't exist, we don't have an interval */
480 if (!info->has_old_version_top) {
481 if (compare_versions (&info->old_version_bottom, name) == 0)
487 /* Check that the version defined by name is valid for the interval */
488 if (compare_versions (&info->old_version_top, name) < 0)
491 /* We should be greater or equal than the small version */
492 if (compare_versions (&info->old_version_bottom, name) > 0)
499 * mono_assembly_names_equal:
501 * @r: second assembly.
503 * Compares two MonoAssemblyNames and returns whether they are equal.
505 * This compares the names, the cultures, the release version and their
508 * Returns: TRUE if both assembly names are equal.
511 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
513 if (!l->name || !r->name)
516 if (strcmp (l->name, r->name))
519 if (l->culture && r->culture && strcmp (l->culture, r->culture))
522 if (l->major != r->major || l->minor != r->minor ||
523 l->build != r->build || l->revision != r->revision)
524 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)))
527 if (!l->public_key_token [0] || !r->public_key_token [0])
530 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
536 static MonoAssembly *
537 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
541 MonoAssembly *result;
543 for (i = 0; search_path [i]; ++i) {
544 fullpath = g_build_filename (search_path [i], basename, NULL);
545 result = mono_assembly_open_full (fullpath, status, refonly);
554 * mono_assembly_setrootdir:
555 * @root_dir: The pathname of the root directory where we will locate assemblies
557 * This routine sets the internal default root directory for looking up
560 * This is used by Windows installations to compute dynamically the
561 * place where the Mono assemblies are located.
565 mono_assembly_setrootdir (const char *root_dir)
568 * Override the MONO_ASSEMBLIES directory configured at compile time.
570 /* Leak if called more than once */
571 default_path [0] = g_strdup (root_dir);
575 * mono_assembly_getrootdir:
577 * Obtains the root directory used for looking up assemblies.
579 * Returns: a string with the directory, this string should not be freed.
581 G_CONST_RETURN gchar *
582 mono_assembly_getrootdir (void)
584 return default_path [0];
588 * mono_native_getrootdir:
590 * Obtains the root directory used for looking up native libs (.so, .dylib).
592 * Returns: a string with the directory, this string should be freed by
596 mono_native_getrootdir (void)
598 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
604 * @assembly_dir: the base directory for assemblies
605 * @config_dir: the base directory for configuration files
607 * This routine is used internally and by developers embedding
608 * the runtime into their own applications.
610 * There are a number of cases to consider: Mono as a system-installed
611 * package that is available on the location preconfigured or Mono in
612 * a relocated location.
614 * If you are using a system-installed Mono, you can pass NULL
615 * to both parameters. If you are not, you should compute both
616 * directory values and call this routine.
618 * The values for a given PREFIX are:
620 * assembly_dir: PREFIX/lib
621 * config_dir: PREFIX/etc
623 * Notice that embedders that use Mono in a relocated way must
624 * compute the location at runtime, as they will be in control
625 * of where Mono is installed.
628 mono_set_dirs (const char *assembly_dir, const char *config_dir)
630 if (assembly_dir == NULL)
631 assembly_dir = mono_config_get_assemblies_dir ();
632 if (config_dir == NULL)
633 config_dir = mono_config_get_cfg_dir ();
634 mono_assembly_setrootdir (assembly_dir);
635 mono_set_config_dir (config_dir);
641 compute_base (char *path)
643 char *p = strrchr (path, '/');
647 /* Not a well known Mono executable, we are embedded, cant guess the base */
648 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
652 p = strrchr (path, '/');
656 if (strcmp (p, "/bin") != 0)
665 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
668 static G_GNUC_UNUSED void
672 char *config, *lib, *mono;
677 * Only /usr prefix is treated specially
679 bindir = mono_config_get_bin_dir ();
681 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
686 config = g_build_filename (base, "etc", NULL);
687 lib = g_build_filename (base, "lib", NULL);
688 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
689 if (stat (mono, &buf) == -1)
692 mono_set_dirs (lib, config);
700 #endif /* HOST_WIN32 */
705 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
706 * this auto-detects the prefix where Mono was installed.
709 mono_set_rootdir (void)
711 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
712 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
715 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
719 * _NSGetExecutablePath may return -1 to indicate buf is not large
720 * enough, but we ignore that case to avoid having to do extra dynamic
721 * allocation for the path and hope that 4096 is enough - this is
722 * ok in the Linux/Solaris case below at least...
726 guint buf_size = sizeof (buf);
729 if (_NSGetExecutablePath (buf, &buf_size) == 0)
730 name = g_strdup (buf);
739 resolvedname = mono_path_resolve_symlinks (name);
741 bindir = g_path_get_dirname (resolvedname);
742 installdir = g_path_get_dirname (bindir);
743 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
745 config = g_build_filename (root, "..", "etc", NULL);
747 mono_set_dirs (root, config);
749 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
750 mono_set_dirs (root, config);
760 g_free (resolvedname);
761 #elif defined(DISABLE_MONO_AUTODETECTION)
769 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
777 /* Solaris 10 style */
778 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
779 s = readlink (str, buf, sizeof (buf)-1);
791 * mono_assemblies_init:
793 * Initialize global variables used by this module.
796 mono_assemblies_init (void)
799 * Initialize our internal paths if we have not been initialized yet.
800 * This happens when embedders use Mono.
802 if (mono_assembly_getrootdir () == NULL)
806 check_extra_gac_path_env ();
808 mono_os_mutex_init_recursive (&assemblies_mutex);
809 mono_os_mutex_init (&assembly_binding_mutex);
811 #ifndef DISABLE_ASSEMBLY_REMAPPING
812 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
815 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
816 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
822 mono_assembly_binding_lock (void)
824 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
828 mono_assembly_binding_unlock (void)
830 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
834 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
836 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
837 guint32 cols [MONO_ASSEMBLY_SIZE];
838 gint32 machine, flags;
843 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
846 aname->hash_value = NULL;
847 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
849 aname->name = g_strdup (aname->name);
850 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
852 aname->culture = g_strdup (aname->culture);
853 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
854 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
855 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
856 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
857 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
858 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
859 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
860 guchar* token = (guchar *)g_malloc (8);
865 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
866 len = mono_metadata_decode_blob_size (pkey, &pkey);
867 aname->public_key = (guchar*)pkey;
869 mono_digest_get_public_token (token, aname->public_key, len);
870 encoded = encode_public_tok (token, 8);
871 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
877 aname->public_key = NULL;
878 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
881 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
882 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
884 const gchar *pkey_end;
885 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
886 pkey_end += len; /* move to end */
887 size_t size = pkey_end - (const gchar*)aname->public_key;
888 guchar *tmp = g_new (guchar, size);
889 memcpy (tmp, aname->public_key, size);
890 aname->public_key = tmp;
895 aname->public_key = 0;
897 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
898 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
900 case COFF_MACHINE_I386:
901 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
902 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
903 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
904 else if ((flags & 0x70) == 0x70)
905 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
907 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
909 case COFF_MACHINE_IA64:
910 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
912 case COFF_MACHINE_AMD64:
913 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
915 case COFF_MACHINE_ARM:
916 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
926 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
928 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
932 * mono_stringify_assembly_name:
933 * @aname: the assembly name.
935 * Convert @aname into its string format. The returned string is dynamically
936 * allocated and should be freed by the caller.
938 * Returns: a newly allocated string with a string representation of
942 mono_stringify_assembly_name (MonoAssemblyName *aname)
944 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
946 return g_strdup_printf (
947 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
948 quote, aname->name, quote,
949 aname->major, aname->minor, aname->build, aname->revision,
950 aname->culture && *aname->culture? aname->culture: "neutral",
951 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
952 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
956 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
958 const gchar *public_tok;
961 public_tok = mono_metadata_blob_heap (image, key_index);
962 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
964 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
966 mono_digest_get_public_token (token, (guchar*)public_tok, len);
967 return encode_public_tok (token, 8);
970 return encode_public_tok ((guchar*)public_tok, len);
974 * mono_assembly_addref:
975 * @assemnly: the assembly to reference
977 * This routine increments the reference count on a MonoAssembly.
978 * The reference count is reduced every time the method mono_assembly_close() is
982 mono_assembly_addref (MonoAssembly *assembly)
984 InterlockedIncrement (&assembly->ref_count);
988 * CAUTION: This table must be kept in sync with
989 * ivkm/reflect/Fusion.cs
992 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
993 #define WINFX_KEY "31bf3856ad364e35"
994 #define ECMA_KEY "b77a5c561934e089"
995 #define MSFINAL_KEY "b03f5f7f11d50a3a"
996 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1004 static KeyRemapEntry key_remap_table[] = {
1005 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1006 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1007 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1008 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1009 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1010 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1011 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1012 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1013 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1014 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1015 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1016 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1017 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1018 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1019 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1020 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1021 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1022 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1023 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1024 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1025 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1026 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1027 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1028 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1029 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1030 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1031 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1032 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1033 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1037 remap_keys (MonoAssemblyName *aname)
1040 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1041 const KeyRemapEntry *entry = &key_remap_table [i];
1043 if (strcmp (aname->name, entry->name) ||
1044 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1047 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1049 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1050 "Remapped public key token of retargetable assembly %s from %s to %s",
1051 aname->name, entry->from, entry->to);
1056 static MonoAssemblyName *
1057 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1059 const MonoRuntimeInfo *current_runtime;
1061 if (aname->name == NULL) return aname;
1063 current_runtime = mono_get_runtime_info ();
1065 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1066 const AssemblyVersionSet* vset;
1068 /* Remap to current runtime */
1069 vset = ¤t_runtime->version_sets [0];
1071 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1072 dest_aname->major = vset->major;
1073 dest_aname->minor = vset->minor;
1074 dest_aname->build = vset->build;
1075 dest_aname->revision = vset->revision;
1076 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1078 /* Remap assembly name */
1079 if (!strcmp (aname->name, "System.Net"))
1080 dest_aname->name = g_strdup ("System");
1082 remap_keys (dest_aname);
1084 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1085 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1087 aname->major, aname->minor, aname->build, aname->revision,
1089 vset->major, vset->minor, vset->build, vset->revision
1095 #ifndef DISABLE_ASSEMBLY_REMAPPING
1096 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1098 const AssemblyVersionSet* vset;
1099 int index = vmap->version_set_index;
1100 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1101 vset = ¤t_runtime->version_sets [index];
1103 if (aname->major == vset->major && aname->minor == vset->minor &&
1104 aname->build == vset->build && aname->revision == vset->revision) {
1105 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1107 aname->major, aname->minor, aname->build, aname->revision);
1111 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1112 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1113 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1115 aname->major, aname->minor, aname->build, aname->revision,
1116 vset->major, vset->minor, vset->build, vset->revision
1121 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1122 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1123 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1125 aname->major, aname->minor, aname->build, aname->revision,
1126 vset->major, vset->minor, vset->build, vset->revision
1129 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1130 dest_aname->major = vset->major;
1131 dest_aname->minor = vset->minor;
1132 dest_aname->build = vset->build;
1133 dest_aname->revision = vset->revision;
1134 if (vmap->new_assembly_name != NULL) {
1135 dest_aname->name = vmap->new_assembly_name;
1136 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1137 "The assembly name %s was remapped to %s",
1149 * mono_assembly_get_assemblyref:
1150 * @image: pointer to the MonoImage to extract the information from.
1151 * @index: index to the assembly reference in the image.
1152 * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1154 * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1157 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1160 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1163 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1165 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1167 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1168 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1169 aname->hash_value = hash;
1170 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1171 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1172 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1173 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1174 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1175 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1176 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1178 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1179 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1180 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1183 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1188 mono_assembly_load_reference (MonoImage *image, int index)
1190 MonoAssembly *reference;
1191 MonoAssemblyName aname;
1192 MonoImageOpenStatus status;
1195 * image->references is shared between threads, so we need to access
1196 * it inside a critical section.
1198 mono_assemblies_lock ();
1199 if (!image->references) {
1200 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1202 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1203 image->nreferences = t->rows;
1205 reference = image->references [index];
1206 mono_assemblies_unlock ();
1210 mono_assembly_get_assemblyref (image, index, &aname);
1212 if (image->assembly && image->assembly->ref_only) {
1213 /* We use the loaded corlib */
1214 if (!strcmp (aname.name, "mscorlib"))
1215 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1217 reference = mono_assembly_loaded_full (&aname, TRUE);
1219 /* Try a postload search hook */
1220 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1224 * Here we must advice that the error was due to
1225 * a non loaded reference using the ReflectionOnly api
1228 reference = (MonoAssembly *)REFERENCE_MISSING;
1230 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1231 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1232 * accordingly, it would fail on the MS runtime before).
1233 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1234 * example bug-349190.2.cs and who knows how much more code in the wild.
1236 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1237 if (!reference && image->assembly)
1238 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1241 if (reference == NULL){
1244 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1245 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 : "" );
1246 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1247 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1248 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1249 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1250 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1251 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1253 extra_msg = g_strdup ("");
1256 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1257 " Assembly: %s (assemblyref_index=%d)\n"
1258 " Version: %d.%d.%d.%d\n"
1259 " Public Key: %s\n%s",
1260 image->name, aname.name, index,
1261 aname.major, aname.minor, aname.build, aname.revision,
1262 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1267 mono_assemblies_lock ();
1268 if (reference == NULL) {
1269 /* Flag as not found */
1270 reference = (MonoAssembly *)REFERENCE_MISSING;
1273 if (!image->references [index]) {
1274 if (reference != REFERENCE_MISSING){
1275 mono_assembly_addref (reference);
1276 if (image->assembly)
1277 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1278 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1280 if (image->assembly)
1281 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1282 image->assembly->aname.name, image->assembly);
1285 image->references [index] = reference;
1287 mono_assemblies_unlock ();
1289 if (image->references [index] != reference) {
1290 /* Somebody loaded it before us */
1291 mono_assembly_close (reference);
1296 * mono_assembly_load_references:
1299 * @deprecated: There is no reason to use this method anymore, it does nothing
1301 * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1304 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1306 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1307 *status = MONO_IMAGE_OK;
1310 typedef struct AssemblyLoadHook AssemblyLoadHook;
1311 struct AssemblyLoadHook {
1312 AssemblyLoadHook *next;
1313 MonoAssemblyLoadFunc func;
1317 AssemblyLoadHook *assembly_load_hook = NULL;
1320 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1322 AssemblyLoadHook *hook;
1324 for (hook = assembly_load_hook; hook; hook = hook->next) {
1325 hook->func (ass, hook->user_data);
1330 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1332 AssemblyLoadHook *hook;
1334 g_return_if_fail (func != NULL);
1336 hook = g_new0 (AssemblyLoadHook, 1);
1338 hook->user_data = user_data;
1339 hook->next = assembly_load_hook;
1340 assembly_load_hook = hook;
1344 free_assembly_load_hooks (void)
1346 AssemblyLoadHook *hook, *next;
1348 for (hook = assembly_load_hook; hook; hook = next) {
1354 typedef struct AssemblySearchHook AssemblySearchHook;
1355 struct AssemblySearchHook {
1356 AssemblySearchHook *next;
1357 MonoAssemblySearchFunc func;
1363 AssemblySearchHook *assembly_search_hook = NULL;
1365 static MonoAssembly*
1366 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1368 AssemblySearchHook *hook;
1370 for (hook = assembly_search_hook; hook; hook = hook->next) {
1371 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1374 * A little explanation is in order here.
1376 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1377 * The embedding API exposes a search hook that doesn't take such argument.
1379 * The original fix would call the default search hook before all the registered ones and pass
1380 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1381 * rely on. Which is the ordering between user hooks and the default runtime hook.
1383 * Registering the hook after mono_jit_init would let your hook run before the default one and
1384 * when using it to handle non standard app layouts this could save your app from a massive amount
1385 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1386 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1388 * So what's the fix? We register the default hook using regular means and special case it when iterating
1389 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1392 if (hook->func == (void*)mono_domain_assembly_postload_search)
1393 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1395 ass = hook->func (aname, hook->user_data);
1405 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1407 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1411 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1413 AssemblySearchHook *hook;
1415 g_return_if_fail (func != NULL);
1417 hook = g_new0 (AssemblySearchHook, 1);
1419 hook->user_data = user_data;
1420 hook->refonly = refonly;
1421 hook->postload = postload;
1422 hook->next = assembly_search_hook;
1423 assembly_search_hook = hook;
1427 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1429 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1433 free_assembly_search_hooks (void)
1435 AssemblySearchHook *hook, *next;
1437 for (hook = assembly_search_hook; hook; hook = next) {
1444 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1446 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1450 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1452 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1456 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1458 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1461 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1462 struct AssemblyPreLoadHook {
1463 AssemblyPreLoadHook *next;
1464 MonoAssemblyPreLoadFunc func;
1468 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1469 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1471 static MonoAssembly *
1472 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1474 AssemblyPreLoadHook *hook;
1475 MonoAssembly *assembly;
1477 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1478 assembly = hook->func (aname, assemblies_path, hook->user_data);
1479 if (assembly != NULL)
1486 static MonoAssembly *
1487 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1489 AssemblyPreLoadHook *hook;
1490 MonoAssembly *assembly;
1492 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1493 assembly = hook->func (aname, assemblies_path, hook->user_data);
1494 if (assembly != NULL)
1502 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1504 AssemblyPreLoadHook *hook;
1506 g_return_if_fail (func != NULL);
1508 hook = g_new0 (AssemblyPreLoadHook, 1);
1510 hook->user_data = user_data;
1511 hook->next = assembly_preload_hook;
1512 assembly_preload_hook = hook;
1516 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1518 AssemblyPreLoadHook *hook;
1520 g_return_if_fail (func != NULL);
1522 hook = g_new0 (AssemblyPreLoadHook, 1);
1524 hook->user_data = user_data;
1525 hook->next = assembly_refonly_preload_hook;
1526 assembly_refonly_preload_hook = hook;
1530 free_assembly_preload_hooks (void)
1532 AssemblyPreLoadHook *hook, *next;
1534 for (hook = assembly_preload_hook; hook; hook = next) {
1539 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1546 absolute_dir (const gchar *filename)
1557 if (g_path_is_absolute (filename)) {
1558 part = g_path_get_dirname (filename);
1559 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1564 cwd = g_get_current_dir ();
1565 mixed = g_build_filename (cwd, filename, NULL);
1566 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1571 for (i = 0; (part = parts [i]) != NULL; i++) {
1572 if (!strcmp (part, "."))
1575 if (!strcmp (part, "..")) {
1576 if (list && list->next) /* Don't remove root */
1577 list = g_list_delete_link (list, list);
1579 list = g_list_prepend (list, part);
1583 result = g_string_new ("");
1584 list = g_list_reverse (list);
1586 /* Ignores last data pointer, which should be the filename */
1587 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1589 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1594 g_string_free (result, FALSE);
1599 return g_strdup (".");
1606 * mono_assembly_open_from_bundle:
1607 * @filename: Filename requested
1608 * @status: return status code
1610 * This routine tries to open the assembly specified by `filename' from the
1611 * defined bundles, if found, returns the MonoImage for it, if not found
1615 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1619 gchar *lowercase_filename;
1620 MonoImage *image = NULL;
1621 gboolean is_satellite = FALSE;
1623 * we do a very simple search for bundled assemblies: it's not a general
1624 * purpose assembly loading mechanism.
1630 lowercase_filename = g_utf8_strdown (filename, -1);
1631 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1632 g_free (lowercase_filename);
1633 name = g_path_get_basename (filename);
1634 mono_assemblies_lock ();
1635 for (i = 0; !image && bundles [i]; ++i) {
1636 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1637 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1641 mono_assemblies_unlock ();
1643 mono_image_addref (image);
1644 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1653 * mono_assemblies_open_full:
1654 * @filename: the file to load
1655 * @status: return status code
1656 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1658 * This loads an assembly from the specified @filename. The @filename allows
1659 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1660 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1661 * is treated as a local path.
1663 * First, an attempt is made to load the assembly from the bundled executable (for those
1664 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1665 * assembly has been registered as an embedded assembly). If this is not the case, then
1666 * the assembly is loaded from disk using `api:mono_image_open_full`.
1668 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1669 * the assembly is made.
1671 * If @refonly is set to true, then the assembly is loaded purely for inspection with
1672 * the `System.Reflection` API.
1674 * Returns: NULL on error, with the @status set to an error code, or a pointer
1678 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1680 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1684 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1689 MonoImageOpenStatus def_status;
1692 gboolean loaded_from_bundle;
1694 g_return_val_if_fail (filename != NULL, NULL);
1697 status = &def_status;
1698 *status = MONO_IMAGE_OK;
1700 if (strncmp (filename, "file://", 7) == 0) {
1701 GError *error = NULL;
1702 gchar *uri = (gchar *) filename;
1706 * MS allows file://c:/... and fails on file://localhost/c:/...
1707 * They also throw an IndexOutOfRangeException if "file://"
1710 uri = g_strdup_printf ("file:///%s", uri + 7);
1713 uri = mono_escape_uri_string (tmpuri);
1714 fname = g_filename_from_uri (uri, NULL, &error);
1717 if (tmpuri != filename)
1720 if (error != NULL) {
1721 g_warning ("%s\n", error->message);
1722 g_error_free (error);
1723 fname = g_strdup (filename);
1726 fname = g_strdup (filename);
1729 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1730 "Assembly Loader probing location: '%s'.", fname);
1733 if (!mono_assembly_is_in_gac (fname)) {
1735 new_fname = mono_make_shadow_copy (fname, &error);
1736 if (!is_ok (&error)) {
1737 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1738 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1739 mono_error_cleanup (&error);
1740 *status = MONO_IMAGE_IMAGE_INVALID;
1745 if (new_fname && new_fname != fname) {
1748 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1749 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1754 // If VM built with mkbundle
1755 loaded_from_bundle = FALSE;
1756 if (bundles != NULL) {
1757 image = mono_assembly_open_from_bundle (fname, status, refonly);
1758 loaded_from_bundle = image != NULL;
1762 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1765 if (*status == MONO_IMAGE_OK)
1766 *status = MONO_IMAGE_ERROR_ERRNO;
1771 if (image->assembly) {
1772 /* Already loaded by another appdomain */
1773 mono_assembly_invoke_load_hook (image->assembly);
1774 mono_image_close (image);
1776 return image->assembly;
1779 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1782 if (!loaded_from_bundle)
1783 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1784 "Assembly Loader loaded assembly from location: '%s'.", filename);
1786 mono_config_for_assembly (ass->image);
1789 /* Clear the reference added by mono_image_open */
1790 mono_image_close (image);
1798 free_item (gpointer val, gpointer user_data)
1804 * mono_assembly_load_friends:
1807 * Load the list of friend assemblies that are allowed to access
1808 * the assembly's internal types and members. They are stored as assembly
1809 * names in custom attributes.
1811 * This is an internal method, we need this because when we load mscorlib
1812 * we do not have the internals visible cattr loaded yet,
1813 * so we need to load these after we initialize the runtime.
1815 * LOCKING: Acquires the assemblies lock plus the loader lock.
1818 mono_assembly_load_friends (MonoAssembly* ass)
1822 MonoCustomAttrInfo* attrs;
1825 if (ass->friend_assembly_names_inited)
1828 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1829 mono_error_assert_ok (&error);
1831 mono_assemblies_lock ();
1832 ass->friend_assembly_names_inited = TRUE;
1833 mono_assemblies_unlock ();
1837 mono_assemblies_lock ();
1838 if (ass->friend_assembly_names_inited) {
1839 mono_assemblies_unlock ();
1842 mono_assemblies_unlock ();
1846 * We build the list outside the assemblies lock, the worse that can happen
1847 * is that we'll need to free the allocated list.
1849 for (i = 0; i < attrs->num_attrs; ++i) {
1850 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1851 MonoAssemblyName *aname;
1853 /* Do some sanity checking */
1854 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1856 if (attr->data_size < 4)
1858 data = (const char*)attr->data;
1859 /* 0xFF means null string, see custom attr format */
1860 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1862 mono_metadata_decode_value (data + 2, &data);
1863 aname = g_new0 (MonoAssemblyName, 1);
1864 /*g_print ("friend ass: %s\n", data);*/
1865 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1866 list = g_slist_prepend (list, aname);
1871 mono_custom_attrs_free (attrs);
1873 mono_assemblies_lock ();
1874 if (ass->friend_assembly_names_inited) {
1875 mono_assemblies_unlock ();
1876 g_slist_foreach (list, free_item, NULL);
1877 g_slist_free (list);
1880 ass->friend_assembly_names = list;
1882 /* Because of the double checked locking pattern above */
1883 mono_memory_barrier ();
1884 ass->friend_assembly_names_inited = TRUE;
1885 mono_assemblies_unlock ();
1888 struct HasReferenceAssemblyAttributeIterData {
1893 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1895 gboolean stop_scanning = FALSE;
1896 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1898 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1899 /* Note we don't check the assembly name, same as coreCLR. */
1900 iter_data->has_attr = TRUE;
1901 stop_scanning = TRUE;
1904 return stop_scanning;
1908 * mono_assembly_has_reference_assembly_attribute:
1909 * @assembly: a MonoAssembly
1910 * @error: set on error.
1912 * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1913 * On error returns FALSE and sets @error.
1916 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1921 * This might be called during assembly loading, so do everything using the low-level
1925 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1927 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1929 return iter_data.has_attr;
1933 * mono_assembly_open:
1934 * @filename: Opens the assembly pointed out by this name
1935 * @status: return status code
1937 * This loads an assembly from the specified @filename. The @filename allows
1938 * a local URL (starting with a file:// prefix). If a file prefix is used, the
1939 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1940 * is treated as a local path.
1942 * First, an attempt is made to load the assembly from the bundled executable (for those
1943 * deployments that have been done with the `mkbundle` tool or for scenarios where the
1944 * assembly has been registered as an embedded assembly). If this is not the case, then
1945 * the assembly is loaded from disk using `api:mono_image_open_full`.
1947 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1948 * the assembly is made.
1950 * Return: a pointer to the MonoAssembly if @filename contains a valid
1951 * assembly or NULL on error. Details about the error are stored in the
1955 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1957 return mono_assembly_open_full (filename, status, FALSE);
1961 * mono_assembly_load_from_full:
1962 * @image: Image to load the assembly from
1963 * @fname: assembly name to associate with the assembly
1964 * @status: returns the status condition
1965 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1967 * If the provided @image has an assembly reference, it will process the given
1968 * image as an assembly with the given name.
1970 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1972 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1973 * set to #MONO_IMAGE_OK; or NULL on error.
1975 * If there is an error loading the assembly the @status will indicate the
1976 * reason with @status being set to `MONO_IMAGE_INVALID` if the
1977 * image did not contain an assembly reference table.
1980 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1981 MonoImageOpenStatus *status, gboolean refonly)
1983 MonoAssembly *ass, *ass2;
1986 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1987 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1988 *status = MONO_IMAGE_IMAGE_INVALID;
1992 #if defined (HOST_WIN32)
1997 tmp_fn = g_strdup (fname);
1998 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1999 if (tmp_fn [i] == '/')
2003 base_dir = absolute_dir (tmp_fn);
2007 base_dir = absolute_dir (fname);
2011 * Create assembly struct, and enter it into the assembly cache
2013 ass = g_new0 (MonoAssembly, 1);
2014 ass->basedir = base_dir;
2015 ass->ref_only = refonly;
2018 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2020 mono_assembly_fill_assembly_name (image, &ass->aname);
2022 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2023 // MS.NET doesn't support loading other mscorlibs
2026 mono_image_addref (mono_defaults.corlib);
2027 *status = MONO_IMAGE_OK;
2028 return mono_defaults.corlib->assembly;
2031 /* Add a non-temporary reference because of ass->image */
2032 mono_image_addref (image);
2034 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);
2037 * The load hooks might take locks so we can't call them while holding the
2040 if (ass->aname.name) {
2041 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2045 mono_image_close (image);
2046 *status = MONO_IMAGE_OK;
2051 /* We need to check for ReferenceAssmeblyAttribute before we
2052 * mark the assembly as loaded and before we fire the load
2053 * hook. Otherwise mono_domain_fire_assembly_load () in
2054 * appdomain.c will cache a mapping from the assembly name to
2055 * this image and we won't be able to look for a different
2059 MonoError refasm_error;
2060 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2061 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2064 mono_image_close (image);
2065 *status = MONO_IMAGE_IMAGE_INVALID;
2068 mono_error_cleanup (&refasm_error);
2071 mono_assemblies_lock ();
2073 if (image->assembly) {
2075 * This means another thread has already loaded the assembly, but not yet
2076 * called the load hooks so the search hook can't find the assembly.
2078 mono_assemblies_unlock ();
2079 ass2 = image->assembly;
2082 mono_image_close (image);
2083 *status = MONO_IMAGE_OK;
2087 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2089 image->assembly = ass;
2091 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2092 mono_assemblies_unlock ();
2095 if (image->is_module_handle)
2096 mono_image_fixup_vtable (image);
2099 mono_assembly_invoke_load_hook (ass);
2101 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2107 * mono_assembly_load_from:
2108 * @image: Image to load the assembly from
2109 * @fname: assembly name to associate with the assembly
2110 * @status: return status code
2112 * If the provided @image has an assembly reference, it will process the given
2113 * image as an assembly with the given name.
2115 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2117 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2118 * @refonly parameter set to FALSE.
2119 * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2120 * set to #MONO_IMAGE_OK; or NULL on error.
2122 * If there is an error loading the assembly the @status will indicate the
2123 * reason with @status being set to `MONO_IMAGE_INVALID` if the
2124 * image did not contain an assembly reference table.
2128 mono_assembly_load_from (MonoImage *image, const char *fname,
2129 MonoImageOpenStatus *status)
2131 return mono_assembly_load_from_full (image, fname, status, FALSE);
2135 * mono_assembly_name_free:
2136 * @aname: assembly name to free
2138 * Frees the provided assembly name object.
2139 * (it does not frees the object itself, only the name members).
2142 mono_assembly_name_free (MonoAssemblyName *aname)
2147 g_free ((void *) aname->name);
2148 g_free ((void *) aname->culture);
2149 g_free ((void *) aname->hash_value);
2150 g_free ((guint8*) aname->public_key);
2154 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2157 gchar header [16], val, *arr;
2158 gint i, j, offset, bitlen, keylen, pkeylen;
2160 keylen = strlen (key) >> 1;
2164 /* allow the ECMA standard key */
2165 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2167 *pubkey = g_strdup (key);
2173 val = g_ascii_xdigit_value (key [0]) << 4;
2174 val |= g_ascii_xdigit_value (key [1]);
2179 val = g_ascii_xdigit_value (key [24]);
2180 val |= g_ascii_xdigit_value (key [25]);
2192 /* We need the first 16 bytes
2193 * to check whether this key is valid or not */
2194 pkeylen = strlen (pkey) >> 1;
2198 for (i = 0, j = 0; i < 16; i++) {
2199 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2200 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2203 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2204 header [1] != 0x02 || /* Version (0x02) */
2205 header [2] != 0x00 || /* Reserved (word) */
2206 header [3] != 0x00 ||
2207 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2210 /* Based on this length, we _should_ be able to know if the length is right */
2211 bitlen = read32 (header + 12) >> 3;
2212 if ((bitlen + 16 + 4) != pkeylen)
2215 /* parsing is OK and the public key itself is not requested back */
2219 /* Encode the size of the blob */
2221 if (keylen <= 127) {
2222 arr = (gchar *)g_malloc (keylen + 1);
2223 arr [offset++] = keylen;
2225 arr = (gchar *)g_malloc (keylen + 2);
2226 arr [offset++] = 0x80; /* 10bs */
2227 arr [offset++] = keylen;
2230 for (i = offset, j = 0; i < keylen + offset; i++) {
2231 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2232 arr [i] |= g_ascii_xdigit_value (key [j++]);
2241 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)
2243 gint major, minor, build, revision;
2246 gchar *pkey, *pkeyptr, *encoded, tok [8];
2248 memset (aname, 0, sizeof (MonoAssemblyName));
2251 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2252 if (version_parts < 2 || version_parts > 4)
2255 /* FIXME: we should set build & revision to -1 (instead of 0)
2256 if these are not set in the version string. That way, later on,
2257 we can still determine if these were specified. */
2258 aname->major = major;
2259 aname->minor = minor;
2260 if (version_parts >= 3)
2261 aname->build = build;
2264 if (version_parts == 4)
2265 aname->revision = revision;
2267 aname->revision = 0;
2270 aname->flags = flags;
2272 aname->name = g_strdup (name);
2275 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2276 aname->culture = g_strdup ("");
2278 aname->culture = g_strdup (culture);
2281 if (token && strncmp (token, "null", 4) != 0) {
2284 /* the constant includes the ending NULL, hence the -1 */
2285 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2286 mono_assembly_name_free (aname);
2289 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2290 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2296 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2297 mono_assembly_name_free (aname);
2302 if (save_public_key)
2303 aname->public_key = (guint8*)pkey;
2306 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2310 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2311 // We also need to generate the key token
2312 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2313 encoded = encode_public_tok ((guchar*) tok, 8);
2314 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2317 if (save_public_key)
2318 aname->public_key = (guint8*) pkey;
2327 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2332 parts = g_strsplit (dirname, "_", 3);
2333 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2338 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2344 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2346 char *eqsign = strchr (pair, '=');
2354 *key = (gchar*)pair;
2355 *keylen = eqsign - *key;
2356 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2358 *value = g_strstrip (eqsign + 1);
2363 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2367 gchar *version = NULL;
2369 gchar *culture = NULL;
2371 gchar *token = NULL;
2375 gchar *retargetable = NULL;
2376 gchar *retargetable_uq;
2380 gchar *value, *part_name;
2381 guint32 part_name_len;
2384 gboolean version_defined;
2385 gboolean token_defined;
2387 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2389 if (!is_version_defined)
2390 is_version_defined = &version_defined;
2391 *is_version_defined = FALSE;
2392 if (!is_token_defined)
2393 is_token_defined = &token_defined;
2394 *is_token_defined = FALSE;
2396 parts = tmp = g_strsplit (name, ",", 6);
2397 if (!tmp || !*tmp) {
2402 dllname = g_strstrip (*tmp);
2407 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2408 goto cleanup_and_fail;
2410 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2411 *is_version_defined = TRUE;
2413 if (strlen (version) == 0) {
2414 goto cleanup_and_fail;
2420 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2422 if (strlen (culture) == 0) {
2423 goto cleanup_and_fail;
2429 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2430 *is_token_defined = TRUE;
2432 if (strlen (token) == 0) {
2433 goto cleanup_and_fail;
2439 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2441 if (strlen (key) == 0) {
2442 goto cleanup_and_fail;
2448 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2449 retargetable = value;
2450 retargetable_uq = unquote (retargetable);
2451 if (retargetable_uq != NULL)
2452 retargetable = retargetable_uq;
2454 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2455 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2456 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2457 g_free (retargetable_uq);
2458 goto cleanup_and_fail;
2461 g_free (retargetable_uq);
2466 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2468 procarch_uq = unquote (procarch);
2469 if (procarch_uq != NULL)
2470 procarch = procarch_uq;
2472 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2473 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2474 else if (!g_ascii_strcasecmp (procarch, "X86"))
2475 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2476 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2477 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2478 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2479 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2481 g_free (procarch_uq);
2482 goto cleanup_and_fail;
2485 g_free (procarch_uq);
2494 /* if retargetable flag is set, then we must have a fully qualified name */
2495 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2496 goto cleanup_and_fail;
2499 dllname_uq = unquote (dllname);
2500 version_uq = unquote (version);
2501 culture_uq = unquote (culture);
2502 token_uq = unquote (token);
2503 key_uq = unquote (key);
2505 res = build_assembly_name (
2506 dllname_uq == NULL ? dllname : dllname_uq,
2507 version_uq == NULL ? version : version_uq,
2508 culture_uq == NULL ? culture : culture_uq,
2509 token_uq == NULL ? token : token_uq,
2510 key_uq == NULL ? key : key_uq,
2511 flags, arch, aname, save_public_key);
2513 g_free (dllname_uq);
2514 g_free (version_uq);
2515 g_free (culture_uq);
2528 unquote (const char *str)
2536 slen = strlen (str);
2540 if (*str != '\'' && *str != '\"')
2543 end = str + slen - 1;
2547 return g_strndup (str + 1, slen - 2);
2551 * mono_assembly_name_parse:
2552 * @name: name to parse
2553 * @aname: the destination assembly name
2555 * Parses an assembly qualified type name and assigns the name,
2556 * version, culture and token to the provided assembly name object.
2558 * Returns: TRUE if the name could be parsed.
2561 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2563 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2567 * mono_assembly_name_new:
2568 * @name: name to parse
2570 * Allocate a new MonoAssemblyName and fill its values from the
2573 * Returns: a newly allocated structure or NULL if there was any failure.
2576 mono_assembly_name_new (const char *name)
2578 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2579 if (mono_assembly_name_parse (name, aname))
2586 mono_assembly_name_get_name (MonoAssemblyName *aname)
2592 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2594 return aname->culture;
2598 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2600 if (aname->public_key_token [0])
2601 return aname->public_key_token;
2606 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2609 *minor = aname->minor;
2611 *build = aname->build;
2613 *revision = aname->revision;
2614 return aname->major;
2617 static MonoAssembly*
2618 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2620 gchar *fullpath = NULL;
2622 const char* direntry;
2623 MonoAssemblyName gac_aname;
2624 gint major=-1, minor=0, build=0, revision=0;
2625 gboolean exact_version;
2627 dirhandle = g_dir_open (basepath, 0, NULL);
2631 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2633 while ((direntry = g_dir_read_name (dirhandle))) {
2634 gboolean match = TRUE;
2636 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2639 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2642 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2643 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2647 if (exact_version) {
2648 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2649 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2651 else if (gac_aname.major < major)
2653 else if (gac_aname.major == major) {
2654 if (gac_aname.minor < minor)
2656 else if (gac_aname.minor == minor) {
2657 if (gac_aname.build < build)
2659 else if (gac_aname.build == build && gac_aname.revision <= revision)
2666 major = gac_aname.major;
2667 minor = gac_aname.minor;
2668 build = gac_aname.build;
2669 revision = gac_aname.revision;
2671 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2674 mono_assembly_name_free (&gac_aname);
2677 g_dir_close (dirhandle);
2679 if (fullpath == NULL)
2682 MonoAssembly *res = mono_assembly_open (fullpath, status);
2689 * mono_assembly_load_with_partial_name:
2690 * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2691 * @status: return status code
2693 * Loads a Mono Assembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2694 * so it might contain a qualified type name, version, culture and token.
2696 * This will load the assembly from the file whose name is derived from the assembly name
2697 * by appending the .dll extension.
2699 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2700 * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2701 * if that fails from the GAC.
2703 * Returns: NULL on failure, or a pointer to a MonoAssembly on success.
2706 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2710 MonoAssemblyName *aname, base_name;
2711 MonoAssemblyName mapped_aname;
2712 gchar *fullname, *gacpath;
2715 memset (&base_name, 0, sizeof (MonoAssemblyName));
2718 if (!mono_assembly_name_parse (name, aname))
2722 * If no specific version has been requested, make sure we load the
2723 * correct version for system assemblies.
2725 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2726 aname = mono_assembly_remap_version (aname, &mapped_aname);
2728 res = mono_assembly_loaded (aname);
2730 mono_assembly_name_free (aname);
2734 res = invoke_assembly_preload_hook (aname, assemblies_path);
2736 res->in_gac = FALSE;
2737 mono_assembly_name_free (aname);
2741 fullname = g_strdup_printf ("%s.dll", aname->name);
2743 if (extra_gac_paths) {
2744 paths = extra_gac_paths;
2745 while (!res && *paths) {
2746 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2747 res = probe_for_partial_name (gacpath, fullname, aname, status);
2756 mono_assembly_name_free (aname);
2760 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2761 res = probe_for_partial_name (gacpath, fullname, aname, status);
2765 mono_assembly_name_free (aname);
2770 MonoDomain *domain = mono_domain_get ();
2772 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2773 if (!is_ok (&error)) {
2774 mono_error_cleanup (&error);
2775 if (*status == MONO_IMAGE_OK)
2776 *status = MONO_IMAGE_IMAGE_INVALID;
2784 mono_assembly_is_in_gac (const gchar *filename)
2786 const gchar *rootdir;
2790 if (filename == NULL)
2793 for (paths = extra_gac_paths; paths && *paths; paths++) {
2794 if (strstr (*paths, filename) != *paths)
2797 gp = (gchar *) (filename + strlen (*paths));
2798 if (*gp != G_DIR_SEPARATOR)
2801 if (strncmp (gp, "lib", 3))
2804 if (*gp != G_DIR_SEPARATOR)
2807 if (strncmp (gp, "mono", 4))
2810 if (*gp != G_DIR_SEPARATOR)
2813 if (strncmp (gp, "gac", 3))
2816 if (*gp != G_DIR_SEPARATOR)
2822 rootdir = mono_assembly_getrootdir ();
2823 if (strstr (filename, rootdir) != filename)
2826 gp = (gchar *) (filename + strlen (rootdir));
2827 if (*gp != G_DIR_SEPARATOR)
2830 if (strncmp (gp, "mono", 4))
2833 if (*gp != G_DIR_SEPARATOR)
2836 if (strncmp (gp, "gac", 3))
2839 if (*gp != G_DIR_SEPARATOR)
2845 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2848 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2852 if (strstr (aname->name, ".dll")) {
2853 len = strlen (aname->name) - 4;
2854 name = (gchar *)g_malloc (len + 1);
2855 memcpy (name, aname->name, len);
2858 name = g_strdup (aname->name);
2861 culture = g_utf8_strdown (aname->culture, -1);
2863 culture = g_strdup ("");
2865 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2866 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2870 filename = g_strconcat (pname, ".dll", NULL);
2871 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2877 if (extra_gac_paths) {
2878 paths = extra_gac_paths;
2879 while (!image && *paths) {
2880 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2881 "lib", "mono", "gac", subpath, NULL);
2882 image = mono_image_open (fullpath, NULL);
2893 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2894 "mono", "gac", subpath, NULL);
2895 image = mono_image_open (fullpath, NULL);
2902 static MonoAssemblyName*
2903 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2905 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2906 dest_name->major = info->new_version.major;
2907 dest_name->minor = info->new_version.minor;
2908 dest_name->build = info->new_version.build;
2909 dest_name->revision = info->new_version.revision;
2914 /* LOCKING: assembly_binding lock must be held */
2915 static MonoAssemblyBindingInfo*
2916 search_binding_loaded (MonoAssemblyName *aname)
2920 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2921 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2922 if (assembly_binding_maps_name (info, aname))
2929 static inline gboolean
2930 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2932 if (left->major != right->major || left->minor != right->minor ||
2933 left->build != right->build || left->revision != right->revision)
2939 static inline gboolean
2940 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2942 if (left->has_old_version_bottom != right->has_old_version_bottom)
2945 if (left->has_old_version_top != right->has_old_version_top)
2948 if (left->has_new_version != right->has_new_version)
2951 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2954 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2957 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2963 /* LOCKING: assumes all the necessary locks are held */
2965 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2967 MonoAssemblyBindingInfo *info_copy;
2969 MonoAssemblyBindingInfo *info_tmp;
2970 MonoDomain *domain = (MonoDomain*)user_data;
2975 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2976 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2977 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2981 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2982 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2984 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2986 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2988 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2992 get_version_number (int major, int minor)
2994 return major * 256 + minor;
2997 static inline gboolean
2998 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3000 int aname_version_number = get_version_number (aname->major, aname->minor);
3001 if (!info->has_old_version_bottom)
3004 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3007 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3010 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3011 info->major = aname->major;
3012 info->minor = aname->minor;
3017 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3018 static MonoAssemblyBindingInfo*
3019 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3021 MonoAssemblyBindingInfo *info;
3024 if (!domain->assembly_bindings)
3028 for (list = domain->assembly_bindings; list; list = list->next) {
3029 info = (MonoAssemblyBindingInfo *)list->data;
3030 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3036 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3037 info->has_new_version && assembly_binding_maps_name (info, aname))
3038 info->is_valid = TRUE;
3040 info->is_valid = FALSE;
3046 static MonoAssemblyName*
3047 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3050 MonoAssemblyBindingInfo *info, *info2;
3054 if (aname->public_key_token [0] == 0)
3057 domain = mono_domain_get ();
3059 mono_assembly_binding_lock ();
3060 info = search_binding_loaded (aname);
3061 mono_assembly_binding_unlock ();
3064 mono_domain_lock (domain);
3065 info = get_per_domain_assembly_binding_info (domain, aname);
3066 mono_domain_unlock (domain);
3070 if (!check_policy_versions (info, aname))
3073 mono_assembly_bind_version (info, aname, dest_name);
3077 if (domain && domain->setup && domain->setup->configuration_file) {
3078 mono_domain_lock (domain);
3079 if (!domain->assembly_bindings_parsed) {
3080 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3081 /* expect this to succeed because mono_domain_set_options_from_config () did
3082 * the same thing when the domain was created. */
3083 mono_error_assert_ok (&error);
3085 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3087 if (!domain_config_file_path)
3088 domain_config_file_path = domain_config_file_name;
3090 mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3091 domain->assembly_bindings_parsed = TRUE;
3092 if (domain_config_file_name != domain_config_file_path)
3093 g_free (domain_config_file_name);
3094 g_free (domain_config_file_path);
3097 info2 = get_per_domain_assembly_binding_info (domain, aname);
3100 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3101 info->name = g_strdup (info2->name);
3102 info->culture = g_strdup (info2->culture);
3103 info->domain_id = domain->domain_id;
3106 mono_domain_unlock (domain);
3110 info = g_new0 (MonoAssemblyBindingInfo, 1);
3111 info->major = aname->major;
3112 info->minor = aname->minor;
3115 if (!info->is_valid) {
3116 ppimage = mono_assembly_load_publisher_policy (aname);
3118 get_publisher_policy_info (ppimage, aname, info);
3119 mono_image_close (ppimage);
3123 /* Define default error value if needed */
3124 if (!info->is_valid) {
3125 info->name = g_strdup (aname->name);
3126 info->culture = g_strdup (aname->culture);
3127 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3130 mono_assembly_binding_lock ();
3131 info2 = search_binding_loaded (aname);
3133 /* This binding was added by another thread
3135 mono_assembly_binding_info_free (info);
3140 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3142 mono_assembly_binding_unlock ();
3144 if (!info->is_valid || !check_policy_versions (info, aname))
3147 mono_assembly_bind_version (info, aname, dest_name);
3152 * mono_assembly_load_from_gac
3154 * @aname: The assembly name object
3156 static MonoAssembly*
3157 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3159 MonoAssembly *result = NULL;
3160 gchar *name, *version, *culture, *fullpath, *subpath;
3165 if (aname->public_key_token [0] == 0) {
3169 if (strstr (aname->name, ".dll")) {
3170 len = strlen (filename) - 4;
3171 name = (gchar *)g_malloc (len + 1);
3172 memcpy (name, aname->name, len);
3175 name = g_strdup (aname->name);
3178 if (aname->culture) {
3179 culture = g_utf8_strdown (aname->culture, -1);
3181 culture = g_strdup ("");
3184 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3185 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3186 aname->minor, aname->build, aname->revision,
3190 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3195 if (extra_gac_paths) {
3196 paths = extra_gac_paths;
3197 while (!result && *paths) {
3198 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3199 result = mono_assembly_open_full (fullpath, status, refonly);
3206 result->in_gac = TRUE;
3211 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3212 "mono", "gac", subpath, NULL);
3213 result = mono_assembly_open_full (fullpath, status, refonly);
3217 result->in_gac = TRUE;
3225 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3228 MonoAssemblyName *aname;
3231 /* g_print ("corlib already loaded\n"); */
3235 // In native client, Corlib is embedded in the executable as static variable corlibData
3236 #if defined(__native_client__)
3237 if (corlibData != NULL && corlibSize != 0) {
3239 /* First "FALSE" instructs mono not to make a copy. */
3240 /* Second "FALSE" says this is not just a ref. */
3241 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3242 if (image == NULL || status != 0)
3243 g_print("mono_image_open_from_data_full failed: %d\n", status);
3244 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3245 if (corlib == NULL || status != 0)
3246 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3252 // A nonstandard preload hook may provide a special mscorlib assembly
3253 aname = mono_assembly_name_new ("mscorlib.dll");
3254 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3255 mono_assembly_name_free (aname);
3258 goto return_corlib_and_facades;
3260 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3261 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3262 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3264 goto return_corlib_and_facades;
3267 /* Normal case: Load corlib from mono/<version> */
3268 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3269 if (assemblies_path) { // Custom assemblies path
3270 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3272 g_free (corlib_file);
3273 goto return_corlib_and_facades;
3276 corlib = load_in_path (corlib_file, default_path, status, FALSE);
3277 g_free (corlib_file);
3279 return_corlib_and_facades:
3280 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3281 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3286 static MonoAssembly*
3287 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3289 MonoError refasm_error;
3290 error_init (&refasm_error);
3291 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3294 mono_error_cleanup (&refasm_error);
3300 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3301 const char *basedir,
3302 MonoImageOpenStatus *status,
3305 MonoAssembly *result;
3306 char *fullpath, *filename;
3307 MonoAssemblyName maped_aname;
3308 MonoAssemblyName maped_name_pp;
3313 aname = mono_assembly_remap_version (aname, &maped_aname);
3315 /* Reflection only assemblies don't get assembly binding */
3317 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3319 result = mono_assembly_loaded_full (aname, refonly);
3323 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3325 result->in_gac = FALSE;
3329 /* Currently we retrieve the loaded corlib for reflection
3330 * only requests, like a common reflection only assembly
3332 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3333 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3336 len = strlen (aname->name);
3337 for (ext_index = 0; ext_index < 2; ext_index ++) {
3338 ext = ext_index == 0 ? ".dll" : ".exe";
3339 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3340 filename = g_strdup (aname->name);
3341 /* Don't try appending .dll/.exe if it already has one of those extensions */
3344 filename = g_strconcat (aname->name, ext, NULL);
3347 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3354 fullpath = g_build_filename (basedir, filename, NULL);
3355 result = mono_assembly_open_full (fullpath, status, refonly);
3358 result->in_gac = FALSE;
3364 result = load_in_path (filename, default_path, status, refonly);
3366 result->in_gac = FALSE;
3376 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3378 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3381 /* Try a postload search hook */
3382 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3383 result = prevent_reference_assembly_from_running (result, refonly);
3389 * mono_assembly_load_full:
3390 * @aname: A MonoAssemblyName with the assembly name to load.
3391 * @basedir: A directory to look up the assembly at.
3392 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3393 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3395 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3396 * attempts to load the assembly from that directory before probing the standard locations.
3398 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
3399 * assembly binding takes place.
3401 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3402 * value pointed by status is updated with an error code.
3405 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3407 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3411 * mono_assembly_load:
3412 * @aname: A MonoAssemblyName with the assembly name to load.
3413 * @basedir: A directory to look up the assembly at.
3414 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3416 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3417 * attempts to load the assembly from that directory before probing the standard locations.
3419 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
3420 * value pointed by status is updated with an error code.
3423 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3425 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3429 * mono_assembly_loaded_full:
3430 * @aname: an assembly to look for.
3431 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3433 * This is used to determine if the specified assembly has been loaded
3434 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3435 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3438 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3441 MonoAssemblyName maped_aname;
3443 aname = mono_assembly_remap_version (aname, &maped_aname);
3445 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3451 * mono_assembly_loaded:
3452 * @aname: an assembly to look for.
3454 * This is used to determine if the specified assembly has been loaded
3456 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3457 * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3460 mono_assembly_loaded (MonoAssemblyName *aname)
3462 return mono_assembly_loaded_full (aname, FALSE);
3466 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3468 if (assembly == NULL || assembly == REFERENCE_MISSING)
3471 if (assembly_is_dynamic (assembly)) {
3473 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3474 for (i = 0; i < dynimg->image.module_count; ++i)
3475 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3476 mono_dynamic_image_release_gc_roots (dynimg);
3481 * Returns whether mono_assembly_close_finish() must be called as
3482 * well. See comment for mono_image_close_except_pools() for why we
3483 * unload in two steps.
3486 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3489 g_return_val_if_fail (assembly != NULL, FALSE);
3491 if (assembly == REFERENCE_MISSING)
3494 /* Might be 0 already */
3495 if (InterlockedDecrement (&assembly->ref_count) > 0)
3498 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3500 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3502 mono_debug_close_image (assembly->image);
3504 mono_assemblies_lock ();
3505 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3506 mono_assemblies_unlock ();
3508 assembly->image->assembly = NULL;
3510 if (!mono_image_close_except_pools (assembly->image))
3511 assembly->image = NULL;
3513 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3514 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3515 mono_assembly_name_free (fname);
3518 g_slist_free (assembly->friend_assembly_names);
3519 g_free (assembly->basedir);
3521 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3527 mono_assembly_close_finish (MonoAssembly *assembly)
3529 g_assert (assembly && assembly != REFERENCE_MISSING);
3531 if (assembly->image)
3532 mono_image_close_finish (assembly->image);
3534 if (assembly_is_dynamic (assembly)) {
3535 g_free ((char*)assembly->aname.culture);
3542 * mono_assembly_close:
3543 * @assembly: the assembly to release.
3545 * This method releases a reference to the @assembly. The assembly is
3546 * only released when all the outstanding references to it are released.
3549 mono_assembly_close (MonoAssembly *assembly)
3551 if (mono_assembly_close_except_image_pools (assembly))
3552 mono_assembly_close_finish (assembly);
3556 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3559 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3560 mono_error_assert_ok (&error);
3565 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3567 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3572 * mono_assembly_foreach:
3573 * @func: function to invoke for each assembly loaded
3574 * @user_data: data passed to the callback
3576 * Invokes the provided @func callback for each assembly loaded into
3577 * the runtime. The first parameter passed to the callback is the
3578 * `MonoAssembly*`, and the second parameter is the @user_data.
3580 * This is done for all assemblies loaded in the runtime, not just
3581 * those loaded in the current application domain.
3584 mono_assembly_foreach (GFunc func, gpointer user_data)
3589 * We make a copy of the list to avoid calling the callback inside the
3590 * lock, which could lead to deadlocks.
3592 mono_assemblies_lock ();
3593 copy = g_list_copy (loaded_assemblies);
3594 mono_assemblies_unlock ();
3596 g_list_foreach (loaded_assemblies, func, user_data);
3602 * mono_assemblies_cleanup:
3604 * Free all resources used by this module.
3607 mono_assemblies_cleanup (void)
3611 mono_os_mutex_destroy (&assemblies_mutex);
3612 mono_os_mutex_destroy (&assembly_binding_mutex);
3614 for (l = loaded_assembly_bindings; l; l = l->next) {
3615 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3617 mono_assembly_binding_info_free (info);
3620 g_slist_free (loaded_assembly_bindings);
3622 free_assembly_load_hooks ();
3623 free_assembly_search_hooks ();
3624 free_assembly_preload_hooks ();
3627 /*LOCKING takes the assembly_binding lock*/
3629 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3633 mono_assembly_binding_lock ();
3634 iter = &loaded_assembly_bindings;
3637 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3639 if (info->domain_id == domain_id) {
3641 mono_assembly_binding_info_free (info);
3648 mono_assembly_binding_unlock ();
3652 * Holds the assembly of the application, for
3653 * System.Diagnostics.Process::MainModule
3655 static MonoAssembly *main_assembly=NULL;
3658 mono_assembly_set_main (MonoAssembly *assembly)
3660 main_assembly = assembly;
3664 * mono_assembly_get_main:
3666 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3669 mono_assembly_get_main (void)
3671 return (main_assembly);
3675 * mono_assembly_get_image:
3676 * @assembly: The assembly to retrieve the image from
3678 * Returns: the MonoImage associated with this assembly.
3681 mono_assembly_get_image (MonoAssembly *assembly)
3683 return assembly->image;
3687 * mono_assembly_get_name:
3688 * @assembly: The assembly to retrieve the name from
3690 * The returned name's lifetime is the same as @assembly's.
3692 * Returns: the MonoAssemblyName associated with this assembly.
3695 mono_assembly_get_name (MonoAssembly *assembly)
3697 return &assembly->aname;
3701 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3703 bundles = assemblies;
3706 #define MONO_DECLSEC_FORMAT_10 0x3C
3707 #define MONO_DECLSEC_FORMAT_20 0x2E
3708 #define MONO_DECLSEC_FIELD 0x53
3709 #define MONO_DECLSEC_PROPERTY 0x54
3711 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3712 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3713 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3714 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3715 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3718 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3722 case MONO_DECLSEC_PROPERTY:
3724 case MONO_DECLSEC_FIELD:
3726 *abort_decoding = TRUE;
3731 if (*p++ != MONO_TYPE_BOOLEAN) {
3732 *abort_decoding = TRUE;
3736 /* property name length */
3737 len = mono_metadata_decode_value (p, &p);
3739 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3750 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3752 int i, j, num, len, params_len;
3754 if (*p == MONO_DECLSEC_FORMAT_10) {
3755 gsize read, written;
3756 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3758 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3764 if (*p++ != MONO_DECLSEC_FORMAT_20)
3767 /* number of encoded permission attributes */
3768 num = mono_metadata_decode_value (p, &p);
3769 for (i = 0; i < num; ++i) {
3770 gboolean is_valid = FALSE;
3771 gboolean abort_decoding = FALSE;
3773 /* attribute name length */
3774 len = mono_metadata_decode_value (p, &p);
3776 /* We don't really need to fully decode the type. Comparing the name is enough */
3777 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3781 /*size of the params table*/
3782 params_len = mono_metadata_decode_value (p, &p);
3784 const char *params_end = p + params_len;
3786 /* number of parameters */
3787 len = mono_metadata_decode_value (p, &p);
3789 for (j = 0; j < len; ++j) {
3790 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3806 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3809 guint32 cols [MONO_DECL_SECURITY_SIZE];
3813 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3814 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3816 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3818 for (i = 0; i < t->rows; ++i) {
3819 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3820 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3822 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3825 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3826 len = mono_metadata_decode_blob_size (blob, &blob);
3830 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3831 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3836 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);