[corlib] Fixed StringBuilder construction bugs in marshalling caused by changes to...
[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  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10  */
11 #include <config.h>
12 #include <stdio.h>
13 #include <glib.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include "assembly.h"
18 #include "image.h"
19 #include "object-internals.h"
20 #include <mono/metadata/loader.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/class-internals.h>
25 #include <mono/metadata/domain-internals.h>
26 #include <mono/metadata/mono-endian.h>
27 #include <mono/metadata/mono-debug.h>
28 #include <mono/io-layer/io-layer.h>
29 #include <mono/utils/mono-uri.h>
30 #include <mono/metadata/mono-config.h>
31 #include <mono/utils/mono-digest.h>
32 #include <mono/utils/mono-logger-internal.h>
33 #include <mono/utils/mono-path.h>
34 #include <mono/metadata/reflection.h>
35 #include <mono/metadata/coree.h>
36 #include <mono/metadata/cil-coff.h>
37 #include <mono/utils/mono-io-portability.h>
38 #include <mono/utils/atomic.h>
39 #include <mono/utils/mono-mutex.h>
40
41 #ifndef HOST_WIN32
42 #include <sys/types.h>
43 #include <unistd.h>
44 #include <sys/stat.h>
45 #endif
46
47 #ifdef PLATFORM_MACOSX
48 #include <mach-o/dyld.h>
49 #endif
50
51 /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
52 typedef struct  {
53         const char* assembly_name;
54         guint8 version_set_index;
55 } AssemblyVersionMap;
56
57 /* the default search path is empty, the first slot is replaced with the computed value */
58 static const char*
59 default_path [] = {
60         NULL,
61         NULL,
62         NULL
63 };
64
65 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
66 static char **assemblies_path = NULL;
67
68 /* Contains the list of directories that point to auxiliary GACs */
69 static char **extra_gac_paths = NULL;
70
71 #ifndef DISABLE_ASSEMBLY_REMAPPING
72 /* The list of system assemblies what will be remapped to the running
73  * runtime version. WARNING: this list must be sorted.
74  * The integer number is an index in the MonoRuntimeInfo structure, whose
75  * values can be found in domain.c - supported_runtimes. Look there
76  * to understand what remapping will be made.
77  */
78 static const AssemblyVersionMap framework_assemblies [] = {
79         {"Accessibility", 0},
80         {"Commons.Xml.Relaxng", 0},
81         {"I18N", 0},
82         {"I18N.CJK", 0},
83         {"I18N.MidEast", 0},
84         {"I18N.Other", 0},
85         {"I18N.Rare", 0},
86         {"I18N.West", 0},
87         {"Microsoft.VisualBasic", 1},
88         {"Microsoft.VisualC", 1},
89         {"Mono.Cairo", 0},
90         {"Mono.CompilerServices.SymbolWriter", 0},
91         {"Mono.Data", 0},
92         {"Mono.Data.SybaseClient", 0},
93         {"Mono.Data.Tds", 0},
94         {"Mono.Data.TdsClient", 0},
95         {"Mono.GetOptions", 0},
96         {"Mono.Http", 0},
97         {"Mono.Posix", 0},
98         {"Mono.Security", 0},
99         {"Mono.Security.Win32", 0},
100         {"Mono.Xml.Ext", 0},
101         {"Novell.Directory.Ldap", 0},
102         {"Npgsql", 0},
103         {"PEAPI", 0},
104         {"System", 0},
105         {"System.ComponentModel.DataAnnotations", 2},
106         {"System.Configuration", 0},
107         {"System.Configuration.Install", 0},
108         {"System.Core", 2},
109         {"System.Data", 0},
110         {"System.Data.Linq", 2},
111         {"System.Data.OracleClient", 0},
112         {"System.Data.Services", 2},
113         {"System.Data.Services.Client", 2},
114         {"System.Data.SqlXml", 0},
115         {"System.Design", 0},
116         {"System.DirectoryServices", 0},
117         {"System.Drawing", 0},
118         {"System.Drawing.Design", 0},
119         {"System.EnterpriseServices", 0},
120         {"System.Management", 0},
121         {"System.Messaging", 0},
122         {"System.Net", 2},
123         {"System.Runtime.Remoting", 0},
124         {"System.Runtime.Serialization", 3},
125         {"System.Runtime.Serialization.Formatters.Soap", 0},
126         {"System.Security", 0},
127         {"System.ServiceModel.Web", 2},
128         {"System.ServiceProcess", 0},
129         {"System.Transactions", 0},
130         {"System.Web", 0},
131         {"System.Web.Abstractions", 2},
132         {"System.Web.DynamicData", 2},
133         {"System.Web.Extensions", 2},
134         {"System.Web.Mobile", 0},
135         {"System.Web.Routing", 2},
136         {"System.Web.Services", 0},
137         {"System.Windows.Forms", 0},
138         {"System.Xml", 0},
139         {"System.Xml.Linq", 2},
140         {"WindowsBase", 3},
141         {"mscorlib", 0}
142 };
143 #endif
144
145 /*
146  * keeps track of loaded assemblies
147  */
148 static GList *loaded_assemblies = NULL;
149 static MonoAssembly *corlib;
150
151 #if defined(__native_client__)
152
153 /* On Native Client, allow mscorlib to be loaded from memory  */
154 /* instead of loaded off disk.  If these are not set, default */
155 /* mscorlib loading will take place                           */
156
157 /* NOTE: If mscorlib data is passed to mono in this way then */
158 /* it needs to remain allocated during the use of mono.      */
159
160 static void *corlibData = NULL;
161 static size_t corlibSize = 0;
162
163 void
164 mono_set_corlib_data (void *data, size_t size)
165 {
166   corlibData = data;
167   corlibSize = size;
168 }
169
170 #endif
171
172 /* This protects loaded_assemblies and image->references */
173 #define mono_assemblies_lock() mono_mutex_lock (&assemblies_mutex)
174 #define mono_assemblies_unlock() mono_mutex_unlock (&assemblies_mutex)
175 static mono_mutex_t assemblies_mutex;
176
177 /* If defined, points to the bundled assembly information */
178 const MonoBundledAssembly **bundles;
179
180 static mono_mutex_t assembly_binding_mutex;
181
182 /* Loaded assembly binding info */
183 static GSList *loaded_assembly_bindings = NULL;
184
185 static MonoAssembly*
186 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
187 static MonoAssembly*
188 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
189 static MonoBoolean
190 mono_assembly_is_in_gac (const gchar *filanem);
191
192 static gchar*
193 encode_public_tok (const guchar *token, gint32 len)
194 {
195         const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
196         gchar *res;
197         int i;
198
199         res = g_malloc (len * 2 + 1);
200         for (i = 0; i < len; i++) {
201                 res [i * 2] = allowed [token [i] >> 4];
202                 res [i * 2 + 1] = allowed [token [i] & 0xF];
203         }
204         res [len * 2] = 0;
205         return res;
206 }
207
208 /**
209  * mono_public_tokens_are_equal:
210  * @pubt1: first public key token
211  * @pubt2: second public key token
212  *
213  * Compare two public key tokens and return #TRUE is they are equal and #FALSE
214  * otherwise.
215  */
216 gboolean
217 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
218 {
219         return memcmp (pubt1, pubt2, 16) == 0;
220 }
221
222 /**
223  * mono_set_assemblies_path:
224  * @path: list of paths that contain directories where Mono will look for assemblies
225  *
226  * Use this method to override the standard assembly lookup system and
227  * override any assemblies coming from the GAC.  This is the method
228  * that supports the MONO_PATH variable.
229  *
230  * Notice that MONO_PATH and this method are really a very bad idea as
231  * it prevents the GAC from working and it prevents the standard
232  * resolution mechanisms from working.  Nonetheless, for some debugging
233  * situations and bootstrapping setups, this is useful to have. 
234  */
235 void
236 mono_set_assemblies_path (const char* path)
237 {
238         char **splitted, **dest;
239
240         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
241         if (assemblies_path)
242                 g_strfreev (assemblies_path);
243         assemblies_path = dest = splitted;
244         while (*splitted) {
245                 char *tmp = *splitted;
246                 if (*tmp)
247                         *dest++ = mono_path_canonicalize (tmp);
248                 g_free (tmp);
249                 splitted++;
250         }
251         *dest = *splitted;
252
253         if (g_getenv ("MONO_DEBUG") == NULL)
254                 return;
255
256         splitted = assemblies_path;
257         while (*splitted) {
258                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
259                         g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
260
261                 splitted++;
262         }
263 }
264
265 /* Native Client can't get this info from an environment variable so */
266 /* it's passed in to the runtime, or set manually by embedding code. */
267 #ifdef __native_client__
268 char* nacl_mono_path = NULL;
269 #endif
270
271 static void
272 check_path_env (void)
273 {
274         const char* path;
275         path = g_getenv ("MONO_PATH");
276 #ifdef __native_client__
277         if (!path)
278                 path = nacl_mono_path;
279 #endif
280         if (!path || assemblies_path != NULL)
281                 return;
282
283         mono_set_assemblies_path(path);
284 }
285
286 static void
287 check_extra_gac_path_env (void) {
288         const char *path;
289         char **splitted, **dest;
290         
291         path = g_getenv ("MONO_GAC_PREFIX");
292         if (!path)
293                 return;
294
295         splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
296         if (extra_gac_paths)
297                 g_strfreev (extra_gac_paths);
298         extra_gac_paths = dest = splitted;
299         while (*splitted){
300                 if (**splitted)
301                         *dest++ = *splitted;
302                 splitted++;
303         }
304         *dest = *splitted;
305         
306         if (g_getenv ("MONO_DEBUG") == NULL)
307                 return;
308
309         while (*splitted) {
310                 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
311                         g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
312
313                 splitted++;
314         }
315 }
316
317 static gboolean
318 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
319 {
320         if (!info || !info->name)
321                 return FALSE;
322
323         if (strcmp (info->name, aname->name))
324                 return FALSE;
325
326         if (info->major != aname->major || info->minor != aname->minor)
327                 return FALSE;
328
329         if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0])) 
330                 return FALSE;
331         
332         if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
333                 return FALSE;
334         
335         if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
336                 return FALSE;
337
338         return TRUE;
339 }
340
341 static void
342 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
343 {
344         if (!info)
345                 return;
346
347         g_free (info->name);
348         g_free (info->culture);
349 }
350
351 static void
352 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
353 {
354         MonoTableInfo *t;
355         guint32 cols [MONO_MANIFEST_SIZE];
356         const gchar *filename;
357         gchar *subpath, *fullpath;
358
359         t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
360         /* MS Impl. accepts policy assemblies with more than
361          * one manifest resource, and only takes the first one */
362         if (t->rows < 1) {
363                 binding_info->is_valid = FALSE;
364                 return;
365         }
366         
367         mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
368         if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
369                 binding_info->is_valid = FALSE;
370                 return;
371         }
372         
373         filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
374         g_assert (filename != NULL);
375         
376         subpath = g_path_get_dirname (image->name);
377         fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
378         mono_config_parse_publisher_policy (fullpath, binding_info);
379         g_free (subpath);
380         g_free (fullpath);
381         
382         /* Define the optional elements/attributes before checking */
383         if (!binding_info->culture)
384                 binding_info->culture = g_strdup ("");
385         
386         /* Check that the most important elements/attributes exist */
387         if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
388                         !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
389                 mono_assembly_binding_info_free (binding_info);
390                 binding_info->is_valid = FALSE;
391                 return;
392         }
393
394         binding_info->is_valid = TRUE;
395 }
396
397 static int
398 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
399 {
400         if (v->major > aname->major)
401                 return 1;
402         else if (v->major < aname->major)
403                 return -1;
404
405         if (v->minor > aname->minor)
406                 return 1;
407         else if (v->minor < aname->minor)
408                 return -1;
409
410         if (v->build > aname->build)
411                 return 1;
412         else if (v->build < aname->build)
413                 return -1;
414
415         if (v->revision > aname->revision)
416                 return 1;
417         else if (v->revision < aname->revision)
418                 return -1;
419
420         return 0;
421 }
422
423 static gboolean
424 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
425 {
426         if (!info->is_valid)
427                 return FALSE;
428         
429         /* If has_old_version_top doesn't exist, we don't have an interval */
430         if (!info->has_old_version_top) {
431                 if (compare_versions (&info->old_version_bottom, name) == 0)
432                         return TRUE;
433
434                 return FALSE;
435         }
436
437         /* Check that the version defined by name is valid for the interval */
438         if (compare_versions (&info->old_version_top, name) < 0)
439                 return FALSE;
440
441         /* We should be greater or equal than the small version */
442         if (compare_versions (&info->old_version_bottom, name) > 0)
443                 return FALSE;
444
445         return TRUE;
446 }
447
448 /**
449  * mono_assembly_names_equal:
450  * @l: first assembly
451  * @r: second assembly.
452  *
453  * Compares two MonoAssemblyNames and returns whether they are equal.
454  *
455  * This compares the names, the cultures, the release version and their
456  * public tokens.
457  *
458  * Returns: TRUE if both assembly names are equal.
459  */
460 gboolean
461 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
462 {
463         if (!l->name || !r->name)
464                 return FALSE;
465
466         if (strcmp (l->name, r->name))
467                 return FALSE;
468
469         if (l->culture && r->culture && strcmp (l->culture, r->culture))
470                 return FALSE;
471
472         if (l->major != r->major || l->minor != r->minor ||
473                         l->build != r->build || l->revision != r->revision)
474                 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)))
475                         return FALSE;
476
477         if (!l->public_key_token [0] || !r->public_key_token [0])
478                 return TRUE;
479
480         if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
481                 return FALSE;
482
483         return TRUE;
484 }
485
486 static MonoAssembly *
487 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
488 {
489         int i;
490         char *fullpath;
491         MonoAssembly *result;
492
493         for (i = 0; search_path [i]; ++i) {
494                 fullpath = g_build_filename (search_path [i], basename, NULL);
495                 result = mono_assembly_open_full (fullpath, status, refonly);
496                 g_free (fullpath);
497                 if (result)
498                         return result;
499         }
500         return NULL;
501 }
502
503 /**
504  * mono_assembly_setrootdir:
505  * @root_dir: The pathname of the root directory where we will locate assemblies
506  *
507  * This routine sets the internal default root directory for looking up
508  * assemblies.
509  *
510  * This is used by Windows installations to compute dynamically the
511  * place where the Mono assemblies are located.
512  *
513  */
514 void
515 mono_assembly_setrootdir (const char *root_dir)
516 {
517         /*
518          * Override the MONO_ASSEMBLIES directory configured at compile time.
519          */
520         /* Leak if called more than once */
521         default_path [0] = g_strdup (root_dir);
522 }
523
524 /**
525  * mono_assembly_getrootdir:
526  * 
527  * Obtains the root directory used for looking up assemblies.
528  *
529  * Returns: a string with the directory, this string should not be freed.
530  */
531 G_CONST_RETURN gchar *
532 mono_assembly_getrootdir (void)
533 {
534         return default_path [0];
535 }
536
537 /**
538  * mono_set_dirs:
539  * @assembly_dir: the base directory for assemblies
540  * @config_dir: the base directory for configuration files
541  *
542  * This routine is used internally and by developers embedding
543  * the runtime into their own applications.
544  *
545  * There are a number of cases to consider: Mono as a system-installed
546  * package that is available on the location preconfigured or Mono in
547  * a relocated location.
548  *
549  * If you are using a system-installed Mono, you can pass NULL
550  * to both parameters.  If you are not, you should compute both
551  * directory values and call this routine.
552  *
553  * The values for a given PREFIX are:
554  *
555  *    assembly_dir: PREFIX/lib
556  *    config_dir:   PREFIX/etc
557  *
558  * Notice that embedders that use Mono in a relocated way must
559  * compute the location at runtime, as they will be in control
560  * of where Mono is installed.
561  */
562 void
563 mono_set_dirs (const char *assembly_dir, const char *config_dir)
564 {
565 #if defined (MONO_ASSEMBLIES)
566         if (assembly_dir == NULL)
567                 assembly_dir = MONO_ASSEMBLIES;
568 #endif
569 #if defined (MONO_CFG_DIR)
570         if (config_dir == NULL)
571                 config_dir = MONO_CFG_DIR;
572 #endif
573         mono_assembly_setrootdir (assembly_dir);
574         mono_set_config_dir (config_dir);
575 }
576
577 #ifndef HOST_WIN32
578
579 static char *
580 compute_base (char *path)
581 {
582         char *p = strrchr (path, '/');
583         if (p == NULL)
584                 return NULL;
585
586         /* Not a well known Mono executable, we are embedded, cant guess the base  */
587         if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
588                 return NULL;
589             
590         *p = 0;
591         p = strrchr (path, '/');
592         if (p == NULL)
593                 return NULL;
594         
595         if (strcmp (p, "/bin") != 0)
596                 return NULL;
597         *p = 0;
598         return path;
599 }
600
601 static void
602 fallback (void)
603 {
604         mono_set_dirs (MONO_ASSEMBLIES, MONO_CFG_DIR);
605 }
606
607 static G_GNUC_UNUSED void
608 set_dirs (char *exe)
609 {
610         char *base;
611         char *config, *lib, *mono;
612         struct stat buf;
613         
614         /*
615          * Only /usr prefix is treated specially
616          */
617         if (strncmp (exe, MONO_BINDIR, strlen (MONO_BINDIR)) == 0 || (base = compute_base (exe)) == NULL){
618                 fallback ();
619                 return;
620         }
621
622         config = g_build_filename (base, "etc", NULL);
623         lib = g_build_filename (base, "lib", NULL);
624         mono = g_build_filename (lib, "mono/2.0", NULL);
625         if (stat (mono, &buf) == -1)
626                 fallback ();
627         else {
628                 mono_set_dirs (lib, config);
629         }
630         
631         g_free (config);
632         g_free (lib);
633         g_free (mono);
634 }
635
636 #endif /* HOST_WIN32 */
637
638 /**
639  * mono_set_rootdir:
640  *
641  * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
642  * this auto-detects the prefix where Mono was installed. 
643  */
644 void
645 mono_set_rootdir (void)
646 {
647 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
648         gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
649
650 #ifdef HOST_WIN32
651         name = mono_get_module_file_name ((HMODULE) &__ImageBase);
652 #else
653         {
654                 /* 
655                  * _NSGetExecutablePath may return -1 to indicate buf is not large
656                  *  enough, but we ignore that case to avoid having to do extra dynamic
657                  *  allocation for the path and hope that 4096 is enough - this is 
658                  *  ok in the Linux/Solaris case below at least...
659                  */
660                 
661                 gchar buf[4096];
662                 guint buf_size = sizeof (buf);
663  
664                 name = NULL;
665                 if (_NSGetExecutablePath (buf, &buf_size) == 0)
666                         name = g_strdup (buf);
667  
668                 if (name == NULL) {
669                         fallback ();
670                         return;
671                 }
672         }
673 #endif
674
675         resolvedname = mono_path_resolve_symlinks (name);
676
677         bindir = g_path_get_dirname (resolvedname);
678         installdir = g_path_get_dirname (bindir);
679         root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
680
681         config = g_build_filename (root, "..", "etc", NULL);
682 #ifdef HOST_WIN32
683         mono_set_dirs (root, config);
684 #else
685         if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
686                 mono_set_dirs (root, config);
687         else
688                 fallback ();
689 #endif
690
691         g_free (config);
692         g_free (root);
693         g_free (installdir);
694         g_free (bindir);
695         g_free (name);
696         g_free (resolvedname);
697 #elif defined(DISABLE_MONO_AUTODETECTION)
698         fallback ();
699 #else
700         char buf [4096];
701         int  s;
702         char *str;
703
704         /* Linux style */
705         s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
706
707         if (s != -1){
708                 buf [s] = 0;
709                 set_dirs (buf);
710                 return;
711         }
712
713         /* Solaris 10 style */
714         str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
715         s = readlink (str, buf, sizeof (buf)-1);
716         g_free (str);
717         if (s != -1){
718                 buf [s] = 0;
719                 set_dirs (buf);
720                 return;
721         } 
722         fallback ();
723 #endif
724 }
725
726 /**
727  * mono_assemblies_init:
728  *
729  *  Initialize global variables used by this module.
730  */
731 void
732 mono_assemblies_init (void)
733 {
734         /*
735          * Initialize our internal paths if we have not been initialized yet.
736          * This happens when embedders use Mono.
737          */
738         if (mono_assembly_getrootdir () == NULL)
739                 mono_set_rootdir ();
740
741         check_path_env ();
742         check_extra_gac_path_env ();
743
744         mono_mutex_init_recursive (&assemblies_mutex);
745         mono_mutex_init (&assembly_binding_mutex);
746 }
747
748 static void
749 mono_assembly_binding_lock (void)
750 {
751         mono_locks_mutex_acquire (&assembly_binding_mutex, AssemblyBindingLock);
752 }
753
754 static void
755 mono_assembly_binding_unlock (void)
756 {
757         mono_locks_mutex_release (&assembly_binding_mutex, AssemblyBindingLock);
758 }
759
760 gboolean
761 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
762 {
763         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
764         guint32 cols [MONO_ASSEMBLY_SIZE];
765         gint32 machine, flags;
766
767         if (!t->rows)
768                 return FALSE;
769
770         mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
771
772         aname->hash_len = 0;
773         aname->hash_value = NULL;
774         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
775         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
776         aname->flags = cols [MONO_ASSEMBLY_FLAGS];
777         aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
778         aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
779         aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
780         aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
781         aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
782         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
783                 guchar* token = g_malloc (8);
784                 gchar* encoded;
785                 const gchar* pkey;
786                 int len;
787
788                 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
789                 len = mono_metadata_decode_blob_size (pkey, &pkey);
790                 aname->public_key = (guchar*)pkey;
791
792                 mono_digest_get_public_token (token, aname->public_key, len);
793                 encoded = encode_public_tok (token, 8);
794                 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
795
796                 g_free (encoded);
797                 g_free (token);
798         }
799         else {
800                 aname->public_key = NULL;
801                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
802         }
803
804         if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
805                 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
806         }
807         else
808                 aname->public_key = 0;
809
810         machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
811         flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
812         switch (machine) {
813         case COFF_MACHINE_I386:
814                 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
815                 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
816                         aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
817                 else if ((flags & 0x70) == 0x70)
818                         aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
819                 else
820                         aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
821                 break;
822         case COFF_MACHINE_IA64:
823                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
824                 break;
825         case COFF_MACHINE_AMD64:
826                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
827                 break;
828         case COFF_MACHINE_ARM:
829                 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
830                 break;
831         default:
832                 break;
833         }
834
835         return TRUE;
836 }
837
838 /**
839  * mono_stringify_assembly_name:
840  * @aname: the assembly name.
841  *
842  * Convert @aname into its string format. The returned string is dynamically
843  * allocated and should be freed by the caller.
844  *
845  * Returns: a newly allocated string with a string representation of
846  * the assembly name.
847  */
848 char*
849 mono_stringify_assembly_name (MonoAssemblyName *aname)
850 {
851         const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
852
853         return g_strdup_printf (
854                 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
855                 quote, aname->name, quote,
856                 aname->major, aname->minor, aname->build, aname->revision,
857                 aname->culture && *aname->culture? aname->culture: "neutral",
858                 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
859                 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
860 }
861
862 static gchar*
863 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
864 {
865         const gchar *public_tok;
866         int len;
867
868         public_tok = mono_metadata_blob_heap (image, key_index);
869         len = mono_metadata_decode_blob_size (public_tok, &public_tok);
870
871         if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
872                 guchar token [8];
873                 mono_digest_get_public_token (token, (guchar*)public_tok, len);
874                 return encode_public_tok (token, 8);
875         }
876
877         return encode_public_tok ((guchar*)public_tok, len);
878 }
879
880 /**
881  * mono_assembly_addref:
882  * @assemnly: the assembly to reference
883  *
884  * This routine increments the reference count on a MonoAssembly.
885  * The reference count is reduced every time the method mono_assembly_close() is
886  * invoked.
887  */
888 void
889 mono_assembly_addref (MonoAssembly *assembly)
890 {
891         InterlockedIncrement (&assembly->ref_count);
892 }
893
894 /*
895  * CAUTION: This table must be kept in sync with
896  *          ivkm/reflect/Fusion.cs
897  */
898
899 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
900 #define WINFX_KEY "31bf3856ad364e35"
901 #define ECMA_KEY "b77a5c561934e089"
902 #define MSFINAL_KEY "b03f5f7f11d50a3a"
903
904 typedef struct {
905         const char *name;
906         const char *from;
907         const char *to;
908 } KeyRemapEntry;
909
910 static KeyRemapEntry key_remap_table[] = {
911         { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
912         { "System", SILVERLIGHT_KEY, ECMA_KEY },
913         { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
914         { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
915         { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
916         // FIXME: MS uses MSFINAL_KEY for .NET 4.5
917         { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
918         { "System.Numerics", WINFX_KEY, ECMA_KEY },
919         { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
920         { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
921         { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
922         { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
923         { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
924         { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
925         { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
926 };
927
928 static void
929 remap_keys (MonoAssemblyName *aname)
930 {
931         int i;
932         for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
933                 const KeyRemapEntry *entry = &key_remap_table [i];
934
935                 if (strcmp (aname->name, entry->name) ||
936                     !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
937                         continue;
938
939                 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
940                      
941                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
942                             "Remapped public key token of retargetable assembly %s from %s to %s",
943                             aname->name, entry->from, entry->to);
944                 return;
945         }
946 }
947
948 static MonoAssemblyName *
949 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
950 {
951         const MonoRuntimeInfo *current_runtime;
952         int pos, first, last;
953
954         if (aname->name == NULL) return aname;
955
956         current_runtime = mono_get_runtime_info ();
957
958         if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
959                 const AssemblyVersionSet* vset;
960
961                 /* Remap to current runtime */
962                 vset = &current_runtime->version_sets [0];
963
964                 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
965                 dest_aname->major = vset->major;
966                 dest_aname->minor = vset->minor;
967                 dest_aname->build = vset->build;
968                 dest_aname->revision = vset->revision;
969                 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
970
971                 /* Remap assembly name */
972                 if (!strcmp (aname->name, "System.Net"))
973                         dest_aname->name = g_strdup ("System");
974                 
975                 remap_keys (dest_aname);
976
977                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
978                                         "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
979                                         aname->name,
980                                         aname->major, aname->minor, aname->build, aname->revision,
981                                         dest_aname->name,
982                                         vset->major, vset->minor, vset->build, vset->revision
983                                         );
984
985                 return dest_aname;
986         }
987         
988 #ifndef DISABLE_ASSEMBLY_REMAPPING
989         first = 0;
990         last = G_N_ELEMENTS (framework_assemblies) - 1;
991         
992         while (first <= last) {
993                 int res;
994                 pos = first + (last - first) / 2;
995                 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
996                 if (res == 0) {
997                         const AssemblyVersionSet* vset;
998                         int index = framework_assemblies[pos].version_set_index;
999                         g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1000                         vset = &current_runtime->version_sets [index];
1001
1002                         if (aname->major == vset->major && aname->minor == vset->minor &&
1003                                 aname->build == vset->build && aname->revision == vset->revision)
1004                                 return aname;
1005                 
1006                         if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1007                                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1008                                         "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1009                                                         aname->name,
1010                                                         aname->major, aname->minor, aname->build, aname->revision,
1011                                                         vset->major, vset->minor, vset->build, vset->revision
1012                                                         );
1013                         
1014                         memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1015                         dest_aname->major = vset->major;
1016                         dest_aname->minor = vset->minor;
1017                         dest_aname->build = vset->build;
1018                         dest_aname->revision = vset->revision;
1019                         return dest_aname;
1020                 } else if (res < 0) {
1021                         last = pos - 1;
1022                 } else {
1023                         first = pos + 1;
1024                 }
1025         }
1026 #endif
1027
1028         return aname;
1029 }
1030
1031 /*
1032  * mono_assembly_get_assemblyref:
1033  *
1034  *   Fill out ANAME with the assembly name of the INDEXth assembly reference in IMAGE.
1035  */
1036 void
1037 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1038 {
1039         MonoTableInfo *t;
1040         guint32 cols [MONO_ASSEMBLYREF_SIZE];
1041         const char *hash;
1042
1043         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1044
1045         mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1046                 
1047         hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1048         aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1049         aname->hash_value = hash;
1050         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1051         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1052         aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1053         aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1054         aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1055         aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1056         aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1057
1058         if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1059                 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1060                 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1061                 g_free (token);
1062         } else {
1063                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1064         }
1065 }
1066
1067 void
1068 mono_assembly_load_reference (MonoImage *image, int index)
1069 {
1070         MonoAssembly *reference;
1071         MonoAssemblyName aname;
1072         MonoImageOpenStatus status;
1073
1074         /*
1075          * image->references is shared between threads, so we need to access
1076          * it inside a critical section.
1077          */
1078         mono_assemblies_lock ();
1079         if (!image->references) {
1080                 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1081         
1082                 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1083                 image->nreferences = t->rows;
1084         }
1085         reference = image->references [index];
1086         mono_assemblies_unlock ();
1087         if (reference)
1088                 return;
1089
1090         mono_assembly_get_assemblyref (image, index, &aname);
1091
1092         if (image->assembly && image->assembly->ref_only) {
1093                 /* We use the loaded corlib */
1094                 if (!strcmp (aname.name, "mscorlib"))
1095                         reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1096                 else {
1097                         reference = mono_assembly_loaded_full (&aname, TRUE);
1098                         if (!reference)
1099                                 /* Try a postload search hook */
1100                                 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1101                 }
1102
1103                 /*
1104                  * Here we must advice that the error was due to
1105                  * a non loaded reference using the ReflectionOnly api
1106                 */
1107                 if (!reference)
1108                         reference = REFERENCE_MISSING;
1109         } else {
1110                 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1111                  * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1112                  * accordingly, it would fail on the MS runtime before).
1113                  * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1114                  * example bug-349190.2.cs and who knows how much more code in the wild.
1115                  */
1116                 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1117                 if (!reference && image->assembly)
1118                         reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1119         }
1120
1121         if (reference == NULL){
1122                 char *extra_msg;
1123
1124                 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1125                         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 != NULL ? image->assembly->basedir : "" );
1126                 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1127                         extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1128                 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1129                         extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1130                 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1131                         extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1132                 } else {
1133                         extra_msg = g_strdup ("");
1134                 }
1135                 
1136                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1137                                    "     Assembly:   %s    (assemblyref_index=%d)\n"
1138                                    "     Version:    %d.%d.%d.%d\n"
1139                                    "     Public Key: %s\n%s",
1140                                    image->name, aname.name, index,
1141                                    aname.major, aname.minor, aname.build, aname.revision,
1142                                    strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1143                 g_free (extra_msg);
1144         }
1145
1146         mono_assemblies_lock ();
1147         if (reference == NULL) {
1148                 /* Flag as not found */
1149                 reference = REFERENCE_MISSING;
1150         }       
1151
1152         if (!image->references [index]) {
1153                 if (reference != REFERENCE_MISSING){
1154                         mono_assembly_addref (reference);
1155                         if (image->assembly)
1156                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1157                                     image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1158                 } else {
1159                         if (image->assembly)
1160                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1161                                     image->assembly->aname.name, image->assembly);
1162                 }
1163                 
1164                 image->references [index] = reference;
1165         }
1166         mono_assemblies_unlock ();
1167
1168         if (image->references [index] != reference) {
1169                 /* Somebody loaded it before us */
1170                 mono_assembly_close (reference);
1171         }
1172 }
1173
1174 void
1175 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1176 {
1177         /* This is a no-op now but it is part of the embedding API so we can't remove it */
1178         *status = MONO_IMAGE_OK;
1179 }
1180
1181 typedef struct AssemblyLoadHook AssemblyLoadHook;
1182 struct AssemblyLoadHook {
1183         AssemblyLoadHook *next;
1184         MonoAssemblyLoadFunc func;
1185         gpointer user_data;
1186 };
1187
1188 AssemblyLoadHook *assembly_load_hook = NULL;
1189
1190 void
1191 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1192 {
1193         AssemblyLoadHook *hook;
1194
1195         for (hook = assembly_load_hook; hook; hook = hook->next) {
1196                 hook->func (ass, hook->user_data);
1197         }
1198 }
1199
1200 void
1201 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1202 {
1203         AssemblyLoadHook *hook;
1204         
1205         g_return_if_fail (func != NULL);
1206
1207         hook = g_new0 (AssemblyLoadHook, 1);
1208         hook->func = func;
1209         hook->user_data = user_data;
1210         hook->next = assembly_load_hook;
1211         assembly_load_hook = hook;
1212 }
1213
1214 static void
1215 free_assembly_load_hooks (void)
1216 {
1217         AssemblyLoadHook *hook, *next;
1218
1219         for (hook = assembly_load_hook; hook; hook = next) {
1220                 next = hook->next;
1221                 g_free (hook);
1222         }
1223 }
1224
1225 typedef struct AssemblySearchHook AssemblySearchHook;
1226 struct AssemblySearchHook {
1227         AssemblySearchHook *next;
1228         MonoAssemblySearchFunc func;
1229         gboolean refonly;
1230         gboolean postload;
1231         gpointer user_data;
1232 };
1233
1234 AssemblySearchHook *assembly_search_hook = NULL;
1235
1236 static MonoAssembly*
1237 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1238 {
1239         AssemblySearchHook *hook;
1240
1241         for (hook = assembly_search_hook; hook; hook = hook->next) {
1242                 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1243                         MonoAssembly *ass;
1244                         /**
1245                           * A little explanation is in order here.
1246                           *
1247                           * The default postload search hook needs to know the requesting assembly to report it to managed code.
1248                           * The embedding API exposes a search hook that doesn't take such argument.
1249                           *
1250                           * The original fix would call the default search hook before all the registered ones and pass
1251                           * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1252                           * rely on. Which is the ordering between user hooks and the default runtime hook.
1253                           *
1254                           * Registering the hook after mono_jit_init would let your hook run before the default one and
1255                           * when using it to handle non standard app layouts this could save your app from a massive amount
1256                           * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1257                           * are all using this trick and if we broke this assumption they would be very disapointed at us.
1258                           *
1259                           * So what's the fix? We register the default hook using regular means and special case it when iterating
1260                           * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1261                           * assembly.
1262                           */
1263                         if (hook->func == (void*)mono_domain_assembly_postload_search)
1264                                 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1265                         else
1266                                 ass = hook->func (aname, hook->user_data);
1267                         if (ass)
1268                                 return ass;
1269                 }
1270         }
1271
1272         return NULL;
1273 }
1274
1275 MonoAssembly*
1276 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1277 {
1278         return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1279 }
1280
1281 static void
1282 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1283 {
1284         AssemblySearchHook *hook;
1285         
1286         g_return_if_fail (func != NULL);
1287
1288         hook = g_new0 (AssemblySearchHook, 1);
1289         hook->func = func;
1290         hook->user_data = user_data;
1291         hook->refonly = refonly;
1292         hook->postload = postload;
1293         hook->next = assembly_search_hook;
1294         assembly_search_hook = hook;
1295 }
1296
1297 void          
1298 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1299 {
1300         mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1301 }       
1302
1303 static void
1304 free_assembly_search_hooks (void)
1305 {
1306         AssemblySearchHook *hook, *next;
1307
1308         for (hook = assembly_search_hook; hook; hook = next) {
1309                 next = hook->next;
1310                 g_free (hook);
1311         }
1312 }
1313
1314 void
1315 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1316 {
1317         mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1318 }
1319
1320 void          
1321 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1322 {
1323         mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1324 }       
1325
1326 void
1327 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1328 {
1329         mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1330 }
1331
1332 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1333 struct AssemblyPreLoadHook {
1334         AssemblyPreLoadHook *next;
1335         MonoAssemblyPreLoadFunc func;
1336         gpointer user_data;
1337 };
1338
1339 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1340 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1341
1342 static MonoAssembly *
1343 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1344 {
1345         AssemblyPreLoadHook *hook;
1346         MonoAssembly *assembly;
1347
1348         for (hook = assembly_preload_hook; hook; hook = hook->next) {
1349                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1350                 if (assembly != NULL)
1351                         return assembly;
1352         }
1353
1354         return NULL;
1355 }
1356
1357 static MonoAssembly *
1358 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1359 {
1360         AssemblyPreLoadHook *hook;
1361         MonoAssembly *assembly;
1362
1363         for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1364                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1365                 if (assembly != NULL)
1366                         return assembly;
1367         }
1368
1369         return NULL;
1370 }
1371
1372 void
1373 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1374 {
1375         AssemblyPreLoadHook *hook;
1376         
1377         g_return_if_fail (func != NULL);
1378
1379         hook = g_new0 (AssemblyPreLoadHook, 1);
1380         hook->func = func;
1381         hook->user_data = user_data;
1382         hook->next = assembly_preload_hook;
1383         assembly_preload_hook = hook;
1384 }
1385
1386 void
1387 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1388 {
1389         AssemblyPreLoadHook *hook;
1390         
1391         g_return_if_fail (func != NULL);
1392
1393         hook = g_new0 (AssemblyPreLoadHook, 1);
1394         hook->func = func;
1395         hook->user_data = user_data;
1396         hook->next = assembly_refonly_preload_hook;
1397         assembly_refonly_preload_hook = hook;
1398 }
1399
1400 static void
1401 free_assembly_preload_hooks (void)
1402 {
1403         AssemblyPreLoadHook *hook, *next;
1404
1405         for (hook = assembly_preload_hook; hook; hook = next) {
1406                 next = hook->next;
1407                 g_free (hook);
1408         }
1409
1410         for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1411                 next = hook->next;
1412                 g_free (hook);
1413         }
1414 }
1415
1416 static gchar *
1417 absolute_dir (const gchar *filename)
1418 {
1419         gchar *cwd;
1420         gchar *mixed;
1421         gchar **parts;
1422         gchar *part;
1423         GList *list, *tmp;
1424         GString *result;
1425         gchar *res;
1426         gint i;
1427
1428         if (g_path_is_absolute (filename)) {
1429                 part = g_path_get_dirname (filename);
1430                 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1431                 g_free (part);
1432                 return res;
1433         }
1434
1435         cwd = g_get_current_dir ();
1436         mixed = g_build_filename (cwd, filename, NULL);
1437         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1438         g_free (mixed);
1439         g_free (cwd);
1440
1441         list = NULL;
1442         for (i = 0; (part = parts [i]) != NULL; i++) {
1443                 if (!strcmp (part, "."))
1444                         continue;
1445
1446                 if (!strcmp (part, "..")) {
1447                         if (list && list->next) /* Don't remove root */
1448                                 list = g_list_delete_link (list, list);
1449                 } else {
1450                         list = g_list_prepend (list, part);
1451                 }
1452         }
1453
1454         result = g_string_new ("");
1455         list = g_list_reverse (list);
1456
1457         /* Ignores last data pointer, which should be the filename */
1458         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1459                 if (tmp->data)
1460                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
1461                                                                 G_DIR_SEPARATOR);
1462         }
1463
1464         res = result->str;
1465         g_string_free (result, FALSE);
1466         g_list_free (list);
1467         g_strfreev (parts);
1468         if (*res == '\0') {
1469                 g_free (res);
1470                 return g_strdup (".");
1471         }
1472
1473         return res;
1474 }
1475
1476 /** 
1477  * mono_assembly_open_from_bundle:
1478  * @filename: Filename requested
1479  * @status: return value
1480  *
1481  * This routine tries to open the assembly specified by `filename' from the
1482  * defined bundles, if found, returns the MonoImage for it, if not found
1483  * returns NULL
1484  */
1485 MonoImage *
1486 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1487 {
1488         int i;
1489         char *name;
1490         MonoImage *image = NULL;
1491
1492         /*
1493          * we do a very simple search for bundled assemblies: it's not a general 
1494          * purpose assembly loading mechanism.
1495          */
1496
1497         if (!bundles)
1498                 return NULL;
1499
1500         name = g_path_get_basename (filename);
1501
1502         mono_assemblies_lock ();
1503         for (i = 0; !image && bundles [i]; ++i) {
1504                 if (strcmp (bundles [i]->name, name) == 0) {
1505                         image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1506                         break;
1507                 }
1508         }
1509         mono_assemblies_unlock ();
1510         if (image) {
1511                 mono_image_addref (image);
1512                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
1513                 g_free (name);
1514                 return image;
1515         }
1516         g_free (name);
1517         return NULL;
1518 }
1519
1520 MonoAssembly *
1521 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1522 {
1523         MonoImage *image;
1524         MonoAssembly *ass;
1525         MonoImageOpenStatus def_status;
1526         gchar *fname;
1527         gchar *new_fname;
1528         gboolean loaded_from_bundle;
1529         
1530         g_return_val_if_fail (filename != NULL, NULL);
1531
1532         if (!status)
1533                 status = &def_status;
1534         *status = MONO_IMAGE_OK;
1535
1536         if (strncmp (filename, "file://", 7) == 0) {
1537                 GError *error = NULL;
1538                 gchar *uri = (gchar *) filename;
1539                 gchar *tmpuri;
1540
1541                 /*
1542                  * MS allows file://c:/... and fails on file://localhost/c:/... 
1543                  * They also throw an IndexOutOfRangeException if "file://"
1544                  */
1545                 if (uri [7] != '/')
1546                         uri = g_strdup_printf ("file:///%s", uri + 7);
1547         
1548                 tmpuri = uri;
1549                 uri = mono_escape_uri_string (tmpuri);
1550                 fname = g_filename_from_uri (uri, NULL, &error);
1551                 g_free (uri);
1552
1553                 if (tmpuri != filename)
1554                         g_free (tmpuri);
1555
1556                 if (error != NULL) {
1557                         g_warning ("%s\n", error->message);
1558                         g_error_free (error);
1559                         fname = g_strdup (filename);
1560                 }
1561         } else {
1562                 fname = g_strdup (filename);
1563         }
1564
1565         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1566                         "Assembly Loader probing location: '%s'.", fname);
1567
1568         new_fname = NULL;
1569         if (!mono_assembly_is_in_gac (fname))
1570                 new_fname = mono_make_shadow_copy (fname);
1571         if (new_fname && new_fname != fname) {
1572                 g_free (fname);
1573                 fname = new_fname;
1574                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1575                             "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1576         }
1577         
1578         image = NULL;
1579
1580         loaded_from_bundle = FALSE;
1581         if (bundles != NULL) {
1582                 image = mono_assembly_open_from_bundle (fname, status, refonly);
1583                 loaded_from_bundle = image != NULL;
1584         }
1585
1586         if (!image)
1587                 image = mono_image_open_full (fname, status, refonly);
1588
1589         if (!image){
1590                 if (*status == MONO_IMAGE_OK)
1591                         *status = MONO_IMAGE_ERROR_ERRNO;
1592                 g_free (fname);
1593                 return NULL;
1594         }
1595
1596         if (image->assembly) {
1597                 /* Already loaded by another appdomain */
1598                 mono_assembly_invoke_load_hook (image->assembly);
1599                 mono_image_close (image);
1600                 g_free (fname);
1601                 return image->assembly;
1602         }
1603
1604         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1605
1606         if (ass) {
1607                 if (!loaded_from_bundle)
1608                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1609                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1610                 if (!refonly)
1611                         mono_config_for_assembly (ass->image);
1612         }
1613
1614         /* Clear the reference added by mono_image_open */
1615         mono_image_close (image);
1616         
1617         g_free (fname);
1618
1619         return ass;
1620 }
1621
1622 static void
1623 free_item (gpointer val, gpointer user_data)
1624 {
1625         g_free (val);
1626 }
1627
1628 /*
1629  * mono_assembly_load_friends:
1630  * @ass: an assembly
1631  *
1632  * Load the list of friend assemblies that are allowed to access
1633  * the assembly's internal types and members. They are stored as assembly
1634  * names in custom attributes.
1635  *
1636  * This is an internal method, we need this because when we load mscorlib
1637  * we do not have the mono_defaults.internals_visible_class loaded yet,
1638  * so we need to load these after we initialize the runtime. 
1639  *
1640  * LOCKING: Acquires the assemblies lock plus the loader lock.
1641  */
1642 void
1643 mono_assembly_load_friends (MonoAssembly* ass)
1644 {
1645         int i;
1646         MonoCustomAttrInfo* attrs;
1647         GSList *list;
1648
1649         if (ass->friend_assembly_names_inited)
1650                 return;
1651
1652         attrs = mono_custom_attrs_from_assembly (ass);
1653         if (!attrs) {
1654                 mono_assemblies_lock ();
1655                 ass->friend_assembly_names_inited = TRUE;
1656                 mono_assemblies_unlock ();
1657                 return;
1658         }
1659
1660         mono_assemblies_lock ();
1661         if (ass->friend_assembly_names_inited) {
1662                 mono_assemblies_unlock ();
1663                 return;
1664         }
1665         mono_assemblies_unlock ();
1666
1667         list = NULL;
1668         /* 
1669          * We build the list outside the assemblies lock, the worse that can happen
1670          * is that we'll need to free the allocated list.
1671          */
1672         for (i = 0; i < attrs->num_attrs; ++i) {
1673                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1674                 MonoAssemblyName *aname;
1675                 const gchar *data;
1676                 /* Do some sanity checking */
1677                 if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class)
1678                         continue;
1679                 if (attr->data_size < 4)
1680                         continue;
1681                 data = (const char*)attr->data;
1682                 /* 0xFF means null string, see custom attr format */
1683                 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1684                         continue;
1685                 mono_metadata_decode_value (data + 2, &data);
1686                 aname = g_new0 (MonoAssemblyName, 1);
1687                 /*g_print ("friend ass: %s\n", data);*/
1688                 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1689                         list = g_slist_prepend (list, aname);
1690                 } else {
1691                         g_free (aname);
1692                 }
1693         }
1694         mono_custom_attrs_free (attrs);
1695
1696         mono_assemblies_lock ();
1697         if (ass->friend_assembly_names_inited) {
1698                 mono_assemblies_unlock ();
1699                 g_slist_foreach (list, free_item, NULL);
1700                 g_slist_free (list);
1701                 return;
1702         }
1703         ass->friend_assembly_names = list;
1704
1705         /* Because of the double checked locking pattern above */
1706         mono_memory_barrier ();
1707         ass->friend_assembly_names_inited = TRUE;
1708         mono_assemblies_unlock ();
1709 }
1710
1711 /**
1712  * mono_assembly_open:
1713  * @filename: Opens the assembly pointed out by this name
1714  * @status: where a status code can be returned
1715  *
1716  * mono_assembly_open opens the PE-image pointed by @filename, and
1717  * loads any external assemblies referenced by it.
1718  *
1719  * Return: a pointer to the MonoAssembly if @filename contains a valid
1720  * assembly or NULL on error.  Details about the error are stored in the
1721  * @status variable.
1722  */
1723 MonoAssembly *
1724 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1725 {
1726         return mono_assembly_open_full (filename, status, FALSE);
1727 }
1728
1729 MonoAssembly *
1730 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1731                               MonoImageOpenStatus *status, gboolean refonly)
1732 {
1733         MonoAssembly *ass, *ass2;
1734         char *base_dir;
1735
1736         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1737                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1738                 *status = MONO_IMAGE_IMAGE_INVALID;
1739                 return NULL;
1740         }
1741
1742 #if defined (HOST_WIN32)
1743         {
1744                 gchar *tmp_fn;
1745                 int i;
1746
1747                 tmp_fn = g_strdup (fname);
1748                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1749                         if (tmp_fn [i] == '/')
1750                                 tmp_fn [i] = '\\';
1751                 }
1752
1753                 base_dir = absolute_dir (tmp_fn);
1754                 g_free (tmp_fn);
1755         }
1756 #else
1757         base_dir = absolute_dir (fname);
1758 #endif
1759
1760         /*
1761          * Create assembly struct, and enter it into the assembly cache
1762          */
1763         ass = g_new0 (MonoAssembly, 1);
1764         ass->basedir = base_dir;
1765         ass->ref_only = refonly;
1766         ass->image = image;
1767
1768         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1769
1770         mono_assembly_fill_assembly_name (image, &ass->aname);
1771
1772         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1773                 // MS.NET doesn't support loading other mscorlibs
1774                 g_free (ass);
1775                 g_free (base_dir);
1776                 mono_image_addref (mono_defaults.corlib);
1777                 *status = MONO_IMAGE_OK;
1778                 return mono_defaults.corlib->assembly;
1779         }
1780
1781         /* Add a non-temporary reference because of ass->image */
1782         mono_image_addref (image);
1783
1784         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s[%p] -> %s[%p]: %d", ass->aname.name, ass, image->name, image, image->ref_count);
1785
1786         /* 
1787          * The load hooks might take locks so we can't call them while holding the
1788          * assemblies lock.
1789          */
1790         if (ass->aname.name) {
1791                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1792                 if (ass2) {
1793                         g_free (ass);
1794                         g_free (base_dir);
1795                         mono_image_close (image);
1796                         *status = MONO_IMAGE_OK;
1797                         return ass2;
1798                 }
1799         }
1800
1801         mono_assemblies_lock ();
1802
1803         if (image->assembly) {
1804                 /* 
1805                  * This means another thread has already loaded the assembly, but not yet
1806                  * called the load hooks so the search hook can't find the assembly.
1807                  */
1808                 mono_assemblies_unlock ();
1809                 ass2 = image->assembly;
1810                 g_free (ass);
1811                 g_free (base_dir);
1812                 mono_image_close (image);
1813                 *status = MONO_IMAGE_OK;
1814                 return ass2;
1815         }
1816
1817         image->assembly = ass;
1818
1819         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1820         mono_assemblies_unlock ();
1821
1822 #ifdef HOST_WIN32
1823         if (image->is_module_handle)
1824                 mono_image_fixup_vtable (image);
1825 #endif
1826
1827         mono_assembly_invoke_load_hook (ass);
1828
1829         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1830         
1831         return ass;
1832 }
1833
1834 MonoAssembly *
1835 mono_assembly_load_from (MonoImage *image, const char *fname,
1836                          MonoImageOpenStatus *status)
1837 {
1838         return mono_assembly_load_from_full (image, fname, status, FALSE);
1839 }
1840
1841 /**
1842  * mono_assembly_name_free:
1843  * @aname: assembly name to free
1844  * 
1845  * Frees the provided assembly name object.
1846  * (it does not frees the object itself, only the name members).
1847  */
1848 void
1849 mono_assembly_name_free (MonoAssemblyName *aname)
1850 {
1851         if (aname == NULL)
1852                 return;
1853
1854         g_free ((void *) aname->name);
1855         g_free ((void *) aname->culture);
1856         g_free ((void *) aname->hash_value);
1857 }
1858
1859 static gboolean
1860 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
1861 {
1862         const gchar *pkey;
1863         gchar header [16], val, *arr;
1864         gint i, j, offset, bitlen, keylen, pkeylen;
1865         
1866         keylen = strlen (key) >> 1;
1867         if (keylen < 1)
1868                 return FALSE;
1869
1870         /* allow the ECMA standard key */
1871         if (strcmp (key, "00000000000000000400000000000000") == 0) {
1872                 if (pubkey) {
1873                         *pubkey = g_strdup (key);
1874                         *is_ecma = TRUE;
1875                 }
1876                 return TRUE;
1877         }
1878         *is_ecma = FALSE;
1879         val = g_ascii_xdigit_value (key [0]) << 4;
1880         val |= g_ascii_xdigit_value (key [1]);
1881         switch (val) {
1882                 case 0x00:
1883                         if (keylen < 13)
1884                                 return FALSE;
1885                         val = g_ascii_xdigit_value (key [24]);
1886                         val |= g_ascii_xdigit_value (key [25]);
1887                         if (val != 0x06)
1888                                 return FALSE;
1889                         pkey = key + 24;
1890                         break;
1891                 case 0x06:
1892                         pkey = key;
1893                         break;
1894                 default:
1895                         return FALSE;
1896         }
1897                 
1898         /* We need the first 16 bytes
1899         * to check whether this key is valid or not */
1900         pkeylen = strlen (pkey) >> 1;
1901         if (pkeylen < 16)
1902                 return FALSE;
1903                 
1904         for (i = 0, j = 0; i < 16; i++) {
1905                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
1906                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
1907         }
1908
1909         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
1910                         header [1] != 0x02 || /* Version (0x02) */
1911                         header [2] != 0x00 || /* Reserved (word) */
1912                         header [3] != 0x00 ||
1913                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
1914                 return FALSE;
1915
1916         /* Based on this length, we _should_ be able to know if the length is right */
1917         bitlen = read32 (header + 12) >> 3;
1918         if ((bitlen + 16 + 4) != pkeylen)
1919                 return FALSE;
1920
1921         /* parsing is OK and the public key itself is not requested back */
1922         if (!pubkey)
1923                 return TRUE;
1924                 
1925         /* Encode the size of the blob */
1926         offset = 0;
1927         if (keylen <= 127) {
1928                 arr = g_malloc (keylen + 1);
1929                 arr [offset++] = keylen;
1930         } else {
1931                 arr = g_malloc (keylen + 2);
1932                 arr [offset++] = 0x80; /* 10bs */
1933                 arr [offset++] = keylen;
1934         }
1935                 
1936         for (i = offset, j = 0; i < keylen + offset; i++) {
1937                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
1938                 arr [i] |= g_ascii_xdigit_value (key [j++]);
1939         }
1940
1941         *pubkey = arr;
1942
1943         return TRUE;
1944 }
1945
1946 static gboolean
1947 build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, guint32 arch, MonoAssemblyName *aname, gboolean save_public_key)
1948 {
1949         gint major, minor, build, revision;
1950         gint len;
1951         gint version_parts;
1952         gchar *pkey, *pkeyptr, *encoded, tok [8];
1953
1954         memset (aname, 0, sizeof (MonoAssemblyName));
1955
1956         if (version) {
1957                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
1958                 if (version_parts < 2 || version_parts > 4)
1959                         return FALSE;
1960
1961                 /* FIXME: we should set build & revision to -1 (instead of 0)
1962                 if these are not set in the version string. That way, later on,
1963                 we can still determine if these were specified. */
1964                 aname->major = major;
1965                 aname->minor = minor;
1966                 if (version_parts >= 3)
1967                         aname->build = build;
1968                 else
1969                         aname->build = 0;
1970                 if (version_parts == 4)
1971                         aname->revision = revision;
1972                 else
1973                         aname->revision = 0;
1974         }
1975         
1976         aname->flags = flags;
1977         aname->arch = arch;
1978         aname->name = g_strdup (name);
1979         
1980         if (culture) {
1981                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
1982                         aname->culture = g_strdup ("");
1983                 else
1984                         aname->culture = g_strdup (culture);
1985         }
1986         
1987         if (token && strncmp (token, "null", 4) != 0) {
1988                 char *lower;
1989
1990                 /* the constant includes the ending NULL, hence the -1 */
1991                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
1992                         mono_assembly_name_free (aname);
1993                         return FALSE;
1994                 }
1995                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1996                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1997                 g_free (lower);
1998         }
1999
2000         if (key) {
2001                 gboolean is_ecma;
2002                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2003                         mono_assembly_name_free (aname);
2004                         return FALSE;
2005                 }
2006
2007                 if (is_ecma) {
2008                         if (save_public_key)
2009                                 aname->public_key = (guint8*)pkey;
2010                         else
2011                                 g_free (pkey);
2012                         g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2013                         return TRUE;
2014                 }
2015                 
2016                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2017                 // We also need to generate the key token
2018                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2019                 encoded = encode_public_tok ((guchar*) tok, 8);
2020                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2021                 g_free (encoded);
2022
2023                 if (save_public_key)
2024                         aname->public_key = (guint8*) pkey;
2025                 else
2026                         g_free (pkey);
2027         }
2028
2029         return TRUE;
2030 }
2031
2032 static gboolean
2033 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2034 {
2035         gchar **parts;
2036         gboolean res;
2037         
2038         parts = g_strsplit (dirname, "_", 3);
2039         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2040                 g_strfreev (parts);
2041                 return FALSE;
2042         }
2043         
2044         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2045         g_strfreev (parts);
2046         return res;
2047 }
2048
2049 static gboolean
2050 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2051 {
2052         char *eqsign = strchr (pair, '=');
2053         if (!eqsign) {
2054                 *key = NULL;
2055                 *keylen = 0;
2056                 *value = NULL;
2057                 return FALSE;
2058         }
2059
2060         *key = (gchar*)pair;
2061         *keylen = eqsign - *key;
2062         while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2063                 (*keylen)--;
2064         *value = g_strstrip (eqsign + 1);
2065         return TRUE;
2066 }
2067
2068 gboolean
2069 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2070 {
2071         gchar *dllname;
2072         gchar *version = NULL;
2073         gchar *culture = NULL;
2074         gchar *token = NULL;
2075         gchar *key = NULL;
2076         gchar *retargetable = NULL;
2077         gboolean res;
2078         gchar *value, *part_name;
2079         guint32 part_name_len;
2080         gchar **parts;
2081         gchar **tmp;
2082         gboolean version_defined;
2083         gboolean token_defined;
2084         guint32 flags = 0;
2085         guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2086
2087         if (!is_version_defined)
2088                 is_version_defined = &version_defined;
2089         *is_version_defined = FALSE;
2090         if (!is_token_defined)
2091                 is_token_defined = &token_defined;
2092         *is_token_defined = FALSE;
2093         
2094         parts = tmp = g_strsplit (name, ",", 6);
2095         if (!tmp || !*tmp) {
2096                 g_strfreev (tmp);
2097                 return FALSE;
2098         }
2099
2100         dllname = g_strstrip (*tmp);
2101         
2102         tmp++;
2103
2104         while (*tmp) {
2105                 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2106                         goto cleanup_and_fail;
2107
2108                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2109                         *is_version_defined = TRUE;
2110                         version = value;
2111                         if (strlen (version) == 0) {
2112                                 goto cleanup_and_fail;
2113                         }
2114                         tmp++;
2115                         continue;
2116                 }
2117
2118                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2119                         culture = value;
2120                         if (strlen (culture) == 0) {
2121                                 goto cleanup_and_fail;
2122                         }
2123                         tmp++;
2124                         continue;
2125                 }
2126
2127                 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2128                         *is_token_defined = TRUE;
2129                         token = value;
2130                         if (strlen (token) == 0) {
2131                                 goto cleanup_and_fail;
2132                         }
2133                         tmp++;
2134                         continue;
2135                 }
2136
2137                 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2138                         key = value;
2139                         if (strlen (key) == 0) {
2140                                 goto cleanup_and_fail;
2141                         }
2142                         tmp++;
2143                         continue;
2144                 }
2145
2146                 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2147                         retargetable = value;
2148                         if (strlen (retargetable) == 0) {
2149                                 goto cleanup_and_fail;
2150                         }
2151                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
2152                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2153                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
2154                                 goto cleanup_and_fail;
2155                         }
2156                         tmp++;
2157                         continue;
2158                 }
2159
2160                 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2161                         if (!g_ascii_strcasecmp (value, "MSIL"))
2162                                 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2163                         else if (!g_ascii_strcasecmp (value, "X86"))
2164                                 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2165                         else if (!g_ascii_strcasecmp (value, "IA64"))
2166                                 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2167                         else if (!g_ascii_strcasecmp (value, "AMD64"))
2168                                 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2169                         else
2170                                 goto cleanup_and_fail;
2171                         tmp++;
2172                         continue;
2173                 }
2174
2175                 g_strfreev (parts);
2176                 return FALSE;
2177         }
2178
2179         /* if retargetable flag is set, then we must have a fully qualified name */
2180         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2181                 goto cleanup_and_fail;
2182         }
2183
2184         res = build_assembly_name (dllname, version, culture, token, key, flags, arch,
2185                 aname, save_public_key);
2186         g_strfreev (parts);
2187         return res;
2188
2189 cleanup_and_fail:
2190         g_strfreev (parts);
2191         return FALSE;
2192 }
2193
2194 /**
2195  * mono_assembly_name_parse:
2196  * @name: name to parse
2197  * @aname: the destination assembly name
2198  * 
2199  * Parses an assembly qualified type name and assigns the name,
2200  * version, culture and token to the provided assembly name object.
2201  *
2202  * Returns: true if the name could be parsed.
2203  */
2204 gboolean
2205 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2206 {
2207         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2208 }
2209
2210 /**
2211  * mono_assembly_name_new:
2212  * @name: name to parse
2213  *
2214  * Allocate a new MonoAssemblyName and fill its values from the
2215  * passed @name.
2216  *
2217  * Returns: a newly allocated structure or NULL if there was any failure.
2218  */
2219 MonoAssemblyName*
2220 mono_assembly_name_new (const char *name)
2221 {
2222         MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2223         if (mono_assembly_name_parse (name, aname))
2224                 return aname;
2225         g_free (aname);
2226         return NULL;
2227 }
2228
2229 const char*
2230 mono_assembly_name_get_name (MonoAssemblyName *aname)
2231 {
2232         return aname->name;
2233 }
2234
2235 const char*
2236 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2237 {
2238         return aname->culture;
2239 }
2240
2241 mono_byte*
2242 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2243 {
2244         if (aname->public_key_token [0])
2245                 return aname->public_key_token;
2246         return NULL;
2247 }
2248
2249 uint16_t
2250 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2251 {
2252         if (minor)
2253                 *minor = aname->minor;
2254         if (build)
2255                 *build = aname->build;
2256         if (revision)
2257                 *revision = aname->revision;
2258         return aname->major;
2259 }
2260
2261 static MonoAssembly*
2262 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2263 {
2264         gchar *fullpath = NULL;
2265         GDir *dirhandle;
2266         const char* direntry;
2267         MonoAssemblyName gac_aname;
2268         gint major=-1, minor=0, build=0, revision=0;
2269         gboolean exact_version;
2270         
2271         dirhandle = g_dir_open (basepath, 0, NULL);
2272         if (!dirhandle)
2273                 return NULL;
2274                 
2275         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2276
2277         while ((direntry = g_dir_read_name (dirhandle))) {
2278                 gboolean match = TRUE;
2279                 
2280                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2281                         continue;
2282                 
2283                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2284                         match = FALSE;
2285                         
2286                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
2287                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2288                         match = FALSE;
2289                 
2290                 if (match) {
2291                         if (exact_version) {
2292                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2293                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
2294                         }
2295                         else if (gac_aname.major < major)
2296                                 match = FALSE;
2297                         else if (gac_aname.major == major) {
2298                                 if (gac_aname.minor < minor)
2299                                         match = FALSE;
2300                                 else if (gac_aname.minor == minor) {
2301                                         if (gac_aname.build < build)
2302                                                 match = FALSE;
2303                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
2304                                                 match = FALSE; 
2305                                 }
2306                         }
2307                 }
2308                 
2309                 if (match) {
2310                         major = gac_aname.major;
2311                         minor = gac_aname.minor;
2312                         build = gac_aname.build;
2313                         revision = gac_aname.revision;
2314                         g_free (fullpath);
2315                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2316                 }
2317
2318                 mono_assembly_name_free (&gac_aname);
2319         }
2320         
2321         g_dir_close (dirhandle);
2322         
2323         if (fullpath == NULL)
2324                 return NULL;
2325         else {
2326                 MonoAssembly *res = mono_assembly_open (fullpath, status);
2327                 g_free (fullpath);
2328                 return res;
2329         }
2330 }
2331
2332 MonoAssembly*
2333 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2334 {
2335         MonoAssembly *res;
2336         MonoAssemblyName *aname, base_name;
2337         MonoAssemblyName mapped_aname;
2338         gchar *fullname, *gacpath;
2339         gchar **paths;
2340
2341         memset (&base_name, 0, sizeof (MonoAssemblyName));
2342         aname = &base_name;
2343
2344         if (!mono_assembly_name_parse (name, aname))
2345                 return NULL;
2346
2347         /* 
2348          * If no specific version has been requested, make sure we load the
2349          * correct version for system assemblies.
2350          */ 
2351         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2352                 aname = mono_assembly_remap_version (aname, &mapped_aname);
2353         
2354         res = mono_assembly_loaded (aname);
2355         if (res) {
2356                 mono_assembly_name_free (aname);
2357                 return res;
2358         }
2359
2360         res = invoke_assembly_preload_hook (aname, assemblies_path);
2361         if (res) {
2362                 res->in_gac = FALSE;
2363                 mono_assembly_name_free (aname);
2364                 return res;
2365         }
2366
2367         fullname = g_strdup_printf ("%s.dll", aname->name);
2368
2369         if (extra_gac_paths) {
2370                 paths = extra_gac_paths;
2371                 while (!res && *paths) {
2372                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2373                         res = probe_for_partial_name (gacpath, fullname, aname, status);
2374                         g_free (gacpath);
2375                         paths++;
2376                 }
2377         }
2378
2379         if (res) {
2380                 res->in_gac = TRUE;
2381                 g_free (fullname);
2382                 mono_assembly_name_free (aname);
2383                 return res;
2384         }
2385
2386         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2387         res = probe_for_partial_name (gacpath, fullname, aname, status);
2388         g_free (gacpath);
2389
2390         if (res)
2391                 res->in_gac = TRUE;
2392         else {
2393                 MonoDomain *domain = mono_domain_get ();
2394                 MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE);
2395                 if (refasm)
2396                         res = refasm->assembly;
2397         }
2398         
2399         g_free (fullname);
2400         mono_assembly_name_free (aname);
2401
2402         return res;
2403 }
2404
2405 static MonoBoolean
2406 mono_assembly_is_in_gac (const gchar *filename)
2407 {
2408         const gchar *rootdir;
2409         gchar *gp;
2410         gchar **paths;
2411
2412         if (filename == NULL)
2413                 return FALSE;
2414
2415         for (paths = extra_gac_paths; paths && *paths; paths++) {
2416                 if (strstr (*paths, filename) != *paths)
2417                         continue;
2418
2419                 gp = (gchar *) (filename + strlen (*paths));
2420                 if (*gp != G_DIR_SEPARATOR)
2421                         continue;
2422                 gp++;
2423                 if (strncmp (gp, "lib", 3))
2424                         continue;
2425                 gp += 3;
2426                 if (*gp != G_DIR_SEPARATOR)
2427                         continue;
2428                 gp++;
2429                 if (strncmp (gp, "mono", 4))
2430                         continue;
2431                 gp += 4;
2432                 if (*gp != G_DIR_SEPARATOR)
2433                         continue;
2434                 gp++;
2435                 if (strncmp (gp, "gac", 3))
2436                         continue;
2437                 gp += 3;
2438                 if (*gp != G_DIR_SEPARATOR)
2439                         continue;
2440
2441                 return TRUE;
2442         }
2443
2444         rootdir = mono_assembly_getrootdir ();
2445         if (strstr (filename, rootdir) != filename)
2446                 return FALSE;
2447
2448         gp = (gchar *) (filename + strlen (rootdir));
2449         if (*gp != G_DIR_SEPARATOR)
2450                 return FALSE;
2451         gp++;
2452         if (strncmp (gp, "mono", 4))
2453                 return FALSE;
2454         gp += 4;
2455         if (*gp != G_DIR_SEPARATOR)
2456                 return FALSE;
2457         gp++;
2458         if (strncmp (gp, "gac", 3))
2459                 return FALSE;
2460         gp += 3;
2461         if (*gp != G_DIR_SEPARATOR)
2462                 return FALSE;
2463         return TRUE;
2464 }
2465
2466 static MonoImage*
2467 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2468 {
2469         MonoImage *image;
2470         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2471         gchar **paths;
2472         gint32 len;
2473
2474         if (strstr (aname->name, ".dll")) {
2475                 len = strlen (aname->name) - 4;
2476                 name = g_malloc (len);
2477                 strncpy (name, aname->name, len);
2478         } else
2479                 name = g_strdup (aname->name);
2480         
2481         if (aname->culture)
2482                 culture = g_utf8_strdown (aname->culture, -1);
2483         else
2484                 culture = g_strdup ("");
2485         
2486         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2487         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2488         g_free (name);
2489         g_free (culture);
2490         
2491         filename = g_strconcat (pname, ".dll", NULL);
2492         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2493         g_free (pname);
2494         g_free (version);
2495         g_free (filename);
2496
2497         image = NULL;
2498         if (extra_gac_paths) {
2499                 paths = extra_gac_paths;
2500                 while (!image && *paths) {
2501                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2502                                         "lib", "mono", "gac", subpath, NULL);
2503                         image = mono_image_open (fullpath, NULL);
2504                         g_free (fullpath);
2505                         paths++;
2506                 }
2507         }
2508
2509         if (image) {
2510                 g_free (subpath);
2511                 return image;
2512         }
2513
2514         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
2515                         "mono", "gac", subpath, NULL);
2516         image = mono_image_open (fullpath, NULL);
2517         g_free (subpath);
2518         g_free (fullpath);
2519         
2520         return image;
2521 }
2522
2523 static MonoAssemblyName*
2524 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2525 {
2526         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2527         dest_name->major = info->new_version.major;
2528         dest_name->minor = info->new_version.minor;
2529         dest_name->build = info->new_version.build;
2530         dest_name->revision = info->new_version.revision;
2531         
2532         return dest_name;
2533 }
2534
2535 /* LOCKING: assembly_binding lock must be held */
2536 static MonoAssemblyBindingInfo*
2537 search_binding_loaded (MonoAssemblyName *aname)
2538 {
2539         GSList *tmp;
2540
2541         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2542                 MonoAssemblyBindingInfo *info = tmp->data;
2543                 if (assembly_binding_maps_name (info, aname))
2544                         return info;
2545         }
2546
2547         return NULL;
2548 }
2549
2550 static inline gboolean
2551 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2552 {
2553         if (left->major != right->major || left->minor != right->minor ||
2554             left->build != right->build || left->revision != right->revision)
2555                 return FALSE;
2556
2557         return TRUE;
2558 }
2559
2560 static inline gboolean
2561 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2562 {
2563         if (left->has_old_version_bottom != right->has_old_version_bottom)
2564                 return FALSE;
2565
2566         if (left->has_old_version_top != right->has_old_version_top)
2567                 return FALSE;
2568
2569         if (left->has_new_version != right->has_new_version)
2570                 return FALSE;
2571
2572         if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2573                 return FALSE;
2574
2575         if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2576                 return FALSE;
2577
2578         if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2579                 return FALSE;
2580
2581         return TRUE;
2582 }
2583
2584 /* LOCKING: assumes all the necessary locks are held */
2585 static void
2586 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2587 {
2588         MonoAssemblyBindingInfo *info_copy;
2589         GSList *tmp;
2590         MonoAssemblyBindingInfo *info_tmp;
2591         MonoDomain *domain = (MonoDomain*)user_data;
2592
2593         if (!domain)
2594                 return;
2595
2596         for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2597                 info_tmp = tmp->data;
2598                 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2599                         return;
2600         }
2601
2602         info_copy = mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2603         memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2604         if (info->name)
2605                 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2606         if (info->culture)
2607                 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2608
2609         domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2610 }
2611
2612 static int
2613 get_version_number (int major, int minor)
2614 {
2615         return major * 256 + minor;
2616 }
2617
2618 static inline gboolean
2619 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2620 {
2621         int aname_version_number = get_version_number (aname->major, aname->minor);
2622         if (!info->has_old_version_bottom)
2623                 return FALSE;
2624
2625         if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2626                 return FALSE;
2627
2628         if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2629                 return FALSE;
2630
2631         /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2632         info->major = aname->major;
2633         info->minor = aname->minor;
2634
2635         return TRUE;
2636 }
2637
2638 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2639 static MonoAssemblyBindingInfo*
2640 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2641 {
2642         MonoAssemblyBindingInfo *info;
2643         GSList *list;
2644
2645         if (!domain->assembly_bindings)
2646                 return NULL;
2647
2648         info = NULL;
2649         for (list = domain->assembly_bindings; list; list = list->next) {
2650                 info = list->data;
2651                 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2652                         break;
2653                 info = NULL;
2654         }
2655
2656         if (info) {
2657                 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2658                     info->has_new_version && assembly_binding_maps_name (info, aname))
2659                         info->is_valid = TRUE;
2660                 else
2661                         info->is_valid = FALSE;
2662         }
2663
2664         return info;
2665 }
2666
2667 static MonoAssemblyName*
2668 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2669 {
2670         MonoAssemblyBindingInfo *info, *info2;
2671         MonoImage *ppimage;
2672         MonoDomain *domain;
2673
2674         if (aname->public_key_token [0] == 0)
2675                 return aname;
2676
2677         domain = mono_domain_get ();
2678
2679         mono_assembly_binding_lock ();
2680         info = search_binding_loaded (aname);
2681         mono_assembly_binding_unlock ();
2682
2683         if (!info) {
2684                 mono_domain_lock (domain);
2685                 info = get_per_domain_assembly_binding_info (domain, aname);
2686                 mono_domain_unlock (domain);
2687         }
2688
2689         if (info) {
2690                 if (!check_policy_versions (info, aname))
2691                         return aname;
2692                 
2693                 mono_assembly_bind_version (info, aname, dest_name);
2694                 return dest_name;
2695         }
2696
2697         if (domain && domain->setup && domain->setup->configuration_file) {
2698                 mono_domain_lock (domain);
2699                 if (!domain->assembly_bindings_parsed) {
2700                         gchar *domain_config_file_name = mono_string_to_utf8 (domain->setup->configuration_file);
2701                         gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2702
2703                         if (!domain_config_file_path)
2704                                 domain_config_file_path = domain_config_file_name;
2705                         
2706                         mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2707                         domain->assembly_bindings_parsed = TRUE;
2708                         if (domain_config_file_name != domain_config_file_path)
2709                                 g_free (domain_config_file_name);
2710                         g_free (domain_config_file_path);
2711                 }
2712
2713                 info2 = get_per_domain_assembly_binding_info (domain, aname);
2714
2715                 if (info2) {
2716                         info = g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2717                         info->name = g_strdup (info2->name);
2718                         info->culture = g_strdup (info2->culture);
2719                         info->domain_id = domain->domain_id;
2720                 }
2721
2722                 mono_domain_unlock (domain);
2723         }
2724
2725         if (!info) {
2726                 info = g_new0 (MonoAssemblyBindingInfo, 1);
2727                 info->major = aname->major;
2728                 info->minor = aname->minor;
2729         }
2730
2731         if (!info->is_valid) {
2732                 ppimage = mono_assembly_load_publisher_policy (aname);
2733                 if (ppimage) {
2734                         get_publisher_policy_info (ppimage, aname, info);
2735                         mono_image_close (ppimage);
2736                 }
2737         }
2738
2739         /* Define default error value if needed */
2740         if (!info->is_valid) {
2741                 info->name = g_strdup (aname->name);
2742                 info->culture = g_strdup (aname->culture);
2743                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2744         }
2745         
2746         mono_assembly_binding_lock ();
2747         info2 = search_binding_loaded (aname);
2748         if (info2) {
2749                 /* This binding was added by another thread 
2750                  * before us */
2751                 mono_assembly_binding_info_free (info);
2752                 g_free (info);
2753                 
2754                 info = info2;
2755         } else
2756                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2757                 
2758         mono_assembly_binding_unlock ();
2759         
2760         if (!info->is_valid || !check_policy_versions (info, aname))
2761                 return aname;
2762
2763         mono_assembly_bind_version (info, aname, dest_name);
2764         return dest_name;
2765 }
2766
2767 /**
2768  * mono_assembly_load_from_gac
2769  *
2770  * @aname: The assembly name object
2771  */
2772 static MonoAssembly*
2773 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
2774 {
2775         MonoAssembly *result = NULL;
2776         gchar *name, *version, *culture, *fullpath, *subpath;
2777         gint32 len;
2778         gchar **paths;
2779         char *pubtok;
2780
2781         if (aname->public_key_token [0] == 0) {
2782                 return NULL;
2783         }
2784
2785         if (strstr (aname->name, ".dll")) {
2786                 len = strlen (filename) - 4;
2787                 name = g_malloc (len);
2788                 strncpy (name, aname->name, len);
2789         } else {
2790                 name = g_strdup (aname->name);
2791         }
2792
2793         if (aname->culture) {
2794                 culture = g_utf8_strdown (aname->culture, -1);
2795         } else {
2796                 culture = g_strdup ("");
2797         }
2798
2799         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2800         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
2801                         aname->minor, aname->build, aname->revision,
2802                         culture, pubtok);
2803         g_free (pubtok);
2804         
2805         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
2806         g_free (name);
2807         g_free (version);
2808         g_free (culture);
2809
2810         if (extra_gac_paths) {
2811                 paths = extra_gac_paths;
2812                 while (!result && *paths) {
2813                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
2814                         result = mono_assembly_open_full (fullpath, status, refonly);
2815                         g_free (fullpath);
2816                         paths++;
2817                 }
2818         }
2819
2820         if (result) {
2821                 result->in_gac = TRUE;
2822                 g_free (subpath);
2823                 return result;
2824         }
2825
2826         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
2827                         "mono", "gac", subpath, NULL);
2828         result = mono_assembly_open_full (fullpath, status, refonly);
2829         g_free (fullpath);
2830
2831         if (result)
2832                 result->in_gac = TRUE;
2833         
2834         g_free (subpath);
2835
2836         return result;
2837 }
2838
2839 MonoAssembly*
2840 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
2841 {
2842         char *corlib_file;
2843         MonoAssemblyName *aname;
2844
2845         if (corlib) {
2846                 /* g_print ("corlib already loaded\n"); */
2847                 return corlib;
2848         }
2849
2850 #if defined(__native_client__)
2851         if (corlibData != NULL && corlibSize != 0) {
2852                 int status = 0;
2853                 /* First "FALSE" instructs mono not to make a copy. */
2854                 /* Second "FALSE" says this is not just a ref.      */
2855                 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
2856                 if (image == NULL || status != 0)
2857                         g_print("mono_image_open_from_data_full failed: %d\n", status);
2858                 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
2859                 if (corlib == NULL || status != 0)
2860                         g_print ("mono_assembly_load_from_full failed: %d\n", status);
2861                 if (corlib)
2862                         return corlib;
2863         }
2864 #endif
2865
2866         aname = mono_assembly_name_new ("mscorlib.dll");
2867         corlib = invoke_assembly_preload_hook (aname, assemblies_path);
2868         mono_assembly_name_free (aname);
2869         g_free (aname);
2870         if (corlib != NULL)
2871                 return corlib;
2872
2873         if (assemblies_path) {
2874                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
2875                 if (corlib)
2876                         return corlib;
2877         }
2878
2879         /* Load corlib from mono/<version> */
2880         
2881         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
2882         if (assemblies_path) {
2883                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
2884                 if (corlib) {
2885                         g_free (corlib_file);
2886                         return corlib;
2887                 }
2888         }
2889         corlib = load_in_path (corlib_file, default_path, status, FALSE);
2890         g_free (corlib_file);
2891         
2892         if (corlib && !strcmp (runtime->framework_version, "4.5"))
2893                 default_path [1] = g_strdup_printf ("%s/mono/4.5/Facades", default_path [0]);
2894                 
2895         return corlib;
2896 }
2897
2898 MonoAssembly*
2899 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
2900                                                                   const char       *basedir, 
2901                                                                   MonoImageOpenStatus *status,
2902                                                                   gboolean refonly)
2903 {
2904         MonoAssembly *result;
2905         char *fullpath, *filename;
2906         MonoAssemblyName maped_aname;
2907         MonoAssemblyName maped_name_pp;
2908         int ext_index;
2909         const char *ext;
2910         int len;
2911
2912         aname = mono_assembly_remap_version (aname, &maped_aname);
2913         
2914         /* Reflection only assemblies don't get assembly binding */
2915         if (!refonly)
2916                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
2917         
2918         result = mono_assembly_loaded_full (aname, refonly);
2919         if (result)
2920                 return result;
2921
2922         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
2923         if (result) {
2924                 result->in_gac = FALSE;
2925                 return result;
2926         }
2927
2928         /* Currently we retrieve the loaded corlib for reflection 
2929          * only requests, like a common reflection only assembly 
2930          */
2931         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
2932                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
2933         }
2934
2935         len = strlen (aname->name);
2936         for (ext_index = 0; ext_index < 2; ext_index ++) {
2937                 ext = ext_index == 0 ? ".dll" : ".exe";
2938                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
2939                         filename = g_strdup (aname->name);
2940                         /* Don't try appending .dll/.exe if it already has one of those extensions */
2941                         ext_index++;
2942                 } else {
2943                         filename = g_strconcat (aname->name, ext, NULL);
2944                 }
2945
2946                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
2947                 if (result) {
2948                         g_free (filename);
2949                         return result;
2950                 }
2951
2952                 if (basedir) {
2953                         fullpath = g_build_filename (basedir, filename, NULL);
2954                         result = mono_assembly_open_full (fullpath, status, refonly);
2955                         g_free (fullpath);
2956                         if (result) {
2957                                 result->in_gac = FALSE;
2958                                 g_free (filename);
2959                                 return result;
2960                         }
2961                 }
2962
2963                 result = load_in_path (filename, default_path, status, refonly);
2964                 if (result)
2965                         result->in_gac = FALSE;
2966                 g_free (filename);
2967                 if (result)
2968                         return result;
2969         }
2970
2971         return result;
2972 }
2973
2974 MonoAssembly*
2975 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
2976 {
2977         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
2978
2979         if (!result)
2980                 /* Try a postload search hook */
2981                 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
2982         return result;
2983 }
2984
2985 /**
2986  * mono_assembly_load_full:
2987  * @aname: A MonoAssemblyName with the assembly name to load.
2988  * @basedir: A directory to look up the assembly at.
2989  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
2990  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
2991  *
2992  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
2993  * attempts to load the assembly from that directory before probing the standard locations.
2994  *
2995  * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
2996  * assembly binding takes place.
2997  *
2998  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
2999  * value pointed by status is updated with an error code.
3000  */
3001 MonoAssembly*
3002 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3003 {
3004         return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3005 }
3006
3007 /**
3008  * mono_assembly_load:
3009  * @aname: A MonoAssemblyName with the assembly name to load.
3010  * @basedir: A directory to look up the assembly at.
3011  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3012  *
3013  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3014  * attempts to load the assembly from that directory before probing the standard locations.
3015  *
3016  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3017  * value pointed by status is updated with an error code.
3018  */
3019 MonoAssembly*
3020 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3021 {
3022         return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3023 }
3024
3025 MonoAssembly*
3026 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3027 {
3028         MonoAssembly *res;
3029         MonoAssemblyName maped_aname;
3030
3031         aname = mono_assembly_remap_version (aname, &maped_aname);
3032
3033         res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3034
3035         return res;
3036 }
3037
3038 /**
3039  * mono_assembly_loaded:
3040  * @aname: an assembly to look for.
3041  *
3042  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3043  * a MonoAssembly that matches the MonoAssemblyName specified.
3044  */
3045 MonoAssembly*
3046 mono_assembly_loaded (MonoAssemblyName *aname)
3047 {
3048         return mono_assembly_loaded_full (aname, FALSE);
3049 }
3050
3051 void
3052 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3053 {
3054         if (assembly == NULL || assembly == REFERENCE_MISSING)
3055                 return;
3056
3057         if (assembly_is_dynamic (assembly)) {
3058                 int i;
3059                 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3060                 for (i = 0; i < dynimg->image.module_count; ++i)
3061                         mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3062                 mono_dynamic_image_release_gc_roots (dynimg);
3063         }
3064 }
3065
3066 /*
3067  * Returns whether mono_assembly_close_finish() must be called as
3068  * well.  See comment for mono_image_close_except_pools() for why we
3069  * unload in two steps.
3070  */
3071 gboolean
3072 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3073 {
3074         GSList *tmp;
3075         g_return_val_if_fail (assembly != NULL, FALSE);
3076
3077         if (assembly == REFERENCE_MISSING)
3078                 return FALSE;
3079
3080         /* Might be 0 already */
3081         if (InterlockedDecrement (&assembly->ref_count) > 0)
3082                 return FALSE;
3083
3084         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3085
3086         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3087
3088         mono_debug_close_image (assembly->image);
3089
3090         mono_assemblies_lock ();
3091         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3092         mono_assemblies_unlock ();
3093
3094         assembly->image->assembly = NULL;
3095
3096         if (!mono_image_close_except_pools (assembly->image))
3097                 assembly->image = NULL;
3098
3099         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3100                 MonoAssemblyName *fname = tmp->data;
3101                 mono_assembly_name_free (fname);
3102                 g_free (fname);
3103         }
3104         g_slist_free (assembly->friend_assembly_names);
3105         g_free (assembly->basedir);
3106
3107         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3108
3109         return TRUE;
3110 }
3111
3112 void
3113 mono_assembly_close_finish (MonoAssembly *assembly)
3114 {
3115         g_assert (assembly && assembly != REFERENCE_MISSING);
3116
3117         if (assembly->image)
3118                 mono_image_close_finish (assembly->image);
3119
3120         if (assembly_is_dynamic (assembly)) {
3121                 g_free ((char*)assembly->aname.culture);
3122         } else {
3123                 g_free (assembly);
3124         }
3125 }
3126
3127 /**
3128  * mono_assembly_close:
3129  * @assembly: the assembly to release.
3130  *
3131  * This method releases a reference to the @assembly.  The assembly is
3132  * only released when all the outstanding references to it are released.
3133  */
3134 void
3135 mono_assembly_close (MonoAssembly *assembly)
3136 {
3137         if (mono_assembly_close_except_image_pools (assembly))
3138                 mono_assembly_close_finish (assembly);
3139 }
3140
3141 MonoImage*
3142 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3143 {
3144         return mono_image_load_file_for_image (assembly->image, idx);
3145 }
3146
3147 void
3148 mono_assembly_foreach (GFunc func, gpointer user_data)
3149 {
3150         GList *copy;
3151
3152         /*
3153          * We make a copy of the list to avoid calling the callback inside the 
3154          * lock, which could lead to deadlocks.
3155          */
3156         mono_assemblies_lock ();
3157         copy = g_list_copy (loaded_assemblies);
3158         mono_assemblies_unlock ();
3159
3160         g_list_foreach (loaded_assemblies, func, user_data);
3161
3162         g_list_free (copy);
3163 }
3164
3165 /**
3166  * mono_assemblies_cleanup:
3167  *
3168  * Free all resources used by this module.
3169  */
3170 void
3171 mono_assemblies_cleanup (void)
3172 {
3173         GSList *l;
3174
3175         mono_mutex_destroy (&assemblies_mutex);
3176         mono_mutex_destroy (&assembly_binding_mutex);
3177
3178         for (l = loaded_assembly_bindings; l; l = l->next) {
3179                 MonoAssemblyBindingInfo *info = l->data;
3180
3181                 mono_assembly_binding_info_free (info);
3182                 g_free (info);
3183         }
3184         g_slist_free (loaded_assembly_bindings);
3185
3186         free_assembly_load_hooks ();
3187         free_assembly_search_hooks ();
3188         free_assembly_preload_hooks ();
3189 }
3190
3191 /*LOCKING takes the assembly_binding lock*/
3192 void
3193 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3194 {
3195         GSList **iter;
3196
3197         mono_assembly_binding_lock ();
3198         iter = &loaded_assembly_bindings;
3199         while (*iter) {
3200                 GSList *l = *iter;
3201                 MonoAssemblyBindingInfo *info = l->data;
3202
3203                 if (info->domain_id == domain_id) {
3204                         *iter = l->next;
3205                         mono_assembly_binding_info_free (info);
3206                         g_free (info);
3207                         g_slist_free_1 (l);
3208                 } else {
3209                         iter = &l->next;
3210                 }
3211         }
3212         mono_assembly_binding_unlock ();
3213 }
3214
3215 /*
3216  * Holds the assembly of the application, for
3217  * System.Diagnostics.Process::MainModule
3218  */
3219 static MonoAssembly *main_assembly=NULL;
3220
3221 void
3222 mono_assembly_set_main (MonoAssembly *assembly)
3223 {
3224         main_assembly = assembly;
3225 }
3226
3227 /**
3228  * mono_assembly_get_main:
3229  *
3230  * Returns: the assembly for the application, the first assembly that is loaded by the VM
3231  */
3232 MonoAssembly *
3233 mono_assembly_get_main (void)
3234 {
3235         return (main_assembly);
3236 }
3237
3238 /**
3239  * mono_assembly_get_image:
3240  * @assembly: The assembly to retrieve the image from
3241  *
3242  * Returns: the MonoImage associated with this assembly.
3243  */
3244 MonoImage*
3245 mono_assembly_get_image (MonoAssembly *assembly)
3246 {
3247         return assembly->image;
3248 }
3249
3250 void
3251 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3252 {
3253         bundles = assemblies;
3254 }
3255
3256 #define MONO_DECLSEC_FORMAT_10          0x3C
3257 #define MONO_DECLSEC_FORMAT_20          0x2E
3258 #define MONO_DECLSEC_FIELD              0x53
3259 #define MONO_DECLSEC_PROPERTY           0x54
3260
3261 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3262 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3263 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3264 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3265 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3266
3267 static gboolean
3268 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3269 {
3270         int len;
3271         switch (*p++) {
3272         case MONO_DECLSEC_PROPERTY:
3273                 break;
3274         case MONO_DECLSEC_FIELD:
3275         default:
3276                 *abort_decoding = TRUE;
3277                 return FALSE;
3278                 break;
3279         }
3280
3281         if (*p++ != MONO_TYPE_BOOLEAN) {
3282                 *abort_decoding = TRUE;
3283                 return FALSE;
3284         }
3285                 
3286         /* property name length */
3287         len = mono_metadata_decode_value (p, &p);
3288
3289         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3290                 p += len;
3291                 return *p;
3292         }
3293         p += len + 1;
3294
3295         *resp = p;
3296         return FALSE;
3297 }
3298
3299 static gboolean
3300 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3301 {
3302         int i, j, num, len, params_len;
3303
3304         if (*p == MONO_DECLSEC_FORMAT_10) {
3305                 gsize read, written;
3306                 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3307                 if (res) {
3308                         gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3309                         g_free (res);
3310                         return found;
3311                 }
3312                 return FALSE;
3313         }
3314         if (*p++ != MONO_DECLSEC_FORMAT_20)
3315                 return FALSE;
3316
3317         /* number of encoded permission attributes */
3318         num = mono_metadata_decode_value (p, &p);
3319         for (i = 0; i < num; ++i) {
3320                 gboolean is_valid = FALSE;
3321                 gboolean abort_decoding = FALSE;
3322
3323                 /* attribute name length */
3324                 len =  mono_metadata_decode_value (p, &p);
3325
3326                 /* We don't really need to fully decode the type. Comparing the name is enough */
3327                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3328
3329                 p += len;
3330
3331                 /*size of the params table*/
3332                 params_len =  mono_metadata_decode_value (p, &p);
3333                 if (is_valid) {
3334                         const char *params_end = p + params_len;
3335                         
3336                         /* number of parameters */
3337                         len = mono_metadata_decode_value (p, &p);
3338         
3339                         for (j = 0; j < len; ++j) {
3340                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3341                                         return TRUE;
3342                                 if (abort_decoding)
3343                                         break;
3344                         }
3345                         p = params_end;
3346                 } else {
3347                         p += params_len;
3348                 }
3349         }
3350         
3351         return FALSE;
3352 }
3353
3354
3355 gboolean
3356 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3357 {
3358         MonoTableInfo *t;       
3359         guint32 cols [MONO_DECL_SECURITY_SIZE];
3360         const char *blob;
3361         int i, len;
3362
3363         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3364                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3365
3366         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3367
3368         for (i = 0; i < t->rows; ++i) {
3369                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3370                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3371                         continue;
3372                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3373                         continue;
3374
3375                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3376                 len = mono_metadata_decode_blob_size (blob, &blob);
3377                 if (!len)
3378                         continue;
3379
3380                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3381                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3382                         return TRUE;
3383                 }
3384         }
3385
3386         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
3387         return FALSE;
3388 }