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-internal.h>
32 #include <mono/metadata/reflection.h>
33 #include <mono/metadata/coree.h>
36 #include <sys/types.h>
41 #ifdef PLATFORM_MACOSX
42 #include <mach-o/dyld.h>
45 /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
47 const char* assembly_name
;
48 guint8 version_set_index
;
51 /* the default search path is empty, the first slot is replaced with the computed value */
58 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
59 static char **assemblies_path
= NULL
;
61 /* Contains the list of directories that point to auxiliary GACs */
62 static char **extra_gac_paths
= NULL
;
64 /* The list of system assemblies what will be remapped to the running
65 * runtime version. WARNING: this list must be sorted.
67 static const AssemblyVersionMap framework_assemblies
[] = {
69 {"Commons.Xml.Relaxng", 0},
76 {"Microsoft.VisualBasic", 1},
77 {"Microsoft.VisualC", 1},
79 {"Mono.CompilerServices.SymbolWriter", 0},
81 {"Mono.Data.SybaseClient", 0},
83 {"Mono.Data.TdsClient", 0},
84 {"Mono.GetOptions", 0},
88 {"Mono.Security.Win32", 0},
90 {"Novell.Directory.Ldap", 0},
94 {"System.Configuration.Install", 0},
96 {"System.Data.OracleClient", 0},
97 {"System.Data.SqlXml", 0},
99 {"System.DirectoryServices", 0},
100 {"System.Drawing", 0},
101 {"System.Drawing.Design", 0},
102 {"System.EnterpriseServices", 0},
103 {"System.Management", 0},
104 {"System.Messaging", 0},
105 {"System.Runtime.Remoting", 0},
106 {"System.Runtime.Serialization.Formatters.Soap", 0},
107 {"System.Security", 0},
108 {"System.ServiceProcess", 0},
110 {"System.Web.Mobile", 0},
111 {"System.Web.Services", 0},
112 {"System.Windows.Forms", 0},
118 * keeps track of loaded assemblies
120 static GList
*loaded_assemblies
= NULL
;
121 static MonoAssembly
*corlib
;
123 /* This protects loaded_assemblies and image->references */
124 #define mono_assemblies_lock() EnterCriticalSection (&assemblies_mutex)
125 #define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex)
126 static CRITICAL_SECTION assemblies_mutex
;
128 /* If defined, points to the bundled assembly information */
129 const MonoBundledAssembly
**bundles
;
131 /* Loaded assembly binding info */
132 static GSList
*loaded_assembly_bindings
= NULL
;
135 mono_assembly_invoke_search_hook_internal (MonoAssemblyName
*aname
, gboolean refonly
, gboolean postload
);
137 mono_assembly_is_in_gac (const gchar
*filanem
);
140 encode_public_tok (const guchar
*token
, gint32 len
)
142 const static gchar allowed
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
146 res
= g_malloc (len
* 2 + 1);
147 for (i
= 0; i
< len
; i
++) {
148 res
[i
* 2] = allowed
[token
[i
] >> 4];
149 res
[i
* 2 + 1] = allowed
[token
[i
] & 0xF];
156 * mono_public_tokens_are_equal:
157 * @pubt1: first public key token
158 * @pubt2: second public key token
160 * Compare two public key tokens and return #TRUE is they are equal and #FALSE
164 mono_public_tokens_are_equal (const unsigned char *pubt1
, const unsigned char *pubt2
)
166 return memcmp (pubt1
, pubt2
, 16) == 0;
170 check_path_env (void)
173 char **splitted
, **dest
;
175 path
= g_getenv ("MONO_PATH");
179 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
181 g_strfreev (assemblies_path
);
182 assemblies_path
= dest
= splitted
;
190 if (g_getenv ("MONO_DEBUG") == NULL
)
193 splitted
= assemblies_path
;
195 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
196 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted
);
203 check_extra_gac_path_env (void) {
205 char **splitted
, **dest
;
207 path
= g_getenv ("MONO_GAC_PREFIX");
211 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
213 g_strfreev (extra_gac_paths
);
214 extra_gac_paths
= dest
= splitted
;
222 if (g_getenv ("MONO_DEBUG") == NULL
)
226 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
227 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted
);
234 assembly_binding_maps_name (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
236 if (!info
|| !info
->name
)
239 if (strcmp (info
->name
, aname
->name
))
242 if (info
->major
!= aname
->major
|| info
->minor
!= aname
->minor
)
245 if ((info
->culture
!= NULL
&& info
->culture
[0]) != (aname
->culture
!= NULL
&& aname
->culture
[0]))
248 if (info
->culture
&& aname
->culture
&& strcmp (info
->culture
, aname
->culture
))
251 if (!mono_public_tokens_are_equal (info
->public_key_token
, aname
->public_key_token
))
258 mono_assembly_binding_info_free (MonoAssemblyBindingInfo
*info
)
264 g_free (info
->culture
);
268 get_publisher_policy_info (MonoImage
*image
, MonoAssemblyName
*aname
, MonoAssemblyBindingInfo
*binding_info
)
271 guint32 cols
[MONO_MANIFEST_SIZE
];
272 const gchar
*filename
;
273 gchar
*subpath
, *fullpath
;
275 t
= &image
->tables
[MONO_TABLE_MANIFESTRESOURCE
];
276 /* MS Impl. accepts policy assemblies with more than
277 * one manifest resource, and only takes the first one */
279 binding_info
->is_valid
= FALSE
;
283 mono_metadata_decode_row (t
, 0, cols
, MONO_MANIFEST_SIZE
);
284 if ((cols
[MONO_MANIFEST_IMPLEMENTATION
] & MONO_IMPLEMENTATION_MASK
) != MONO_IMPLEMENTATION_FILE
) {
285 binding_info
->is_valid
= FALSE
;
289 filename
= mono_metadata_string_heap (image
, cols
[MONO_MANIFEST_NAME
]);
290 g_assert (filename
!= NULL
);
292 subpath
= g_path_get_dirname (image
->name
);
293 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, subpath
, filename
, NULL
);
294 mono_config_parse_publisher_policy (fullpath
, binding_info
);
298 /* Define the optional elements/attributes before checking */
299 if (!binding_info
->culture
)
300 binding_info
->culture
= g_strdup ("");
302 /* Check that the most important elements/attributes exist */
303 if (!binding_info
->name
|| !binding_info
->public_key_token
[0] || !binding_info
->has_old_version_bottom
||
304 !binding_info
->has_new_version
|| !assembly_binding_maps_name (binding_info
, aname
)) {
305 mono_assembly_binding_info_free (binding_info
);
306 binding_info
->is_valid
= FALSE
;
310 binding_info
->is_valid
= TRUE
;
314 compare_versions (AssemblyVersionSet
*v
, MonoAssemblyName
*aname
)
316 if (v
->major
> aname
->major
)
318 else if (v
->major
< aname
->major
)
321 if (v
->minor
> aname
->minor
)
323 else if (v
->minor
< aname
->minor
)
326 if (v
->build
> aname
->build
)
328 else if (v
->build
< aname
->build
)
331 if (v
->revision
> aname
->revision
)
333 else if (v
->revision
< aname
->revision
)
340 check_policy_versions (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*name
)
345 /* If has_old_version_top doesn't exist, we don't have an interval */
346 if (!info
->has_old_version_top
) {
347 if (compare_versions (&info
->old_version_bottom
, name
) == 0)
353 /* Check that the version defined by name is valid for the interval */
354 if (compare_versions (&info
->old_version_top
, name
) < 0)
357 /* We should be greater or equal than the small version */
358 if (compare_versions (&info
->old_version_bottom
, name
) > 0)
365 * mono_assembly_names_equal:
367 * @r: second assembly.
369 * Compares two MonoAssemblyNames and returns whether they are equal.
371 * This compares the names, the cultures, the release version and their
374 * Returns: TRUE if both assembly names are equal.
377 mono_assembly_names_equal (MonoAssemblyName
*l
, MonoAssemblyName
*r
)
379 if (!l
->name
|| !r
->name
)
382 if (strcmp (l
->name
, r
->name
))
385 if (l
->culture
&& r
->culture
&& strcmp (l
->culture
, r
->culture
))
388 if (l
->major
!= r
->major
|| l
->minor
!= r
->minor
||
389 l
->build
!= r
->build
|| l
->revision
!= r
->revision
)
390 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)))
393 if (!l
->public_key_token
[0] || !r
->public_key_token
[0])
396 if (!mono_public_tokens_are_equal (l
->public_key_token
, r
->public_key_token
))
402 static MonoAssembly
*
403 load_in_path (const char *basename
, const char** search_path
, MonoImageOpenStatus
*status
, MonoBoolean refonly
)
407 MonoAssembly
*result
;
409 for (i
= 0; search_path
[i
]; ++i
) {
410 fullpath
= g_build_filename (search_path
[i
], basename
, NULL
);
411 result
= mono_assembly_open_full (fullpath
, status
, refonly
);
420 * mono_assembly_setrootdir:
421 * @root_dir: The pathname of the root directory where we will locate assemblies
423 * This routine sets the internal default root directory for looking up
426 * This is used by Windows installations to compute dynamically the
427 * place where the Mono assemblies are located.
431 mono_assembly_setrootdir (const char *root_dir
)
434 * Override the MONO_ASSEMBLIES directory configured at compile time.
436 /* Leak if called more than once */
437 default_path
[0] = g_strdup (root_dir
);
441 * mono_assembly_getrootdir:
443 * Obtains the root directory used for looking up assemblies.
445 * Returns: a string with the directory, this string should not be freed.
447 G_CONST_RETURN gchar
*
448 mono_assembly_getrootdir (void)
450 return default_path
[0];
455 * @assembly_dir: the base directory for assemblies
456 * @config_dir: the base directory for configuration files
458 * This routine is used internally and by developers embedding
459 * the runtime into their own applications.
461 * There are a number of cases to consider: Mono as a system-installed
462 * package that is available on the location preconfigured or Mono in
463 * a relocated location.
465 * If you are using a system-installed Mono, you can pass NULL
466 * to both parameters. If you are not, you should compute both
467 * directory values and call this routine.
469 * The values for a given PREFIX are:
471 * assembly_dir: PREFIX/lib
472 * config_dir: PREFIX/etc
474 * Notice that embedders that use Mono in a relocated way must
475 * compute the location at runtime, as they will be in control
476 * of where Mono is installed.
479 mono_set_dirs (const char *assembly_dir
, const char *config_dir
)
481 #if defined (MONO_ASSEMBLIES)
482 if (assembly_dir
== NULL
)
483 assembly_dir
= MONO_ASSEMBLIES
;
485 #if defined (MONO_CFG_DIR)
486 if (config_dir
== NULL
)
487 config_dir
= MONO_CFG_DIR
;
489 mono_assembly_setrootdir (assembly_dir
);
490 mono_set_config_dir (config_dir
);
496 compute_base (char *path
)
498 char *p
= strrchr (path
, '/');
502 /* Not a well known Mono executable, we are embedded, cant guess the base */
503 if (strcmp (p
, "/mono") && strcmp (p
, "/monodis") && strcmp (p
, "/mint") && strcmp (p
, "/monodiet"))
507 p
= strrchr (path
, '/');
511 if (strcmp (p
, "/bin") != 0)
520 mono_set_dirs (MONO_ASSEMBLIES
, MONO_CFG_DIR
);
527 char *config
, *lib
, *mono
;
531 * Only /usr prefix is treated specially
533 if (strncmp (exe
, MONO_BINDIR
, strlen (MONO_BINDIR
)) == 0 || (base
= compute_base (exe
)) == NULL
){
538 config
= g_build_filename (base
, "etc", NULL
);
539 lib
= g_build_filename (base
, "lib", NULL
);
540 mono
= g_build_filename (lib
, "mono/1.0", NULL
);
541 if (stat (mono
, &buf
) == -1)
544 mono_set_dirs (lib
, config
);
552 #endif /* HOST_WIN32 */
557 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
558 * this auto-detects the prefix where Mono was installed.
561 mono_set_rootdir (void)
563 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
564 gchar
*bindir
, *installdir
, *root
, *name
, *config
;
567 name
= mono_get_module_file_name ((HMODULE
) &__ImageBase
);
571 * _NSGetExecutablePath may return -1 to indicate buf is not large
572 * enough, but we ignore that case to avoid having to do extra dynamic
573 * allocation for the path and hope that 4096 is enough - this is
574 * ok in the Linux/Solaris case below at least...
578 guint buf_size
= sizeof (buf
);
580 if (_NSGetExecutablePath (buf
, &buf_size
) == 0)
581 name
= g_strdup (buf
);
590 bindir
= g_path_get_dirname (name
);
591 installdir
= g_path_get_dirname (bindir
);
592 root
= g_build_path (G_DIR_SEPARATOR_S
, installdir
, "lib", NULL
);
594 config
= g_build_filename (root
, "..", "etc", NULL
);
596 mono_set_dirs (root
, config
);
598 if (g_file_test (root
, G_FILE_TEST_EXISTS
) && g_file_test (config
, G_FILE_TEST_EXISTS
))
599 mono_set_dirs (root
, config
);
609 #elif defined(DISABLE_MONO_AUTODETECTION)
617 s
= readlink ("/proc/self/exe", buf
, sizeof (buf
)-1);
625 /* Solaris 10 style */
626 str
= g_strdup_printf ("/proc/%d/path/a.out", getpid ());
627 s
= readlink (str
, buf
, sizeof (buf
)-1);
639 * mono_assemblies_init:
641 * Initialize global variables used by this module.
644 mono_assemblies_init (void)
647 * Initialize our internal paths if we have not been initialized yet.
648 * This happens when embedders use Mono.
650 if (mono_assembly_getrootdir () == NULL
)
654 check_extra_gac_path_env ();
656 InitializeCriticalSection (&assemblies_mutex
);
660 mono_assembly_fill_assembly_name (MonoImage
*image
, MonoAssemblyName
*aname
)
662 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLY
];
663 guint32 cols
[MONO_ASSEMBLY_SIZE
];
668 mono_metadata_decode_row (t
, 0, cols
, MONO_ASSEMBLY_SIZE
);
671 aname
->hash_value
= NULL
;
672 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_NAME
]);
673 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_CULTURE
]);
674 aname
->flags
= cols
[MONO_ASSEMBLY_FLAGS
];
675 aname
->major
= cols
[MONO_ASSEMBLY_MAJOR_VERSION
];
676 aname
->minor
= cols
[MONO_ASSEMBLY_MINOR_VERSION
];
677 aname
->build
= cols
[MONO_ASSEMBLY_BUILD_NUMBER
];
678 aname
->revision
= cols
[MONO_ASSEMBLY_REV_NUMBER
];
679 aname
->hash_alg
= cols
[MONO_ASSEMBLY_HASH_ALG
];
680 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
681 guchar
* token
= g_malloc (8);
686 pkey
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
687 len
= mono_metadata_decode_blob_size (pkey
, &pkey
);
688 aname
->public_key
= (guchar
*)pkey
;
690 mono_digest_get_public_token (token
, aname
->public_key
, len
);
691 encoded
= encode_public_tok (token
, 8);
692 g_strlcpy ((char*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
698 aname
->public_key
= NULL
;
699 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
702 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
703 aname
->public_key
= (guchar
*)mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
706 aname
->public_key
= 0;
712 * mono_stringify_assembly_name:
713 * @aname: the assembly name.
715 * Convert @aname into its string format. The returned string is dynamically
716 * allocated and should be freed by the caller.
718 * Returns: a newly allocated string with a string representation of
722 mono_stringify_assembly_name (MonoAssemblyName
*aname
)
724 return g_strdup_printf (
725 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
727 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
728 aname
->culture
&& *aname
->culture
? aname
->culture
: "neutral",
729 aname
->public_key_token
[0] ? (char *)aname
->public_key_token
: "null",
730 (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
734 assemblyref_public_tok (MonoImage
*image
, guint32 key_index
, guint32 flags
)
736 const gchar
*public_tok
;
739 public_tok
= mono_metadata_blob_heap (image
, key_index
);
740 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
742 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
744 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
745 return encode_public_tok (token
, 8);
748 return encode_public_tok ((guchar
*)public_tok
, len
);
752 * mono_assembly_addref:
753 * @assemnly: the assembly to reference
755 * This routine increments the reference count on a MonoAssembly.
756 * The reference count is reduced every time the method mono_assembly_close() is
760 mono_assembly_addref (MonoAssembly
*assembly
)
762 InterlockedIncrement (&assembly
->ref_count
);
765 static MonoAssemblyName
*
766 mono_assembly_remap_version (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_aname
)
768 const MonoRuntimeInfo
*current_runtime
;
769 int pos
, first
, last
;
771 if (aname
->name
== NULL
) return aname
;
772 current_runtime
= mono_get_runtime_info ();
775 last
= G_N_ELEMENTS (framework_assemblies
) - 1;
777 while (first
<= last
) {
779 pos
= first
+ (last
- first
) / 2;
780 res
= strcmp (aname
->name
, framework_assemblies
[pos
].assembly_name
);
782 const AssemblyVersionSet
* vset
;
783 int index
= framework_assemblies
[pos
].version_set_index
;
784 g_assert (index
< G_N_ELEMENTS (current_runtime
->version_sets
));
785 vset
= ¤t_runtime
->version_sets
[index
];
787 if (aname
->major
== vset
->major
&& aname
->minor
== vset
->minor
&&
788 aname
->build
== vset
->build
&& aname
->revision
== vset
->revision
)
791 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0)
792 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
793 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
795 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
796 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
799 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
800 dest_aname
->major
= vset
->major
;
801 dest_aname
->minor
= vset
->minor
;
802 dest_aname
->build
= vset
->build
;
803 dest_aname
->revision
= vset
->revision
;
805 } else if (res
< 0) {
815 * mono_assembly_get_assemblyref:
817 * Fill out ANAME with the assembly name of the INDEXth assembly reference in IMAGE.
820 mono_assembly_get_assemblyref (MonoImage
*image
, int index
, MonoAssemblyName
*aname
)
823 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
826 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
828 mono_metadata_decode_row (t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
);
830 hash
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
]);
831 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
832 aname
->hash_value
= hash
;
833 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_NAME
]);
834 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_CULTURE
]);
835 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
836 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
837 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
838 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
839 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
841 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
842 gchar
*token
= assemblyref_public_tok (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
);
843 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
846 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
851 mono_assembly_load_reference (MonoImage
*image
, int index
)
853 MonoAssembly
*reference
;
854 MonoAssemblyName aname
;
855 MonoImageOpenStatus status
;
858 * image->references is shared between threads, so we need to access
859 * it inside a critical section.
861 mono_assemblies_lock ();
862 if (!image
->references
) {
863 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
865 image
->references
= g_new0 (MonoAssembly
*, t
->rows
+ 1);
867 reference
= image
->references
[index
];
868 mono_assemblies_unlock ();
872 mono_assembly_get_assemblyref (image
, index
, &aname
);
874 if (image
->assembly
&& image
->assembly
->ref_only
) {
875 /* We use the loaded corlib */
876 if (!strcmp (aname
.name
, "mscorlib"))
877 reference
= mono_assembly_load_full (&aname
, image
->assembly
->basedir
, &status
, FALSE
);
879 reference
= mono_assembly_loaded_full (&aname
, TRUE
);
881 /* Try a postload search hook */
882 reference
= mono_assembly_invoke_search_hook_internal (&aname
, TRUE
, TRUE
);
886 * Here we must advice that the error was due to
887 * a non loaded reference using the ReflectionOnly api
890 reference
= REFERENCE_MISSING
;
892 reference
= mono_assembly_load (&aname
, image
->assembly
? image
->assembly
->basedir
: NULL
, &status
);
894 if (reference
== NULL
){
897 if (status
== MONO_IMAGE_ERROR_ERRNO
&& errno
== ENOENT
) {
898 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
: "" );
899 } else if (status
== MONO_IMAGE_ERROR_ERRNO
) {
900 extra_msg
= g_strdup_printf ("System error: %s\n", strerror (errno
));
901 } else if (status
== MONO_IMAGE_MISSING_ASSEMBLYREF
) {
902 extra_msg
= g_strdup ("Cannot find an assembly referenced from this one.\n");
903 } else if (status
== MONO_IMAGE_IMAGE_INVALID
) {
904 extra_msg
= g_strdup ("The file exists but is not a valid assembly.\n");
906 extra_msg
= g_strdup ("");
909 g_warning ("The following assembly referenced from %s could not be loaded:\n"
910 " Assembly: %s (assemblyref_index=%d)\n"
911 " Version: %d.%d.%d.%d\n"
912 " Public Key: %s\n%s",
913 image
->name
, aname
.name
, index
,
914 aname
.major
, aname
.minor
, aname
.build
, aname
.revision
,
915 strlen ((char*)aname
.public_key_token
) == 0 ? "(none)" : (char*)aname
.public_key_token
, extra_msg
);
919 mono_assemblies_lock ();
920 if (reference
== NULL
) {
921 /* Flag as not found */
922 reference
= REFERENCE_MISSING
;
925 if (!image
->references
[index
]) {
926 if (reference
!= REFERENCE_MISSING
){
927 mono_assembly_addref (reference
);
929 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly Ref addref %s %p -> %s %p: %d\n",
930 image
->assembly
->aname
.name
, image
->assembly
, reference
->aname
.name
, reference
, reference
->ref_count
);
933 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Failed to load assembly %s %p\n",
934 image
->assembly
->aname
.name
, image
->assembly
);
937 image
->references
[index
] = reference
;
939 mono_assemblies_unlock ();
941 if (image
->references
[index
] != reference
) {
942 /* Somebody loaded it before us */
943 mono_assembly_close (reference
);
948 mono_assembly_load_references (MonoImage
*image
, MonoImageOpenStatus
*status
)
950 /* This is a no-op now but it is part of the embedding API so we can't remove it */
951 *status
= MONO_IMAGE_OK
;
954 typedef struct AssemblyLoadHook AssemblyLoadHook
;
955 struct AssemblyLoadHook
{
956 AssemblyLoadHook
*next
;
957 MonoAssemblyLoadFunc func
;
961 AssemblyLoadHook
*assembly_load_hook
= NULL
;
964 mono_assembly_invoke_load_hook (MonoAssembly
*ass
)
966 AssemblyLoadHook
*hook
;
968 for (hook
= assembly_load_hook
; hook
; hook
= hook
->next
) {
969 hook
->func (ass
, hook
->user_data
);
974 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func
, gpointer user_data
)
976 AssemblyLoadHook
*hook
;
978 g_return_if_fail (func
!= NULL
);
980 hook
= g_new0 (AssemblyLoadHook
, 1);
982 hook
->user_data
= user_data
;
983 hook
->next
= assembly_load_hook
;
984 assembly_load_hook
= hook
;
988 free_assembly_load_hooks (void)
990 AssemblyLoadHook
*hook
, *next
;
992 for (hook
= assembly_load_hook
; hook
; hook
= next
) {
998 typedef struct AssemblySearchHook AssemblySearchHook
;
999 struct AssemblySearchHook
{
1000 AssemblySearchHook
*next
;
1001 MonoAssemblySearchFunc func
;
1007 AssemblySearchHook
*assembly_search_hook
= NULL
;
1009 static MonoAssembly
*
1010 mono_assembly_invoke_search_hook_internal (MonoAssemblyName
*aname
, gboolean refonly
, gboolean postload
)
1012 AssemblySearchHook
*hook
;
1014 for (hook
= assembly_search_hook
; hook
; hook
= hook
->next
) {
1015 if ((hook
->refonly
== refonly
) && (hook
->postload
== postload
)) {
1016 MonoAssembly
*ass
= hook
->func (aname
, hook
->user_data
);
1026 mono_assembly_invoke_search_hook (MonoAssemblyName
*aname
)
1028 return mono_assembly_invoke_search_hook_internal (aname
, FALSE
, FALSE
);
1032 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func
, gpointer user_data
, gboolean refonly
, gboolean postload
)
1034 AssemblySearchHook
*hook
;
1036 g_return_if_fail (func
!= NULL
);
1038 hook
= g_new0 (AssemblySearchHook
, 1);
1040 hook
->user_data
= user_data
;
1041 hook
->refonly
= refonly
;
1042 hook
->postload
= postload
;
1043 hook
->next
= assembly_search_hook
;
1044 assembly_search_hook
= hook
;
1048 mono_install_assembly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1050 mono_install_assembly_search_hook_internal (func
, user_data
, FALSE
, FALSE
);
1054 free_assembly_search_hooks (void)
1056 AssemblySearchHook
*hook
, *next
;
1058 for (hook
= assembly_search_hook
; hook
; hook
= next
) {
1065 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1067 mono_install_assembly_search_hook_internal (func
, user_data
, TRUE
, FALSE
);
1071 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1073 mono_install_assembly_search_hook_internal (func
, user_data
, FALSE
, TRUE
);
1077 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1079 mono_install_assembly_search_hook_internal (func
, user_data
, TRUE
, TRUE
);
1082 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook
;
1083 struct AssemblyPreLoadHook
{
1084 AssemblyPreLoadHook
*next
;
1085 MonoAssemblyPreLoadFunc func
;
1089 static AssemblyPreLoadHook
*assembly_preload_hook
= NULL
;
1090 static AssemblyPreLoadHook
*assembly_refonly_preload_hook
= NULL
;
1092 static MonoAssembly
*
1093 invoke_assembly_preload_hook (MonoAssemblyName
*aname
, gchar
**assemblies_path
)
1095 AssemblyPreLoadHook
*hook
;
1096 MonoAssembly
*assembly
;
1098 for (hook
= assembly_preload_hook
; hook
; hook
= hook
->next
) {
1099 assembly
= hook
->func (aname
, assemblies_path
, hook
->user_data
);
1100 if (assembly
!= NULL
)
1107 static MonoAssembly
*
1108 invoke_assembly_refonly_preload_hook (MonoAssemblyName
*aname
, gchar
**assemblies_path
)
1110 AssemblyPreLoadHook
*hook
;
1111 MonoAssembly
*assembly
;
1113 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= hook
->next
) {
1114 assembly
= hook
->func (aname
, assemblies_path
, hook
->user_data
);
1115 if (assembly
!= NULL
)
1123 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
1125 AssemblyPreLoadHook
*hook
;
1127 g_return_if_fail (func
!= NULL
);
1129 hook
= g_new0 (AssemblyPreLoadHook
, 1);
1131 hook
->user_data
= user_data
;
1132 hook
->next
= assembly_preload_hook
;
1133 assembly_preload_hook
= hook
;
1137 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
1139 AssemblyPreLoadHook
*hook
;
1141 g_return_if_fail (func
!= NULL
);
1143 hook
= g_new0 (AssemblyPreLoadHook
, 1);
1145 hook
->user_data
= user_data
;
1146 hook
->next
= assembly_refonly_preload_hook
;
1147 assembly_refonly_preload_hook
= hook
;
1151 free_assembly_preload_hooks (void)
1153 AssemblyPreLoadHook
*hook
, *next
;
1155 for (hook
= assembly_preload_hook
; hook
; hook
= next
) {
1160 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= next
) {
1167 absolute_dir (const gchar
*filename
)
1178 if (g_path_is_absolute (filename
)) {
1179 part
= g_path_get_dirname (filename
);
1180 res
= g_strconcat (part
, G_DIR_SEPARATOR_S
, NULL
);
1185 cwd
= g_get_current_dir ();
1186 mixed
= g_build_filename (cwd
, filename
, NULL
);
1187 parts
= g_strsplit (mixed
, G_DIR_SEPARATOR_S
, 0);
1192 for (i
= 0; (part
= parts
[i
]) != NULL
; i
++) {
1193 if (!strcmp (part
, "."))
1196 if (!strcmp (part
, "..")) {
1197 if (list
&& list
->next
) /* Don't remove root */
1198 list
= g_list_delete_link (list
, list
);
1200 list
= g_list_prepend (list
, part
);
1204 result
= g_string_new ("");
1205 list
= g_list_reverse (list
);
1207 /* Ignores last data pointer, which should be the filename */
1208 for (tmp
= list
; tmp
&& tmp
->next
!= NULL
; tmp
= tmp
->next
){
1210 g_string_append_printf (result
, "%s%c", (char *) tmp
->data
,
1215 g_string_free (result
, FALSE
);
1220 return g_strdup (".");
1227 * mono_assembly_open_from_bundle:
1228 * @filename: Filename requested
1229 * @status: return value
1231 * This routine tries to open the assembly specified by `filename' from the
1232 * defined bundles, if found, returns the MonoImage for it, if not found
1236 mono_assembly_open_from_bundle (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
1240 MonoImage
*image
= NULL
;
1243 * we do a very simple search for bundled assemblies: it's not a general
1244 * purpose assembly loading mechanism.
1250 name
= g_path_get_basename (filename
);
1252 mono_assemblies_lock ();
1253 for (i
= 0; !image
&& bundles
[i
]; ++i
) {
1254 if (strcmp (bundles
[i
]->name
, name
) == 0) {
1255 image
= mono_image_open_from_data_with_name ((char*)bundles
[i
]->data
, bundles
[i
]->size
, FALSE
, status
, refonly
, name
);
1259 mono_assemblies_unlock ();
1262 mono_image_addref (image
);
1269 mono_assembly_open_full (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
1273 MonoImageOpenStatus def_status
;
1277 g_return_val_if_fail (filename
!= NULL
, NULL
);
1280 status
= &def_status
;
1281 *status
= MONO_IMAGE_OK
;
1283 if (strncmp (filename
, "file://", 7) == 0) {
1284 GError
*error
= NULL
;
1285 gchar
*uri
= (gchar
*) filename
;
1289 * MS allows file://c:/... and fails on file://localhost/c:/...
1290 * They also throw an IndexOutOfRangeException if "file://"
1293 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
1296 uri
= mono_escape_uri_string (tmpuri
);
1297 fname
= g_filename_from_uri (uri
, NULL
, &error
);
1300 if (tmpuri
!= filename
)
1303 if (error
!= NULL
) {
1304 g_warning ("%s\n", error
->message
);
1305 g_error_free (error
);
1306 fname
= g_strdup (filename
);
1309 fname
= g_strdup (filename
);
1312 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1313 "Assembly Loader probing location: '%s'.", fname
);
1316 if (!mono_assembly_is_in_gac (fname
))
1317 new_fname
= mono_make_shadow_copy (fname
);
1318 if (new_fname
&& new_fname
!= fname
) {
1321 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1322 "Assembly Loader shadow-copied assembly to: '%s'.", fname
);
1327 if (bundles
!= NULL
)
1328 image
= mono_assembly_open_from_bundle (fname
, status
, refonly
);
1331 image
= mono_image_open_full (fname
, status
, refonly
);
1334 if (*status
== MONO_IMAGE_OK
)
1335 *status
= MONO_IMAGE_ERROR_ERRNO
;
1340 if (image
->assembly
) {
1341 /* Already loaded by another appdomain */
1342 mono_assembly_invoke_load_hook (image
->assembly
);
1343 mono_image_close (image
);
1345 return image
->assembly
;
1348 ass
= mono_assembly_load_from_full (image
, fname
, status
, refonly
);
1351 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1352 "Assembly Loader loaded assembly from location: '%s'.", filename
);
1354 mono_config_for_assembly (ass
->image
);
1357 /* Clear the reference added by mono_image_open */
1358 mono_image_close (image
);
1366 free_item (gpointer val
, gpointer user_data
)
1372 * mono_assembly_load_friends:
1375 * Load the list of friend assemblies that are allowed to access
1376 * the assembly's internal types and members. They are stored as assembly
1377 * names in custom attributes.
1379 * This is an internal method, we need this because when we load mscorlib
1380 * we do not have the mono_defaults.internals_visible_class loaded yet,
1381 * so we need to load these after we initialize the runtime.
1383 * LOCKING: Acquires the assemblies lock plus the loader lock.
1386 mono_assembly_load_friends (MonoAssembly
* ass
)
1389 MonoCustomAttrInfo
* attrs
;
1392 if (ass
->friend_assembly_names_inited
)
1395 attrs
= mono_custom_attrs_from_assembly (ass
);
1397 mono_assemblies_lock ();
1398 ass
->friend_assembly_names_inited
= TRUE
;
1399 mono_assemblies_unlock ();
1403 mono_assemblies_lock ();
1404 if (ass
->friend_assembly_names_inited
) {
1405 mono_assemblies_unlock ();
1408 mono_assemblies_unlock ();
1412 * We build the list outside the assemblies lock, the worse that can happen
1413 * is that we'll need to free the allocated list.
1415 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
1416 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
1417 MonoAssemblyName
*aname
;
1420 /* Do some sanity checking */
1421 if (!attr
->ctor
|| attr
->ctor
->klass
!= mono_defaults
.internals_visible_class
)
1423 if (attr
->data_size
< 4)
1425 data
= (const char*)attr
->data
;
1426 /* 0xFF means null string, see custom attr format */
1427 if (data
[0] != 1 || data
[1] != 0 || (data
[2] & 0xFF) == 0xFF)
1429 slen
= mono_metadata_decode_value (data
+ 2, &data
);
1430 aname
= g_new0 (MonoAssemblyName
, 1);
1431 /*g_print ("friend ass: %s\n", data);*/
1432 if (mono_assembly_name_parse_full (data
, aname
, TRUE
, NULL
, NULL
)) {
1433 list
= g_slist_prepend (list
, aname
);
1438 mono_custom_attrs_free (attrs
);
1440 mono_assemblies_lock ();
1441 if (ass
->friend_assembly_names_inited
) {
1442 mono_assemblies_unlock ();
1443 g_slist_foreach (list
, free_item
, NULL
);
1444 g_slist_free (list
);
1447 ass
->friend_assembly_names
= list
;
1449 /* Because of the double checked locking pattern above */
1450 mono_memory_barrier ();
1451 ass
->friend_assembly_names_inited
= TRUE
;
1452 mono_assemblies_unlock ();
1456 * mono_assembly_open:
1457 * @filename: Opens the assembly pointed out by this name
1458 * @status: where a status code can be returned
1460 * mono_assembly_open opens the PE-image pointed by @filename, and
1461 * loads any external assemblies referenced by it.
1463 * Return: a pointer to the MonoAssembly if @filename contains a valid
1464 * assembly or NULL on error. Details about the error are stored in the
1468 mono_assembly_open (const char *filename
, MonoImageOpenStatus
*status
)
1470 return mono_assembly_open_full (filename
, status
, FALSE
);
1474 mono_assembly_load_from_full (MonoImage
*image
, const char*fname
,
1475 MonoImageOpenStatus
*status
, gboolean refonly
)
1477 MonoAssembly
*ass
, *ass2
;
1480 if (!image
->tables
[MONO_TABLE_ASSEMBLY
].rows
) {
1481 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1482 *status
= MONO_IMAGE_IMAGE_INVALID
;
1486 #if defined (HOST_WIN32)
1491 tmp_fn
= g_strdup (fname
);
1492 for (i
= strlen (tmp_fn
) - 1; i
>= 0; i
--) {
1493 if (tmp_fn
[i
] == '/')
1497 base_dir
= absolute_dir (tmp_fn
);
1501 base_dir
= absolute_dir (fname
);
1505 * Create assembly struct, and enter it into the assembly cache
1507 ass
= g_new0 (MonoAssembly
, 1);
1508 ass
->basedir
= base_dir
;
1509 ass
->ref_only
= refonly
;
1512 mono_profiler_assembly_event (ass
, MONO_PROFILE_START_LOAD
);
1514 mono_assembly_fill_assembly_name (image
, &ass
->aname
);
1516 if (mono_defaults
.corlib
&& strcmp (ass
->aname
.name
, "mscorlib") == 0) {
1517 // MS.NET doesn't support loading other mscorlibs
1520 mono_image_addref (mono_defaults
.corlib
);
1521 *status
= MONO_IMAGE_OK
;
1522 return mono_defaults
.corlib
->assembly
;
1525 /* Add a non-temporary reference because of ass->image */
1526 mono_image_addref (image
);
1528 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
);
1531 * The load hooks might take locks so we can't call them while holding the
1534 if (ass
->aname
.name
) {
1535 ass2
= mono_assembly_invoke_search_hook_internal (&ass
->aname
, refonly
, FALSE
);
1539 mono_image_close (image
);
1540 *status
= MONO_IMAGE_OK
;
1545 mono_assemblies_lock ();
1547 if (image
->assembly
) {
1549 * This means another thread has already loaded the assembly, but not yet
1550 * called the load hooks so the search hook can't find the assembly.
1552 mono_assemblies_unlock ();
1553 ass2
= image
->assembly
;
1556 mono_image_close (image
);
1557 *status
= MONO_IMAGE_OK
;
1561 image
->assembly
= ass
;
1563 loaded_assemblies
= g_list_prepend (loaded_assemblies
, ass
);
1564 mono_assemblies_unlock ();
1567 if (image
->is_module_handle
)
1568 mono_image_fixup_vtable (image
);
1571 mono_assembly_invoke_load_hook (ass
);
1573 mono_profiler_assembly_loaded (ass
, MONO_PROFILE_OK
);
1579 mono_assembly_load_from (MonoImage
*image
, const char *fname
,
1580 MonoImageOpenStatus
*status
)
1582 return mono_assembly_load_from_full (image
, fname
, status
, FALSE
);
1586 * mono_assembly_name_free:
1587 * @aname: assembly name to free
1589 * Frees the provided assembly name object.
1590 * (it does not frees the object itself, only the name members).
1593 mono_assembly_name_free (MonoAssemblyName
*aname
)
1598 g_free ((void *) aname
->name
);
1599 g_free ((void *) aname
->culture
);
1600 g_free ((void *) aname
->hash_value
);
1604 parse_public_key (const gchar
*key
, gchar
** pubkey
)
1607 gchar header
[16], val
, *arr
;
1608 gint i
, j
, offset
, bitlen
, keylen
, pkeylen
;
1610 keylen
= strlen (key
) >> 1;
1614 val
= g_ascii_xdigit_value (key
[0]) << 4;
1615 val
|= g_ascii_xdigit_value (key
[1]);
1620 val
= g_ascii_xdigit_value (key
[24]);
1621 val
|= g_ascii_xdigit_value (key
[25]);
1633 /* We need the first 16 bytes
1634 * to check whether this key is valid or not */
1635 pkeylen
= strlen (pkey
) >> 1;
1639 for (i
= 0, j
= 0; i
< 16; i
++) {
1640 header
[i
] = g_ascii_xdigit_value (pkey
[j
++]) << 4;
1641 header
[i
] |= g_ascii_xdigit_value (pkey
[j
++]);
1644 if (header
[0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
1645 header
[1] != 0x02 || /* Version (0x02) */
1646 header
[2] != 0x00 || /* Reserved (word) */
1647 header
[3] != 0x00 ||
1648 (guint
)(read32 (header
+ 8)) != 0x31415352) /* DWORD magic = RSA1 */
1651 /* Based on this length, we _should_ be able to know if the length is right */
1652 bitlen
= read32 (header
+ 12) >> 3;
1653 if ((bitlen
+ 16 + 4) != pkeylen
)
1656 /* parsing is OK and the public key itself is not requested back */
1660 /* Encode the size of the blob */
1662 if (keylen
<= 127) {
1663 arr
= g_malloc (keylen
+ 1);
1664 arr
[offset
++] = keylen
;
1666 arr
= g_malloc (keylen
+ 2);
1667 arr
[offset
++] = 0x80; /* 10bs */
1668 arr
[offset
++] = keylen
;
1671 for (i
= offset
, j
= 0; i
< keylen
+ offset
; i
++) {
1672 arr
[i
] = g_ascii_xdigit_value (key
[j
++]) << 4;
1673 arr
[i
] |= g_ascii_xdigit_value (key
[j
++]);
1682 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
)
1684 gint major
, minor
, build
, revision
;
1687 gchar
*pkey
, *pkeyptr
, *encoded
, tok
[8];
1689 memset (aname
, 0, sizeof (MonoAssemblyName
));
1692 version_parts
= sscanf (version
, "%u.%u.%u.%u", &major
, &minor
, &build
, &revision
);
1693 if (version_parts
< 2 || version_parts
> 4)
1696 /* FIXME: we should set build & revision to -1 (instead of 0)
1697 if these are not set in the version string. That way, later on,
1698 we can still determine if these were specified. */
1699 aname
->major
= major
;
1700 aname
->minor
= minor
;
1701 if (version_parts
>= 3)
1702 aname
->build
= build
;
1705 if (version_parts
== 4)
1706 aname
->revision
= revision
;
1708 aname
->revision
= 0;
1711 aname
->flags
= flags
;
1712 aname
->name
= g_strdup (name
);
1715 if (g_ascii_strcasecmp (culture
, "neutral") == 0)
1716 aname
->culture
= g_strdup ("");
1718 aname
->culture
= g_strdup (culture
);
1721 if (token
&& strncmp (token
, "null", 4) != 0) {
1724 /* the constant includes the ending NULL, hence the -1 */
1725 if (strlen (token
) != (MONO_PUBLIC_KEY_TOKEN_LENGTH
- 1)) {
1726 mono_assembly_name_free (aname
);
1729 lower
= g_ascii_strdown (token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1730 g_strlcpy ((char*)aname
->public_key_token
, lower
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1735 if (strcmp (key
, "null") == 0 || !parse_public_key (key
, &pkey
)) {
1736 mono_assembly_name_free (aname
);
1740 len
= mono_metadata_decode_blob_size ((const gchar
*) pkey
, (const gchar
**) &pkeyptr
);
1741 // We also need to generate the key token
1742 mono_digest_get_public_token ((guchar
*) tok
, (guint8
*) pkeyptr
, len
);
1743 encoded
= encode_public_tok ((guchar
*) tok
, 8);
1744 g_strlcpy ((gchar
*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1747 if (save_public_key
)
1748 aname
->public_key
= (guint8
*) pkey
;
1757 parse_assembly_directory_name (const char *name
, const char *dirname
, MonoAssemblyName
*aname
)
1762 parts
= g_strsplit (dirname
, "_", 3);
1763 if (!parts
|| !parts
[0] || !parts
[1] || !parts
[2]) {
1768 res
= build_assembly_name (name
, parts
[0], parts
[1], parts
[2], NULL
, 0, aname
, FALSE
);
1774 mono_assembly_name_parse_full (const char *name
, MonoAssemblyName
*aname
, gboolean save_public_key
, gboolean
*is_version_defined
, gboolean
*is_token_defined
)
1777 gchar
*version
= NULL
;
1778 gchar
*culture
= NULL
;
1779 gchar
*token
= NULL
;
1781 gchar
*retargetable
= NULL
;
1786 gboolean version_defined
;
1787 gboolean token_defined
;
1790 if (!is_version_defined
)
1791 is_version_defined
= &version_defined
;
1792 *is_version_defined
= FALSE
;
1793 if (!is_token_defined
)
1794 is_token_defined
= &token_defined
;
1795 *is_token_defined
= FALSE
;
1797 parts
= tmp
= g_strsplit (name
, ",", 6);
1798 if (!tmp
|| !*tmp
) {
1803 dllname
= g_strstrip (*tmp
);
1808 value
= g_strstrip (*tmp
);
1809 if (!g_ascii_strncasecmp (value
, "Version=", 8)) {
1810 *is_version_defined
= TRUE
;
1811 version
= g_strstrip (value
+ 8);
1812 if (strlen (version
) == 0) {
1813 goto cleanup_and_fail
;
1819 if (!g_ascii_strncasecmp (value
, "Culture=", 8)) {
1820 culture
= g_strstrip (value
+ 8);
1821 if (strlen (culture
) == 0) {
1822 goto cleanup_and_fail
;
1828 if (!g_ascii_strncasecmp (value
, "PublicKeyToken=", 15)) {
1829 *is_token_defined
= TRUE
;
1830 token
= g_strstrip (value
+ 15);
1831 if (strlen (token
) == 0) {
1832 goto cleanup_and_fail
;
1838 if (!g_ascii_strncasecmp (value
, "PublicKey=", 10)) {
1839 key
= g_strstrip (value
+ 10);
1840 if (strlen (key
) == 0) {
1841 goto cleanup_and_fail
;
1847 if (!g_ascii_strncasecmp (value
, "Retargetable=", 13)) {
1848 retargetable
= g_strstrip (value
+ 13);
1849 if (strlen (retargetable
) == 0) {
1850 goto cleanup_and_fail
;
1852 if (!g_ascii_strcasecmp (retargetable
, "yes")) {
1853 flags
|= ASSEMBLYREF_RETARGETABLE_FLAG
;
1854 } else if (g_ascii_strcasecmp (retargetable
, "no")) {
1855 goto cleanup_and_fail
;
1861 if (!g_ascii_strncasecmp (value
, "ProcessorArchitecture=", 22)) {
1862 /* this is ignored for now, until we can change MonoAssemblyName */
1871 /* if retargetable flag is set, then we must have a fully qualified name */
1872 if (retargetable
!= NULL
&& (version
== NULL
|| culture
== NULL
|| (key
== NULL
&& token
== NULL
))) {
1873 goto cleanup_and_fail
;
1876 res
= build_assembly_name (dllname
, version
, culture
, token
, key
, flags
,
1877 aname
, save_public_key
);
1887 * mono_assembly_name_parse:
1888 * @name: name to parse
1889 * @aname: the destination assembly name
1891 * Parses an assembly qualified type name and assigns the name,
1892 * version, culture and token to the provided assembly name object.
1894 * Returns: true if the name could be parsed.
1897 mono_assembly_name_parse (const char *name
, MonoAssemblyName
*aname
)
1899 return mono_assembly_name_parse_full (name
, aname
, FALSE
, NULL
, NULL
);
1903 * mono_assembly_name_new:
1904 * @name: name to parse
1906 * Allocate a new MonoAssemblyName and fill its values from the
1909 * Returns: a newly allocated structure or NULL if there was any failure.
1912 mono_assembly_name_new (const char *name
)
1914 MonoAssemblyName
*aname
= g_new0 (MonoAssemblyName
, 1);
1915 if (mono_assembly_name_parse (name
, aname
))
1922 mono_assembly_name_get_name (MonoAssemblyName
*aname
)
1928 mono_assembly_name_get_culture (MonoAssemblyName
*aname
)
1930 return aname
->culture
;
1934 mono_assembly_name_get_pubkeytoken (MonoAssemblyName
*aname
)
1936 if (aname
->public_key_token
[0])
1937 return aname
->public_key_token
;
1942 mono_assembly_name_get_version (MonoAssemblyName
*aname
, uint16_t *minor
, uint16_t *build
, uint16_t *revision
)
1945 *minor
= aname
->minor
;
1947 *build
= aname
->build
;
1949 *revision
= aname
->revision
;
1950 return aname
->major
;
1953 static MonoAssembly
*
1954 probe_for_partial_name (const char *basepath
, const char *fullname
, MonoAssemblyName
*aname
, MonoImageOpenStatus
*status
)
1956 gchar
*fullpath
= NULL
;
1958 const char* direntry
;
1959 MonoAssemblyName gac_aname
;
1960 gint major
=-1, minor
=0, build
=0, revision
=0;
1961 gboolean exact_version
;
1963 dirhandle
= g_dir_open (basepath
, 0, NULL
);
1967 exact_version
= (aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0;
1969 while ((direntry
= g_dir_read_name (dirhandle
))) {
1970 gboolean match
= TRUE
;
1972 if(!parse_assembly_directory_name (aname
->name
, direntry
, &gac_aname
))
1975 if (aname
->culture
!= NULL
&& strcmp (aname
->culture
, gac_aname
.culture
) != 0)
1978 if (match
&& strlen ((char*)aname
->public_key_token
) > 0 &&
1979 !mono_public_tokens_are_equal (aname
->public_key_token
, gac_aname
.public_key_token
))
1983 if (exact_version
) {
1984 match
= (aname
->major
== gac_aname
.major
&& aname
->minor
== gac_aname
.minor
&&
1985 aname
->build
== gac_aname
.build
&& aname
->revision
== gac_aname
.revision
);
1987 else if (gac_aname
.major
< major
)
1989 else if (gac_aname
.major
== major
) {
1990 if (gac_aname
.minor
< minor
)
1992 else if (gac_aname
.minor
== minor
) {
1993 if (gac_aname
.build
< build
)
1995 else if (gac_aname
.build
== build
&& gac_aname
.revision
<= revision
)
2002 major
= gac_aname
.major
;
2003 minor
= gac_aname
.minor
;
2004 build
= gac_aname
.build
;
2005 revision
= gac_aname
.revision
;
2007 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, basepath
, direntry
, fullname
, NULL
);
2010 mono_assembly_name_free (&gac_aname
);
2013 g_dir_close (dirhandle
);
2015 if (fullpath
== NULL
)
2018 MonoAssembly
*res
= mono_assembly_open (fullpath
, status
);
2025 mono_assembly_load_with_partial_name (const char *name
, MonoImageOpenStatus
*status
)
2028 MonoAssemblyName
*aname
, base_name
, maped_aname
;
2029 gchar
*fullname
, *gacpath
;
2032 memset (&base_name
, 0, sizeof (MonoAssemblyName
));
2035 if (!mono_assembly_name_parse (name
, aname
))
2039 * If no specific version has been requested, make sure we load the
2040 * correct version for system assemblies.
2042 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) == 0)
2043 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
2045 res
= mono_assembly_loaded (aname
);
2047 mono_assembly_name_free (aname
);
2051 res
= invoke_assembly_preload_hook (aname
, assemblies_path
);
2053 res
->in_gac
= FALSE
;
2054 mono_assembly_name_free (aname
);
2058 fullname
= g_strdup_printf ("%s.dll", aname
->name
);
2060 if (extra_gac_paths
) {
2061 paths
= extra_gac_paths
;
2062 while (!res
&& *paths
) {
2063 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", aname
->name
, NULL
);
2064 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
2073 mono_assembly_name_free (aname
);
2077 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), "mono", "gac", aname
->name
, NULL
);
2078 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
2084 MonoDomain
*domain
= mono_domain_get ();
2085 MonoReflectionAssembly
*refasm
= mono_try_assembly_resolve (domain
, mono_string_new (domain
, name
), FALSE
);
2087 res
= refasm
->assembly
;
2091 mono_assembly_name_free (aname
);
2097 mono_assembly_is_in_gac (const gchar
*filename
)
2099 const gchar
*rootdir
;
2103 if (filename
== NULL
)
2106 for (paths
= extra_gac_paths
; paths
&& *paths
; paths
++) {
2107 if (strstr (*paths
, filename
) != *paths
)
2110 gp
= (gchar
*) (filename
+ strlen (*paths
));
2111 if (*gp
!= G_DIR_SEPARATOR
)
2114 if (strncmp (gp
, "lib", 3))
2117 if (*gp
!= G_DIR_SEPARATOR
)
2120 if (strncmp (gp
, "mono", 4))
2123 if (*gp
!= G_DIR_SEPARATOR
)
2126 if (strncmp (gp
, "gac", 3))
2129 if (*gp
!= G_DIR_SEPARATOR
)
2135 rootdir
= mono_assembly_getrootdir ();
2136 if (strstr (filename
, rootdir
) != filename
)
2139 gp
= (gchar
*) (filename
+ strlen (rootdir
));
2140 if (*gp
!= G_DIR_SEPARATOR
)
2143 if (strncmp (gp
, "mono", 4))
2146 if (*gp
!= G_DIR_SEPARATOR
)
2149 if (strncmp (gp
, "gac", 3))
2152 if (*gp
!= G_DIR_SEPARATOR
)
2158 mono_assembly_load_publisher_policy (MonoAssemblyName
*aname
)
2161 gchar
*filename
, *pname
, *name
, *culture
, *version
, *fullpath
, *subpath
;
2165 if (strstr (aname
->name
, ".dll")) {
2166 len
= strlen (aname
->name
) - 4;
2167 name
= g_malloc (len
);
2168 strncpy (name
, aname
->name
, len
);
2170 name
= g_strdup (aname
->name
);
2173 culture
= g_utf8_strdown (aname
->culture
, -1);
2175 culture
= g_strdup ("");
2177 pname
= g_strdup_printf ("policy.%d.%d.%s", aname
->major
, aname
->minor
, name
);
2178 version
= g_strdup_printf ("0.0.0.0_%s_%s", culture
, aname
->public_key_token
);
2182 filename
= g_strconcat (pname
, ".dll", NULL
);
2183 subpath
= g_build_path (G_DIR_SEPARATOR_S
, pname
, version
, filename
, NULL
);
2189 if (extra_gac_paths
) {
2190 paths
= extra_gac_paths
;
2191 while (!image
&& *paths
) {
2192 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
,
2193 "lib", "mono", "gac", subpath
, NULL
);
2194 image
= mono_image_open (fullpath
, NULL
);
2205 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
2206 "mono", "gac", subpath
, NULL
);
2207 image
= mono_image_open (fullpath
, NULL
);
2214 static MonoAssemblyName
*
2215 mono_assembly_bind_version (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
2217 memcpy (dest_name
, aname
, sizeof (MonoAssemblyName
));
2218 dest_name
->major
= info
->new_version
.major
;
2219 dest_name
->minor
= info
->new_version
.minor
;
2220 dest_name
->build
= info
->new_version
.build
;
2221 dest_name
->revision
= info
->new_version
.revision
;
2226 /* LOCKING: Assumes that we are already locked */
2227 static MonoAssemblyBindingInfo
*
2228 search_binding_loaded (MonoAssemblyName
*aname
)
2232 for (tmp
= loaded_assembly_bindings
; tmp
; tmp
= tmp
->next
) {
2233 MonoAssemblyBindingInfo
*info
= tmp
->data
;
2234 if (assembly_binding_maps_name (info
, aname
))
2241 static inline gboolean
2242 info_compare_versions (AssemblyVersionSet
*left
, AssemblyVersionSet
*right
)
2244 if (left
->major
!= right
->major
|| left
->minor
!= right
->minor
||
2245 left
->build
!= right
->build
|| left
->revision
!= right
->revision
)
2251 static inline gboolean
2252 info_versions_equal (MonoAssemblyBindingInfo
*left
, MonoAssemblyBindingInfo
*right
)
2254 if (left
->has_old_version_bottom
!= right
->has_old_version_bottom
)
2257 if (left
->has_old_version_top
!= right
->has_old_version_top
)
2260 if (left
->has_new_version
!= right
->has_new_version
)
2263 if (left
->has_old_version_bottom
&& !info_compare_versions (&left
->old_version_bottom
, &right
->old_version_bottom
))
2266 if (left
->has_old_version_top
&& !info_compare_versions (&left
->old_version_top
, &right
->old_version_top
))
2269 if (left
->has_new_version
&& !info_compare_versions (&left
->new_version
, &right
->new_version
))
2275 /* LOCKING: assumes all the necessary locks are held */
2277 assembly_binding_info_parsed (MonoAssemblyBindingInfo
*info
, void *user_data
)
2279 MonoAssemblyBindingInfo
*info_copy
;
2281 MonoAssemblyBindingInfo
*info_tmp
;
2282 MonoDomain
*domain
= (MonoDomain
*)user_data
;
2287 for (tmp
= domain
->assembly_bindings
; tmp
; tmp
= tmp
->next
) {
2288 info_tmp
= tmp
->data
;
2289 if (strcmp (info
->name
, info_tmp
->name
) == 0 && info_versions_equal (info
, info_tmp
))
2293 info_copy
= mono_mempool_alloc0 (domain
->mp
, sizeof (MonoAssemblyBindingInfo
));
2294 memcpy (info_copy
, info
, sizeof (MonoAssemblyBindingInfo
));
2296 info_copy
->name
= mono_mempool_strdup (domain
->mp
, info
->name
);
2298 info_copy
->culture
= mono_mempool_strdup (domain
->mp
, info
->culture
);
2300 domain
->assembly_bindings
= g_slist_append_mempool (domain
->mp
, domain
->assembly_bindings
, info_copy
);
2303 static inline gboolean
2304 info_major_minor_in_range (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
2306 if (!info
->has_old_version_bottom
)
2309 if (info
->old_version_bottom
.major
> aname
->major
|| info
->old_version_bottom
.minor
> aname
->minor
)
2312 if (info
->has_old_version_top
&& (info
->old_version_top
.major
< aname
->major
|| info
->old_version_top
.minor
< aname
->minor
))
2315 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2316 info
->major
= aname
->major
;
2317 info
->minor
= aname
->minor
;
2322 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2323 static MonoAssemblyBindingInfo
*
2324 get_per_domain_assembly_binding_info (MonoDomain
*domain
, MonoAssemblyName
*aname
)
2326 MonoAssemblyBindingInfo
*info
;
2329 if (!domain
->assembly_bindings
)
2333 for (list
= domain
->assembly_bindings
; list
; list
= list
->next
) {
2335 if (info
&& !strcmp (aname
->name
, info
->name
) && info_major_minor_in_range (info
, aname
))
2341 if (info
->name
&& info
->public_key_token
[0] && info
->has_old_version_bottom
&&
2342 info
->has_new_version
&& assembly_binding_maps_name (info
, aname
))
2343 info
->is_valid
= TRUE
;
2345 info
->is_valid
= FALSE
;
2351 static MonoAssemblyName
*
2352 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
2354 MonoAssemblyBindingInfo
*info
, *info2
;
2358 if (aname
->public_key_token
[0] == 0)
2361 domain
= mono_domain_get ();
2362 mono_loader_lock ();
2363 info
= search_binding_loaded (aname
);
2365 mono_domain_lock (domain
);
2366 info
= get_per_domain_assembly_binding_info (domain
, aname
);
2367 mono_domain_unlock (domain
);
2370 mono_loader_unlock ();
2372 if (!check_policy_versions (info
, aname
))
2375 mono_assembly_bind_version (info
, aname
, dest_name
);
2379 if (domain
&& domain
->setup
&& domain
->setup
->configuration_file
) {
2380 mono_domain_lock (domain
);
2381 if (!domain
->assembly_bindings_parsed
) {
2382 gchar
*domain_config_file
= mono_string_to_utf8 (domain
->setup
->configuration_file
);
2384 mono_config_parse_assembly_bindings (domain_config_file
, aname
->major
, aname
->minor
, domain
, assembly_binding_info_parsed
);
2385 domain
->assembly_bindings_parsed
= TRUE
;
2386 g_free (domain_config_file
);
2388 mono_domain_unlock (domain
);
2390 mono_loader_lock ();
2391 mono_domain_lock (domain
);
2392 info
= get_per_domain_assembly_binding_info (domain
, aname
);
2393 mono_domain_unlock (domain
);
2394 mono_loader_unlock ();
2398 info
= g_new0 (MonoAssemblyBindingInfo
, 1);
2399 info
->major
= aname
->major
;
2400 info
->minor
= aname
->minor
;
2403 if (!info
->is_valid
) {
2404 ppimage
= mono_assembly_load_publisher_policy (aname
);
2406 get_publisher_policy_info (ppimage
, aname
, info
);
2407 mono_image_close (ppimage
);
2411 /* Define default error value if needed */
2412 if (!info
->is_valid
) {
2413 info
->name
= g_strdup (aname
->name
);
2414 info
->culture
= g_strdup (aname
->culture
);
2415 g_strlcpy ((char *)info
->public_key_token
, (const char *)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
2418 mono_loader_lock ();
2419 info2
= search_binding_loaded (aname
);
2421 /* This binding was added by another thread
2423 mono_assembly_binding_info_free (info
);
2428 loaded_assembly_bindings
= g_slist_prepend (loaded_assembly_bindings
, info
);
2430 mono_loader_unlock ();
2432 if (!info
->is_valid
|| !check_policy_versions (info
, aname
))
2435 mono_assembly_bind_version (info
, aname
, dest_name
);
2440 * mono_assembly_load_from_gac
2442 * @aname: The assembly name object
2444 static MonoAssembly
*
2445 mono_assembly_load_from_gac (MonoAssemblyName
*aname
, gchar
*filename
, MonoImageOpenStatus
*status
, MonoBoolean refonly
)
2447 MonoAssembly
*result
= NULL
;
2448 gchar
*name
, *version
, *culture
, *fullpath
, *subpath
;
2453 if (aname
->public_key_token
[0] == 0) {
2457 if (strstr (aname
->name
, ".dll")) {
2458 len
= strlen (filename
) - 4;
2459 name
= g_malloc (len
);
2460 strncpy (name
, aname
->name
, len
);
2462 name
= g_strdup (aname
->name
);
2465 if (aname
->culture
) {
2466 culture
= g_utf8_strdown (aname
->culture
, -1);
2468 culture
= g_strdup ("");
2471 pubtok
= g_ascii_strdown ((char*)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
2472 version
= g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname
->major
,
2473 aname
->minor
, aname
->build
, aname
->revision
,
2477 subpath
= g_build_path (G_DIR_SEPARATOR_S
, name
, version
, filename
, NULL
);
2482 if (extra_gac_paths
) {
2483 paths
= extra_gac_paths
;
2484 while (!result
&& *paths
) {
2485 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", subpath
, NULL
);
2486 result
= mono_assembly_open_full (fullpath
, status
, refonly
);
2493 result
->in_gac
= TRUE
;
2498 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
2499 "mono", "gac", subpath
, NULL
);
2500 result
= mono_assembly_open_full (fullpath
, status
, refonly
);
2504 result
->in_gac
= TRUE
;
2513 mono_assembly_load_corlib (const MonoRuntimeInfo
*runtime
, MonoImageOpenStatus
*status
)
2518 /* g_print ("corlib already loaded\n"); */
2522 if (assemblies_path
) {
2523 corlib
= load_in_path ("mscorlib.dll", (const char**)assemblies_path
, status
, FALSE
);
2528 /* Load corlib from mono/<version> */
2530 corlib_file
= g_build_filename ("mono", runtime
->framework_version
, "mscorlib.dll", NULL
);
2531 if (assemblies_path
) {
2532 corlib
= load_in_path (corlib_file
, (const char**)assemblies_path
, status
, FALSE
);
2534 g_free (corlib_file
);
2538 corlib
= load_in_path (corlib_file
, default_path
, status
, FALSE
);
2539 g_free (corlib_file
);
2545 mono_assembly_load_full_nosearch (MonoAssemblyName
*aname
,
2546 const char *basedir
,
2547 MonoImageOpenStatus
*status
,
2550 MonoAssembly
*result
;
2551 char *fullpath
, *filename
;
2552 MonoAssemblyName maped_aname
, maped_name_pp
;
2557 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
2559 /* Reflection only assemblies don't get assembly binding */
2561 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
2563 result
= mono_assembly_loaded_full (aname
, refonly
);
2567 result
= refonly
? invoke_assembly_refonly_preload_hook (aname
, assemblies_path
) : invoke_assembly_preload_hook (aname
, assemblies_path
);
2569 result
->in_gac
= FALSE
;
2573 /* Currently we retrieve the loaded corlib for reflection
2574 * only requests, like a common reflection only assembly
2576 if (strcmp (aname
->name
, "mscorlib") == 0 || strcmp (aname
->name
, "mscorlib.dll") == 0) {
2577 return mono_assembly_load_corlib (mono_get_runtime_info (), status
);
2580 len
= strlen (aname
->name
);
2581 for (ext_index
= 0; ext_index
< 2; ext_index
++) {
2582 ext
= ext_index
== 0 ? ".dll" : ".exe";
2583 if (len
> 4 && (!strcmp (aname
->name
+ len
- 4, ".dll") || !strcmp (aname
->name
+ len
- 4, ".exe"))) {
2584 filename
= g_strdup (aname
->name
);
2585 /* Don't try appending .dll/.exe if it already has one of those extensions */
2588 filename
= g_strconcat (aname
->name
, ext
, NULL
);
2591 result
= mono_assembly_load_from_gac (aname
, filename
, status
, refonly
);
2598 fullpath
= g_build_filename (basedir
, filename
, NULL
);
2599 result
= mono_assembly_open_full (fullpath
, status
, refonly
);
2602 result
->in_gac
= FALSE
;
2608 result
= load_in_path (filename
, default_path
, status
, refonly
);
2610 result
->in_gac
= FALSE
;
2620 * mono_assembly_load_full:
2621 * @aname: A MonoAssemblyName with the assembly name to load.
2622 * @basedir: A directory to look up the assembly at.
2623 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2624 * @refonly: Whether this assembly is being opened in "reflection-only" mode.
2626 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2627 * attempts to load the assembly from that directory before probing the standard locations.
2629 * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no
2630 * assembly binding takes place.
2632 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
2633 * value pointed by status is updated with an error code.
2636 mono_assembly_load_full (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
, gboolean refonly
)
2638 MonoAssembly
*result
= mono_assembly_load_full_nosearch (aname
, basedir
, status
, refonly
);
2641 /* Try a postload search hook */
2642 result
= mono_assembly_invoke_search_hook_internal (aname
, refonly
, TRUE
);
2647 * mono_assembly_load:
2648 * @aname: A MonoAssemblyName with the assembly name to load.
2649 * @basedir: A directory to look up the assembly at.
2650 * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2652 * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2653 * attempts to load the assembly from that directory before probing the standard locations.
2655 * Returns: the assembly referenced by @aname loaded or NULL on error. On error the
2656 * value pointed by status is updated with an error code.
2659 mono_assembly_load (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
)
2661 return mono_assembly_load_full (aname
, basedir
, status
, FALSE
);
2665 mono_assembly_loaded_full (MonoAssemblyName
*aname
, gboolean refonly
)
2668 MonoAssemblyName maped_aname
;
2670 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
2672 res
= mono_assembly_invoke_search_hook_internal (aname
, refonly
, FALSE
);
2678 * mono_assembly_loaded:
2679 * @aname: an assembly to look for.
2681 * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
2682 * a MonoAssembly that matches the MonoAssemblyName specified.
2685 mono_assembly_loaded (MonoAssemblyName
*aname
)
2687 return mono_assembly_loaded_full (aname
, FALSE
);
2691 * Returns whether mono_assembly_close_finish() must be called as
2692 * well. See comment for mono_image_close_except_pools() for why we
2693 * unload in two steps.
2696 mono_assembly_close_except_image_pools (MonoAssembly
*assembly
)
2699 g_return_val_if_fail (assembly
!= NULL
, FALSE
);
2701 if (assembly
== REFERENCE_MISSING
)
2704 /* Might be 0 already */
2705 if (InterlockedDecrement (&assembly
->ref_count
) > 0)
2708 mono_profiler_assembly_event (assembly
, MONO_PROFILE_START_UNLOAD
);
2710 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Unloading assembly %s [%p].", assembly
->aname
.name
, assembly
);
2712 mono_debug_close_image (assembly
->image
);
2714 mono_assemblies_lock ();
2715 loaded_assemblies
= g_list_remove (loaded_assemblies
, assembly
);
2716 mono_assemblies_unlock ();
2718 assembly
->image
->assembly
= NULL
;
2720 if (!mono_image_close_except_pools (assembly
->image
))
2721 assembly
->image
= NULL
;
2723 for (tmp
= assembly
->friend_assembly_names
; tmp
; tmp
= tmp
->next
) {
2724 MonoAssemblyName
*fname
= tmp
->data
;
2725 mono_assembly_name_free (fname
);
2728 g_slist_free (assembly
->friend_assembly_names
);
2729 g_free (assembly
->basedir
);
2731 mono_profiler_assembly_event (assembly
, MONO_PROFILE_END_UNLOAD
);
2737 mono_assembly_close_finish (MonoAssembly
*assembly
)
2739 g_assert (assembly
&& assembly
!= REFERENCE_MISSING
);
2741 if (assembly
->image
)
2742 mono_image_close_finish (assembly
->image
);
2744 if (assembly
->dynamic
) {
2745 g_free ((char*)assembly
->aname
.culture
);
2752 * mono_assembly_close:
2753 * @assembly: the assembly to release.
2755 * This method releases a reference to the @assembly. The assembly is
2756 * only released when all the outstanding references to it are released.
2759 mono_assembly_close (MonoAssembly
*assembly
)
2761 if (mono_assembly_close_except_image_pools (assembly
))
2762 mono_assembly_close_finish (assembly
);
2766 mono_assembly_load_module (MonoAssembly
*assembly
, guint32 idx
)
2768 return mono_image_load_file_for_image (assembly
->image
, idx
);
2772 mono_assembly_foreach (GFunc func
, gpointer user_data
)
2777 * We make a copy of the list to avoid calling the callback inside the
2778 * lock, which could lead to deadlocks.
2780 mono_assemblies_lock ();
2781 copy
= g_list_copy (loaded_assemblies
);
2782 mono_assemblies_unlock ();
2784 g_list_foreach (loaded_assemblies
, func
, user_data
);
2790 * mono_assemblies_cleanup:
2792 * Free all resources used by this module.
2795 mono_assemblies_cleanup (void)
2799 DeleteCriticalSection (&assemblies_mutex
);
2801 for (l
= loaded_assembly_bindings
; l
; l
= l
->next
) {
2802 MonoAssemblyBindingInfo
*info
= l
->data
;
2804 mono_assembly_binding_info_free (info
);
2807 g_slist_free (loaded_assembly_bindings
);
2809 free_assembly_load_hooks ();
2810 free_assembly_search_hooks ();
2811 free_assembly_preload_hooks ();
2815 * Holds the assembly of the application, for
2816 * System.Diagnostics.Process::MainModule
2818 static MonoAssembly
*main_assembly
=NULL
;
2821 mono_assembly_set_main (MonoAssembly
*assembly
)
2823 main_assembly
= assembly
;
2827 * mono_assembly_get_main:
2829 * Returns: the assembly for the application, the first assembly that is loaded by the VM
2832 mono_assembly_get_main (void)
2834 return (main_assembly
);
2838 * mono_assembly_get_image:
2839 * @assembly: The assembly to retrieve the image from
2841 * Returns: the MonoImage associated with this assembly.
2844 mono_assembly_get_image (MonoAssembly
*assembly
)
2846 return assembly
->image
;
2850 mono_register_bundled_assemblies (const MonoBundledAssembly
**assemblies
)
2852 bundles
= assemblies
;
2855 #define MONO_DECLSEC_FORMAT_10 0x3C
2856 #define MONO_DECLSEC_FORMAT_20 0x2E
2857 #define MONO_DECLSEC_FIELD 0x53
2858 #define MONO_DECLSEC_PROPERTY 0x54
2860 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
2861 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
2862 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
2863 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
2864 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
2867 mono_assembly_try_decode_skip_verification_param (const char *p
, const char **resp
, gboolean
*abort_decoding
)
2871 case MONO_DECLSEC_PROPERTY
:
2873 case MONO_DECLSEC_FIELD
:
2875 *abort_decoding
= TRUE
;
2880 if (*p
++ != MONO_TYPE_BOOLEAN
) {
2881 *abort_decoding
= TRUE
;
2885 /* property name length */
2886 len
= mono_metadata_decode_value (p
, &p
);
2888 if (len
>= SKIP_VISIBILITY_PROPERTY_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_PROPERTY_NAME
, SKIP_VISIBILITY_PROPERTY_SIZE
)) {
2899 mono_assembly_try_decode_skip_verification (const char *p
, const char *endn
)
2901 int i
, j
, num
, len
, params_len
;
2903 if (*p
== MONO_DECLSEC_FORMAT_10
) {
2904 gsize read
, written
;
2905 char *res
= g_convert (p
, endn
- p
, "UTF-8", "UTF-16LE", &read
, &written
, NULL
);
2907 gboolean found
= strstr (res
, SKIP_VISIBILITY_XML_ATTRIBUTE
) != NULL
;
2913 if (*p
++ != MONO_DECLSEC_FORMAT_20
)
2916 /* number of encoded permission attributes */
2917 num
= mono_metadata_decode_value (p
, &p
);
2918 for (i
= 0; i
< num
; ++i
) {
2919 gboolean is_valid
= FALSE
;
2920 gboolean abort_decoding
= FALSE
;
2922 /* attribute name length */
2923 len
= mono_metadata_decode_value (p
, &p
);
2925 /* We don't really need to fully decode the type. Comparing the name is enough */
2926 is_valid
= len
>= SKIP_VISIBILITY_ATTRIBUTE_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_ATTRIBUTE_NAME
, SKIP_VISIBILITY_ATTRIBUTE_SIZE
);
2930 /*size of the params table*/
2931 params_len
= mono_metadata_decode_value (p
, &p
);
2933 const char *params_end
= p
+ params_len
;
2935 /* number of parameters */
2936 len
= mono_metadata_decode_value (p
, &p
);
2938 for (j
= 0; j
< len
; ++j
) {
2939 if (mono_assembly_try_decode_skip_verification_param (p
, &p
, &abort_decoding
))
2955 mono_assembly_has_skip_verification (MonoAssembly
*assembly
)
2958 guint32 cols
[MONO_DECL_SECURITY_SIZE
];
2962 if (MONO_SECMAN_FLAG_INIT (assembly
->skipverification
))
2963 return MONO_SECMAN_FLAG_GET_VALUE (assembly
->skipverification
);
2965 t
= &assembly
->image
->tables
[MONO_TABLE_DECLSECURITY
];
2967 for (i
= 0; i
< t
->rows
; ++i
) {
2968 mono_metadata_decode_row (t
, i
, cols
, MONO_DECL_SECURITY_SIZE
);
2969 if ((cols
[MONO_DECL_SECURITY_PARENT
] & MONO_HAS_DECL_SECURITY_MASK
) != MONO_HAS_DECL_SECURITY_ASSEMBLY
)
2971 if (cols
[MONO_DECL_SECURITY_ACTION
] != SECURITY_ACTION_REQMIN
)
2974 blob
= mono_metadata_blob_heap (assembly
->image
, cols
[MONO_DECL_SECURITY_PERMISSIONSET
]);
2975 len
= mono_metadata_decode_blob_size (blob
, &blob
);
2979 if (mono_assembly_try_decode_skip_verification (blob
, blob
+ len
)) {
2980 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, TRUE
);
2985 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, FALSE
);