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>
28 /* the default search path is just MONO_ASSEMBLIES */
35 static char **assemblies_path = NULL;
38 * keeps track of loaded assemblies
40 static GList *loaded_assemblies = NULL;
41 static MonoAssembly *corlib;
43 /* This protects loaded_assemblies and image->references */
44 static CRITICAL_SECTION assemblies_mutex;
46 /* A hastable of thread->assembly list mappings */
47 static GHashTable *assemblies_loading;
52 init_default_path (void)
56 default_path [0] = g_strdup (MONO_ASSEMBLIES);
57 for (i = strlen (MONO_ASSEMBLIES) - 1; i >= 0; i--) {
58 if (default_path [0][i] == '/')
59 ((char*) default_path [0])[i] = '\\';
69 path = getenv ("MONO_PATH");
72 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
74 g_strfreev (assemblies_path);
75 assemblies_path = splitted;
78 /* assemblies_mutex must be held by the caller */
80 search_loaded (MonoAssemblyName* aname)
86 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
90 /* we just compare the name, but later we'll do all the checks */
91 /* g_print ("compare %s %s\n", aname->name, ass->aname.name); */
92 if (strcmp (aname->name, ass->aname.name))
94 /* g_print ("success\n"); */
100 * The assembly might be under load by this thread. In this case, it is
101 * safe to return an incomplete instance to prevent loops.
103 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
104 for (tmp = loading; tmp; tmp = tmp->next) {
106 if (!ass->aname.name)
108 if (strcmp (aname->name, ass->aname.name))
117 static MonoAssembly *
118 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
122 MonoAssembly *result;
124 for (i = 0; search_path [i]; ++i) {
125 fullpath = g_build_filename (search_path [i], basename, NULL);
126 result = mono_assembly_open (fullpath, status);
135 * mono_assembly_setrootdir:
136 * @root_dir: The pathname of the root directory where we will locate assemblies
138 * This routine sets the internal default root directory for looking up
139 * assemblies. This is used by Windows installations to compute dynamically
140 * the place where the Mono assemblies are located.
144 mono_assembly_setrootdir (const char *root_dir)
147 * Override the MONO_ASSEMBLIES directory configured at compile time.
149 /* Leak if called more than once */
150 default_path [0] = g_strdup (root_dir);
154 * mono_assemblies_init:
156 * Initialize global variables used by this module.
159 mono_assemblies_init (void)
161 #ifdef PLATFORM_WIN32
162 init_default_path ();
167 InitializeCriticalSection (&assemblies_mutex);
169 assemblies_loading = g_hash_table_new (NULL, NULL);
173 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
175 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
176 guint32 cols [MONO_ASSEMBLY_SIZE];
181 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
184 aname->hash_value = NULL;
185 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
186 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
187 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
188 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
189 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
190 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
191 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
192 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
193 if (cols [MONO_ASSEMBLY_PUBLIC_KEY])
194 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
196 aname->public_key = 0;
202 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
205 guint32 cols [MONO_ASSEMBLYREF_SIZE];
208 MonoAssembly **references = NULL;
210 *status = MONO_IMAGE_OK;
213 * image->references is shared between threads, so we need to access
214 * it inside a critical section.
216 EnterCriticalSection (&assemblies_mutex);
217 references = image->references;
218 LeaveCriticalSection (&assemblies_mutex);
222 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
224 references = g_new0 (MonoAssembly *, t->rows + 1);
227 * Load any assemblies this image references
229 for (i = 0; i < t->rows; i++) {
230 MonoAssemblyName aname;
232 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
234 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
235 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
236 aname.hash_value = hash;
237 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
238 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
239 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
240 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
241 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
242 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
243 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
245 references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
247 if (references [i] == NULL){
250 for (j = 0; j < i; j++)
251 mono_assembly_close (references [j]);
254 g_warning ("Could not find assembly %s", aname.name);
255 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
260 * This check is disabled since lots of people seem to have an older
261 * corlib which triggers this.
264 if (image->references [i]->image == image)
265 g_error ("Error: Assembly %s references itself", image->name);
268 references [i] = NULL;
270 /* resolve assembly references for modules */
271 t = &image->tables [MONO_TABLE_MODULEREF];
272 for (i = 0; i < t->rows; i++){
273 if (image->modules [i]) {
274 image->modules [i]->assembly = image->assembly;
275 mono_assembly_load_references (image->modules [i], status);
279 EnterCriticalSection (&assemblies_mutex);
280 if (!image->references)
281 image->references = references;
282 LeaveCriticalSection (&assemblies_mutex);
284 if (image->references != references) {
285 /* Somebody loaded it before us */
286 for (i = 0; i < t->rows; i++)
287 mono_assembly_close (references [i]);
292 typedef struct AssemblyLoadHook AssemblyLoadHook;
293 struct AssemblyLoadHook {
294 AssemblyLoadHook *next;
295 MonoAssemblyLoadFunc func;
299 AssemblyLoadHook *assembly_load_hook = NULL;
302 mono_assembly_invoke_load_hook (MonoAssembly *ass)
304 AssemblyLoadHook *hook;
306 for (hook = assembly_load_hook; hook; hook = hook->next) {
307 hook->func (ass, hook->user_data);
312 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
314 AssemblyLoadHook *hook;
316 g_return_if_fail (func != NULL);
318 hook = g_new0 (AssemblyLoadHook, 1);
320 hook->user_data = user_data;
321 hook->next = assembly_load_hook;
322 assembly_load_hook = hook;
325 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
326 struct AssemblyPreLoadHook {
327 AssemblyPreLoadHook *next;
328 MonoAssemblyPreLoadFunc func;
332 AssemblyPreLoadHook *assembly_preload_hook = NULL;
334 static MonoAssembly *
335 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
337 AssemblyPreLoadHook *hook;
338 MonoAssembly *assembly;
340 for (hook = assembly_preload_hook; hook; hook = hook->next) {
341 assembly = hook->func (aname, assemblies_path, hook->user_data);
342 if (assembly != NULL)
350 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
352 AssemblyPreLoadHook *hook;
354 g_return_if_fail (func != NULL);
356 hook = g_new0 (AssemblyPreLoadHook, 1);
358 hook->user_data = user_data;
359 hook->next = assembly_preload_hook;
360 assembly_preload_hook = hook;
364 absolute_dir (const gchar *filename)
375 if (g_path_is_absolute (filename))
376 return g_path_get_dirname (filename);
378 cwd = g_get_current_dir ();
379 mixed = g_build_filename (cwd, filename, NULL);
380 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
385 for (i = 0; (part = parts [i]) != NULL; i++) {
386 if (!strcmp (part, "."))
389 if (!strcmp (part, "..")) {
390 if (list && list->next) /* Don't remove root */
391 list = g_list_delete_link (list, list);
393 list = g_list_prepend (list, part);
397 result = g_string_new ("");
398 list = g_list_reverse (list);
400 /* Ignores last data pointer, which should be the filename */
401 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
403 g_string_append_printf (result, "%s%c", (char *) tmp->data,
407 g_string_free (result, FALSE);
412 return g_strdup (".");
419 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
421 MonoImage *image = NULL;
424 char *name = g_path_get_basename (filename);
425 char *dot = strrchr (name, '.');
431 if (strcmp (name, "corlib") == 0) {
433 name = g_strdup ("mscorlib");
435 /* we do a very simple search for bundled assemblies: it's not a general
436 * purpose assembly loading mechanism.
438 EnterCriticalSection (&assemblies_mutex);
439 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
441 if (!ass->aname.name)
443 if (strcmp (name, ass->aname.name))
449 for (i = 0; !image && bundled_assemblies [i]; ++i) {
450 if (strcmp (bundled_assemblies [i]->name, name) == 0) {
451 image = mono_image_open_from_data ((char*)bundled_assemblies [i]->data, bundled_assemblies [i]->size, FALSE, status);
455 LeaveCriticalSection (&assemblies_mutex);
458 mono_image_addref (image);
462 EnterCriticalSection (&assemblies_mutex);
463 image = mono_image_open (filename, status);
464 LeaveCriticalSection (&assemblies_mutex);
470 * mono_assembly_open:
471 * @filename: Opens the assembly pointed out by this name
472 * @status: where a status code can be returned
474 * mono_assembly_open opens the PE-image pointed by @filename, and
475 * loads any external assemblies referenced by it.
477 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
481 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
485 MonoImageOpenStatus def_status;
488 g_return_val_if_fail (filename != NULL, NULL);
491 status = &def_status;
492 *status = MONO_IMAGE_OK;
494 if (strncmp (filename, "file://", 7) == 0) {
495 GError *error = NULL;
496 gchar *uri = (gchar *) filename;
500 * MS allows file://c:/... and fails on file://localhost/c:/...
501 * They also throw an IndexOutOfRangeException if "file://"
504 uri = g_strdup_printf ("file:///%s", uri + 7);
507 uri = mono_escape_uri_string (tmpuri);
508 fname = g_filename_from_uri (uri, NULL, &error);
511 if (tmpuri != filename)
515 g_warning ("%s\n", error->message);
516 g_error_free (error);
517 fname = g_strdup (filename);
520 fname = g_strdup (filename);
523 /* g_print ("file loading %s\n", fname); */
524 image = do_mono_assembly_open (fname, status);
527 *status = MONO_IMAGE_ERROR_ERRNO;
532 ass = mono_assembly_load_from (image, fname, status);
540 mono_assembly_load_from (MonoImage *image, const char*fname,
541 MonoImageOpenStatus *status)
543 MonoAssembly *ass, *ass2;
547 #if defined (PLATFORM_WIN32)
552 tmp_fn = g_strdup (fname);
553 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
554 if (tmp_fn [i] == '/')
558 base_dir = absolute_dir (tmp_fn);
562 base_dir = absolute_dir (fname);
566 * To avoid deadlocks and scalability problems, we load assemblies outside
567 * the assembly lock. This means that multiple threads might try to load
568 * the same assembly at the same time. The first one to load it completely
569 * "wins", the other threads free their copy and use the one loaded by
570 * the winning thread.
574 * Create assembly struct, and enter it into the assembly cache
576 ass = g_new0 (MonoAssembly, 1);
577 ass->basedir = base_dir;
580 mono_assembly_fill_assembly_name (image, &ass->aname);
583 * Atomically search the loaded list and add ourselves to it if necessary.
585 EnterCriticalSection (&assemblies_mutex);
587 /* avoid loading the same assembly twice for now... */
588 if ((ass2 = search_loaded (&ass->aname))) {
591 mono_image_close (image);
592 *status = MONO_IMAGE_OK;
593 LeaveCriticalSection (&assemblies_mutex);
596 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
597 loading = g_list_prepend (loading, ass);
598 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
599 LeaveCriticalSection (&assemblies_mutex);
601 image->assembly = ass;
604 * We load referenced assemblies outside the lock to prevent deadlocks
605 * with regards to preload hooks.
607 mono_assembly_load_references (image, status);
609 EnterCriticalSection (&assemblies_mutex);
611 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
612 loading = g_list_remove (loading, ass);
614 /* Prevent memory leaks */
615 g_hash_table_remove (assemblies_loading, GetCurrentThread ());
617 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
618 if (*status != MONO_IMAGE_OK) {
619 LeaveCriticalSection (&assemblies_mutex);
620 mono_assembly_close (ass);
624 if (ass->aname.name) {
625 ass2 = search_loaded (&ass->aname);
627 /* Somebody else has loaded the assembly before us */
628 LeaveCriticalSection (&assemblies_mutex);
629 mono_assembly_close (ass);
634 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
635 LeaveCriticalSection (&assemblies_mutex);
637 mono_assembly_invoke_load_hook (ass);
643 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
645 MonoAssembly *result;
646 char *fullpath, *filename;
648 result = invoke_assembly_preload_hook (aname, assemblies_path);
652 /* g_print ("loading %s\n", aname->name); */
653 /* special case corlib */
654 if ((strcmp (aname->name, "mscorlib") == 0) || (strcmp (aname->name, "corlib") == 0)) {
656 /* g_print ("corlib already loaded\n"); */
659 /* g_print ("corlib load\n"); */
660 if (assemblies_path) {
661 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status);
664 corlib = load_in_path ("corlib.dll", (const char**)assemblies_path, status);
668 corlib = load_in_path ("mscorlib.dll", default_path, status);
670 corlib = load_in_path ("corlib.dll", default_path, status);
673 result = search_loaded (aname);
676 /* g_print ("%s not found in cache\n", aname->name); */
677 if (strstr (aname->name, ".dll"))
678 filename = g_strdup (aname->name);
680 filename = g_strconcat (aname->name, ".dll", NULL);
682 fullpath = g_build_filename (basedir, filename, NULL);
683 result = mono_assembly_open (fullpath, status);
690 if (assemblies_path) {
691 result = load_in_path (filename, (const char**)assemblies_path, status);
697 result = load_in_path (filename, default_path, status);
703 mono_assembly_loaded (MonoAssemblyName *aname)
707 EnterCriticalSection (&assemblies_mutex);
708 res = search_loaded (aname);
709 LeaveCriticalSection (&assemblies_mutex);
715 mono_assembly_close (MonoAssembly *assembly)
720 g_return_if_fail (assembly != NULL);
722 EnterCriticalSection (&assemblies_mutex);
723 if (--assembly->ref_count != 0) {
724 LeaveCriticalSection (&assemblies_mutex);
727 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
728 LeaveCriticalSection (&assemblies_mutex);
729 image = assembly->image;
730 if (image->references) {
731 for (i = 0; image->references [i] != NULL; i++)
732 mono_image_close (image->references [i]->image);
733 g_free (image->references);
736 mono_image_close (assembly->image);
738 g_free (assembly->basedir);
743 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
745 MonoImageOpenStatus status;
748 module = mono_image_load_file_for_image (assembly->image, idx);
750 mono_assembly_load_references (module, &status);
756 mono_assembly_foreach (GFunc func, gpointer user_data)
761 * We make a copy of the list to avoid calling the callback inside the
762 * lock, which could lead to deadlocks.
764 EnterCriticalSection (&assemblies_mutex);
765 copy = g_list_copy (loaded_assemblies);
766 LeaveCriticalSection (&assemblies_mutex);
768 g_list_foreach (loaded_assemblies, func, user_data);
773 /* Holds the assembly of the application, for
774 * System.Diagnostics.Process::MainModule
776 static MonoAssembly *main_assembly=NULL;
779 mono_assembly_set_main (MonoAssembly *assembly)
781 main_assembly=assembly;
785 mono_assembly_get_main (void)
787 return(main_assembly);