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