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