2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc. http://www.ximian.com
19 #include "rawbuffer.h"
20 #include <mono/metadata/loader.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/domain-internals.h>
25 #include <mono/io-layer/io-layer.h>
26 #include <mono/utils/mono-uri.h>
27 #include <mono/metadata/mono-config.h>
28 #include <mono/utils/mono-digest.h>
29 #include <mono/utils/mono-logger.h>
31 #include <mono/os/util.h>
33 /* not used on Windows - see mono_set_rootdir () */
34 #define MONO_ASSEMBLIES NULL
38 /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
40 const char* assembly_name;
41 guint8 version_set_index;
44 /* the default search path is just MONO_ASSEMBLIES */
51 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
52 static char **assemblies_path = NULL;
54 /* Contains the list of directories that point to auxiliary GACs */
55 static char **extra_gac_paths = NULL;
57 /* The list of system assemblies what will be remapped to the running
58 * runtime version. WARNING: this list must be sorted.
60 static const AssemblyVersionMap framework_assemblies [] = {
62 {"Commons.Xml.Relaxng", 0},
69 {"Microsoft.VisualBasic", 1},
70 {"Microsoft.VisualC", 1},
72 {"Mono.CompilerServices.SymbolWriter", 0},
74 {"Mono.Data.SqliteClient", 0},
75 {"Mono.Data.SybaseClient", 0},
77 {"Mono.Data.TdsClient", 0},
78 {"Mono.GetOptions", 0},
82 {"Mono.Security.Win32", 0},
84 {"Novell.Directory.Ldap", 0},
88 {"System.Configuration.Install", 0},
90 {"System.Data.OracleClient", 0},
91 {"System.Data.SqlXml", 0},
93 {"System.DirectoryServices", 0},
94 {"System.Drawing", 0},
95 {"System.Drawing.Design", 0},
96 {"System.EnterpriseServices", 0},
97 {"System.Management", 0},
98 {"System.Messaging", 0},
99 {"System.Runtime.Remoting", 0},
100 {"System.Runtime.Serialization.Formatters.Soap", 0},
101 {"System.Security", 0},
102 {"System.ServiceProcess", 0},
104 {"System.Web.Mobile", 0},
105 {"System.Web.Services", 0},
106 {"System.Windows.Forms", 0},
112 * keeps track of loaded assemblies
114 static GList *loaded_assemblies = NULL;
115 static MonoAssembly *corlib;
117 /* This protects loaded_assemblies and image->references */
118 static CRITICAL_SECTION assemblies_mutex;
120 /* A hastable of thread->assembly list mappings */
121 static GHashTable *assemblies_loading;
123 /* A hashtable of reflection only load thread->assemblies mappings */
124 static GHashTable *assemblies_refonly_loading;
126 /* If defined, points to the bundled assembly information */
127 const MonoBundledAssembly **bundles;
129 /* Reflection only private hook functions */
130 static MonoAssembly* mono_assembly_refonly_invoke_search_hook (MonoAssemblyName *aname);
132 /* Loaded assembly binding info */
133 static GSList *loaded_assembly_bindings = NULL;
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 check_path_env (void)
157 path = g_getenv ("MONO_PATH");
161 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
163 g_strfreev (assemblies_path);
164 assemblies_path = splitted;
165 if (g_getenv ("MONO_DEBUG") == NULL)
169 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
170 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
177 check_extra_gac_path_env (void) {
181 path = g_getenv ("MONO_GAC_PREFIX");
185 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
187 g_strfreev (extra_gac_paths);
188 extra_gac_paths = splitted;
189 if (g_getenv ("MONO_DEBUG") == NULL)
193 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
194 g_warning ("'%s' in MONO_GAC_PATH doesn't exist or has wrong permissions.", *splitted);
201 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
203 if (strcmp (info->name, aname->name))
206 if (info->major != aname->major || info->minor != aname->minor)
209 if ((info->culture != NULL) != (aname->culture != NULL))
212 if (info->culture && strcmp (info->culture, aname->culture))
215 if (strcmp ((const char *)info->public_key_token, (const char *)aname->public_key_token))
222 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
225 g_free (info->culture);
229 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
232 guint32 cols [MONO_MANIFEST_SIZE];
233 const gchar *filename;
234 gchar *subpath, *fullpath;
236 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
237 /* MS Impl. accepts policy assemblies with more than
238 * one manifest resource, and only takes the first one */
240 binding_info->is_valid = FALSE;
244 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
245 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
246 binding_info->is_valid = FALSE;
250 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
251 g_assert (filename != NULL);
253 subpath = g_path_get_dirname (image->name);
254 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
255 mono_config_parse_publisher_policy (fullpath, binding_info);
259 /* Define the optional elements/attributes before checking */
260 if (!binding_info->culture)
261 binding_info->culture = g_strdup ("");
263 /* Check that the most important elements/attributes exist */
264 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
265 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
266 mono_assembly_binding_info_free (binding_info);
267 binding_info->is_valid = FALSE;
271 binding_info->is_valid = TRUE;
275 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
277 if (v->major > aname->major)
279 else if (v->major < aname->major)
282 if (v->minor > aname->minor)
284 else if (v->minor < aname->minor)
287 if (v->build > aname->build)
289 else if (v->build < aname->build)
292 if (v->revision > aname->revision)
294 else if (v->revision < aname->revision)
301 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
306 /* If has_old_version_top doesn't exist, we don't have an interval */
307 if (!info->has_old_version_top) {
308 if (compare_versions (&info->old_version_bottom, name) == 0)
314 /* Check that the version defined by name is valid for the interval */
315 if (compare_versions (&info->old_version_top, name) < 0)
318 /* We should be greater or equal than the small version */
319 if (compare_versions (&info->old_version_bottom, name) > 0)
326 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
328 if (!l->name || !r->name)
331 if (strcmp (l->name, r->name))
334 if (l->culture && r->culture && strcmp (l->culture, r->culture))
337 if (l->major != r->major || l->minor != r->minor ||
338 l->build != r->build || l->revision != r->revision)
339 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)))
342 if (!l->public_key_token [0] || !r->public_key_token [0])
345 if (strcmp (l->public_key_token, r->public_key_token))
352 search_loaded (MonoAssemblyName* aname, gboolean refonly)
358 ass = refonly ? mono_assembly_refonly_invoke_search_hook (aname) : mono_assembly_invoke_search_hook (aname);
363 * The assembly might be under load by this thread. In this case, it is
364 * safe to return an incomplete instance to prevent loops.
366 loading = g_hash_table_lookup (refonly ? assemblies_refonly_loading : assemblies_loading, GetCurrentThread ());
367 for (tmp = loading; tmp; tmp = tmp->next) {
369 if (!mono_assembly_names_equal (aname, &ass->aname))
378 static MonoAssembly *
379 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
383 MonoAssembly *result;
385 for (i = 0; search_path [i]; ++i) {
386 fullpath = g_build_filename (search_path [i], basename, NULL);
387 result = mono_assembly_open_full (fullpath, status, refonly);
396 * mono_assembly_setrootdir:
397 * @root_dir: The pathname of the root directory where we will locate assemblies
399 * This routine sets the internal default root directory for looking up
400 * assemblies. This is used by Windows installations to compute dynamically
401 * the place where the Mono assemblies are located.
405 mono_assembly_setrootdir (const char *root_dir)
408 * Override the MONO_ASSEMBLIES directory configured at compile time.
410 /* Leak if called more than once */
411 default_path [0] = g_strdup (root_dir);
414 G_CONST_RETURN gchar *
415 mono_assembly_getrootdir (void)
417 return default_path [0];
421 * mono_assemblies_init:
423 * Initialize global variables used by this module.
426 mono_assemblies_init (void)
428 #ifdef PLATFORM_WIN32
433 check_extra_gac_path_env ();
435 InitializeCriticalSection (&assemblies_mutex);
437 assemblies_loading = g_hash_table_new (NULL, NULL);
438 assemblies_refonly_loading = g_hash_table_new (NULL, NULL);
442 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
444 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
445 guint32 cols [MONO_ASSEMBLY_SIZE];
450 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
453 aname->hash_value = NULL;
454 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
455 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
456 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
457 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
458 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
459 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
460 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
461 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
462 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
463 gchar* token = g_malloc (8);
467 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
468 len = mono_metadata_decode_blob_size (aname->public_key, (const char**)&aname->public_key);
470 mono_digest_get_public_token (token, aname->public_key, len);
471 encoded = encode_public_tok (token, 8);
472 g_strlcpy (aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
478 aname->public_key = NULL;
479 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
482 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
483 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
486 aname->public_key = 0;
492 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
494 const gchar *public_tok;
497 public_tok = mono_metadata_blob_heap (image, key_index);
498 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
500 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
502 mono_digest_get_public_token (token, public_tok, len);
503 return encode_public_tok (token, 8);
506 return encode_public_tok (public_tok, len);
510 mono_assembly_addref (MonoAssembly *assembly)
512 InterlockedIncrement (&assembly->ref_count);
515 static MonoAssemblyName *
516 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
518 const MonoRuntimeInfo *current_runtime;
519 int pos, first, last;
521 if (aname->name == NULL) return aname;
522 current_runtime = mono_get_runtime_info ();
525 last = G_N_ELEMENTS (framework_assemblies) - 1;
527 while (first <= last) {
529 pos = first + (last - first) / 2;
530 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
532 const AssemblyVersionSet* vset;
533 int index = framework_assemblies[pos].version_set_index;
534 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
535 vset = ¤t_runtime->version_sets [index];
537 if (aname->major == vset->major && aname->minor == vset->minor &&
538 aname->build == vset->build && aname->revision == vset->revision)
541 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
542 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
543 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
545 aname->major, aname->minor, aname->build, aname->revision,
546 vset->major, vset->minor, vset->build, vset->revision
549 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
550 dest_aname->major = vset->major;
551 dest_aname->minor = vset->minor;
552 dest_aname->build = vset->build;
553 dest_aname->revision = vset->revision;
555 } else if (res < 0) {
565 mono_assembly_load_reference (MonoImage *image, int index)
568 guint32 cols [MONO_ASSEMBLYREF_SIZE];
570 MonoAssembly *reference;
571 MonoAssemblyName aname;
572 MonoImageOpenStatus status;
575 * image->references is shared between threads, so we need to access
576 * it inside a critical section.
578 EnterCriticalSection (&assemblies_mutex);
579 reference = image->references [index];
580 LeaveCriticalSection (&assemblies_mutex);
584 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
586 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
588 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
589 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
590 aname.hash_value = hash;
591 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
592 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
593 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
594 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
595 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
596 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
597 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
599 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
600 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname.flags);
601 g_strlcpy (aname.public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
604 memset (aname.public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
607 if (image->assembly->ref_only) {
608 /* We use the loaded corlib */
609 if (!strcmp (aname.name, "mscorlib"))
610 reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
612 reference = mono_assembly_loaded_full (&aname, TRUE);
614 * Here we must advice that the error was due to
615 * a non loaded reference using the ReflectionOnly api
618 reference = (gpointer)-1;
620 reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
622 if (reference == NULL){
623 char *extra_msg = g_strdup ("");
625 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
626 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->basedir);
627 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
628 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
629 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
630 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
631 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
632 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
635 g_warning ("The following assembly referenced from %s could not be loaded:\n"
636 " Assembly: %s (assemblyref_index=%d)\n"
637 " Version: %d.%d.%d.%d\n"
638 " Public Key: %s\n%s",
639 image->name, aname.name, index,
640 aname.major, aname.minor, aname.build, aname.revision,
641 strlen(aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
645 EnterCriticalSection (&assemblies_mutex);
646 if (reference == NULL) {
647 /* Flag as not found */
648 reference = (gpointer)-1;
650 mono_assembly_addref (reference);
653 if (!image->references [index])
654 image->references [index] = reference;
655 LeaveCriticalSection (&assemblies_mutex);
657 if (image->references [index] != reference) {
658 /* Somebody loaded it before us */
659 mono_assembly_close (reference);
664 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
669 *status = MONO_IMAGE_OK;
671 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
673 image->references = g_new0 (MonoAssembly *, t->rows + 1);
675 /* resolve assembly references for modules */
676 for (i = 0; i < image->module_count; i++){
677 if (image->modules [i]) {
678 image->modules [i]->assembly = image->assembly;
679 mono_assembly_load_references (image->modules [i], status);
684 typedef struct AssemblyLoadHook AssemblyLoadHook;
685 struct AssemblyLoadHook {
686 AssemblyLoadHook *next;
687 MonoAssemblyLoadFunc func;
691 AssemblyLoadHook *assembly_load_hook = NULL;
694 mono_assembly_invoke_load_hook (MonoAssembly *ass)
696 AssemblyLoadHook *hook;
698 for (hook = assembly_load_hook; hook; hook = hook->next) {
699 hook->func (ass, hook->user_data);
704 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
706 AssemblyLoadHook *hook;
708 g_return_if_fail (func != NULL);
710 hook = g_new0 (AssemblyLoadHook, 1);
712 hook->user_data = user_data;
713 hook->next = assembly_load_hook;
714 assembly_load_hook = hook;
717 typedef struct AssemblySearchHook AssemblySearchHook;
718 struct AssemblySearchHook {
719 AssemblySearchHook *next;
720 MonoAssemblySearchFunc func;
724 AssemblySearchHook *assembly_search_hook = NULL;
725 static AssemblySearchHook *assembly_refonly_search_hook = NULL;
728 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
730 AssemblySearchHook *hook;
732 for (hook = assembly_search_hook; hook; hook = hook->next) {
733 MonoAssembly *ass = hook->func (aname, hook->user_data);
742 mono_assembly_refonly_invoke_search_hook (MonoAssemblyName *aname)
744 AssemblySearchHook *hook;
746 for (hook = assembly_refonly_search_hook; hook; hook = hook->next) {
747 MonoAssembly *ass = hook->func (aname, hook->user_data);
756 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
758 AssemblySearchHook *hook;
760 g_return_if_fail (func != NULL);
762 hook = g_new0 (AssemblySearchHook, 1);
764 hook->user_data = user_data;
765 hook->next = assembly_search_hook;
766 assembly_search_hook = hook;
770 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
772 AssemblySearchHook *hook;
774 g_return_if_fail (func != NULL);
776 hook = g_new0 (AssemblySearchHook, 1);
778 hook->user_data = user_data;
779 hook->next = assembly_refonly_search_hook;
780 assembly_refonly_search_hook = hook;
783 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
784 struct AssemblyPreLoadHook {
785 AssemblyPreLoadHook *next;
786 MonoAssemblyPreLoadFunc func;
790 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
791 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
793 static MonoAssembly *
794 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
796 AssemblyPreLoadHook *hook;
797 MonoAssembly *assembly;
799 for (hook = assembly_preload_hook; hook; hook = hook->next) {
800 assembly = hook->func (aname, assemblies_path, hook->user_data);
801 if (assembly != NULL)
808 static MonoAssembly *
809 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
811 AssemblyPreLoadHook *hook;
812 MonoAssembly *assembly;
814 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
815 assembly = hook->func (aname, assemblies_path, hook->user_data);
816 if (assembly != NULL)
824 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
826 AssemblyPreLoadHook *hook;
828 g_return_if_fail (func != NULL);
830 hook = g_new0 (AssemblyPreLoadHook, 1);
832 hook->user_data = user_data;
833 hook->next = assembly_preload_hook;
834 assembly_preload_hook = hook;
838 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
840 AssemblyPreLoadHook *hook;
842 g_return_if_fail (func != NULL);
844 hook = g_new0 (AssemblyPreLoadHook, 1);
846 hook->user_data = user_data;
847 hook->next = assembly_refonly_preload_hook;
848 assembly_refonly_preload_hook = hook;
852 absolute_dir (const gchar *filename)
863 if (g_path_is_absolute (filename))
864 return g_path_get_dirname (filename);
866 cwd = g_get_current_dir ();
867 mixed = g_build_filename (cwd, filename, NULL);
868 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
873 for (i = 0; (part = parts [i]) != NULL; i++) {
874 if (!strcmp (part, "."))
877 if (!strcmp (part, "..")) {
878 if (list && list->next) /* Don't remove root */
879 list = g_list_delete_link (list, list);
881 list = g_list_prepend (list, part);
885 result = g_string_new ("");
886 list = g_list_reverse (list);
888 /* Ignores last data pointer, which should be the filename */
889 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
891 g_string_append_printf (result, "%s%c", (char *) tmp->data,
895 g_string_free (result, FALSE);
900 return g_strdup (".");
907 * mono_assembly_open_from_bundle:
908 * @filename: Filename requested
909 * @status: return value
911 * This routine tries to open the assembly specified by `filename' from the
912 * defined bundles, if found, returns the MonoImage for it, if not found
916 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
919 char *name = g_path_get_basename (filename);
920 MonoImage *image = NULL;
923 * we do a very simple search for bundled assemblies: it's not a general
924 * purpose assembly loading mechanism.
926 EnterCriticalSection (&assemblies_mutex);
927 for (i = 0; !image && bundles [i]; ++i) {
928 if (strcmp (bundles [i]->name, name) == 0) {
929 image = mono_image_open_from_data_full ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly);
933 LeaveCriticalSection (&assemblies_mutex);
936 mono_image_addref (image);
943 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
945 MonoImage *image = NULL;
947 if (bundles != NULL){
948 image = mono_assembly_open_from_bundle (filename, status, refonly);
953 EnterCriticalSection (&assemblies_mutex);
954 image = mono_image_open_full (filename, status, refonly);
955 LeaveCriticalSection (&assemblies_mutex);
961 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
965 MonoImageOpenStatus def_status;
968 g_return_val_if_fail (filename != NULL, NULL);
971 status = &def_status;
972 *status = MONO_IMAGE_OK;
974 if (strncmp (filename, "file://", 7) == 0) {
975 GError *error = NULL;
976 gchar *uri = (gchar *) filename;
980 * MS allows file://c:/... and fails on file://localhost/c:/...
981 * They also throw an IndexOutOfRangeException if "file://"
984 uri = g_strdup_printf ("file:///%s", uri + 7);
987 uri = mono_escape_uri_string (tmpuri);
988 fname = g_filename_from_uri (uri, NULL, &error);
991 if (tmpuri != filename)
995 g_warning ("%s\n", error->message);
996 g_error_free (error);
997 fname = g_strdup (filename);
1000 fname = g_strdup (filename);
1003 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1004 "Assembly Loader probing location: '%s'.", filename);
1005 image = do_mono_assembly_open (fname, status, refonly);
1008 *status = MONO_IMAGE_ERROR_ERRNO;
1013 ass = mono_assembly_load_from_full (image, fname, status, refonly);
1016 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1017 "Assembly Loader loaded assembly from location: '%s'.", filename);
1019 mono_config_for_assembly (ass->image);
1028 * mono_assembly_open:
1029 * @filename: Opens the assembly pointed out by this name
1030 * @status: where a status code can be returned
1032 * mono_assembly_open opens the PE-image pointed by @filename, and
1033 * loads any external assemblies referenced by it.
1035 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
1039 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1041 return mono_assembly_open_full (filename, status, FALSE);
1045 mono_assembly_load_from_full (MonoImage *image, const char*fname,
1046 MonoImageOpenStatus *status, gboolean refonly)
1048 MonoAssembly *ass, *ass2;
1051 GHashTable *ass_loading;
1053 #if defined (PLATFORM_WIN32)
1058 tmp_fn = g_strdup (fname);
1059 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1060 if (tmp_fn [i] == '/')
1064 base_dir = absolute_dir (tmp_fn);
1068 base_dir = absolute_dir (fname);
1072 * To avoid deadlocks and scalability problems, we load assemblies outside
1073 * the assembly lock. This means that multiple threads might try to load
1074 * the same assembly at the same time. The first one to load it completely
1075 * "wins", the other threads free their copy and use the one loaded by
1076 * the winning thread.
1080 * Create assembly struct, and enter it into the assembly cache
1082 ass = g_new0 (MonoAssembly, 1);
1083 ass->basedir = base_dir;
1084 ass->ref_only = refonly;
1088 mono_assembly_fill_assembly_name (image, &ass->aname);
1091 * Atomically search the loaded list and add ourselves to it if necessary.
1093 EnterCriticalSection (&assemblies_mutex);
1094 if (ass->aname.name) {
1095 /* avoid loading the same assembly twice for now... */
1096 ass2 = search_loaded (&ass->aname, refonly);
1100 mono_image_close (image);
1101 *status = MONO_IMAGE_OK;
1102 LeaveCriticalSection (&assemblies_mutex);
1106 ass_loading = refonly ? assemblies_refonly_loading : assemblies_loading;
1107 loading = g_hash_table_lookup (ass_loading, GetCurrentThread ());
1108 loading = g_list_prepend (loading, ass);
1109 g_hash_table_insert (ass_loading, GetCurrentThread (), loading);
1110 LeaveCriticalSection (&assemblies_mutex);
1112 image->assembly = ass;
1114 mono_assembly_load_references (image, status);
1116 EnterCriticalSection (&assemblies_mutex);
1118 loading = g_hash_table_lookup (ass_loading, GetCurrentThread ());
1119 loading = g_list_remove (loading, ass);
1120 if (loading == NULL)
1121 /* Prevent memory leaks */
1122 g_hash_table_remove (ass_loading, GetCurrentThread ());
1124 g_hash_table_insert (ass_loading, GetCurrentThread (), loading);
1125 if (*status != MONO_IMAGE_OK) {
1126 LeaveCriticalSection (&assemblies_mutex);
1127 mono_assembly_close (ass);
1131 if (ass->aname.name) {
1132 ass2 = search_loaded (&ass->aname, refonly);
1134 /* Somebody else has loaded the assembly before us */
1135 LeaveCriticalSection (&assemblies_mutex);
1136 mono_assembly_close (ass);
1141 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1142 LeaveCriticalSection (&assemblies_mutex);
1144 mono_assembly_invoke_load_hook (ass);
1150 mono_assembly_load_from (MonoImage *image, const char *fname,
1151 MonoImageOpenStatus *status)
1153 return mono_assembly_load_from_full (image, fname, status, FALSE);
1157 * mono_assembly_name_free:
1158 * @aname: assembly name to free
1160 * Frees the provided assembly name object.
1161 * (it does not frees the object itself, only the name members).
1164 mono_assembly_name_free (MonoAssemblyName *aname)
1169 g_free ((void *) aname->name);
1170 g_free ((void *) aname->culture);
1171 g_free ((void *) aname->hash_value);
1175 build_assembly_name (const char *name, const char *version, const char *culture, const char *token, MonoAssemblyName *aname)
1177 gint major, minor, build, revision;
1179 memset (aname, 0, sizeof (MonoAssemblyName));
1182 if (sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4)
1185 aname->major = major;
1186 aname->minor = minor;
1187 aname->build = build;
1188 aname->revision = revision;
1191 aname->name = g_strdup (name);
1194 if (g_strcasecmp (culture, "neutral") == 0)
1195 aname->culture = g_strdup ("");
1197 aname->culture = g_strdup (culture);
1200 if (token && strncmp (token, "null", 4) != 0)
1201 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1207 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
1212 parts = g_strsplit (dirname, "_", 3);
1213 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
1218 res = build_assembly_name (name, parts[0], parts[1], parts[2], aname);
1224 * mono_assembly_name_parse:
1225 * @name: name to parse
1226 * @aname: the destination assembly name
1227 * Returns: true if the name could be parsed.
1229 * Parses an assembly qualified type name and assigns the name,
1230 * version, culture and token to the provided assembly name object.
1233 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
1236 gchar *version = NULL;
1237 gchar *culture = NULL;
1238 gchar *token = NULL;
1244 parts = tmp = g_strsplit (name, ",", 4);
1245 if (!tmp || !*tmp) {
1250 dllname = g_strstrip (*tmp);
1255 value = g_strstrip (*tmp);
1256 if (!g_ascii_strncasecmp (value, "Version=", 8)) {
1257 version = g_strstrip (value + 8);
1262 if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
1263 culture = g_strstrip (value + 8);
1268 if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
1269 token = g_strstrip (value + 15);
1278 res = build_assembly_name (dllname, version, culture, token, aname);
1283 static MonoAssembly*
1284 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
1286 gchar *fullpath = NULL;
1288 const char* direntry;
1289 MonoAssemblyName gac_aname;
1290 gint major=-1, minor=0, build=0, revision=0;
1291 gboolean exact_version;
1293 dirhandle = g_dir_open (basepath, 0, NULL);
1297 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
1299 while ((direntry = g_dir_read_name (dirhandle))) {
1300 gboolean match = TRUE;
1302 parse_assembly_directory_name (aname->name, direntry, &gac_aname);
1304 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
1307 if (match && strlen ((char*)aname->public_key_token) > 0 &&
1308 strcmp ((char*)aname->public_key_token, (char*)gac_aname.public_key_token) != 0)
1312 if (exact_version) {
1313 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
1314 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
1316 else if (gac_aname.major < major)
1318 else if (gac_aname.major == major) {
1319 if (gac_aname.minor < minor)
1321 else if (gac_aname.minor == minor) {
1322 if (gac_aname.build < build)
1324 else if (gac_aname.build == build && gac_aname.revision <= revision)
1331 major = gac_aname.major;
1332 minor = gac_aname.minor;
1333 build = gac_aname.build;
1334 revision = gac_aname.revision;
1336 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
1339 mono_assembly_name_free (&gac_aname);
1342 g_dir_close (dirhandle);
1344 if (fullpath == NULL)
1347 MonoAssembly *res = mono_assembly_open (fullpath, status);
1354 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
1357 MonoAssemblyName *aname, base_name, maped_aname;
1358 gchar *fullname, *gacpath;
1361 memset (&base_name, 0, sizeof (MonoAssemblyName));
1364 if (!mono_assembly_name_parse (name, aname))
1368 * If no specific version has been requested, make sure we load the
1369 * correct version for system assemblies.
1371 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
1372 aname = mono_assembly_remap_version (aname, &maped_aname);
1374 res = mono_assembly_loaded (aname);
1376 mono_assembly_name_free (aname);
1380 res = invoke_assembly_preload_hook (aname, assemblies_path);
1382 res->in_gac = FALSE;
1383 mono_assembly_name_free (aname);
1387 fullname = g_strdup_printf ("%s.dll", aname->name);
1389 if (extra_gac_paths) {
1390 paths = extra_gac_paths;
1391 while (!res && *paths) {
1392 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
1393 res = probe_for_partial_name (gacpath, fullname, aname, status);
1402 mono_assembly_name_free (aname);
1406 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
1407 res = probe_for_partial_name (gacpath, fullname, aname, status);
1414 mono_assembly_name_free (aname);
1420 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
1423 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
1427 if (strstr (aname->name, ".dll")) {
1428 len = strlen (aname->name) - 4;
1429 name = g_malloc (len);
1430 strncpy (name, aname->name, len);
1432 name = g_strdup (aname->name);
1434 if (aname->culture) {
1435 culture = g_strdup (aname->culture);
1436 g_strdown (culture);
1438 culture = g_strdup ("");
1440 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
1441 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
1445 filename = g_strconcat (pname, ".dll", NULL);
1446 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
1452 if (extra_gac_paths) {
1453 paths = extra_gac_paths;
1454 while (!image && *paths) {
1455 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
1456 "lib", "mono", "gac", subpath, NULL);
1457 image = mono_image_open (fullpath, NULL);
1468 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
1469 "mono", "gac", subpath, NULL);
1470 image = mono_image_open (fullpath, NULL);
1477 static MonoAssemblyName*
1478 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
1480 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
1481 dest_name->major = info->new_version.major;
1482 dest_name->minor = info->new_version.minor;
1483 dest_name->build = info->new_version.build;
1484 dest_name->revision = info->new_version.revision;
1489 /* LOCKING: Assumes that we are already locked */
1490 static MonoAssemblyBindingInfo*
1491 search_binding_loaded (MonoAssemblyName *aname)
1495 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
1496 MonoAssemblyBindingInfo *info = tmp->data;
1497 if (assembly_binding_maps_name (info, aname))
1504 static MonoAssemblyName*
1505 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
1507 MonoAssemblyBindingInfo *info, *info2;
1510 if (aname->public_key_token [0] == 0)
1513 mono_loader_lock ();
1514 info = search_binding_loaded (aname);
1515 mono_loader_unlock ();
1517 if (!check_policy_versions (info, aname))
1520 mono_assembly_bind_version (info, aname, dest_name);
1524 info = g_new0 (MonoAssemblyBindingInfo, 1);
1525 info->major = aname->major;
1526 info->minor = aname->minor;
1528 ppimage = mono_assembly_load_publisher_policy (aname);
1530 get_publisher_policy_info (ppimage, aname, info);
1531 mono_image_close (ppimage);
1534 /* Define default error value if needed */
1535 if (!info->is_valid) {
1536 info->name = g_strdup (aname->name);
1537 info->culture = g_strdup (aname->culture);
1538 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1541 mono_loader_lock ();
1542 info2 = search_binding_loaded (aname);
1544 /* This binding was added by another thread
1546 mono_assembly_binding_info_free (info);
1551 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
1553 mono_loader_unlock ();
1555 if (!info->is_valid || !check_policy_versions (info, aname))
1558 mono_assembly_bind_version (info, aname, dest_name);
1563 * mono_assembly_load_from_gac
1565 * @aname: The assembly name object
1567 static MonoAssembly*
1568 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
1570 MonoAssembly *result = NULL;
1571 gchar *name, *version, *culture, *fullpath, *subpath;
1575 if (aname->public_key_token [0] == 0) {
1579 if (strstr (aname->name, ".dll")) {
1580 len = strlen (filename) - 4;
1581 name = g_malloc (len);
1582 strncpy (name, aname->name, len);
1584 name = g_strdup (aname->name);
1587 if (aname->culture) {
1588 culture = g_strdup (aname->culture);
1589 g_strdown (culture);
1591 culture = g_strdup ("");
1594 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
1595 aname->minor, aname->build, aname->revision,
1596 culture, aname->public_key_token);
1598 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
1603 if (extra_gac_paths) {
1604 paths = extra_gac_paths;
1605 while (!result && *paths) {
1606 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
1607 result = mono_assembly_open_full (fullpath, status, refonly);
1614 result->in_gac = TRUE;
1619 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
1620 "mono", "gac", subpath, NULL);
1621 result = mono_assembly_open_full (fullpath, status, refonly);
1625 result->in_gac = TRUE;
1634 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
1639 /* g_print ("corlib already loaded\n"); */
1643 if (assemblies_path) {
1644 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
1649 /* Load corlib from mono/<version> */
1651 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
1652 if (assemblies_path) {
1653 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
1655 g_free (corlib_file);
1659 corlib = load_in_path (corlib_file, default_path, status, FALSE);
1660 g_free (corlib_file);
1667 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
1669 MonoAssembly *result;
1670 char *fullpath, *filename;
1671 MonoAssemblyName maped_aname, maped_name_pp;
1675 aname = mono_assembly_remap_version (aname, &maped_aname);
1677 /* Reflection only assemblies don't get assembly binding */
1679 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
1681 result = mono_assembly_loaded_full (aname, refonly);
1685 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
1687 result->in_gac = FALSE;
1691 /* Currently we retrieve the loaded corlib for reflection
1692 * only requests, like a common reflection only assembly
1694 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
1695 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
1698 for (ext_index = 0; ext_index < 2; ext_index ++) {
1699 ext = ext_index == 0 ? ".dll" : ".exe";
1700 if (strstr (aname->name, ".dll"))
1701 filename = g_strdup (aname->name);
1703 filename = g_strconcat (aname->name, ext, NULL);
1705 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
1712 fullpath = g_build_filename (basedir, filename, NULL);
1713 result = mono_assembly_open_full (fullpath, status, refonly);
1716 result->in_gac = FALSE;
1722 result = load_in_path (filename, default_path, status, refonly);
1724 result->in_gac = FALSE;
1734 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
1736 return mono_assembly_load_full (aname, basedir, status, FALSE);
1740 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
1743 MonoAssemblyName maped_aname;
1745 aname = mono_assembly_remap_version (aname, &maped_aname);
1747 EnterCriticalSection (&assemblies_mutex);
1748 res = search_loaded (aname, refonly);
1749 LeaveCriticalSection (&assemblies_mutex);
1755 mono_assembly_loaded (MonoAssemblyName *aname)
1757 return mono_assembly_loaded_full (aname, FALSE);
1761 mono_assembly_close (MonoAssembly *assembly)
1763 g_return_if_fail (assembly != NULL);
1765 if (InterlockedDecrement (&assembly->ref_count))
1768 EnterCriticalSection (&assemblies_mutex);
1769 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
1770 LeaveCriticalSection (&assemblies_mutex);
1771 /* assemblies belong to domains, so the domain code takes care of unloading the
1772 * referenced assemblies
1775 mono_image_close (assembly->image);
1777 g_free (assembly->basedir);
1778 if (!assembly->dynamic)
1783 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
1785 MonoImageOpenStatus status;
1788 module = mono_image_load_file_for_image (assembly->image, idx);
1790 mono_assembly_load_references (module, &status);
1796 mono_assembly_foreach (GFunc func, gpointer user_data)
1801 * We make a copy of the list to avoid calling the callback inside the
1802 * lock, which could lead to deadlocks.
1804 EnterCriticalSection (&assemblies_mutex);
1805 copy = g_list_copy (loaded_assemblies);
1806 LeaveCriticalSection (&assemblies_mutex);
1808 g_list_foreach (loaded_assemblies, func, user_data);
1814 * Holds the assembly of the application, for
1815 * System.Diagnostics.Process::MainModule
1817 static MonoAssembly *main_assembly=NULL;
1820 mono_assembly_set_main (MonoAssembly *assembly)
1822 main_assembly=assembly;
1826 mono_assembly_get_main (void)
1828 return(main_assembly);
1832 mono_assembly_get_image (MonoAssembly *assembly)
1834 return assembly->image;
1838 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
1840 bundles = assemblies;