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