2004-01-19 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / assembly.c
1 /*
2  * assembly.c: Routines for loading assemblies.
3  * 
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.  http://www.ximian.com
8  *
9  * TODO:
10  *   Implement big-endian versions of the reading routines.
11  */
12 #include <config.h>
13 #include <stdio.h>
14 #include <glib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include "assembly.h"
19 #include "image.h"
20 #include "cil-coff.h"
21 #include "rawbuffer.h"
22 #ifdef WITH_BUNDLE
23 #include "mono-bundle.h"
24 #endif
25 #include <mono/io-layer/io-layer.h>
26 #include <mono/utils/mono-uri.h>
27
28 /* the default search path is just MONO_ASSEMBLIES */
29 static const char*
30 default_path [] = {
31         MONO_ASSEMBLIES,
32         NULL
33 };
34
35 static char **assemblies_path = NULL;
36
37 /*
38  * keeps track of loaded assemblies
39  */
40 static GList *loaded_assemblies = NULL;
41 static MonoAssembly *corlib;
42
43 /* This protects loaded_assemblies and image->references */
44 static CRITICAL_SECTION assemblies_mutex;
45
46 /* A hastable of thread->assembly list mappings */
47 static GHashTable *assemblies_loading;
48
49 #ifdef PLATFORM_WIN32
50
51 static void
52 init_default_path (void)
53 {
54         int i;
55
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] = '\\';
60         }
61 }
62 #endif
63
64 static void
65 check_env (void) {
66         const char *path;
67         char **splitted;
68         
69         path = getenv ("MONO_PATH");
70         if (!path)
71                 return;
72         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
73         if (assemblies_path)
74                 g_strfreev (assemblies_path);
75         assemblies_path = splitted;
76 }
77
78 /* assemblies_mutex must be held by the caller */
79 static MonoAssembly*
80 search_loaded (MonoAssemblyName* aname)
81 {
82         GList *tmp;
83         MonoAssembly *ass;
84         GList *loading;
85         
86         for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
87                 ass = tmp->data;
88                 if (!ass->aname.name)
89                         continue;
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))
93                         continue;
94                 /* g_print ("success\n"); */
95
96                 return ass;
97         }
98
99         /*
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.
102          */
103         loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
104         for (tmp = loading; tmp; tmp = tmp->next) {
105                 ass = tmp->data;
106                 if (!ass->aname.name)
107                         continue;
108                 if (strcmp (aname->name, ass->aname.name))
109                         continue;
110
111                 return ass;
112         }
113
114         return NULL;
115 }
116
117 static MonoAssembly *
118 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
119 {
120         int i;
121         char *fullpath;
122         MonoAssembly *result;
123
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);
127                 g_free (fullpath);
128                 if (result)
129                         return result;
130         }
131         return NULL;
132 }
133
134 /**
135  * mono_assembly_setrootdir:
136  * @root_dir: The pathname of the root directory where we will locate assemblies
137  *
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.
141  *
142  */
143 void
144 mono_assembly_setrootdir (const char *root_dir)
145 {
146         /*
147          * Override the MONO_ASSEMBLIES directory configured at compile time.
148          */
149         /* Leak if called more than once */
150         default_path [0] = g_strdup (root_dir);
151 }
152
153 /**
154  * mono_assemblies_init:
155  *
156  *  Initialize global variables used by this module.
157  */
158 void
159 mono_assemblies_init (void)
160 {
161 #ifdef PLATFORM_WIN32
162         init_default_path ();
163 #endif
164
165         check_env ();
166
167         InitializeCriticalSection (&assemblies_mutex);
168
169         assemblies_loading = g_hash_table_new (NULL, NULL);
170 }
171
172 gboolean
173 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
174 {
175         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
176         guint32 cols [MONO_ASSEMBLY_SIZE];
177
178         if (!t->rows)
179                 return FALSE;
180
181         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
182
183         aname->hash_len = 0;
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]);
195         else
196                 aname->public_key = 0;
197
198         return TRUE;
199 }
200
201 void
202 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
203 {
204         MonoTableInfo *t;
205         guint32 cols [MONO_ASSEMBLYREF_SIZE];
206         const char *hash;
207         int i;
208
209         *status = MONO_IMAGE_OK;
210
211         if (image->references)
212                 return;
213
214         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
215
216         image->references = g_new0 (MonoAssembly *, t->rows + 1);
217
218         /*
219          * Load any assemblies this image references
220          */
221         for (i = 0; i < t->rows; i++) {
222                 MonoAssemblyName aname;
223
224                 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
225                 
226                 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
227                 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
228                 aname.hash_value = hash;
229                 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
230                 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
231                 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
232                 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
233                 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
234                 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
235                 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
236
237                 image->references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
238
239                 if (image->references [i] == NULL){
240                         int j;
241                         
242                         for (j = 0; j < i; j++)
243                                 mono_assembly_close (image->references [j]);
244                         g_free (image->references);
245
246                         g_warning ("Could not find assembly %s", aname.name);
247                         *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
248                         return;
249                 }
250
251                 /* 
252                  * This check is disabled since lots of people seem to have an older
253                  * corlib which triggers this.
254                  */
255                 /* 
256                 if (image->references [i]->image == image)
257                         g_error ("Error: Assembly %s references itself", image->name);
258                 */
259         }
260         image->references [i] = NULL;
261
262         /* resolve assembly references for modules */
263         t = &image->tables [MONO_TABLE_MODULEREF];
264         for (i = 0; i < t->rows; i++){
265                 if (image->modules [i]) {
266                         image->modules [i]->assembly = image->assembly;
267                         mono_assembly_load_references (image->modules [i], status);
268                 }
269         }
270 }
271
272 typedef struct AssemblyLoadHook AssemblyLoadHook;
273 struct AssemblyLoadHook {
274         AssemblyLoadHook *next;
275         MonoAssemblyLoadFunc func;
276         gpointer user_data;
277 };
278
279 AssemblyLoadHook *assembly_load_hook = NULL;
280
281 void
282 mono_assembly_invoke_load_hook (MonoAssembly *ass)
283 {
284         AssemblyLoadHook *hook;
285
286         for (hook = assembly_load_hook; hook; hook = hook->next) {
287                 hook->func (ass, hook->user_data);
288         }
289 }
290
291 void
292 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
293 {
294         AssemblyLoadHook *hook;
295         
296         g_return_if_fail (func != NULL);
297
298         hook = g_new0 (AssemblyLoadHook, 1);
299         hook->func = func;
300         hook->user_data = user_data;
301         hook->next = assembly_load_hook;
302         assembly_load_hook = hook;
303 }
304
305 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
306 struct AssemblyPreLoadHook {
307         AssemblyPreLoadHook *next;
308         MonoAssemblyPreLoadFunc func;
309         gpointer user_data;
310 };
311
312 AssemblyPreLoadHook *assembly_preload_hook = NULL;
313
314 static MonoAssembly *
315 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
316 {
317         AssemblyPreLoadHook *hook;
318         MonoAssembly *assembly;
319
320         for (hook = assembly_preload_hook; hook; hook = hook->next) {
321                 assembly = hook->func (aname, assemblies_path, hook->user_data);
322                 if (assembly != NULL)
323                         return assembly;
324         }
325
326         return NULL;
327 }
328
329 void
330 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
331 {
332         AssemblyPreLoadHook *hook;
333         
334         g_return_if_fail (func != NULL);
335
336         hook = g_new0 (AssemblyPreLoadHook, 1);
337         hook->func = func;
338         hook->user_data = user_data;
339         hook->next = assembly_preload_hook;
340         assembly_preload_hook = hook;
341 }
342
343 static gchar *
344 absolute_dir (const gchar *filename)
345 {
346         gchar *cwd;
347         gchar *mixed;
348         gchar **parts;
349         gchar *part;
350         GList *list, *tmp;
351         GString *result;
352         gchar *res;
353         gint i;
354
355         if (g_path_is_absolute (filename))
356                 return g_path_get_dirname (filename);
357
358         cwd = g_get_current_dir ();
359         mixed = g_build_filename (cwd, filename, NULL);
360         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
361         g_free (mixed);
362         g_free (cwd);
363
364         list = NULL;
365         for (i = 0; (part = parts [i]) != NULL; i++) {
366                 if (!strcmp (part, "."))
367                         continue;
368
369                 if (!strcmp (part, "..")) {
370                         if (list && list->next) /* Don't remove root */
371                                 list = g_list_delete_link (list, list);
372                 } else {
373                         list = g_list_prepend (list, part);
374                 }
375         }
376
377         result = g_string_new ("");
378         list = g_list_reverse (list);
379
380         /* Ignores last data pointer, which should be the filename */
381         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
382                 if (tmp->data)
383                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
384                                                                 G_DIR_SEPARATOR);
385         
386         res = result->str;
387         g_string_free (result, FALSE);
388         g_list_free (list);
389         g_strfreev (parts);
390         if (*res == '\0') {
391                 g_free (res);
392                 return g_strdup (".");
393         }
394
395         return res;
396 }
397
398 static MonoImage*
399 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
400 {
401         MonoImage *image = NULL;
402 #ifdef WITH_BUNDLE
403         int i;
404         char *name = g_path_get_basename (filename);
405         char *dot = strrchr (name, '.');
406         GList *tmp;
407         MonoAssembly *ass;
408         
409         if (dot)
410                 *dot = 0;
411         if (strcmp (name, "corlib") == 0) {
412                 g_free (name);
413                 name = g_strdup ("mscorlib");
414         }
415         /* we do a very simple search for bundled assemblies: it's not a general 
416          * purpose assembly loading mechanism.
417          */
418         EnterCriticalSection (&assemblies_mutex);
419         for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
420                 ass = tmp->data;
421                 if (!ass->aname.name)
422                         continue;
423                 if (strcmp (name, ass->aname.name))
424                         continue;
425                 image = ass->image;
426                 break;
427         }
428         LeaveCriticalSection (&assemblies_mutex);
429         for (i = 0; !image && bundled_assemblies [i]; ++i) {
430                 if (strcmp (bundled_assemblies [i]->name, name) == 0) {
431                         image = mono_image_open_from_data ((char*)bundled_assemblies [i]->data, bundled_assemblies [i]->size, FALSE, status);
432                         break;
433                 }
434         }
435         g_free (name);
436         if (image) {
437                 InterlockedIncrement (&image->ref_count);
438                 return image;
439         }
440 #endif
441         image = mono_image_open (filename, status);
442         return image;
443 }
444
445 /**
446  * mono_assembly_open:
447  * @filename: Opens the assembly pointed out by this name
448  * @status: where a status code can be returned
449  *
450  * mono_assembly_open opens the PE-image pointed by @filename, and
451  * loads any external assemblies referenced by it.
452  *
453  * NOTE: we could do lazy loading of the assemblies.  Or maybe not worth
454  * it. 
455  */
456 MonoAssembly *
457 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
458 {
459         MonoImage *image;
460         MonoAssembly *ass;
461         MonoImageOpenStatus def_status;
462         gchar *fname;
463         
464         g_return_val_if_fail (filename != NULL, NULL);
465
466         if (!status)
467                 status = &def_status;
468         *status = MONO_IMAGE_OK;
469
470         if (strncmp (filename, "file://", 7) == 0) {
471                 GError *error = NULL;
472                 gchar *uri = (gchar *) filename;
473                 gchar *tmpuri;
474
475                 /*
476                  * MS allows file://c:/... and fails on file://localhost/c:/... 
477                  * They also throw an IndexOutOfRangeException if "file://"
478                  */
479                 if (uri [7] != '/')
480                         uri = g_strdup_printf ("file:///%s", uri + 7);
481         
482                 tmpuri = uri;
483                 uri = mono_escape_uri_string (tmpuri);
484                 fname = g_filename_from_uri (uri, NULL, &error);
485                 g_free (uri);
486
487                 if (tmpuri != filename)
488                         g_free (tmpuri);
489
490                 if (error != NULL) {
491                         g_warning ("%s\n", error->message);
492                         g_error_free (error);
493                         fname = g_strdup (filename);
494                 }
495         } else {
496                 fname = g_strdup (filename);
497         }
498
499         /* g_print ("file loading %s\n", fname); */
500         image = do_mono_assembly_open (fname, status);
501
502         if (!image){
503                 *status = MONO_IMAGE_ERROR_ERRNO;
504                 g_free (fname);
505                 return NULL;
506         }
507
508         ass = mono_assembly_load_from (image, fname, status);
509
510         g_free (fname);
511
512         return ass;
513 }
514
515 MonoAssembly *
516 mono_assembly_load_from (MonoImage *image, const char*fname, 
517                                                  MonoImageOpenStatus *status)
518 {
519         MonoAssembly *ass, *ass2;
520         char *base_dir;
521         GList *loading;
522
523 #if defined (PLATFORM_WIN32)
524         {
525                 gchar *tmp_fn;
526                 int i;
527
528                 tmp_fn = g_strdup (fname);
529                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
530                         if (tmp_fn [i] == '/')
531                                 tmp_fn [i] = '\\';
532                 }
533
534                 base_dir = absolute_dir (tmp_fn);
535                 g_free (tmp_fn);
536         }
537 #else
538         base_dir = absolute_dir (fname);
539 #endif
540
541         /*
542          * Create assembly struct, and enter it into the assembly cache
543          */
544         ass = g_new0 (MonoAssembly, 1);
545         ass->basedir = base_dir;
546         ass->image = image;
547
548         mono_assembly_fill_assembly_name (image, &ass->aname);
549
550         /* 
551          * Atomically search the loaded list and add ourselves to it if necessary.
552          */
553         EnterCriticalSection (&assemblies_mutex);
554         if (ass->aname.name)
555                 /* avoid loading the same assembly twice for now... */
556                 if ((ass2 = search_loaded (&ass->aname))) {
557                         g_free (ass);
558                         g_free (base_dir);
559                         mono_image_close (image);
560                         *status = MONO_IMAGE_OK;
561                         LeaveCriticalSection (&assemblies_mutex);
562                         return ass2;
563                 }
564         loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
565         loading = g_list_prepend (loading, ass);
566         g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
567         LeaveCriticalSection (&assemblies_mutex);
568
569         image->assembly = ass;
570
571         /*
572          * We load referenced assemblies outside the lock to prevent deadlocks
573          * with regards to preload hooks.
574          */
575         mono_assembly_load_references (image, status);
576
577         EnterCriticalSection (&assemblies_mutex);
578
579         loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
580         loading = g_list_remove (loading, ass);
581         if (loading == NULL)
582                 /* Prevent memory leaks */
583                 g_hash_table_remove (assemblies_loading, GetCurrentThread ());
584         else
585                 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
586         if (*status != MONO_IMAGE_OK) {
587                 LeaveCriticalSection (&assemblies_mutex);
588                 mono_assembly_close (ass);
589                 return NULL;
590         }
591
592         if (ass->aname.name) {
593                 ass2 = search_loaded (&ass->aname);
594                 if (ass2) {
595                         /* Somebody else has loaded the assembly before us */
596                         LeaveCriticalSection (&assemblies_mutex);
597                         mono_assembly_close (ass);
598                         return ass2;
599                 }
600         }
601
602         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
603         LeaveCriticalSection (&assemblies_mutex);
604
605         mono_assembly_invoke_load_hook (ass);
606
607         return ass;
608 }
609
610 MonoAssembly*
611 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
612 {
613         MonoAssembly *result;
614         char *fullpath, *filename;
615
616         result = invoke_assembly_preload_hook (aname, assemblies_path);
617         if (result)
618                 return result;
619
620         /* g_print ("loading %s\n", aname->name); */
621         /* special case corlib */
622         if ((strcmp (aname->name, "mscorlib") == 0) || (strcmp (aname->name, "corlib") == 0)) {
623                 if (corlib) {
624                         /* g_print ("corlib already loaded\n"); */
625                         return corlib;
626                 }
627                 /* g_print ("corlib load\n"); */
628                 if (assemblies_path) {
629                         corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status);
630                         if (corlib)
631                                 return corlib;
632                         corlib = load_in_path ("corlib.dll", (const char**)assemblies_path, status);
633                         if (corlib)
634                                 return corlib;
635                 }
636                 corlib = load_in_path ("mscorlib.dll", default_path, status);
637                 if (!corlib)
638                         corlib = load_in_path ("corlib.dll", default_path, status);
639                 return corlib;
640         }
641         result = search_loaded (aname);
642         if (result)
643                 return result;
644         /* g_print ("%s not found in cache\n", aname->name); */
645         if (strstr (aname->name, ".dll"))
646                 filename = g_strdup (aname->name);
647         else
648                 filename = g_strconcat (aname->name, ".dll", NULL);
649         if (basedir) {
650                 fullpath = g_build_filename (basedir, filename, NULL);
651                 result = mono_assembly_open (fullpath, status);
652                 g_free (fullpath);
653                 if (result) {
654                         g_free (filename);
655                         return result;
656                 }
657         }
658         if (assemblies_path) {
659                 result = load_in_path (filename, (const char**)assemblies_path, status);
660                 if (result) {
661                         g_free (filename);
662                         return result;
663                 }
664         }
665         result = load_in_path (filename, default_path, status);
666         g_free (filename);
667         return result;
668 }
669
670 MonoAssembly*
671 mono_assembly_loaded (MonoAssemblyName *aname)
672 {
673         MonoAssembly *res;
674
675         EnterCriticalSection (&assemblies_mutex);
676         res = search_loaded (aname);
677         LeaveCriticalSection (&assemblies_mutex);
678
679         return res;
680 }
681
682 void
683 mono_assembly_close (MonoAssembly *assembly)
684 {
685         MonoImage *image;
686         int i;
687         
688         g_return_if_fail (assembly != NULL);
689
690         EnterCriticalSection (&assemblies_mutex);
691         if (--assembly->ref_count != 0) {
692                 LeaveCriticalSection (&assemblies_mutex);
693                 return;
694         }
695         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
696         LeaveCriticalSection (&assemblies_mutex);
697         image = assembly->image;
698         if (image->references) {
699                 for (i = 0; image->references [i] != NULL; i++)
700                         mono_image_close (image->references [i]->image);
701                 g_free (image->references);
702         }
703
704         mono_image_close (assembly->image);
705
706         g_free (assembly->basedir);
707         g_free (assembly);
708 }
709
710 MonoImage*
711 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
712 {
713         MonoImageOpenStatus status;
714         MonoImage *module;
715
716         module = mono_image_load_file_for_image (assembly->image, idx);
717         if (module)
718                 mono_assembly_load_references (module, &status);
719
720         return module;
721 }
722
723 void
724 mono_assembly_foreach (GFunc func, gpointer user_data)
725 {
726         GList *copy;
727
728         /*
729      * We make a copy of the list to avoid calling the callback inside the 
730          * lock, which could lead to deadlocks.
731          */
732         EnterCriticalSection (&assemblies_mutex);
733         copy = g_list_copy (loaded_assemblies);
734         LeaveCriticalSection (&assemblies_mutex);
735
736         g_list_foreach (loaded_assemblies, func, user_data);
737
738         g_list_free (copy);
739 }
740
741 /* Holds the assembly of the application, for
742  * System.Diagnostics.Process::MainModule
743  */
744 static MonoAssembly *main_assembly=NULL;
745
746 void
747 mono_assembly_set_main (MonoAssembly *assembly)
748 {
749         main_assembly=assembly;
750 }
751
752 MonoAssembly *
753 mono_assembly_get_main (void)
754 {
755         return(main_assembly);
756 }