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