2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc. http://www.ximian.com
10 * Implement big-endian versions of the reading routines.
21 #include "rawbuffer.h"
23 #include "mono-bundle.h"
25 #include <mono/io-layer/io-layer.h>
26 #include <mono/utils/mono-uri.h>
27 #include <mono/metadata/mono-config.h>
29 /* the default search path is just MONO_ASSEMBLIES */
36 static char **assemblies_path = NULL;
39 * keeps track of loaded assemblies
41 static GList *loaded_assemblies = NULL;
42 static MonoAssembly *corlib;
44 /* This protects loaded_assemblies and image->references */
45 static CRITICAL_SECTION assemblies_mutex;
47 /* A hastable of thread->assembly list mappings */
48 static GHashTable *assemblies_loading;
53 init_default_path (void)
57 default_path [0] = g_strdup (MONO_ASSEMBLIES);
58 for (i = strlen (MONO_ASSEMBLIES) - 1; i >= 0; i--) {
59 if (default_path [0][i] == '/')
60 ((char*) default_path [0])[i] = '\\';
70 path = getenv ("MONO_PATH");
73 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
75 g_strfreev (assemblies_path);
76 assemblies_path = splitted;
79 /* assemblies_mutex must be held by the caller */
81 search_loaded (MonoAssemblyName* aname)
87 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
91 /* we just compare the name, but later we'll do all the checks */
92 /* g_print ("compare %s %s\n", aname->name, ass->aname.name); */
93 if (strcmp (aname->name, ass->aname.name))
95 /* g_print ("success\n"); */
101 * The assembly might be under load by this thread. In this case, it is
102 * safe to return an incomplete instance to prevent loops.
104 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
105 for (tmp = loading; tmp; tmp = tmp->next) {
107 if (!ass->aname.name)
109 if (strcmp (aname->name, ass->aname.name))
118 static MonoAssembly *
119 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
123 MonoAssembly *result;
125 for (i = 0; search_path [i]; ++i) {
126 fullpath = g_build_filename (search_path [i], basename, NULL);
127 result = mono_assembly_open (fullpath, status);
136 * mono_assembly_setrootdir:
137 * @root_dir: The pathname of the root directory where we will locate assemblies
139 * This routine sets the internal default root directory for looking up
140 * assemblies. This is used by Windows installations to compute dynamically
141 * the place where the Mono assemblies are located.
145 mono_assembly_setrootdir (const char *root_dir)
148 * Override the MONO_ASSEMBLIES directory configured at compile time.
150 /* Leak if called more than once */
151 default_path [0] = g_strdup (root_dir);
155 * mono_assemblies_init:
157 * Initialize global variables used by this module.
160 mono_assemblies_init (void)
162 #ifdef PLATFORM_WIN32
163 init_default_path ();
168 InitializeCriticalSection (&assemblies_mutex);
170 assemblies_loading = g_hash_table_new (NULL, NULL);
174 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
176 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
177 guint32 cols [MONO_ASSEMBLY_SIZE];
182 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
185 aname->hash_value = NULL;
186 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
187 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
188 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
189 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
190 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
191 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
192 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
193 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
194 if (cols [MONO_ASSEMBLY_PUBLIC_KEY])
195 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
197 aname->public_key = 0;
203 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
206 guint32 cols [MONO_ASSEMBLYREF_SIZE];
209 MonoAssembly **references = NULL;
211 *status = MONO_IMAGE_OK;
214 * image->references is shared between threads, so we need to access
215 * it inside a critical section.
217 EnterCriticalSection (&assemblies_mutex);
218 references = image->references;
219 LeaveCriticalSection (&assemblies_mutex);
223 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
225 references = g_new0 (MonoAssembly *, t->rows + 1);
228 * Load any assemblies this image references
230 for (i = 0; i < t->rows; i++) {
231 MonoAssemblyName aname;
233 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
235 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
236 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
237 aname.hash_value = hash;
238 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
239 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
240 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
241 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
242 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
243 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
244 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
246 references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
248 if (references [i] == NULL){
251 for (j = 0; j < i; j++)
252 mono_assembly_close (references [j]);
255 g_warning ("Could not find assembly %s", aname.name);
256 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
261 * This check is disabled since lots of people seem to have an older
262 * corlib which triggers this.
265 if (image->references [i]->image == image)
266 g_error ("Error: Assembly %s references itself", image->name);
269 references [i] = NULL;
271 /* resolve assembly references for modules */
272 t = &image->tables [MONO_TABLE_MODULEREF];
273 for (i = 0; i < t->rows; i++){
274 if (image->modules [i]) {
275 image->modules [i]->assembly = image->assembly;
276 mono_assembly_load_references (image->modules [i], status);
280 EnterCriticalSection (&assemblies_mutex);
281 if (!image->references)
282 image->references = references;
283 LeaveCriticalSection (&assemblies_mutex);
285 if (image->references != references) {
286 /* Somebody loaded it before us */
287 for (i = 0; i < t->rows; i++)
288 mono_assembly_close (references [i]);
293 typedef struct AssemblyLoadHook AssemblyLoadHook;
294 struct AssemblyLoadHook {
295 AssemblyLoadHook *next;
296 MonoAssemblyLoadFunc func;
300 AssemblyLoadHook *assembly_load_hook = NULL;
303 mono_assembly_invoke_load_hook (MonoAssembly *ass)
305 AssemblyLoadHook *hook;
307 for (hook = assembly_load_hook; hook; hook = hook->next) {
308 hook->func (ass, hook->user_data);
313 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
315 AssemblyLoadHook *hook;
317 g_return_if_fail (func != NULL);
319 hook = g_new0 (AssemblyLoadHook, 1);
321 hook->user_data = user_data;
322 hook->next = assembly_load_hook;
323 assembly_load_hook = hook;
326 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
327 struct AssemblyPreLoadHook {
328 AssemblyPreLoadHook *next;
329 MonoAssemblyPreLoadFunc func;
333 AssemblyPreLoadHook *assembly_preload_hook = NULL;
335 static MonoAssembly *
336 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
338 AssemblyPreLoadHook *hook;
339 MonoAssembly *assembly;
341 for (hook = assembly_preload_hook; hook; hook = hook->next) {
342 assembly = hook->func (aname, assemblies_path, hook->user_data);
343 if (assembly != NULL)
351 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
353 AssemblyPreLoadHook *hook;
355 g_return_if_fail (func != NULL);
357 hook = g_new0 (AssemblyPreLoadHook, 1);
359 hook->user_data = user_data;
360 hook->next = assembly_preload_hook;
361 assembly_preload_hook = hook;
365 absolute_dir (const gchar *filename)
376 if (g_path_is_absolute (filename))
377 return g_path_get_dirname (filename);
379 cwd = g_get_current_dir ();
380 mixed = g_build_filename (cwd, filename, NULL);
381 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
386 for (i = 0; (part = parts [i]) != NULL; i++) {
387 if (!strcmp (part, "."))
390 if (!strcmp (part, "..")) {
391 if (list && list->next) /* Don't remove root */
392 list = g_list_delete_link (list, list);
394 list = g_list_prepend (list, part);
398 result = g_string_new ("");
399 list = g_list_reverse (list);
401 /* Ignores last data pointer, which should be the filename */
402 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
404 g_string_append_printf (result, "%s%c", (char *) tmp->data,
408 g_string_free (result, FALSE);
413 return g_strdup (".");
420 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
422 MonoImage *image = NULL;
425 char *name = g_path_get_basename (filename);
426 char *dot = strrchr (name, '.');
432 if (strcmp (name, "corlib") == 0) {
434 name = g_strdup ("mscorlib");
436 /* we do a very simple search for bundled assemblies: it's not a general
437 * purpose assembly loading mechanism.
439 EnterCriticalSection (&assemblies_mutex);
440 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
442 if (!ass->aname.name)
444 if (strcmp (name, ass->aname.name))
450 for (i = 0; !image && bundled_assemblies [i]; ++i) {
451 if (strcmp (bundled_assemblies [i]->name, name) == 0) {
452 image = mono_image_open_from_data ((char*)bundled_assemblies [i]->data, bundled_assemblies [i]->size, FALSE, status);
456 LeaveCriticalSection (&assemblies_mutex);
459 mono_image_addref (image);
463 EnterCriticalSection (&assemblies_mutex);
464 image = mono_image_open (filename, status);
465 LeaveCriticalSection (&assemblies_mutex);
471 * mono_assembly_open:
472 * @filename: Opens the assembly pointed out by this name
473 * @status: where a status code can be returned
475 * mono_assembly_open opens the PE-image pointed by @filename, and
476 * loads any external assemblies referenced by it.
478 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
482 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
486 MonoImageOpenStatus def_status;
489 g_return_val_if_fail (filename != NULL, NULL);
492 status = &def_status;
493 *status = MONO_IMAGE_OK;
495 if (strncmp (filename, "file://", 7) == 0) {
496 GError *error = NULL;
497 gchar *uri = (gchar *) filename;
501 * MS allows file://c:/... and fails on file://localhost/c:/...
502 * They also throw an IndexOutOfRangeException if "file://"
505 uri = g_strdup_printf ("file:///%s", uri + 7);
508 uri = mono_escape_uri_string (tmpuri);
509 fname = g_filename_from_uri (uri, NULL, &error);
512 if (tmpuri != filename)
516 g_warning ("%s\n", error->message);
517 g_error_free (error);
518 fname = g_strdup (filename);
521 fname = g_strdup (filename);
524 /* g_print ("file loading %s\n", fname); */
525 image = do_mono_assembly_open (fname, status);
528 *status = MONO_IMAGE_ERROR_ERRNO;
533 ass = mono_assembly_load_from (image, fname, status);
535 mono_config_for_assembly (ass->image);
543 mono_assembly_load_from (MonoImage *image, const char*fname,
544 MonoImageOpenStatus *status)
546 MonoAssembly *ass, *ass2;
550 #if defined (PLATFORM_WIN32)
555 tmp_fn = g_strdup (fname);
556 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
557 if (tmp_fn [i] == '/')
561 base_dir = absolute_dir (tmp_fn);
565 base_dir = absolute_dir (fname);
569 * To avoid deadlocks and scalability problems, we load assemblies outside
570 * the assembly lock. This means that multiple threads might try to load
571 * the same assembly at the same time. The first one to load it completely
572 * "wins", the other threads free their copy and use the one loaded by
573 * the winning thread.
577 * Create assembly struct, and enter it into the assembly cache
579 ass = g_new0 (MonoAssembly, 1);
580 ass->basedir = base_dir;
583 mono_assembly_fill_assembly_name (image, &ass->aname);
586 * Atomically search the loaded list and add ourselves to it if necessary.
588 EnterCriticalSection (&assemblies_mutex);
590 /* avoid loading the same assembly twice for now... */
591 if ((ass2 = search_loaded (&ass->aname))) {
594 mono_image_close (image);
595 *status = MONO_IMAGE_OK;
596 LeaveCriticalSection (&assemblies_mutex);
599 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
600 loading = g_list_prepend (loading, ass);
601 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
602 LeaveCriticalSection (&assemblies_mutex);
604 image->assembly = ass;
607 * We load referenced assemblies outside the lock to prevent deadlocks
608 * with regards to preload hooks.
610 mono_assembly_load_references (image, status);
612 EnterCriticalSection (&assemblies_mutex);
614 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
615 loading = g_list_remove (loading, ass);
617 /* Prevent memory leaks */
618 g_hash_table_remove (assemblies_loading, GetCurrentThread ());
620 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
621 if (*status != MONO_IMAGE_OK) {
622 LeaveCriticalSection (&assemblies_mutex);
623 mono_assembly_close (ass);
627 if (ass->aname.name) {
628 ass2 = search_loaded (&ass->aname);
630 /* Somebody else has loaded the assembly before us */
631 LeaveCriticalSection (&assemblies_mutex);
632 mono_assembly_close (ass);
637 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
638 LeaveCriticalSection (&assemblies_mutex);
640 mono_assembly_invoke_load_hook (ass);
646 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
648 MonoAssembly *result;
649 char *fullpath, *filename;
651 result = invoke_assembly_preload_hook (aname, assemblies_path);
655 /* g_print ("loading %s\n", aname->name); */
656 /* special case corlib */
657 if ((strcmp (aname->name, "mscorlib") == 0) || (strcmp (aname->name, "corlib") == 0)) {
659 /* g_print ("corlib already loaded\n"); */
662 /* g_print ("corlib load\n"); */
663 if (assemblies_path) {
664 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status);
667 corlib = load_in_path ("corlib.dll", (const char**)assemblies_path, status);
671 corlib = load_in_path ("mscorlib.dll", default_path, status);
673 corlib = load_in_path ("corlib.dll", default_path, status);
676 result = search_loaded (aname);
679 /* g_print ("%s not found in cache\n", aname->name); */
680 if (strstr (aname->name, ".dll"))
681 filename = g_strdup (aname->name);
683 filename = g_strconcat (aname->name, ".dll", NULL);
685 fullpath = g_build_filename (basedir, filename, NULL);
686 result = mono_assembly_open (fullpath, status);
693 if (assemblies_path) {
694 result = load_in_path (filename, (const char**)assemblies_path, status);
700 result = load_in_path (filename, default_path, status);
706 mono_assembly_loaded (MonoAssemblyName *aname)
710 EnterCriticalSection (&assemblies_mutex);
711 res = search_loaded (aname);
712 LeaveCriticalSection (&assemblies_mutex);
718 mono_assembly_close (MonoAssembly *assembly)
723 g_return_if_fail (assembly != NULL);
725 EnterCriticalSection (&assemblies_mutex);
726 if (--assembly->ref_count != 0) {
727 LeaveCriticalSection (&assemblies_mutex);
730 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
731 LeaveCriticalSection (&assemblies_mutex);
732 image = assembly->image;
733 if (image->references) {
734 for (i = 0; image->references [i] != NULL; i++)
735 mono_image_close (image->references [i]->image);
736 g_free (image->references);
739 mono_image_close (assembly->image);
741 g_free (assembly->basedir);
746 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
748 MonoImageOpenStatus status;
751 module = mono_image_load_file_for_image (assembly->image, idx);
753 mono_assembly_load_references (module, &status);
759 mono_assembly_foreach (GFunc func, gpointer user_data)
764 * We make a copy of the list to avoid calling the callback inside the
765 * lock, which could lead to deadlocks.
767 EnterCriticalSection (&assemblies_mutex);
768 copy = g_list_copy (loaded_assemblies);
769 LeaveCriticalSection (&assemblies_mutex);
771 g_list_foreach (loaded_assemblies, func, user_data);
776 /* Holds the assembly of the application, for
777 * System.Diagnostics.Process::MainModule
779 static MonoAssembly *main_assembly=NULL;
782 mono_assembly_set_main (MonoAssembly *assembly)
784 main_assembly=assembly;
788 mono_assembly_get_main (void)
790 return(main_assembly);