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