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