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/domain-internals.h>
24 #include <mono/io-layer/io-layer.h>
25 #include <mono/utils/mono-uri.h>
26 #include <mono/metadata/mono-config.h>
27 #include <mono/utils/mono-digest.h>
28 #include <mono/utils/mono-logger.h>
30 #include <mono/os/util.h>
32 /* not used on Windows - see mono_set_rootdir () */
33 #define MONO_ASSEMBLIES NULL
37 /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
39 const char* assembly_name;
40 guint8 version_set_index;
43 /* the default search path is just MONO_ASSEMBLIES */
50 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
51 static char **assemblies_path = NULL;
53 /* Contains the list of directories that point to auxiliary GACs */
54 static char **extra_gac_paths = NULL;
56 /* The list of system assemblies what will be remapped to the running
57 * runtime version. WARNING: this list must be sorted.
59 static const AssemblyVersionMap framework_assemblies [] = {
61 {"Commons.Xml.Relaxng", 0},
68 {"Microsoft.VisualBasic", 1},
69 {"Microsoft.VisualC", 1},
71 {"Mono.CompilerServices.SymbolWriter", 0},
73 {"Mono.Data.SqliteClient", 0},
74 {"Mono.Data.SybaseClient", 0},
76 {"Mono.Data.TdsClient", 0},
77 {"Mono.GetOptions", 0},
81 {"Mono.Security.Win32", 0},
83 {"Novell.Directory.Ldap", 0},
87 {"System.Configuration.Install", 0},
89 {"System.Data.OracleClient", 0},
90 {"System.Data.SqlXml", 0},
92 {"System.DirectoryServices", 0},
93 {"System.Drawing", 0},
94 {"System.Drawing.Design", 0},
95 {"System.EnterpriseServices", 0},
96 {"System.Management", 0},
97 {"System.Messaging", 0},
98 {"System.Runtime.Remoting", 0},
99 {"System.Runtime.Serialization.Formatters.Soap", 0},
100 {"System.Security", 0},
101 {"System.ServiceProcess", 0},
103 {"System.Web.Mobile", 0},
104 {"System.Web.Services", 0},
105 {"System.Windows.Forms", 0},
111 * keeps track of loaded assemblies
113 static GList *loaded_assemblies = NULL;
114 static MonoAssembly *corlib;
116 /* This protects loaded_assemblies and image->references */
117 static CRITICAL_SECTION assemblies_mutex;
119 /* A hastable of thread->assembly list mappings */
120 static GHashTable *assemblies_loading;
122 /* A hashtable of reflection only load thread->assemblies mappings */
123 static GHashTable *assemblies_refonly_loading;
125 /* If defined, points to the bundled assembly information */
126 const MonoBundledAssembly **bundles;
128 /* Reflection only private hook functions */
129 static MonoAssembly* mono_assembly_refonly_invoke_search_hook (MonoAssemblyName *aname);
132 encode_public_tok (const guchar *token, gint32 len)
134 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
138 res = g_malloc (len * 2 + 1);
139 for (i = 0; i < len; i++) {
140 res [i * 2] = allowed [token [i] >> 4];
141 res [i * 2 + 1] = allowed [token [i] & 0xF];
148 check_path_env (void)
153 path = g_getenv ("MONO_PATH");
157 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
159 g_strfreev (assemblies_path);
160 assemblies_path = splitted;
161 if (g_getenv ("MONO_DEBUG") == NULL)
165 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
166 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
173 check_extra_gac_path_env (void) {
177 path = g_getenv ("MONO_GAC_PREFIX");
181 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
183 g_strfreev (extra_gac_paths);
184 extra_gac_paths = splitted;
185 if (g_getenv ("MONO_DEBUG") == NULL)
189 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
190 g_warning ("'%s' in MONO_GAC_PATH doesn't exist or has wrong permissions.", *splitted);
197 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
199 if (!l->name || !r->name)
202 if (strcmp (l->name, r->name))
205 if (l->culture && r->culture && strcmp (l->culture, r->culture))
208 if (l->major != r->major || l->minor != r->minor ||
209 l->build != r->build || l->revision != r->revision)
210 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)))
213 if (!l->public_key_token [0] || !r->public_key_token [0])
216 if (strcmp (l->public_key_token, r->public_key_token))
223 search_loaded (MonoAssemblyName* aname, gboolean refonly)
229 ass = refonly ? mono_assembly_refonly_invoke_search_hook (aname) : mono_assembly_invoke_search_hook (aname);
234 * The assembly might be under load by this thread. In this case, it is
235 * safe to return an incomplete instance to prevent loops.
237 loading = g_hash_table_lookup (refonly ? assemblies_refonly_loading : assemblies_loading, GetCurrentThread ());
238 for (tmp = loading; tmp; tmp = tmp->next) {
240 if (!mono_assembly_names_equal (aname, &ass->aname))
249 static MonoAssembly *
250 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
254 MonoAssembly *result;
256 for (i = 0; search_path [i]; ++i) {
257 fullpath = g_build_filename (search_path [i], basename, NULL);
258 result = mono_assembly_open_full (fullpath, status, refonly);
267 * mono_assembly_setrootdir:
268 * @root_dir: The pathname of the root directory where we will locate assemblies
270 * This routine sets the internal default root directory for looking up
271 * assemblies. This is used by Windows installations to compute dynamically
272 * the place where the Mono assemblies are located.
276 mono_assembly_setrootdir (const char *root_dir)
279 * Override the MONO_ASSEMBLIES directory configured at compile time.
281 /* Leak if called more than once */
282 default_path [0] = g_strdup (root_dir);
285 G_CONST_RETURN gchar *
286 mono_assembly_getrootdir (void)
288 return default_path [0];
292 * mono_assemblies_init:
294 * Initialize global variables used by this module.
297 mono_assemblies_init (void)
299 #ifdef PLATFORM_WIN32
304 check_extra_gac_path_env ();
306 InitializeCriticalSection (&assemblies_mutex);
308 assemblies_loading = g_hash_table_new (NULL, NULL);
309 assemblies_refonly_loading = g_hash_table_new (NULL, NULL);
313 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
315 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
316 guint32 cols [MONO_ASSEMBLY_SIZE];
321 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
324 aname->hash_value = NULL;
325 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
326 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
327 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
328 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
329 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
330 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
331 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
332 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
333 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
334 gchar* token = g_malloc (8);
338 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
339 len = mono_metadata_decode_blob_size (aname->public_key, (const char**)&aname->public_key);
341 mono_digest_get_public_token (token, aname->public_key, len);
342 encoded = encode_public_tok (token, 8);
343 g_strlcpy (aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
349 aname->public_key = NULL;
350 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
353 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
354 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
357 aname->public_key = 0;
363 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
365 const gchar *public_tok;
368 public_tok = mono_metadata_blob_heap (image, key_index);
369 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
371 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
373 mono_digest_get_public_token (token, public_tok, len);
374 return encode_public_tok (token, 8);
377 return encode_public_tok (public_tok, len);
381 mono_assembly_addref (MonoAssembly *assembly)
383 EnterCriticalSection (&assemblies_mutex);
384 /*g_print ("adding ref from %d to %s (%p)\n", assembly->ref_count, assembly->aname.name, assembly);*/
385 assembly->ref_count++;
386 LeaveCriticalSection (&assemblies_mutex);
389 static MonoAssemblyName *
390 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
392 const MonoRuntimeInfo *current_runtime;
393 int pos, first, last;
395 if (aname->name == NULL) return aname;
396 current_runtime = mono_get_runtime_info ();
399 last = G_N_ELEMENTS (framework_assemblies) - 1;
401 while (first <= last) {
403 pos = first + (last - first) / 2;
404 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
406 const AssemblyVersionSet* vset;
407 int index = framework_assemblies[pos].version_set_index;
408 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
409 vset = ¤t_runtime->version_sets [index];
411 if (aname->major == vset->major && aname->minor == vset->minor &&
412 aname->build == vset->build && aname->revision == vset->revision)
415 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
416 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
417 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
419 aname->major, aname->minor, aname->build, aname->revision,
420 vset->major, vset->minor, vset->build, vset->revision
423 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
424 dest_aname->major = vset->major;
425 dest_aname->minor = vset->minor;
426 dest_aname->build = vset->build;
427 dest_aname->revision = vset->revision;
429 } else if (res < 0) {
439 mono_assembly_load_reference (MonoImage *image, int index)
442 guint32 cols [MONO_ASSEMBLYREF_SIZE];
444 MonoAssembly *reference;
445 MonoAssemblyName aname;
446 MonoImageOpenStatus status;
449 * image->references is shared between threads, so we need to access
450 * it inside a critical section.
452 EnterCriticalSection (&assemblies_mutex);
453 reference = image->references [index];
454 LeaveCriticalSection (&assemblies_mutex);
458 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
460 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
462 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
463 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
464 aname.hash_value = hash;
465 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
466 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
467 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
468 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
469 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
470 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
471 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
473 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
474 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname.flags);
475 g_strlcpy (aname.public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
478 memset (aname.public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
481 if (image->assembly->ref_only) {
482 /* We use the loaded corlib */
483 if (!strcmp (aname.name, "mscorlib"))
484 reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
486 reference = mono_assembly_loaded_full (&aname, TRUE);
488 * Here we must advice that the error was due to
489 * a non loaded reference using the ReflectionOnly api
492 reference = (gpointer)-1;
494 reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
496 if (reference == NULL){
497 char *extra_msg = g_strdup ("");
499 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
500 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);
501 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
502 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
503 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
504 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
505 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
506 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
509 g_warning ("The following assembly referenced from %s could not be loaded:\n"
510 " Assembly: %s (assemblyref_index=%d)\n"
511 " Version: %d.%d.%d.%d\n"
512 " Public Key: %s\n%s",
513 image->name, aname.name, index,
514 aname.major, aname.minor, aname.build, aname.revision,
515 strlen(aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
519 EnterCriticalSection (&assemblies_mutex);
520 if (reference == NULL) {
521 /* Flag as not found */
522 reference = (gpointer)-1;
524 reference->ref_count++;
527 if (!image->references [index])
528 image->references [index] = reference;
529 LeaveCriticalSection (&assemblies_mutex);
531 if (image->references [index] != reference) {
532 /* Somebody loaded it before us */
533 mono_assembly_close (reference);
538 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
543 *status = MONO_IMAGE_OK;
545 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
547 image->references = g_new0 (MonoAssembly *, t->rows + 1);
549 /* resolve assembly references for modules */
550 for (i = 0; i < image->module_count; i++){
551 if (image->modules [i]) {
552 image->modules [i]->assembly = image->assembly;
553 mono_assembly_load_references (image->modules [i], status);
558 typedef struct AssemblyLoadHook AssemblyLoadHook;
559 struct AssemblyLoadHook {
560 AssemblyLoadHook *next;
561 MonoAssemblyLoadFunc func;
565 AssemblyLoadHook *assembly_load_hook = NULL;
568 mono_assembly_invoke_load_hook (MonoAssembly *ass)
570 AssemblyLoadHook *hook;
572 for (hook = assembly_load_hook; hook; hook = hook->next) {
573 hook->func (ass, hook->user_data);
578 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
580 AssemblyLoadHook *hook;
582 g_return_if_fail (func != NULL);
584 hook = g_new0 (AssemblyLoadHook, 1);
586 hook->user_data = user_data;
587 hook->next = assembly_load_hook;
588 assembly_load_hook = hook;
591 typedef struct AssemblySearchHook AssemblySearchHook;
592 struct AssemblySearchHook {
593 AssemblySearchHook *next;
594 MonoAssemblySearchFunc func;
598 AssemblySearchHook *assembly_search_hook = NULL;
599 static AssemblySearchHook *assembly_refonly_search_hook = NULL;
602 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
604 AssemblySearchHook *hook;
606 for (hook = assembly_search_hook; hook; hook = hook->next) {
607 MonoAssembly *ass = hook->func (aname, hook->user_data);
616 mono_assembly_refonly_invoke_search_hook (MonoAssemblyName *aname)
618 AssemblySearchHook *hook;
620 for (hook = assembly_refonly_search_hook; hook; hook = hook->next) {
621 MonoAssembly *ass = hook->func (aname, hook->user_data);
630 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
632 AssemblySearchHook *hook;
634 g_return_if_fail (func != NULL);
636 hook = g_new0 (AssemblySearchHook, 1);
638 hook->user_data = user_data;
639 hook->next = assembly_search_hook;
640 assembly_search_hook = hook;
644 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
646 AssemblySearchHook *hook;
648 g_return_if_fail (func != NULL);
650 hook = g_new0 (AssemblySearchHook, 1);
652 hook->user_data = user_data;
653 hook->next = assembly_refonly_search_hook;
654 assembly_refonly_search_hook = hook;
657 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
658 struct AssemblyPreLoadHook {
659 AssemblyPreLoadHook *next;
660 MonoAssemblyPreLoadFunc func;
664 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
665 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
667 static MonoAssembly *
668 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
670 AssemblyPreLoadHook *hook;
671 MonoAssembly *assembly;
673 for (hook = assembly_preload_hook; hook; hook = hook->next) {
674 assembly = hook->func (aname, assemblies_path, hook->user_data);
675 if (assembly != NULL)
682 static MonoAssembly *
683 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
685 AssemblyPreLoadHook *hook;
686 MonoAssembly *assembly;
688 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
689 assembly = hook->func (aname, assemblies_path, hook->user_data);
690 if (assembly != NULL)
698 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
700 AssemblyPreLoadHook *hook;
702 g_return_if_fail (func != NULL);
704 hook = g_new0 (AssemblyPreLoadHook, 1);
706 hook->user_data = user_data;
707 hook->next = assembly_preload_hook;
708 assembly_preload_hook = hook;
712 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
714 AssemblyPreLoadHook *hook;
716 g_return_if_fail (func != NULL);
718 hook = g_new0 (AssemblyPreLoadHook, 1);
720 hook->user_data = user_data;
721 hook->next = assembly_refonly_preload_hook;
722 assembly_refonly_preload_hook = hook;
726 absolute_dir (const gchar *filename)
737 if (g_path_is_absolute (filename))
738 return g_path_get_dirname (filename);
740 cwd = g_get_current_dir ();
741 mixed = g_build_filename (cwd, filename, NULL);
742 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
747 for (i = 0; (part = parts [i]) != NULL; i++) {
748 if (!strcmp (part, "."))
751 if (!strcmp (part, "..")) {
752 if (list && list->next) /* Don't remove root */
753 list = g_list_delete_link (list, list);
755 list = g_list_prepend (list, part);
759 result = g_string_new ("");
760 list = g_list_reverse (list);
762 /* Ignores last data pointer, which should be the filename */
763 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
765 g_string_append_printf (result, "%s%c", (char *) tmp->data,
769 g_string_free (result, FALSE);
774 return g_strdup (".");
781 * mono_assembly_open_from_bundle:
782 * @filename: Filename requested
783 * @status: return value
785 * This routine tries to open the assembly specified by `filename' from the
786 * defined bundles, if found, returns the MonoImage for it, if not found
790 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status)
793 char *name = g_path_get_basename (filename);
794 MonoImage *image = NULL;
797 * we do a very simple search for bundled assemblies: it's not a general
798 * purpose assembly loading mechanism.
800 EnterCriticalSection (&assemblies_mutex);
801 for (i = 0; !image && bundles [i]; ++i) {
802 if (strcmp (bundles [i]->name, name) == 0) {
803 image = mono_image_open_from_data ((char*)bundles [i]->data, bundles [i]->size, FALSE, status);
807 LeaveCriticalSection (&assemblies_mutex);
810 mono_image_addref (image);
817 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
819 MonoImage *image = NULL;
821 if (bundles != NULL){
822 image = mono_assembly_open_from_bundle (filename, status);
827 EnterCriticalSection (&assemblies_mutex);
828 image = mono_image_open (filename, status);
829 LeaveCriticalSection (&assemblies_mutex);
835 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
839 MonoImageOpenStatus def_status;
842 g_return_val_if_fail (filename != NULL, NULL);
845 status = &def_status;
846 *status = MONO_IMAGE_OK;
848 if (strncmp (filename, "file://", 7) == 0) {
849 GError *error = NULL;
850 gchar *uri = (gchar *) filename;
854 * MS allows file://c:/... and fails on file://localhost/c:/...
855 * They also throw an IndexOutOfRangeException if "file://"
858 uri = g_strdup_printf ("file:///%s", uri + 7);
861 uri = mono_escape_uri_string (tmpuri);
862 fname = g_filename_from_uri (uri, NULL, &error);
865 if (tmpuri != filename)
869 g_warning ("%s\n", error->message);
870 g_error_free (error);
871 fname = g_strdup (filename);
874 fname = g_strdup (filename);
877 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
878 "Assembly Loader probing location: '%s'.", filename);
879 image = do_mono_assembly_open (fname, status);
882 *status = MONO_IMAGE_ERROR_ERRNO;
887 ass = mono_assembly_load_from_full (image, fname, status, refonly);
890 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
891 "Assembly Loader loaded assembly from location: '%s'.", filename);
893 mono_config_for_assembly (ass->image);
902 * mono_assembly_open:
903 * @filename: Opens the assembly pointed out by this name
904 * @status: where a status code can be returned
906 * mono_assembly_open opens the PE-image pointed by @filename, and
907 * loads any external assemblies referenced by it.
909 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
913 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
915 return mono_assembly_open_full (filename, status, FALSE);
919 mono_assembly_load_from_full (MonoImage *image, const char*fname,
920 MonoImageOpenStatus *status, gboolean refonly)
922 MonoAssembly *ass, *ass2;
925 GHashTable *ass_loading;
927 #if defined (PLATFORM_WIN32)
932 tmp_fn = g_strdup (fname);
933 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
934 if (tmp_fn [i] == '/')
938 base_dir = absolute_dir (tmp_fn);
942 base_dir = absolute_dir (fname);
946 * To avoid deadlocks and scalability problems, we load assemblies outside
947 * the assembly lock. This means that multiple threads might try to load
948 * the same assembly at the same time. The first one to load it completely
949 * "wins", the other threads free their copy and use the one loaded by
950 * the winning thread.
954 * Create assembly struct, and enter it into the assembly cache
956 ass = g_new0 (MonoAssembly, 1);
957 ass->basedir = base_dir;
958 ass->ref_only = refonly;
962 mono_assembly_fill_assembly_name (image, &ass->aname);
965 * Atomically search the loaded list and add ourselves to it if necessary.
967 EnterCriticalSection (&assemblies_mutex);
968 if (ass->aname.name) {
969 /* avoid loading the same assembly twice for now... */
970 ass2 = search_loaded (&ass->aname, refonly);
974 mono_image_close (image);
975 *status = MONO_IMAGE_OK;
976 LeaveCriticalSection (&assemblies_mutex);
980 ass_loading = refonly ? assemblies_refonly_loading : assemblies_loading;
981 loading = g_hash_table_lookup (ass_loading, GetCurrentThread ());
982 loading = g_list_prepend (loading, ass);
983 g_hash_table_insert (ass_loading, GetCurrentThread (), loading);
984 LeaveCriticalSection (&assemblies_mutex);
986 image->assembly = ass;
988 mono_assembly_load_references (image, status);
990 EnterCriticalSection (&assemblies_mutex);
992 loading = g_hash_table_lookup (ass_loading, GetCurrentThread ());
993 loading = g_list_remove (loading, ass);
995 /* Prevent memory leaks */
996 g_hash_table_remove (ass_loading, GetCurrentThread ());
998 g_hash_table_insert (ass_loading, GetCurrentThread (), loading);
999 if (*status != MONO_IMAGE_OK) {
1000 LeaveCriticalSection (&assemblies_mutex);
1001 mono_assembly_close (ass);
1005 if (ass->aname.name) {
1006 ass2 = search_loaded (&ass->aname, refonly);
1008 /* Somebody else has loaded the assembly before us */
1009 LeaveCriticalSection (&assemblies_mutex);
1010 mono_assembly_close (ass);
1015 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1016 LeaveCriticalSection (&assemblies_mutex);
1018 mono_assembly_invoke_load_hook (ass);
1024 mono_assembly_load_from (MonoImage *image, const char *fname,
1025 MonoImageOpenStatus *status)
1027 return mono_assembly_load_from_full (image, fname, status, FALSE);
1031 * mono_assembly_name_free:
1032 * @aname: assembly name to free
1034 * Frees the provided assembly name object.
1035 * (it does not frees the object itself, only the name members).
1038 mono_assembly_name_free (MonoAssemblyName *aname)
1043 g_free ((void *) aname->name);
1044 g_free ((void *) aname->culture);
1045 g_free ((void *) aname->hash_value);
1049 build_assembly_name (const char *name, const char *version, const char *culture, const char *token, MonoAssemblyName *aname)
1051 gint major, minor, build, revision;
1053 memset (aname, 0, sizeof (MonoAssemblyName));
1056 if (sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4)
1059 aname->major = major;
1060 aname->minor = minor;
1061 aname->build = build;
1062 aname->revision = revision;
1065 aname->name = g_strdup (name);
1068 if (g_strcasecmp (culture, "neutral") == 0)
1069 aname->culture = g_strdup ("");
1071 aname->culture = g_strdup (culture);
1074 if (token && strncmp (token, "null", 4) != 0)
1075 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1081 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
1086 parts = g_strsplit (dirname, "_", 3);
1087 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
1092 res = build_assembly_name (name, parts[0], parts[1], parts[2], aname);
1098 * mono_assembly_name_parse:
1099 * @name: name to parse
1100 * @aname: the destination assembly name
1101 * Returns: true if the name could be parsed.
1103 * Parses an assembly qualified type name and assigns the name,
1104 * version, culture and token to the provided assembly name object.
1107 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
1110 gchar *version = NULL;
1111 gchar *culture = NULL;
1112 gchar *token = NULL;
1118 parts = tmp = g_strsplit (name, ",", 4);
1119 if (!tmp || !*tmp) {
1124 dllname = g_strstrip (*tmp);
1129 value = g_strstrip (*tmp);
1130 if (!g_ascii_strncasecmp (value, "Version=", 8)) {
1131 version = g_strstrip (value + 8);
1136 if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
1137 culture = g_strstrip (value + 8);
1142 if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
1143 token = g_strstrip (value + 15);
1152 res = build_assembly_name (dllname, version, culture, token, aname);
1157 static MonoAssembly*
1158 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
1160 gchar *fullpath = NULL;
1162 const char* direntry;
1163 MonoAssemblyName gac_aname;
1164 gint major=-1, minor=0, build=0, revision=0;
1165 gboolean exact_version;
1167 dirhandle = g_dir_open (basepath, 0, NULL);
1171 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
1173 while ((direntry = g_dir_read_name (dirhandle))) {
1174 gboolean match = TRUE;
1176 parse_assembly_directory_name (aname->name, direntry, &gac_aname);
1178 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
1181 if (match && strlen ((char*)aname->public_key_token) > 0 &&
1182 strcmp ((char*)aname->public_key_token, (char*)gac_aname.public_key_token) != 0)
1186 if (exact_version) {
1187 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
1188 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
1190 else if (gac_aname.major < major)
1192 else if (gac_aname.major == major) {
1193 if (gac_aname.minor < minor)
1195 else if (gac_aname.minor == minor) {
1196 if (gac_aname.build < build)
1198 else if (gac_aname.build == build && gac_aname.revision <= revision)
1205 major = gac_aname.major;
1206 minor = gac_aname.minor;
1207 build = gac_aname.build;
1208 revision = gac_aname.revision;
1210 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
1213 mono_assembly_name_free (&gac_aname);
1216 g_dir_close (dirhandle);
1218 if (fullpath == NULL)
1221 MonoAssembly *res = mono_assembly_open (fullpath, status);
1228 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
1231 MonoAssemblyName *aname, base_name, maped_aname;
1232 gchar *fullname, *gacpath;
1235 memset (&base_name, 0, sizeof (MonoAssemblyName));
1238 if (!mono_assembly_name_parse (name, aname))
1242 * If no specific version has been requested, make sure we load the
1243 * correct version for system assemblies.
1245 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
1246 aname = mono_assembly_remap_version (aname, &maped_aname);
1248 res = mono_assembly_loaded (aname);
1250 mono_assembly_name_free (aname);
1254 res = invoke_assembly_preload_hook (aname, assemblies_path);
1256 res->in_gac = FALSE;
1257 mono_assembly_name_free (aname);
1261 fullname = g_strdup_printf ("%s.dll", aname->name);
1263 if (extra_gac_paths) {
1264 paths = extra_gac_paths;
1265 while (!res && *paths) {
1266 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
1267 res = probe_for_partial_name (gacpath, fullname, aname, status);
1276 mono_assembly_name_free (aname);
1280 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
1281 res = probe_for_partial_name (gacpath, fullname, aname, status);
1288 mono_assembly_name_free (aname);
1294 * mono_assembly_load_from_gac
1296 * @aname: The assembly name object
1298 static MonoAssembly*
1299 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
1301 MonoAssembly *result = NULL;
1302 gchar *name, *version, *culture, *fullpath, *subpath;
1306 if (aname->public_key_token [0] == 0) {
1310 if (strstr (aname->name, ".dll")) {
1311 len = strlen (filename) - 4;
1312 name = g_malloc (len);
1313 strncpy (name, aname->name, len);
1315 name = g_strdup (aname->name);
1318 if (aname->culture) {
1319 culture = g_strdup (aname->culture);
1320 g_strdown (culture);
1322 culture = g_strdup ("");
1325 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
1326 aname->minor, aname->build, aname->revision,
1327 culture, aname->public_key_token);
1329 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
1334 if (extra_gac_paths) {
1335 paths = extra_gac_paths;
1336 while (!result && *paths) {
1337 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
1338 result = mono_assembly_open_full (fullpath, status, refonly);
1345 result->in_gac = TRUE;
1350 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
1351 "mono", "gac", subpath, NULL);
1352 result = mono_assembly_open_full (fullpath, status, refonly);
1356 result->in_gac = TRUE;
1365 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
1370 /* g_print ("corlib already loaded\n"); */
1374 if (assemblies_path) {
1375 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
1380 /* Load corlib from mono/<version> */
1382 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
1383 if (assemblies_path) {
1384 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
1386 g_free (corlib_file);
1390 corlib = load_in_path (corlib_file, default_path, status, FALSE);
1391 g_free (corlib_file);
1398 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
1400 MonoAssembly *result;
1401 char *fullpath, *filename;
1402 MonoAssemblyName maped_aname;
1404 aname = mono_assembly_remap_version (aname, &maped_aname);
1406 result = mono_assembly_loaded_full (aname, refonly);
1410 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
1412 result->in_gac = FALSE;
1416 /* Currently we retrieve the loaded corlib for reflection
1417 * only requests, like a common reflection only assembly
1419 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
1420 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
1423 if (strstr (aname->name, ".dll"))
1424 filename = g_strdup (aname->name);
1426 filename = g_strconcat (aname->name, ".dll", NULL);
1428 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
1435 fullpath = g_build_filename (basedir, filename, NULL);
1436 result = mono_assembly_open_full (fullpath, status, refonly);
1439 result->in_gac = FALSE;
1445 result = load_in_path (filename, default_path, status, refonly);
1447 result->in_gac = FALSE;
1453 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
1455 return mono_assembly_load_full (aname, basedir, status, FALSE);
1459 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
1462 MonoAssemblyName maped_aname;
1464 aname = mono_assembly_remap_version (aname, &maped_aname);
1466 EnterCriticalSection (&assemblies_mutex);
1467 res = search_loaded (aname, refonly);
1468 LeaveCriticalSection (&assemblies_mutex);
1474 mono_assembly_loaded (MonoAssemblyName *aname)
1476 return mono_assembly_loaded_full (aname, FALSE);
1480 mono_assembly_close (MonoAssembly *assembly)
1484 g_return_if_fail (assembly != NULL);
1486 EnterCriticalSection (&assemblies_mutex);
1487 /*g_print ("destroy assembly %p %d (%s)\n", assembly, assembly->ref_count, assembly->image->name);*/
1488 g_assert (assembly->ref_count > 0);
1489 if (--assembly->ref_count != 0) {
1490 LeaveCriticalSection (&assemblies_mutex);
1493 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
1494 LeaveCriticalSection (&assemblies_mutex);
1495 image = assembly->image;
1496 /* assemblies belong to domains, so the domain code takes care of unloading the
1497 * referenced assemblies
1500 mono_image_close (assembly->image);
1502 g_free (assembly->basedir);
1503 if (!assembly->dynamic)
1508 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
1510 MonoImageOpenStatus status;
1513 module = mono_image_load_file_for_image (assembly->image, idx);
1515 mono_assembly_load_references (module, &status);
1521 mono_assembly_foreach (GFunc func, gpointer user_data)
1526 * We make a copy of the list to avoid calling the callback inside the
1527 * lock, which could lead to deadlocks.
1529 EnterCriticalSection (&assemblies_mutex);
1530 copy = g_list_copy (loaded_assemblies);
1531 LeaveCriticalSection (&assemblies_mutex);
1533 g_list_foreach (loaded_assemblies, func, user_data);
1539 * Holds the assembly of the application, for
1540 * System.Diagnostics.Process::MainModule
1542 static MonoAssembly *main_assembly=NULL;
1545 mono_assembly_set_main (MonoAssembly *assembly)
1547 main_assembly=assembly;
1551 mono_assembly_get_main (void)
1553 return(main_assembly);
1557 mono_assembly_get_image (MonoAssembly *assembly)
1559 return assembly->image;
1563 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
1565 bundles = assemblies;