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)
18 #include "object-internals.h"
19 #include <mono/metadata/loader.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/metadata-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/domain-internals.h>
25 #include <mono/metadata/mono-endian.h>
26 #include <mono/metadata/mono-debug.h>
27 #include <mono/io-layer/io-layer.h>
28 #include <mono/utils/mono-uri.h>
29 #include <mono/metadata/mono-config.h>
30 #include <mono/utils/mono-digest.h>
31 #include <mono/utils/mono-logger.h>
32 #include <mono/metadata/reflection.h>
33 #include <mono/metadata/coree.h>
35 #ifndef PLATFORM_WIN32
36 #include <sys/types.h>
41 /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
43 const char* assembly_name
;
44 guint8 version_set_index
;
47 /* the default search path is empty, the first slot is replaced with the computed value */
54 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
55 static char **assemblies_path
= NULL
;
57 /* Contains the list of directories that point to auxiliary GACs */
58 static char **extra_gac_paths
= NULL
;
60 /* The list of system assemblies what will be remapped to the running
61 * runtime version. WARNING: this list must be sorted.
63 static const AssemblyVersionMap framework_assemblies
[] = {
65 {"Commons.Xml.Relaxng", 0},
72 {"Microsoft.VisualBasic", 1},
73 {"Microsoft.VisualC", 1},
75 {"Mono.CompilerServices.SymbolWriter", 0},
77 {"Mono.Data.SybaseClient", 0},
79 {"Mono.Data.TdsClient", 0},
80 {"Mono.GetOptions", 0},
84 {"Mono.Security.Win32", 0},
86 {"Novell.Directory.Ldap", 0},
90 {"System.Configuration.Install", 0},
92 {"System.Data.OracleClient", 0},
93 {"System.Data.SqlXml", 0},
95 {"System.DirectoryServices", 0},
96 {"System.Drawing", 0},
97 {"System.Drawing.Design", 0},
98 {"System.EnterpriseServices", 0},
99 {"System.Management", 0},
100 {"System.Messaging", 0},
101 {"System.Runtime.Remoting", 0},
102 {"System.Runtime.Serialization.Formatters.Soap", 0},
103 {"System.Security", 0},
104 {"System.ServiceProcess", 0},
106 {"System.Web.Mobile", 0},
107 {"System.Web.Services", 0},
108 {"System.Windows.Forms", 0},
114 * keeps track of loaded assemblies
116 static GList
*loaded_assemblies
= NULL
;
117 static MonoAssembly
*corlib
;
119 /* This protects loaded_assemblies and image->references */
120 #define mono_assemblies_lock() EnterCriticalSection (&assemblies_mutex)
121 #define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex)
122 static CRITICAL_SECTION assemblies_mutex
;
124 /* If defined, points to the bundled assembly information */
125 const MonoBundledAssembly
**bundles
;
127 /* Loaded assembly binding info */
128 static GSList
*loaded_assembly_bindings
= NULL
;
131 mono_assembly_invoke_search_hook_internal (MonoAssemblyName
*aname
, gboolean refonly
, gboolean postload
);
133 mono_assembly_is_in_gac (const gchar
*filanem
);
136 encode_public_tok (const guchar
*token
, gint32 len
)
138 const static gchar allowed
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
142 res
= g_malloc (len
* 2 + 1);
143 for (i
= 0; i
< len
; i
++) {
144 res
[i
* 2] = allowed
[token
[i
] >> 4];
145 res
[i
* 2 + 1] = allowed
[token
[i
] & 0xF];
152 * mono_public_tokens_are_equal:
153 * @pubt1: first public key token
154 * @pubt2: second public key token
156 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
160 mono_public_tokens_are_equal (const unsigned char *pubt1
, const unsigned char *pubt2
)
162 return memcmp (pubt1
, pubt2
, 16) == 0;
166 check_path_env (void)
169 char **splitted
, **dest
;
171 path
= g_getenv ("MONO_PATH");
175 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
177 g_strfreev (assemblies_path
);
178 assemblies_path
= dest
= splitted
;
186 if (g_getenv ("MONO_DEBUG") == NULL
)
190 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
191 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted
);
198 check_extra_gac_path_env (void) {
200 char **splitted
, **dest
;
202 path
= g_getenv ("MONO_GAC_PREFIX");
206 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
208 g_strfreev (extra_gac_paths
);
209 extra_gac_paths
= dest
= splitted
;
217 if (g_getenv ("MONO_DEBUG") == NULL
)
221 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
222 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted
);
229 assembly_binding_maps_name (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
231 if (strcmp (info
->name
, aname
->name
))
234 if (info
->major
!= aname
->major
|| info
->minor
!= aname
->minor
)
237 if ((info
->culture
!= NULL
) != (aname
->culture
!= NULL
))
240 if (info
->culture
&& strcmp (info
->culture
, aname
->culture
))
243 if (!mono_public_tokens_are_equal (info
->public_key_token
, aname
->public_key_token
))
250 mono_assembly_binding_info_free (MonoAssemblyBindingInfo
*info
)
253 g_free (info
->culture
);
257 get_publisher_policy_info (MonoImage
*image
, MonoAssemblyName
*aname
, MonoAssemblyBindingInfo
*binding_info
)
260 guint32 cols
[MONO_MANIFEST_SIZE
];
261 const gchar
*filename
;
262 gchar
*subpath
, *fullpath
;
264 t
= &image
->tables
[MONO_TABLE_MANIFESTRESOURCE
];
265 /* MS Impl. accepts policy assemblies with more than
266 * one manifest resource, and only takes the first one */
268 binding_info
->is_valid
= FALSE
;
272 mono_metadata_decode_row (t
, 0, cols
, MONO_MANIFEST_SIZE
);
273 if ((cols
[MONO_MANIFEST_IMPLEMENTATION
] & MONO_IMPLEMENTATION_MASK
) != MONO_IMPLEMENTATION_FILE
) {
274 binding_info
->is_valid
= FALSE
;
278 filename
= mono_metadata_string_heap (image
, cols
[MONO_MANIFEST_NAME
]);
279 g_assert (filename
!= NULL
);
281 subpath
= g_path_get_dirname (image
->name
);
282 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, subpath
, filename
, NULL
);
283 mono_config_parse_publisher_policy (fullpath
, binding_info
);
287 /* Define the optional elements/attributes before checking */
288 if (!binding_info
->culture
)
289 binding_info
->culture
= g_strdup ("");
291 /* Check that the most important elements/attributes exist */
292 if (!binding_info
->name
|| !binding_info
->public_key_token
[0] || !binding_info
->has_old_version_bottom
||
293 !binding_info
->has_new_version
|| !assembly_binding_maps_name (binding_info
, aname
)) {
294 mono_assembly_binding_info_free (binding_info
);
295 binding_info
->is_valid
= FALSE
;
299 binding_info
->is_valid
= TRUE
;
303 compare_versions (AssemblyVersionSet
*v
, MonoAssemblyName
*aname
)
305 if (v
->major
> aname
->major
)
307 else if (v
->major
< aname
->major
)
310 if (v
->minor
> aname
->minor
)
312 else if (v
->minor
< aname
->minor
)
315 if (v
->build
> aname
->build
)
317 else if (v
->build
< aname
->build
)
320 if (v
->revision
> aname
->revision
)
322 else if (v
->revision
< aname
->revision
)
329 check_policy_versions (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*name
)
334 /* If has_old_version_top doesn't exist, we don't have an interval */
335 if (!info
->has_old_version_top
) {
336 if (compare_versions (&info
->old_version_bottom
, name
) == 0)
342 /* Check that the version defined by name is valid for the interval */
343 if (compare_versions (&info
->old_version_top
, name
) < 0)
346 /* We should be greater or equal than the small version */
347 if (compare_versions (&info
->old_version_bottom
, name
) > 0)
354 * mono_assembly_names_equal:
356 * @r: second assembly.
358 * Compares two MonoAssemblyNames and returns whether they are equal.
360 * This compares the names, the cultures, the release version and their
363 * Returns: TRUE if both assembly names are equal.
366 mono_assembly_names_equal (MonoAssemblyName
*l
, MonoAssemblyName
*r
)
368 if (!l
->name
|| !r
->name
)
371 if (strcmp (l
->name
, r
->name
))
374 if (l
->culture
&& r
->culture
&& strcmp (l
->culture
, r
->culture
))
377 if (l
->major
!= r
->major
|| l
->minor
!= r
->minor
||
378 l
->build
!= r
->build
|| l
->revision
!= r
->revision
)
379 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)))
382 if (!l
->public_key_token
[0] || !r
->public_key_token
[0])
385 if (!mono_public_tokens_are_equal (l
->public_key_token
, r
->public_key_token
))
391 static MonoAssembly
*
392 load_in_path (const char *basename
, const char** search_path
, MonoImageOpenStatus
*status
, MonoBoolean refonly
)
396 MonoAssembly
*result
;
398 for (i
= 0; search_path
[i
]; ++i
) {
399 fullpath
= g_build_filename (search_path
[i
], basename
, NULL
);
400 result
= mono_assembly_open_full (fullpath
, status
, refonly
);
409 * mono_assembly_setrootdir:
410 * @root_dir: The pathname of the root directory where we will locate assemblies
412 * This routine sets the internal default root directory for looking up
415 * This is used by Windows installations to compute dynamically the
416 * place where the Mono assemblies are located.
420 mono_assembly_setrootdir (const char *root_dir
)
423 * Override the MONO_ASSEMBLIES directory configured at compile time.
425 /* Leak if called more than once */
426 default_path
[0] = g_strdup (root_dir
);
430 * mono_assembly_getrootdir:
432 * Obtains the root directory used for looking up assemblies.
434 * Returns: a string with the directory, this string should not be freed.
436 G_CONST_RETURN gchar
*
437 mono_assembly_getrootdir (void)
439 return default_path
[0];
444 * @assembly_dir: the base directory for assemblies
445 * @config_dir: the base directory for configuration files
447 * This routine is used internally and by developers embedding
448 * the runtime into their own applications.
450 * There are a number of cases to consider: Mono as a system-installed
451 * package that is available on the location preconfigured or Mono in
452 * a relocated location.
454 * If you are using a system-installed Mono, you can pass NULL
455 * to both parameters. If you are not, you should compute both
456 * directory values and call this routine.
458 * The values for a given PREFIX are:
460 * assembly_dir: PREFIX/lib
461 * config_dir: PREFIX/etc
463 * Notice that embedders that use Mono in a relocated way must
464 * compute the location at runtime, as they will be in control
465 * of where Mono is installed.
468 mono_set_dirs (const char *assembly_dir
, const char *config_dir
)
470 #if defined (MONO_ASSEMBLIES)
471 if (assembly_dir
== NULL
)
472 assembly_dir
= MONO_ASSEMBLIES
;
474 #if defined (MONO_CFG_DIR)
475 if (config_dir
== NULL
)
476 config_dir
= MONO_CFG_DIR
;
478 mono_assembly_setrootdir (assembly_dir
);
479 mono_set_config_dir (config_dir
);
482 #ifndef PLATFORM_WIN32
485 compute_base (char *path
)
487 char *p
= strrchr (path
, '/');
491 /* Not a well known Mono executable, we are embedded, cant guess the base */
492 if (strcmp (p
, "/mono") && strcmp (p
, "/monodis") && strcmp (p
, "/mint") && strcmp (p
, "/monodiet"))
496 p
= strrchr (path
, '/');
500 if (strcmp (p
, "/bin") != 0)
509 mono_set_dirs (MONO_ASSEMBLIES
, MONO_CFG_DIR
);
516 char *config
, *lib
, *mono
;
520 * Only /usr prefix is treated specially
522 if (strncmp (exe
, MONO_BINDIR
, strlen (MONO_BINDIR
)) == 0 || (base
= compute_base (exe
)) == NULL
){
527 config
= g_build_filename (base
, "etc", NULL
);
528 lib
= g_build_filename (base
, "lib", NULL
);
529 mono
= g_build_filename (lib
, "mono/1.0", NULL
);
530 if (stat (mono
, &buf
) == -1)
533 mono_set_dirs (lib
, config
);
541 #endif /* PLATFORM_WIN32 */
546 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
547 * this auto-detects the prefix where Mono was installed.
550 mono_set_rootdir (void)
552 #ifdef PLATFORM_WIN32
553 gchar
*bindir
, *installdir
, *root
, *name
, *config
;
555 name
= mono_get_module_file_name ((HMODULE
) &__ImageBase
);
556 bindir
= g_path_get_dirname (name
);
557 installdir
= g_path_get_dirname (bindir
);
558 root
= g_build_path (G_DIR_SEPARATOR_S
, installdir
, "lib", NULL
);
560 config
= g_build_filename (root
, "..", "etc", NULL
);
561 mono_set_dirs (root
, config
);
568 #elif defined(DISABLE_MONO_AUTODETECTION)
576 s
= readlink ("/proc/self/exe", buf
, sizeof (buf
)-1);
584 /* Solaris 10 style */
585 str
= g_strdup_printf ("/proc/%d/path/a.out", getpid ());
586 s
= readlink (str
, buf
, sizeof (buf
)-1);
598 * mono_assemblies_init:
600 * Initialize global variables used by this module.
603 mono_assemblies_init (void)
606 * Initialize our internal paths if we have not been initialized yet.
607 * This happens when embedders use Mono.
609 if (mono_assembly_getrootdir () == NULL
)
613 check_extra_gac_path_env ();
615 InitializeCriticalSection (&assemblies_mutex
);
619 mono_assembly_fill_assembly_name (MonoImage
*image
, MonoAssemblyName
*aname
)
621 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLY
];
622 guint32 cols
[MONO_ASSEMBLY_SIZE
];
627 mono_metadata_decode_row (t
, 0, cols
, MONO_ASSEMBLY_SIZE
);
630 aname
->hash_value
= NULL
;
631 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_NAME
]);
632 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_CULTURE
]);
633 aname
->flags
= cols
[MONO_ASSEMBLY_FLAGS
];
634 aname
->major
= cols
[MONO_ASSEMBLY_MAJOR_VERSION
];
635 aname
->minor
= cols
[MONO_ASSEMBLY_MINOR_VERSION
];
636 aname
->build
= cols
[MONO_ASSEMBLY_BUILD_NUMBER
];
637 aname
->revision
= cols
[MONO_ASSEMBLY_REV_NUMBER
];
638 aname
->hash_alg
= cols
[MONO_ASSEMBLY_HASH_ALG
];
639 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
640 guchar
* token
= g_malloc (8);
645 pkey
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
646 len
= mono_metadata_decode_blob_size (pkey
, &pkey
);
647 aname
->public_key
= (guchar
*)pkey
;
649 mono_digest_get_public_token (token
, aname
->public_key
, len
);
650 encoded
= encode_public_tok (token
, 8);
651 g_strlcpy ((char*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
657 aname
->public_key
= NULL
;
658 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
661 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
662 aname
->public_key
= (guchar
*)mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
665 aname
->public_key
= 0;
671 * mono_stringify_assembly_name:
672 * @aname: the assembly name.
674 * Convert @aname into its string format. The returned string is dynamically
675 * allocated and should be freed by the caller.
677 * Returns: a newly allocated string with a string representation of
681 mono_stringify_assembly_name (MonoAssemblyName
*aname
)
683 return g_strdup_printf (
684 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
686 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
687 aname
->culture
&& *aname
->culture
? aname
->culture
: "neutral",
688 aname
->public_key_token
[0] ? (char *)aname
->public_key_token
: "null",
689 (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
693 assemblyref_public_tok (MonoImage
*image
, guint32 key_index
, guint32 flags
)
695 const gchar
*public_tok
;
698 public_tok
= mono_metadata_blob_heap (image
, key_index
);
699 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
701 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
703 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
704 return encode_public_tok (token
, 8);
707 return encode_public_tok ((guchar
*)public_tok
, len
);
711 * mono_assembly_addref:
712 * @assemnly: the assembly to reference
714 * This routine increments the reference count on a MonoAssembly.
715 * The reference count is reduced every time the method mono_assembly_close() is
719 mono_assembly_addref (MonoAssembly
*assembly
)
721 InterlockedIncrement (&assembly
->ref_count
);
724 static MonoAssemblyName
*
725 mono_assembly_remap_version (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_aname
)
727 const MonoRuntimeInfo
*current_runtime
;
728 int pos
, first
, last
;
730 if (aname
->name
== NULL
) return aname
;
731 current_runtime
= mono_get_runtime_info ();
734 last
= G_N_ELEMENTS (framework_assemblies
) - 1;
736 while (first
<= last
) {
738 pos
= first
+ (last
- first
) / 2;
739 res
= strcmp (aname
->name
, framework_assemblies
[pos
].assembly_name
);
741 const AssemblyVersionSet
* vset
;
742 int index
= framework_assemblies
[pos
].version_set_index
;
743 g_assert (index
< G_N_ELEMENTS (current_runtime
->version_sets
));
744 vset
= ¤t_runtime
->version_sets
[index
];
746 if (aname
->major
== vset
->major
&& aname
->minor
== vset
->minor
&&
747 aname
->build
== vset
->build
&& aname
->revision
== vset
->revision
)
750 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0)
751 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
752 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
754 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
755 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
758 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
759 dest_aname
->major
= vset
->major
;
760 dest_aname
->minor
= vset
->minor
;
761 dest_aname
->build
= vset
->build
;
762 dest_aname
->revision
= vset
->revision
;
764 } else if (res
< 0) {
774 * mono_assembly_get_assemblyref:
776 * Fill out ANAME with the assembly name of the INDEXth assembly reference in IMAGE.
779 mono_assembly_get_assemblyref (MonoImage
*image
, int index
, MonoAssemblyName
*aname
)
782 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
785 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
787 mono_metadata_decode_row (t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
);
789 hash
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
]);
790 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
791 aname
->hash_value
= hash
;
792 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_NAME
]);
793 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_CULTURE
]);
794 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
795 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
796 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
797 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
798 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
800 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
801 gchar
*token
= assemblyref_public_tok (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
);
802 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
805 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
810 mono_assembly_load_reference (MonoImage
*image
, int index
)
812 MonoAssembly
*reference
;
813 MonoAssemblyName aname
;
814 MonoImageOpenStatus status
;
817 * image->references is shared between threads, so we need to access
818 * it inside a critical section.
820 mono_assemblies_lock ();
821 if (!image
->references
) {
822 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
824 image
->references
= g_new0 (MonoAssembly
*, t
->rows
+ 1);
826 reference
= image
->references
[index
];
827 mono_assemblies_unlock ();
831 mono_assembly_get_assemblyref (image
, index
, &aname
);
833 if (image
->assembly
&& image
->assembly
->ref_only
) {
834 /* We use the loaded corlib */
835 if (!strcmp (aname
.name
, "mscorlib"))
836 reference
= mono_assembly_load_full (&aname
, image
->assembly
->basedir
, &status
, FALSE
);
838 reference
= mono_assembly_loaded_full (&aname
, TRUE
);
840 /* Try a postload search hook */
841 reference
= mono_assembly_invoke_search_hook_internal (&aname
, TRUE
, TRUE
);
845 * Here we must advice that the error was due to
846 * a non loaded reference using the ReflectionOnly api
849 reference
= REFERENCE_MISSING
;
851 reference
= mono_assembly_load (&aname
, image
->assembly
? image
->assembly
->basedir
: NULL
, &status
);
853 if (reference
== NULL
){
854 char *extra_msg
= g_strdup ("");
856 if (status
== MONO_IMAGE_ERROR_ERRNO
&& errno
== ENOENT
) {
857 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
: "" );
858 } else if (status
== MONO_IMAGE_ERROR_ERRNO
) {
859 extra_msg
= g_strdup_printf ("System error: %s\n", strerror (errno
));
860 } else if (status
== MONO_IMAGE_MISSING_ASSEMBLYREF
) {
861 extra_msg
= g_strdup ("Cannot find an assembly referenced from this one.\n");
862 } else if (status
== MONO_IMAGE_IMAGE_INVALID
) {
863 extra_msg
= g_strdup ("The file exists but is not a valid assembly.\n");
866 g_warning ("The following assembly referenced from %s could not be loaded:\n"
867 " Assembly: %s (assemblyref_index=%d)\n"
868 " Version: %d.%d.%d.%d\n"
869 " Public Key: %s\n%s",
870 image
->name
, aname
.name
, index
,
871 aname
.major
, aname
.minor
, aname
.build
, aname
.revision
,
872 strlen ((char*)aname
.public_key_token
) == 0 ? "(none)" : (char*)aname
.public_key_token
, extra_msg
);
876 mono_assemblies_lock ();
877 if (reference
== NULL
) {
878 /* Flag as not found */
879 reference
= REFERENCE_MISSING
;
882 if (!image
->references
[index
]) {
883 if (reference
!= REFERENCE_MISSING
){
884 mono_assembly_addref (reference
);
886 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly Ref addref %s %p -> %s %p: %d\n",
887 image
->assembly
->aname
.name
, image
->assembly
, reference
->aname
.name
, reference
, reference
->ref_count
);
890 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Failed to load assembly %s %p\n",
891 image
->assembly
->aname
.name
, image
->assembly
);
894 image
->references
[index
] = reference
;
896 mono_assemblies_unlock ();
898 if (image
->references
[index
] != reference
) {
899 /* Somebody loaded it before us */
900 mono_assembly_close (reference
);
905 mono_assembly_load_references (MonoImage
*image
, MonoImageOpenStatus
*status
)
907 /* This is a no-op now but it is part of the embedding API so we can't remove it */
908 *status
= MONO_IMAGE_OK
;
911 typedef struct AssemblyLoadHook AssemblyLoadHook
;
912 struct AssemblyLoadHook
{
913 AssemblyLoadHook
*next
;
914 MonoAssemblyLoadFunc func
;
918 AssemblyLoadHook
*assembly_load_hook
= NULL
;
921 mono_assembly_invoke_load_hook (MonoAssembly
*ass
)
923 AssemblyLoadHook
*hook
;
925 for (hook
= assembly_load_hook
; hook
; hook
= hook
->next
) {
926 hook
->func (ass
, hook
->user_data
);
931 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func
, gpointer user_data
)
933 AssemblyLoadHook
*hook
;
935 g_return_if_fail (func
!= NULL
);
937 hook
= g_new0 (AssemblyLoadHook
, 1);
939 hook
->user_data
= user_data
;
940 hook
->next
= assembly_load_hook
;
941 assembly_load_hook
= hook
;
945 free_assembly_load_hooks (void)
947 AssemblyLoadHook
*hook
, *next
;
949 for (hook
= assembly_load_hook
; hook
; hook
= next
) {
955 typedef struct AssemblySearchHook AssemblySearchHook
;
956 struct AssemblySearchHook
{
957 AssemblySearchHook
*next
;
958 MonoAssemblySearchFunc func
;
964 AssemblySearchHook
*assembly_search_hook
= NULL
;
967 mono_assembly_invoke_search_hook_internal (MonoAssemblyName
*aname
, gboolean refonly
, gboolean postload
)
969 AssemblySearchHook
*hook
;
971 for (hook
= assembly_search_hook
; hook
; hook
= hook
->next
) {
972 if ((hook
->refonly
== refonly
) && (hook
->postload
== postload
)) {
973 MonoAssembly
*ass
= hook
->func (aname
, hook
->user_data
);
983 mono_assembly_invoke_search_hook (MonoAssemblyName
*aname
)
985 return mono_assembly_invoke_search_hook_internal (aname
, FALSE
, FALSE
);
989 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func
, gpointer user_data
, gboolean refonly
, gboolean postload
)
991 AssemblySearchHook
*hook
;
993 g_return_if_fail (func
!= NULL
);
995 hook
= g_new0 (AssemblySearchHook
, 1);
997 hook
->user_data
= user_data
;
998 hook
->refonly
= refonly
;
999 hook
->postload
= postload
;
1000 hook
->next
= assembly_search_hook
;
1001 assembly_search_hook
= hook
;
1005 mono_install_assembly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1007 mono_install_assembly_search_hook_internal (func
, user_data
, FALSE
, FALSE
);
1011 free_assembly_search_hooks (void)
1013 AssemblySearchHook
*hook
, *next
;
1015 for (hook
= assembly_search_hook
; hook
; hook
= next
) {
1022 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1024 mono_install_assembly_search_hook_internal (func
, user_data
, TRUE
, FALSE
);
1028 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1030 mono_install_assembly_search_hook_internal (func
, user_data
, FALSE
, TRUE
);
1034 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1036 mono_install_assembly_search_hook_internal (func
, user_data
, TRUE
, TRUE
);
1039 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook
;
1040 struct AssemblyPreLoadHook
{
1041 AssemblyPreLoadHook
*next
;
1042 MonoAssemblyPreLoadFunc func
;
1046 static AssemblyPreLoadHook
*assembly_preload_hook
= NULL
;
1047 static AssemblyPreLoadHook
*assembly_refonly_preload_hook
= NULL
;
1049 static MonoAssembly
*
1050 invoke_assembly_preload_hook (MonoAssemblyName
*aname
, gchar
**assemblies_path
)
1052 AssemblyPreLoadHook
*hook
;
1053 MonoAssembly
*assembly
;
1055 for (hook
= assembly_preload_hook
; hook
; hook
= hook
->next
) {
1056 assembly
= hook
->func (aname
, assemblies_path
, hook
->user_data
);
1057 if (assembly
!= NULL
)
1064 static MonoAssembly
*
1065 invoke_assembly_refonly_preload_hook (MonoAssemblyName
*aname
, gchar
**assemblies_path
)
1067 AssemblyPreLoadHook
*hook
;
1068 MonoAssembly
*assembly
;
1070 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= hook
->next
) {
1071 assembly
= hook
->func (aname
, assemblies_path
, hook
->user_data
);
1072 if (assembly
!= NULL
)
1080 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
1082 AssemblyPreLoadHook
*hook
;
1084 g_return_if_fail (func
!= NULL
);
1086 hook
= g_new0 (AssemblyPreLoadHook
, 1);
1088 hook
->user_data
= user_data
;
1089 hook
->next
= assembly_preload_hook
;
1090 assembly_preload_hook
= hook
;
1094 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
1096 AssemblyPreLoadHook
*hook
;
1098 g_return_if_fail (func
!= NULL
);
1100 hook
= g_new0 (AssemblyPreLoadHook
, 1);
1102 hook
->user_data
= user_data
;
1103 hook
->next
= assembly_refonly_preload_hook
;
1104 assembly_refonly_preload_hook
= hook
;
1108 free_assembly_preload_hooks (void)
1110 AssemblyPreLoadHook
*hook
, *next
;
1112 for (hook
= assembly_preload_hook
; hook
; hook
= next
) {
1117 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= next
) {
1124 absolute_dir (const gchar
*filename
)
1135 if (g_path_is_absolute (filename
)) {
1136 part
= g_path_get_dirname (filename
);
1137 res
= g_strconcat (part
, G_DIR_SEPARATOR_S
, NULL
);
1142 cwd
= g_get_current_dir ();
1143 mixed
= g_build_filename (cwd
, filename
, NULL
);
1144 parts
= g_strsplit (mixed
, G_DIR_SEPARATOR_S
, 0);
1149 for (i
= 0; (part
= parts
[i
]) != NULL
; i
++) {
1150 if (!strcmp (part
, "."))
1153 if (!strcmp (part
, "..")) {
1154 if (list
&& list
->next
) /* Don't remove root */
1155 list
= g_list_delete_link (list
, list
);
1157 list
= g_list_prepend (list
, part
);
1161 result
= g_string_new ("");
1162 list
= g_list_reverse (list
);
1164 /* Ignores last data pointer, which should be the filename */
1165 for (tmp
= list
; tmp
&& tmp
->next
!= NULL
; tmp
= tmp
->next
){
1167 g_string_append_printf (result
, "%s%c", (char *) tmp
->data
,
1172 g_string_free (result
, FALSE
);
1177 return g_strdup (".");
1184 * mono_assembly_open_from_bundle:
1185 * @filename: Filename requested
1186 * @status: return value
1188 * This routine tries to open the assembly specified by `filename' from the
1189 * defined bundles, if found, returns the MonoImage for it, if not found
1193 mono_assembly_open_from_bundle (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
1197 MonoImage
*image
= NULL
;
1200 * we do a very simple search for bundled assemblies: it's not a general
1201 * purpose assembly loading mechanism.
1207 name
= g_path_get_basename (filename
);
1209 mono_assemblies_lock ();
1210 for (i
= 0; !image
&& bundles
[i
]; ++i
) {
1211 if (strcmp (bundles
[i
]->name
, name
) == 0) {
1212 image
= mono_image_open_from_data_full ((char*)bundles
[i
]->data
, bundles
[i
]->size
, FALSE
, status
, refonly
);
1216 mono_assemblies_unlock ();
1219 mono_image_addref (image
);
1226 mono_assembly_open_full (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
1230 MonoImageOpenStatus def_status
;
1234 g_return_val_if_fail (filename
!= NULL
, NULL
);
1237 status
= &def_status
;
1238 *status
= MONO_IMAGE_OK
;
1240 if (strncmp (filename
, "file://", 7) == 0) {
1241 GError
*error
= NULL
;
1242 gchar
*uri
= (gchar
*) filename
;
1246 * MS allows file://c:/... and fails on file://localhost/c:/...
1247 * They also throw an IndexOutOfRangeException if "file://"
1250 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
1253 uri
= mono_escape_uri_string (tmpuri
);
1254 fname
= g_filename_from_uri (uri
, NULL
, &error
);
1257 if (tmpuri
!= filename
)
1260 if (error
!= NULL
) {
1261 g_warning ("%s\n", error
->message
);
1262 g_error_free (error
);
1263 fname
= g_strdup (filename
);
1266 fname
= g_strdup (filename
);
1269 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1270 "Assembly Loader probing location: '%s'.", fname
);
1273 if (!mono_assembly_is_in_gac (fname
))
1274 new_fname
= mono_make_shadow_copy (fname
);
1275 if (new_fname
&& new_fname
!= fname
) {
1278 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1279 "Assembly Loader shadow-copied assembly to: '%s'.", fname
);
1284 if (bundles
!= NULL
)
1285 image
= mono_assembly_open_from_bundle (fname
, status
, refonly
);
1288 image
= mono_image_open_full (fname
, status
, refonly
);
1291 if (*status
== MONO_IMAGE_OK
)
1292 *status
= MONO_IMAGE_ERROR_ERRNO
;
1297 if (image
->assembly
) {
1298 /* Already loaded by another appdomain */
1299 mono_assembly_invoke_load_hook (image
->assembly
);
1300 mono_image_close (image
);
1302 return image
->assembly
;
1305 ass
= mono_assembly_load_from_full (image
, fname
, status
, refonly
);
1308 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1309 "Assembly Loader loaded assembly from location: '%s'.", filename
);
1311 mono_config_for_assembly (ass
->image
);
1314 /* Clear the reference added by mono_image_open */
1315 mono_image_close (image
);
1323 free_item (gpointer val
, gpointer user_data
)
1329 * mono_assembly_load_friends:
1332 * Load the list of friend assemblies that are allowed to access
1333 * the assembly's internal types and members. They are stored as assembly
1334 * names in custom attributes.
1336 * This is an internal method, we need this because when we load mscorlib
1337 * we do not have the mono_defaults.internals_visible_class loaded yet,
1338 * so we need to load these after we initialize the runtime.
1340 * LOCKING: Acquires the assemblies lock plus the loader lock.
1343 mono_assembly_load_friends (MonoAssembly
* ass
)
1346 MonoCustomAttrInfo
* attrs
;
1349 if (ass
->friend_assembly_names_inited
)
1352 attrs
= mono_custom_attrs_from_assembly (ass
);
1354 mono_assemblies_lock ();
1355 ass
->friend_assembly_names_inited
= TRUE
;
1356 mono_assemblies_unlock ();
1360 mono_assemblies_lock ();
1361 if (ass
->friend_assembly_names_inited
) {
1362 mono_assemblies_unlock ();
1365 mono_assemblies_unlock ();
1369 * We build the list outside the assemblies lock, the worse that can happen
1370 * is that we'll need to free the allocated list.
1372 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
1373 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
1374 MonoAssemblyName
*aname
;
1377 /* Do some sanity checking */
1378 if (!attr
->ctor
|| attr
->ctor
->klass
!= mono_defaults
.internals_visible_class
)
1380 if (attr
->data_size
< 4)
1382 data
= (const char*)attr
->data
;
1383 /* 0xFF means null string, see custom attr format */
1384 if (data
[0] != 1 || data
[1] != 0 || (data
[2] & 0xFF) == 0xFF)
1386 slen
= mono_metadata_decode_value (data
+ 2, &data
);
1387 aname
= g_new0 (MonoAssemblyName
, 1);
1388 /*g_print ("friend ass: %s\n", data);*/
1389 if (mono_assembly_name_parse_full (data
, aname
, TRUE
, NULL
, NULL
)) {
1390 list
= g_slist_prepend (list
, aname
);
1395 mono_custom_attrs_free (attrs
);
1397 mono_assemblies_lock ();
1398 if (ass
->friend_assembly_names_inited
) {
1399 mono_assemblies_unlock ();
1400 g_slist_foreach (list
, free_item
, NULL
);
1401 g_slist_free (list
);
1404 ass
->friend_assembly_names
= list
;
1406 /* Because of the double checked locking pattern above */
1407 mono_memory_barrier ();
1408 ass
->friend_assembly_names_inited
= TRUE
;
1409 mono_assemblies_unlock ();
1413 * mono_assembly_open:
1414 * @filename: Opens the assembly pointed out by this name
1415 * @status: where a status code can be returned
1417 * mono_assembly_open opens the PE-image pointed by @filename, and
1418 * loads any external assemblies referenced by it.
1420 * Return: a pointer to the MonoAssembly if @filename contains a valid
1421 * assembly or NULL on error. Details about the error are stored in the
1425 mono_assembly_open (const char *filename
, MonoImageOpenStatus
*status
)
1427 return mono_assembly_open_full (filename
, status
, FALSE
);
1431 mono_assembly_load_from_full (MonoImage
*image
, const char*fname
,
1432 MonoImageOpenStatus
*status
, gboolean refonly
)
1434 MonoAssembly
*ass
, *ass2
;
1437 if (!image
->tables
[MONO_TABLE_ASSEMBLY
].rows
) {
1438 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1439 *status
= MONO_IMAGE_IMAGE_INVALID
;
1443 #if defined (PLATFORM_WIN32)
1448 tmp_fn
= g_strdup (fname
);
1449 for (i
= strlen (tmp_fn
) - 1; i
>= 0; i
--) {
1450 if (tmp_fn
[i
] == '/')
1454 base_dir
= absolute_dir (tmp_fn
);
1458 base_dir
= absolute_dir (fname
);
1462 * Create assembly struct, and enter it into the assembly cache
1464 ass
= g_new0 (MonoAssembly
, 1);
1465 ass
->basedir
= base_dir
;
1466 ass
->ref_only
= refonly
;
1469 mono_profiler_assembly_event (ass
, MONO_PROFILE_START_LOAD
);
1471 mono_assembly_fill_assembly_name (image
, &ass
->aname
);
1473 if (mono_defaults
.corlib
&& strcmp (ass
->aname
.name
, "mscorlib") == 0) {
1474 // MS.NET doesn't support loading other mscorlibs
1477 mono_image_addref (mono_defaults
.corlib
);
1478 *status
= MONO_IMAGE_OK
;
1479 return mono_defaults
.corlib
->assembly
;
1482 /* Add a non-temporary reference because of ass->image */
1483 mono_image_addref (image
);
1485 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Image addref %s %p -> %s %p: %d\n", ass
->aname
.name
, ass
, image
->name
, image
, image
->ref_count
);
1488 * The load hooks might take locks so we can't call them while holding the
1491 if (ass
->aname
.name
) {
1492 ass2
= mono_assembly_invoke_search_hook_internal (&ass
->aname
, refonly
, FALSE
);
1496 mono_image_close (image
);
1497 *status
= MONO_IMAGE_OK
;
1502 mono_assemblies_lock ();
1504 if (image
->assembly
) {
1506 * This means another thread has already loaded the assembly, but not yet
1507 * called the load hooks so the search hook can't find the assembly.
1509 mono_assemblies_unlock ();
1510 ass2
= image
->assembly
;
1513 mono_image_close (image
);
1514 *status
= MONO_IMAGE_OK
;
1518 image
->assembly
= ass
;
1520 loaded_assemblies
= g_list_prepend (loaded_assemblies
, ass
);
1521 mono_assemblies_unlock ();
1523 #ifdef PLATFORM_WIN32
1524 if (image
->is_module_handle
)
1525 mono_image_fixup_vtable (image
);
1528 mono_assembly_invoke_load_hook (ass
);
1530 mono_profiler_assembly_loaded (ass
, MONO_PROFILE_OK
);
1536 mono_assembly_load_from (MonoImage
*image
, const char *fname
,
1537 MonoImageOpenStatus
*status
)
1539 return mono_assembly_load_from_full (image
, fname
, status
, FALSE
);
1543 * mono_assembly_name_free:
1544 * @aname: assembly name to free
1546 * Frees the provided assembly name object.
1547 * (it does not frees the object itself, only the name members).
1550 mono_assembly_name_free (MonoAssemblyName
*aname
)
1555 g_free ((void *) aname
->name
);
1556 g_free ((void *) aname
->culture
);
1557 g_free ((void *) aname
->hash_value
);
1561 parse_public_key (const gchar
*key
, gchar
** pubkey
)
1564 gchar header
[16], val
, *arr
;
1565 gint i
, j
, offset
, bitlen
, keylen
, pkeylen
;
1567 keylen
= strlen (key
) >> 1;
1571 val
= g_ascii_xdigit_value (key
[0]) << 4;
1572 val
|= g_ascii_xdigit_value (key
[1]);
1577 val
= g_ascii_xdigit_value (key
[24]);
1578 val
|= g_ascii_xdigit_value (key
[25]);
1590 /* We need the first 16 bytes
1591 * to check whether this key is valid or not */
1592 pkeylen
= strlen (pkey
) >> 1;
1596 for (i
= 0, j
= 0; i
< 16; i
++) {
1597 header
[i
] = g_ascii_xdigit_value (pkey
[j
++]) << 4;
1598 header
[i
] |= g_ascii_xdigit_value (pkey
[j
++]);
1601 if (header
[0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
1602 header
[1] != 0x02 || /* Version (0x02) */
1603 header
[2] != 0x00 || /* Reserved (word) */
1604 header
[3] != 0x00 ||
1605 (guint
)(read32 (header
+ 8)) != 0x31415352) /* DWORD magic = RSA1 */
1608 /* Based on this length, we _should_ be able to know if the length is right */
1609 bitlen
= read32 (header
+ 12) >> 3;
1610 if ((bitlen
+ 16 + 4) != pkeylen
)
1613 /* parsing is OK and the public key itself is not requested back */
1617 /* Encode the size of the blob */
1619 if (keylen
<= 127) {
1620 arr
= g_malloc (keylen
+ 1);
1621 arr
[offset
++] = keylen
;
1623 arr
= g_malloc (keylen
+ 2);
1624 arr
[offset
++] = 0x80; /* 10bs */
1625 arr
[offset
++] = keylen
;
1628 for (i
= offset
, j
= 0; i
< keylen
+ offset
; i
++) {
1629 arr
[i
] = g_ascii_xdigit_value (key
[j
++]) << 4;
1630 arr
[i
] |= g_ascii_xdigit_value (key
[j
++]);
1639 build_assembly_name (const char *name
, const char *version
, const char *culture
, const char *token
, const char *key
, guint32 flags
, MonoAssemblyName
*aname
, gboolean save_public_key
)
1641 gint major
, minor
, build
, revision
;
1644 gchar
*pkey
, *pkeyptr
, *encoded
, tok
[8];
1646 memset (aname
, 0, sizeof (MonoAssemblyName
));
1649 version_parts
= sscanf (version
, "%u.%u.%u.%u", &major
, &minor
, &build
, &revision
);
1650 if (version_parts
< 2 || version_parts
> 4)
1653 /* FIXME: we should set build & revision to -1 (instead of 0)
1654 if these are not set in the version string. That way, later on,
1655 we can still determine if these were specified. */
1656 aname
->major
= major
;
1657 aname
->minor
= minor
;
1658 if (version_parts
>= 3)
1659 aname
->build
= build
;
1662 if (version_parts
== 4)
1663 aname
->revision
= revision
;
1665 aname
->revision
= 0;
1668 aname
->flags
= flags
;
1669 aname
->name
= g_strdup (name
);
1672 if (g_ascii_strcasecmp (culture
, "neutral") == 0)
1673 aname
->culture
= g_strdup ("");
1675 aname
->culture
= g_strdup (culture
);
1678 if (token
&& strncmp (token
, "null", 4) != 0) {
1681 /* the constant includes the ending NULL, hence the -1 */
1682 if (strlen (token
) != (MONO_PUBLIC_KEY_TOKEN_LENGTH
- 1)) {
1683 mono_assembly_name_free (aname
);
1686 lower
= g_ascii_strdown (token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1687 g_strlcpy ((char*)aname
->public_key_token
, lower
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1692 if (strcmp (key
, "null") == 0 || !parse_public_key (key
, &pkey
)) {
1693 mono_assembly_name_free (aname
);
1697 len
= mono_metadata_decode_blob_size ((const gchar
*) pkey
, (const gchar
**) &pkeyptr
);
1698 // We also need to generate the key token
1699 mono_digest_get_public_token ((guchar
*) tok
, (guint8
*) pkeyptr
, len
);
1700 encoded
= encode_public_tok ((guchar
*) tok
, 8);
1701 g_strlcpy ((gchar
*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1704 if (save_public_key
)
1705 aname
->public_key
= (guint8
*) pkey
;
1714 parse_assembly_directory_name (const char *name
, const char *dirname
, MonoAssemblyName
*aname
)
1719 parts
= g_strsplit (dirname
, "_", 3);
1720 if (!parts
|| !parts
[0] || !parts
[1] || !parts
[2]) {
1725 res
= build_assembly_name (name
, parts
[0], parts
[1], parts
[2], NULL
, 0, aname
, FALSE
);
1731 mono_assembly_name_parse_full (const char *name
, MonoAssemblyName
*aname
, gboolean save_public_key
, gboolean
*is_version_defined
, gboolean
*is_token_defined
)
1734 gchar
*version
= NULL
;
1735 gchar
*culture
= NULL
;
1736 gchar
*token
= NULL
;
1738 gchar
*retargetable
= NULL
;
1743 gboolean version_defined
;
1744 gboolean token_defined
;
1747 if (!is_version_defined
)
1748 is_version_defined
= &version_defined
;
1749 *is_version_defined
= FALSE
;
1750 if (!is_token_defined
)
1751 is_token_defined
= &token_defined
;
1752 *is_token_defined
= FALSE
;
1754 parts
= tmp
= g_strsplit (name
, ",", 6);
1755 if (!tmp
|| !*tmp
) {
1760 dllname
= g_strstrip (*tmp
);
1765 value
= g_strstrip (*tmp
);
1766 if (!g_ascii_strncasecmp (value
, "Version=", 8)) {
1767 *is_version_defined
= TRUE
;
1768 version
= g_strstrip (value
+ 8);
1769 if (strlen (version
) == 0) {
1770 goto cleanup_and_fail
;
1776 if (!g_ascii_strncasecmp (value
, "Culture=", 8)) {
1777 culture
= g_strstrip (value
+ 8);
1778 if (strlen (culture
) == 0) {
1779 goto cleanup_and_fail
;
1785 if (!g_ascii_strncasecmp (value
, "PublicKeyToken=", 15)) {
1786 *is_token_defined
= TRUE
;
1787 token
= g_strstrip (value
+ 15);
1788 if (strlen (token
) == 0) {
1789 goto cleanup_and_fail
;
1795 if (!g_ascii_strncasecmp (value
, "PublicKey=", 10)) {
1796 key
= g_strstrip (value
+ 10);
1797 if (strlen (key
) == 0) {
1798 goto cleanup_and_fail
;
1804 if (!g_ascii_strncasecmp (value
, "Retargetable=", 13)) {
1805 retargetable
= g_strstrip (value
+ 13);
1806 if (strlen (retargetable
) == 0) {
1807 goto cleanup_and_fail
;
1809 if (!g_ascii_strcasecmp (retargetable
, "yes")) {
1810 flags
|= ASSEMBLYREF_RETARGETABLE_FLAG
;
1811 } else if (g_ascii_strcasecmp (retargetable
, "no")) {
1812 goto cleanup_and_fail
;
1818 if (!g_ascii_strncasecmp (value
, "ProcessorArchitecture=", 22)) {
1819 /* this is ignored for now, until we can change MonoAssemblyName */
1828 /* if retargetable flag is set, then we must have a fully qualified name */
1829 if (retargetable
!= NULL
&& (version
== NULL
|| culture
== NULL
|| (key
== NULL
&& token
== NULL
))) {
1830 goto cleanup_and_fail
;
1833 res
= build_assembly_name (dllname
, version
, culture
, token
, key
, flags
,
1834 aname
, save_public_key
);
1844 * mono_assembly_name_parse:
1845 * @name: name to parse
1846 * @aname: the destination assembly name
1848 * Parses an assembly qualified type name and assigns the name,
1849 * version, culture and token to the provided assembly name object.
1851 * Returns: true if the name could be parsed.
1854 mono_assembly_name_parse (const char *name
, MonoAssemblyName
*aname
)
1856 return mono_assembly_name_parse_full (name
, aname
, FALSE
, NULL
, NULL
);
1859 static MonoAssembly
*
1860 probe_for_partial_name (const char *basepath
, const char *fullname
, MonoAssemblyName
*aname
, MonoImageOpenStatus
*status
)
1862 gchar
*fullpath
= NULL
;
1864 const char* direntry
;
1865 MonoAssemblyName gac_aname
;
1866 gint major
=-1, minor
=0, build
=0, revision
=0;
1867 gboolean exact_version
;
1869 dirhandle
= g_dir_open (basepath
, 0, NULL
);
1873 exact_version
= (aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0;
1875 while ((direntry
= g_dir_read_name (dirhandle
))) {
1876 gboolean match
= TRUE
;
1878 if(!parse_assembly_directory_name (aname
->name
, direntry
, &gac_aname
))
1881 if (aname
->culture
!= NULL
&& strcmp (aname
->culture
, gac_aname
.culture
) != 0)
1884 if (match
&& strlen ((char*)aname
->public_key_token
) > 0 &&
1885 !mono_public_tokens_are_equal (aname
->public_key_token
, gac_aname
.public_key_token
))
1889 if (exact_version
) {
1890 match
= (aname
->major
== gac_aname
.major
&& aname
->minor
== gac_aname
.minor
&&
1891 aname
->build
== gac_aname
.build
&& aname
->revision
== gac_aname
.revision
);
1893 else if (gac_aname
.major
< major
)
1895 else if (gac_aname
.major
== major
) {
1896 if (gac_aname
.minor
< minor
)
1898 else if (gac_aname
.minor
== minor
) {
1899 if (gac_aname
.build
< build
)
1901 else if (gac_aname
.build
== build
&& gac_aname
.revision
<= revision
)
1908 major
= gac_aname
.major
;
1909 minor
= gac_aname
.minor
;
1910 build
= gac_aname
.build
;
1911 revision
= gac_aname
.revision
;
1913 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, basepath
, direntry
, fullname
, NULL
);
1916 mono_assembly_name_free (&gac_aname
);
1919 g_dir_close (dirhandle
);
1921 if (fullpath
== NULL
)
1924 MonoAssembly
*res
= mono_assembly_open (fullpath
, status
);
1931 mono_assembly_load_with_partial_name (const char *name
, MonoImageOpenStatus
*status
)
1934 MonoAssemblyName
*aname
, base_name
, maped_aname
;
1935 gchar
*fullname
, *gacpath
;
1938 memset (&base_name
, 0, sizeof (MonoAssemblyName
));
1941 if (!mono_assembly_name_parse (name
, aname
))
1945 * If no specific version has been requested, make sure we load the
1946 * correct version for system assemblies.
1948 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) == 0)
1949 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
1951 res
= mono_assembly_loaded (aname
);
1953 mono_assembly_name_free (aname
);
1957 res
= invoke_assembly_preload_hook (aname
, assemblies_path
);
1959 res
->in_gac
= FALSE
;
1960 mono_assembly_name_free (aname
);
1964 fullname
= g_strdup_printf ("%s.dll", aname
->name
);
1966 if (extra_gac_paths
) {
1967 paths
= extra_gac_paths
;
1968 while (!res
&& *paths
) {
1969 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", aname
->name
, NULL
);
1970 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
1979 mono_assembly_name_free (aname
);
1983 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), "mono", "gac", aname
->name
, NULL
);
1984 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
1990 MonoDomain
*domain
= mono_domain_get ();
1991 MonoReflectionAssembly
*refasm
= mono_try_assembly_resolve (domain
, mono_string_new (domain
, name
), FALSE
);
1993 res
= refasm
->assembly
;
1997 mono_assembly_name_free (aname
);
2003 mono_assembly_is_in_gac (const gchar
*filename
)
2005 const gchar
*rootdir
;
2009 if (filename
== NULL
)
2012 for (paths
= extra_gac_paths
; paths
&& *paths
; paths
++) {
2013 if (strstr (*paths
, filename
) != *paths
)
2016 gp
= (gchar
*) (filename
+ strlen (*paths
));
2017 if (*gp
!= G_DIR_SEPARATOR
)
2020 if (strncmp (gp
, "lib", 3))
2023 if (*gp
!= G_DIR_SEPARATOR
)
2026 if (strncmp (gp
, "mono", 4))
2029 if (*gp
!= G_DIR_SEPARATOR
)
2032 if (strncmp (gp
, "gac", 3))
2035 if (*gp
!= G_DIR_SEPARATOR
)
2041 rootdir
= mono_assembly_getrootdir ();
2042 if (strstr (filename
, rootdir
) != filename
)
2045 gp
= (gchar
*) (filename
+ strlen (rootdir
));
2046 if (*gp
!= G_DIR_SEPARATOR
)
2049 if (strncmp (gp
, "mono", 4))
2052 if (*gp
!= G_DIR_SEPARATOR
)
2055 if (strncmp (gp
, "gac", 3))
2058 if (*gp
!= G_DIR_SEPARATOR
)
2064 mono_assembly_load_publisher_policy (MonoAssemblyName
*aname
)
2067 gchar
*filename
, *pname
, *name
, *culture
, *version
, *fullpath
, *subpath
;
2071 if (strstr (aname
->name
, ".dll")) {
2072 len
= strlen (aname
->name
) - 4;
2073 name
= g_malloc (len
);
2074 strncpy (name
, aname
->name
, len
);
2076 name
= g_strdup (aname
->name
);
2079 culture
= g_utf8_strdown (aname
->culture
, -1);
2081 culture
= g_strdup ("");
2083 pname
= g_strdup_printf ("policy.%d.%d.%s", aname
->major
, aname
->minor
, name
);
2084 version
= g_strdup_printf ("0.0.0.0_%s_%s", culture
, aname
->public_key_token
);
2088 filename
= g_strconcat (pname
, ".dll", NULL
);
2089 subpath
= g_build_path (G_DIR_SEPARATOR_S
, pname
, version
, filename
, NULL
);
2095 if (extra_gac_paths
) {
2096 paths
= extra_gac_paths
;
2097 while (!image
&& *paths
) {
2098 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
,
2099 "lib", "mono", "gac", subpath
, NULL
);
2100 image
= mono_image_open (fullpath
, NULL
);
2111 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
2112 "mono", "gac", subpath
, NULL
);
2113 image
= mono_image_open (fullpath
, NULL
);
2120 static MonoAssemblyName
*
2121 mono_assembly_bind_version (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
2123 memcpy (dest_name
, aname
, sizeof (MonoAssemblyName
));
2124 dest_name
->major
= info
->new_version
.major
;
2125 dest_name
->minor
= info
->new_version
.minor
;
2126 dest_name
->build
= info
->new_version
.build
;
2127 dest_name
->revision
= info
->new_version
.revision
;
2132 /* LOCKING: Assumes that we are already locked */
2133 static MonoAssemblyBindingInfo
*
2134 search_binding_loaded (MonoAssemblyName
*aname
)
2138 for (tmp
= loaded_assembly_bindings
; tmp
; tmp
= tmp
->next
) {
2139 MonoAssemblyBindingInfo
*info
= tmp
->data
;
2140 if (assembly_binding_maps_name (info
, aname
))
2147 static MonoAssemblyName
*
2148 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
2150 MonoAssemblyBindingInfo
*info
, *info2
;
2153 if (aname
->public_key_token
[0] == 0)
2156 mono_loader_lock ();
2157 info
= search_binding_loaded (aname
);
2158 mono_loader_unlock ();
2160 if (!check_policy_versions (info
, aname
))
2163 mono_assembly_bind_version (info
, aname
, dest_name
);
2167 info
= g_new0 (MonoAssemblyBindingInfo
, 1);
2168 info
->major
= aname
->major
;
2169 info
->minor
= aname
->minor
;
2171 ppimage
= mono_assembly_load_publisher_policy (aname
);
2173 get_publisher_policy_info (ppimage
, aname
, info
);
2174 mono_image_close (ppimage
);
2177 /* Define default error value if needed */
2178 if (!info
->is_valid
) {
2179 info
->name
= g_strdup (aname
->name
);
2180 info
->culture
= g_strdup (aname
->culture
);
2181 g_strlcpy ((char *)info
->public_key_token
, (const char *)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
2184 mono_loader_lock ();
2185 info2
= search_binding_loaded (aname
);
2187 /* This binding was added by another thread
2189 mono_assembly_binding_info_free (info
);
2194 loaded_assembly_bindings
= g_slist_prepend (loaded_assembly_bindings
, info
);
2196 mono_loader_unlock ();
2198 if (!info
->is_valid
|| !check_policy_versions (info
, aname
))
2201 mono_assembly_bind_version (info
, aname
, dest_name
);
2206 * mono_assembly_load_from_gac
2208 * @aname: The assembly name object
2210 static MonoAssembly
*
2211 mono_assembly_load_from_gac (MonoAssemblyName
*aname
, gchar
*filename
, MonoImageOpenStatus
*status
, MonoBoolean refonly
)
2213 MonoAssembly
*result
= NULL
;
2214 gchar
*name
, *version
, *culture
, *fullpath
, *subpath
;
2219 if (aname
->public_key_token
[0] == 0) {
2223 if (strstr (aname
->name
, ".dll")) {
2224 len
= strlen (filename
) - 4;
2225 name
= g_malloc (len
);
2226 strncpy (name
, aname
->name
, len
);
2228 name
= g_strdup (aname
->name
);
2231 if (aname
->culture
) {
2232 culture
= g_utf8_strdown (aname
->culture
, -1);
2234 culture
= g_strdup ("");
2237 pubtok
= g_ascii_strdown ((char*)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
2238 version
= g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname
->major
,
2239 aname
->minor
, aname
->build
, aname
->revision
,
2243 subpath
= g_build_path (G_DIR_SEPARATOR_S
, name
, version
, filename
, NULL
);
2248 if (extra_gac_paths
) {
2249 paths
= extra_gac_paths
;
2250 while (!result
&& *paths
) {
2251 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", subpath
, NULL
);
2252 result
= mono_assembly_open_full (fullpath
, status
, refonly
);
2259 result
->in_gac
= TRUE
;
2264 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
2265 "mono", "gac", subpath
, NULL
);
2266 result
= mono_assembly_open_full (fullpath
, status
, refonly
);
2270 result
->in_gac
= TRUE
;
2279 mono_assembly_load_corlib (const MonoRuntimeInfo
*runtime
, MonoImageOpenStatus
*status
)
2284 /* g_print ("corlib already loaded\n"); */
2288 if (assemblies_path
) {
2289 corlib
= load_in_path ("mscorlib.dll", (const char**)assemblies_path
, status
, FALSE
);
2294 /* Load corlib from mono/<version> */
2296 corlib_file
= g_build_filename ("mono", runtime
->framework_version
, "mscorlib.dll", NULL
);
2297 if (assemblies_path
) {
2298 corlib
= load_in_path (corlib_file
, (const char**)assemblies_path
, status
, FALSE
);
2300 g_free (corlib_file
);
2304 corlib
= load_in_path (corlib_file
, default_path
, status
, FALSE
);
2305 g_free (corlib_file
);
2311 mono_assembly_load_full_nosearch (MonoAssemblyName
*aname
,
2312 const char *basedir
,
2313 MonoImageOpenStatus
*status
,
2316 MonoAssembly
*result
;
2317 char *fullpath
, *filename
;
2318 MonoAssemblyName maped_aname
, maped_name_pp
;
2323 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
2325 /* Reflection only assemblies don't get assembly binding */
2327 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
2329 result
= mono_assembly_loaded_full (aname
, refonly
);
2333 result
= refonly
? invoke_assembly_refonly_preload_hook (aname
, assemblies_path
) : invoke_assembly_preload_hook (aname
, assemblies_path
);
2335 result
->in_gac
= FALSE
;
2339 /* Currently we retrieve the loaded corlib for reflection
2340 * only requests, like a common reflection only assembly
2342 if (strcmp (aname
->name
, "mscorlib") == 0 || strcmp (aname
->name
, "mscorlib.dll") == 0) {
2343 return mono_assembly_load_corlib (mono_get_runtime_info (), status
);
2346 len
= strlen (aname
->name
);
2347 for (ext_index
= 0; ext_index
< 2; ext_index
++) {
2348 ext
= ext_index
== 0 ? ".dll" : ".exe";
2349 if (len
> 4 && (!strcmp (aname
->name
+ len
- 4, ".dll") || !strcmp (aname
->name
+ len
- 4, ".exe"))) {
2350 filename
= g_strdup (aname
->name
);
2351 /* Don't try appending .dll/.exe if it already has one of those extensions */
2354 filename
= g_strconcat (aname
->name
, ext
, NULL
);
2357 result
= mono_assembly_load_from_gac (aname
, filename
, status
, refonly
);
2364 fullpath
= g_build_filename (basedir
, filename
, NULL
);
2365 result
= mono_assembly_open_full (fullpath
, status
, refonly
);
2368 result
->in_gac
= FALSE
;
2374 result
= load_in_path (filename
, default_path
, status
, refonly
);
2376 result
->in_gac
= FALSE
;
2386 * mono_assembly_load_full:
2387 * @aname: A MonoAssemblyName with the assembly name to load.
2388 * @basedir: A directory to look up the assembly at.
2389 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2390 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
2392 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2393 * attempts to load the assembly from that directory before probing the standard locations.
2395 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
2396 * assembly binding takes place.
2398 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
2399 * value pointed by status is updated with an error code.
2402 mono_assembly_load_full (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
, gboolean refonly
)
2404 MonoAssembly
*result
= mono_assembly_load_full_nosearch (aname
, basedir
, status
, refonly
);
2407 /* Try a postload search hook */
2408 result
= mono_assembly_invoke_search_hook_internal (aname
, refonly
, TRUE
);
2413 * mono_assembly_load:
2414 * @aname: A MonoAssemblyName with the assembly name to load.
2415 * @basedir: A directory to look up the assembly at.
2416 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2418 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2419 * attempts to load the assembly from that directory before probing the standard locations.
2421 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
2422 * value pointed by status is updated with an error code.
2425 mono_assembly_load (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
)
2427 return mono_assembly_load_full (aname
, basedir
, status
, FALSE
);
2431 mono_assembly_loaded_full (MonoAssemblyName
*aname
, gboolean refonly
)
2434 MonoAssemblyName maped_aname
;
2436 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
2438 res
= mono_assembly_invoke_search_hook_internal (aname
, refonly
, FALSE
);
2444 * mono_assembly_loaded:
2445 * @aname: an assembly to look for.
2447 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
2448 * a MonoAssembly that matches the MonoAssemblyName specified.
2451 mono_assembly_loaded (MonoAssemblyName
*aname
)
2453 return mono_assembly_loaded_full (aname
, FALSE
);
2457 * mono_assembly_close:
2458 * @assembly: the assembly to release.
2460 * This method releases a reference to the @assembly. The assembly is
2461 * only released when all the outstanding references to it are released.
2464 mono_assembly_close (MonoAssembly
*assembly
)
2467 g_return_if_fail (assembly
!= NULL
);
2469 if (assembly
== REFERENCE_MISSING
)
2472 /* Might be 0 already */
2473 if (InterlockedDecrement (&assembly
->ref_count
) > 0)
2476 mono_profiler_assembly_event (assembly
, MONO_PROFILE_START_UNLOAD
);
2478 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Unloading assembly %s [%p].", assembly
->aname
.name
, assembly
);
2480 mono_debug_close_image (assembly
->image
);
2482 mono_assemblies_lock ();
2483 loaded_assemblies
= g_list_remove (loaded_assemblies
, assembly
);
2484 mono_assemblies_unlock ();
2486 assembly
->image
->assembly
= NULL
;
2488 mono_image_close (assembly
->image
);
2490 for (tmp
= assembly
->friend_assembly_names
; tmp
; tmp
= tmp
->next
) {
2491 MonoAssemblyName
*fname
= tmp
->data
;
2492 mono_assembly_name_free (fname
);
2495 g_slist_free (assembly
->friend_assembly_names
);
2496 g_free (assembly
->basedir
);
2497 if (assembly
->dynamic
) {
2498 g_free ((char*)assembly
->aname
.culture
);
2503 mono_profiler_assembly_event (assembly
, MONO_PROFILE_END_UNLOAD
);
2507 mono_assembly_load_module (MonoAssembly
*assembly
, guint32 idx
)
2509 return mono_image_load_file_for_image (assembly
->image
, idx
);
2513 mono_assembly_foreach (GFunc func
, gpointer user_data
)
2518 * We make a copy of the list to avoid calling the callback inside the
2519 * lock, which could lead to deadlocks.
2521 mono_assemblies_lock ();
2522 copy
= g_list_copy (loaded_assemblies
);
2523 mono_assemblies_unlock ();
2525 g_list_foreach (loaded_assemblies
, func
, user_data
);
2531 * mono_assemblies_cleanup:
2533 * Free all resources used by this module.
2536 mono_assemblies_cleanup (void)
2540 DeleteCriticalSection (&assemblies_mutex
);
2542 for (l
= loaded_assembly_bindings
; l
; l
= l
->next
) {
2543 MonoAssemblyBindingInfo
*info
= l
->data
;
2545 mono_assembly_binding_info_free (info
);
2548 g_slist_free (loaded_assembly_bindings
);
2550 free_assembly_load_hooks ();
2551 free_assembly_search_hooks ();
2552 free_assembly_preload_hooks ();
2556 * Holds the assembly of the application, for
2557 * System.Diagnostics.Process::MainModule
2559 static MonoAssembly
*main_assembly
=NULL
;
2562 mono_assembly_set_main (MonoAssembly
*assembly
)
2564 main_assembly
= assembly
;
2568 * mono_assembly_get_main:
2570 * Returns: the assembly for the application, the first assembly that is loaded by the VM
2573 mono_assembly_get_main (void)
2575 return (main_assembly
);
2579 * mono_assembly_get_image:
2580 * @assembly: The assembly to retrieve the image from
2582 * Returns: the MonoImage associated with this assembly.
2585 mono_assembly_get_image (MonoAssembly
*assembly
)
2587 return assembly
->image
;
2591 mono_register_bundled_assemblies (const MonoBundledAssembly
**assemblies
)
2593 bundles
= assemblies
;
2596 #define MONO_DECLSEC_FORMAT_10 0x3C
2597 #define MONO_DECLSEC_FORMAT_20 0x2E
2598 #define MONO_DECLSEC_FIELD 0x53
2599 #define MONO_DECLSEC_PROPERTY 0x54
2601 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
2602 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
2603 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
2604 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
2605 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
2608 mono_assembly_try_decode_skip_verification_param (const char *p
, const char **resp
, gboolean
*abort_decoding
)
2612 case MONO_DECLSEC_PROPERTY
:
2614 case MONO_DECLSEC_FIELD
:
2616 *abort_decoding
= TRUE
;
2621 if (*p
++ != MONO_TYPE_BOOLEAN
) {
2622 *abort_decoding
= TRUE
;
2626 /* property name length */
2627 len
= mono_metadata_decode_value (p
, &p
);
2629 if (len
>= SKIP_VISIBILITY_PROPERTY_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_PROPERTY_NAME
, SKIP_VISIBILITY_PROPERTY_SIZE
)) {
2640 mono_assembly_try_decode_skip_verification (const char *p
, const char *endn
)
2642 int i
, j
, num
, len
, params_len
;
2644 if (*p
== MONO_DECLSEC_FORMAT_10
) {
2645 gsize read
, written
;
2646 char *res
= g_convert (p
, endn
- p
, "UTF-8", "UTF-16LE", &read
, &written
, NULL
);
2648 gboolean found
= strstr (res
, SKIP_VISIBILITY_XML_ATTRIBUTE
) != NULL
;
2654 if (*p
++ != MONO_DECLSEC_FORMAT_20
)
2657 /* number of encoded permission attributes */
2658 num
= mono_metadata_decode_value (p
, &p
);
2659 for (i
= 0; i
< num
; ++i
) {
2660 gboolean is_valid
= FALSE
;
2661 gboolean abort_decoding
= FALSE
;
2663 /* attribute name length */
2664 len
= mono_metadata_decode_value (p
, &p
);
2666 /* We don't really need to fully decode the type. Comparing the name is enough */
2667 is_valid
= len
>= SKIP_VISIBILITY_ATTRIBUTE_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_ATTRIBUTE_NAME
, SKIP_VISIBILITY_ATTRIBUTE_SIZE
);
2671 /*size of the params table*/
2672 params_len
= mono_metadata_decode_value (p
, &p
);
2674 const char *params_end
= p
+ params_len
;
2676 /* number of parameters */
2677 len
= mono_metadata_decode_value (p
, &p
);
2679 for (j
= 0; j
< len
; ++j
) {
2680 if (mono_assembly_try_decode_skip_verification_param (p
, &p
, &abort_decoding
))
2696 mono_assembly_has_skip_verification (MonoAssembly
*assembly
)
2699 guint32 cols
[MONO_DECL_SECURITY_SIZE
];
2703 if (MONO_SECMAN_FLAG_INIT (assembly
->skipverification
))
2704 return MONO_SECMAN_FLAG_GET_VALUE (assembly
->skipverification
);
2706 t
= &assembly
->image
->tables
[MONO_TABLE_DECLSECURITY
];
2708 for (i
= 0; i
< t
->rows
; ++i
) {
2709 mono_metadata_decode_row (t
, i
, cols
, MONO_DECL_SECURITY_SIZE
);
2710 if ((cols
[MONO_DECL_SECURITY_PARENT
] & MONO_HAS_DECL_SECURITY_MASK
) != MONO_HAS_DECL_SECURITY_ASSEMBLY
)
2712 if (cols
[MONO_DECL_SECURITY_ACTION
] != SECURITY_ACTION_REQMIN
)
2715 blob
= mono_metadata_blob_heap (assembly
->image
, cols
[MONO_DECL_SECURITY_PERMISSIONSET
]);
2716 len
= mono_metadata_decode_blob_size (blob
, &blob
);
2720 if (mono_assembly_try_decode_skip_verification (blob
, blob
+ len
)) {
2721 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, TRUE
);
2726 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, FALSE
);