Pass LoadFrom info down to assembly loading.
[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", 3},
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)
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_full (fullpath, status, refonly);
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
1681         MonoImage *image;
1682         MonoAssembly *ass;
1683         MonoImageOpenStatus def_status;
1684         gchar *fname;
1685         gchar *new_fname;
1686         gboolean loaded_from_bundle;
1687         
1688         g_return_val_if_fail (filename != NULL, NULL);
1689
1690         if (!status)
1691                 status = &def_status;
1692         *status = MONO_IMAGE_OK;
1693
1694         if (strncmp (filename, "file://", 7) == 0) {
1695                 GError *error = NULL;
1696                 gchar *uri = (gchar *) filename;
1697                 gchar *tmpuri;
1698
1699                 /*
1700                  * MS allows file://c:/... and fails on file://localhost/c:/... 
1701                  * They also throw an IndexOutOfRangeException if "file://"
1702                  */
1703                 if (uri [7] != '/')
1704                         uri = g_strdup_printf ("file:///%s", uri + 7);
1705         
1706                 tmpuri = uri;
1707                 uri = mono_escape_uri_string (tmpuri);
1708                 fname = g_filename_from_uri (uri, NULL, &error);
1709                 g_free (uri);
1710
1711                 if (tmpuri != filename)
1712                         g_free (tmpuri);
1713
1714                 if (error != NULL) {
1715                         g_warning ("%s\n", error->message);
1716                         g_error_free (error);
1717                         fname = g_strdup (filename);
1718                 }
1719         } else {
1720                 fname = g_strdup (filename);
1721         }
1722
1723         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1724                         "Assembly Loader probing location: '%s'.", fname);
1725
1726         new_fname = NULL;
1727         if (!mono_assembly_is_in_gac (fname)) {
1728                 MonoError error;
1729                 new_fname = mono_make_shadow_copy (fname, &error);
1730                 if (!is_ok (&error)) {
1731                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1732                                     "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1733                         mono_error_cleanup (&error);
1734                         *status = MONO_IMAGE_IMAGE_INVALID;
1735                         g_free (fname);
1736                         return NULL;
1737                 }
1738         }
1739         if (new_fname && new_fname != fname) {
1740                 g_free (fname);
1741                 fname = new_fname;
1742                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1743                             "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1744         }
1745         
1746         image = NULL;
1747
1748         // If VM built with mkbundle
1749         loaded_from_bundle = FALSE;
1750         if (bundles != NULL) {
1751                 image = mono_assembly_open_from_bundle (fname, status, refonly);
1752                 loaded_from_bundle = image != NULL;
1753         }
1754
1755         if (!image)
1756                 image = mono_image_open_full (fname, status, refonly);
1757
1758         if (!image){
1759                 if (*status == MONO_IMAGE_OK)
1760                         *status = MONO_IMAGE_ERROR_ERRNO;
1761                 g_free (fname);
1762                 return NULL;
1763         }
1764
1765         if (image->assembly) {
1766                 /* Already loaded by another appdomain */
1767                 mono_assembly_invoke_load_hook (image->assembly);
1768                 mono_image_close (image);
1769                 g_free (fname);
1770                 return image->assembly;
1771         }
1772
1773         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1774
1775         if (ass) {
1776                 if (!loaded_from_bundle)
1777                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1778                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1779                 if (!refonly)
1780                         mono_config_for_assembly (ass->image);
1781         }
1782
1783         /* Clear the reference added by mono_image_open */
1784         mono_image_close (image);
1785         
1786         g_free (fname);
1787
1788         return ass;
1789 }
1790
1791 static void
1792 free_item (gpointer val, gpointer user_data)
1793 {
1794         g_free (val);
1795 }
1796
1797 /**
1798  * mono_assembly_load_friends:
1799  * @ass: an assembly
1800  *
1801  * Load the list of friend assemblies that are allowed to access
1802  * the assembly's internal types and members. They are stored as assembly
1803  * names in custom attributes.
1804  *
1805  * This is an internal method, we need this because when we load mscorlib
1806  * we do not have the internals visible cattr loaded yet,
1807  * so we need to load these after we initialize the runtime. 
1808  *
1809  * LOCKING: Acquires the assemblies lock plus the loader lock.
1810  */
1811 void
1812 mono_assembly_load_friends (MonoAssembly* ass)
1813 {
1814         MonoError error;
1815         int i;
1816         MonoCustomAttrInfo* attrs;
1817         GSList *list;
1818
1819         if (ass->friend_assembly_names_inited)
1820                 return;
1821
1822         attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1823         mono_error_assert_ok (&error);
1824         if (!attrs) {
1825                 mono_assemblies_lock ();
1826                 ass->friend_assembly_names_inited = TRUE;
1827                 mono_assemblies_unlock ();
1828                 return;
1829         }
1830
1831         mono_assemblies_lock ();
1832         if (ass->friend_assembly_names_inited) {
1833                 mono_assemblies_unlock ();
1834                 return;
1835         }
1836         mono_assemblies_unlock ();
1837
1838         list = NULL;
1839         /* 
1840          * We build the list outside the assemblies lock, the worse that can happen
1841          * is that we'll need to free the allocated list.
1842          */
1843         for (i = 0; i < attrs->num_attrs; ++i) {
1844                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1845                 MonoAssemblyName *aname;
1846                 const gchar *data;
1847                 /* Do some sanity checking */
1848                 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1849                         continue;
1850                 if (attr->data_size < 4)
1851                         continue;
1852                 data = (const char*)attr->data;
1853                 /* 0xFF means null string, see custom attr format */
1854                 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1855                         continue;
1856                 mono_metadata_decode_value (data + 2, &data);
1857                 aname = g_new0 (MonoAssemblyName, 1);
1858                 /*g_print ("friend ass: %s\n", data);*/
1859                 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1860                         list = g_slist_prepend (list, aname);
1861                 } else {
1862                         g_free (aname);
1863                 }
1864         }
1865         mono_custom_attrs_free (attrs);
1866
1867         mono_assemblies_lock ();
1868         if (ass->friend_assembly_names_inited) {
1869                 mono_assemblies_unlock ();
1870                 g_slist_foreach (list, free_item, NULL);
1871                 g_slist_free (list);
1872                 return;
1873         }
1874         ass->friend_assembly_names = list;
1875
1876         /* Because of the double checked locking pattern above */
1877         mono_memory_barrier ();
1878         ass->friend_assembly_names_inited = TRUE;
1879         mono_assemblies_unlock ();
1880 }
1881
1882 struct HasReferenceAssemblyAttributeIterData {
1883         gboolean has_attr;
1884 };
1885
1886 static gboolean
1887 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
1888 {
1889         gboolean stop_scanning = FALSE;
1890         struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
1891
1892         if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
1893                 /* Note we don't check the assembly name, same as coreCLR. */
1894                 iter_data->has_attr = TRUE;
1895                 stop_scanning = TRUE;
1896         }
1897
1898         return stop_scanning;
1899 }
1900
1901 /**
1902  * mono_assembly_has_reference_assembly_attribute:
1903  * @assembly: a MonoAssembly
1904  * @error: set on error.
1905  *
1906  * Returns TRUE if @assembly has the System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
1907  * On error returns FALSE and sets @error.
1908  */
1909 gboolean
1910 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
1911 {
1912         error_init (error);
1913
1914         /*
1915          * This might be called during assembly loading, so do everything using the low-level
1916          * metadata APIs.
1917          */
1918
1919         struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
1920
1921         mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
1922
1923         return iter_data.has_attr;
1924 }
1925
1926 /**
1927  * mono_assembly_open:
1928  * @filename: Opens the assembly pointed out by this name
1929  * @status: return status code
1930  *
1931  * This loads an assembly from the specified @filename.   The @filename allows
1932  * a local URL (starting with a file:// prefix).  If a file prefix is used, the
1933  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
1934  * is treated as a local path.
1935  *
1936  * First, an attempt is made to load the assembly from the bundled executable (for those
1937  * deployments that have been done with the `mkbundle` tool or for scenarios where the
1938  * assembly has been registered as an embedded assembly).   If this is not the case, then
1939  * the assembly is loaded from disk using `api:mono_image_open_full`.
1940  *
1941  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1942  * the assembly is made.
1943  *
1944  * Return: a pointer to the MonoAssembly if @filename contains a valid
1945  * assembly or NULL on error.  Details about the error are stored in the
1946  * @status variable.
1947  */
1948 MonoAssembly *
1949 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1950 {
1951         return mono_assembly_open_full (filename, status, FALSE);
1952 }
1953
1954 /**
1955  * mono_assembly_load_from_full:
1956  * @image: Image to load the assembly from
1957  * @fname: assembly name to associate with the assembly
1958  * @status: returns the status condition
1959  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1960  *
1961  * If the provided @image has an assembly reference, it will process the given
1962  * image as an assembly with the given name.
1963  *
1964  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1965  *
1966  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1967  * set to #MONO_IMAGE_OK;  or NULL on error.
1968  *
1969  * If there is an error loading the assembly the @status will indicate the
1970  * reason with @status being set to `MONO_IMAGE_INVALID` if the
1971  * image did not contain an assembly reference table.
1972  */
1973 MonoAssembly *
1974 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1975                               MonoImageOpenStatus *status, gboolean refonly)
1976 {
1977         MonoAssembly *ass, *ass2;
1978         char *base_dir;
1979
1980         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1981                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1982                 *status = MONO_IMAGE_IMAGE_INVALID;
1983                 return NULL;
1984         }
1985
1986 #if defined (HOST_WIN32)
1987         {
1988                 gchar *tmp_fn;
1989                 int i;
1990
1991                 tmp_fn = g_strdup (fname);
1992                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1993                         if (tmp_fn [i] == '/')
1994                                 tmp_fn [i] = '\\';
1995                 }
1996
1997                 base_dir = absolute_dir (tmp_fn);
1998                 g_free (tmp_fn);
1999         }
2000 #else
2001         base_dir = absolute_dir (fname);
2002 #endif
2003
2004         /*
2005          * Create assembly struct, and enter it into the assembly cache
2006          */
2007         ass = g_new0 (MonoAssembly, 1);
2008         ass->basedir = base_dir;
2009         ass->ref_only = refonly;
2010         ass->image = image;
2011
2012         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2013
2014         mono_assembly_fill_assembly_name (image, &ass->aname);
2015
2016         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2017                 // MS.NET doesn't support loading other mscorlibs
2018                 g_free (ass);
2019                 g_free (base_dir);
2020                 mono_image_addref (mono_defaults.corlib);
2021                 *status = MONO_IMAGE_OK;
2022                 return mono_defaults.corlib->assembly;
2023         }
2024
2025         /* Add a non-temporary reference because of ass->image */
2026         mono_image_addref (image);
2027
2028         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);
2029
2030         /* 
2031          * The load hooks might take locks so we can't call them while holding the
2032          * assemblies lock.
2033          */
2034         if (ass->aname.name) {
2035                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2036                 if (ass2) {
2037                         g_free (ass);
2038                         g_free (base_dir);
2039                         mono_image_close (image);
2040                         *status = MONO_IMAGE_OK;
2041                         return ass2;
2042                 }
2043         }
2044
2045         /* We need to check for ReferenceAssmeblyAttribute before we
2046          * mark the assembly as loaded and before we fire the load
2047          * hook. Otherwise mono_domain_fire_assembly_load () in
2048          * appdomain.c will cache a mapping from the assembly name to
2049          * this image and we won't be able to look for a different
2050          * candidate. */
2051
2052         if (!refonly) {
2053                 MonoError refasm_error;
2054                 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2055                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2056                         g_free (ass);
2057                         g_free (base_dir);
2058                         mono_image_close (image);
2059                         *status = MONO_IMAGE_IMAGE_INVALID;
2060                         return NULL;
2061                 }
2062                 mono_error_cleanup (&refasm_error);
2063         }
2064
2065         mono_assemblies_lock ();
2066
2067         if (image->assembly) {
2068                 /*
2069                  * This means another thread has already loaded the assembly, but not yet
2070                  * called the load hooks so the search hook can't find the assembly.
2071                  */
2072                 mono_assemblies_unlock ();
2073                 ass2 = image->assembly;
2074                 g_free (ass);
2075                 g_free (base_dir);
2076                 mono_image_close (image);
2077                 *status = MONO_IMAGE_OK;
2078                 return ass2;
2079         }
2080
2081         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2082
2083         image->assembly = ass;
2084
2085         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2086         mono_assemblies_unlock ();
2087
2088 #ifdef HOST_WIN32
2089         if (image->is_module_handle)
2090                 mono_image_fixup_vtable (image);
2091 #endif
2092
2093         mono_assembly_invoke_load_hook (ass);
2094
2095         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2096         
2097         return ass;
2098 }
2099
2100 /**
2101  * mono_assembly_load_from:
2102  * @image: Image to load the assembly from
2103  * @fname: assembly name to associate with the assembly
2104  * @status: return status code
2105  *
2106  * If the provided @image has an assembly reference, it will process the given
2107  * image as an assembly with the given name.
2108  *
2109  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2110  *
2111  * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2112  * @refonly parameter set to FALSE.
2113  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
2114  * set to #MONO_IMAGE_OK;  or NULL on error.
2115  *
2116  * If there is an error loading the assembly the @status will indicate the
2117  * reason with @status being set to `MONO_IMAGE_INVALID` if the
2118  * image did not contain an assembly reference table.
2119  
2120  */
2121 MonoAssembly *
2122 mono_assembly_load_from (MonoImage *image, const char *fname,
2123                          MonoImageOpenStatus *status)
2124 {
2125         return mono_assembly_load_from_full (image, fname, status, FALSE);
2126 }
2127
2128 /**
2129  * mono_assembly_name_free:
2130  * @aname: assembly name to free
2131  * 
2132  * Frees the provided assembly name object.
2133  * (it does not frees the object itself, only the name members).
2134  */
2135 void
2136 mono_assembly_name_free (MonoAssemblyName *aname)
2137 {
2138         if (aname == NULL)
2139                 return;
2140
2141         g_free ((void *) aname->name);
2142         g_free ((void *) aname->culture);
2143         g_free ((void *) aname->hash_value);
2144         g_free ((guint8*) aname->public_key);
2145 }
2146
2147 static gboolean
2148 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2149 {
2150         const gchar *pkey;
2151         gchar header [16], val, *arr;
2152         gint i, j, offset, bitlen, keylen, pkeylen;
2153         
2154         keylen = strlen (key) >> 1;
2155         if (keylen < 1)
2156                 return FALSE;
2157
2158         /* allow the ECMA standard key */
2159         if (strcmp (key, "00000000000000000400000000000000") == 0) {
2160                 if (pubkey) {
2161                         *pubkey = g_strdup (key);
2162                         *is_ecma = TRUE;
2163                 }
2164                 return TRUE;
2165         }
2166         *is_ecma = FALSE;
2167         val = g_ascii_xdigit_value (key [0]) << 4;
2168         val |= g_ascii_xdigit_value (key [1]);
2169         switch (val) {
2170                 case 0x00:
2171                         if (keylen < 13)
2172                                 return FALSE;
2173                         val = g_ascii_xdigit_value (key [24]);
2174                         val |= g_ascii_xdigit_value (key [25]);
2175                         if (val != 0x06)
2176                                 return FALSE;
2177                         pkey = key + 24;
2178                         break;
2179                 case 0x06:
2180                         pkey = key;
2181                         break;
2182                 default:
2183                         return FALSE;
2184         }
2185                 
2186         /* We need the first 16 bytes
2187         * to check whether this key is valid or not */
2188         pkeylen = strlen (pkey) >> 1;
2189         if (pkeylen < 16)
2190                 return FALSE;
2191                 
2192         for (i = 0, j = 0; i < 16; i++) {
2193                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2194                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2195         }
2196
2197         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2198                         header [1] != 0x02 || /* Version (0x02) */
2199                         header [2] != 0x00 || /* Reserved (word) */
2200                         header [3] != 0x00 ||
2201                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2202                 return FALSE;
2203
2204         /* Based on this length, we _should_ be able to know if the length is right */
2205         bitlen = read32 (header + 12) >> 3;
2206         if ((bitlen + 16 + 4) != pkeylen)
2207                 return FALSE;
2208
2209         /* parsing is OK and the public key itself is not requested back */
2210         if (!pubkey)
2211                 return TRUE;
2212                 
2213         /* Encode the size of the blob */
2214         offset = 0;
2215         if (keylen <= 127) {
2216                 arr = (gchar *)g_malloc (keylen + 1);
2217                 arr [offset++] = keylen;
2218         } else {
2219                 arr = (gchar *)g_malloc (keylen + 2);
2220                 arr [offset++] = 0x80; /* 10bs */
2221                 arr [offset++] = keylen;
2222         }
2223                 
2224         for (i = offset, j = 0; i < keylen + offset; i++) {
2225                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2226                 arr [i] |= g_ascii_xdigit_value (key [j++]);
2227         }
2228
2229         *pubkey = arr;
2230
2231         return TRUE;
2232 }
2233
2234 static gboolean
2235 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)
2236 {
2237         gint major, minor, build, revision;
2238         gint len;
2239         gint version_parts;
2240         gchar *pkey, *pkeyptr, *encoded, tok [8];
2241
2242         memset (aname, 0, sizeof (MonoAssemblyName));
2243
2244         if (version) {
2245                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2246                 if (version_parts < 2 || version_parts > 4)
2247                         return FALSE;
2248
2249                 /* FIXME: we should set build & revision to -1 (instead of 0)
2250                 if these are not set in the version string. That way, later on,
2251                 we can still determine if these were specified. */
2252                 aname->major = major;
2253                 aname->minor = minor;
2254                 if (version_parts >= 3)
2255                         aname->build = build;
2256                 else
2257                         aname->build = 0;
2258                 if (version_parts == 4)
2259                         aname->revision = revision;
2260                 else
2261                         aname->revision = 0;
2262         }
2263         
2264         aname->flags = flags;
2265         aname->arch = arch;
2266         aname->name = g_strdup (name);
2267         
2268         if (culture) {
2269                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2270                         aname->culture = g_strdup ("");
2271                 else
2272                         aname->culture = g_strdup (culture);
2273         }
2274         
2275         if (token && strncmp (token, "null", 4) != 0) {
2276                 char *lower;
2277
2278                 /* the constant includes the ending NULL, hence the -1 */
2279                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2280                         mono_assembly_name_free (aname);
2281                         return FALSE;
2282                 }
2283                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2284                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2285                 g_free (lower);
2286         }
2287
2288         if (key) {
2289                 gboolean is_ecma;
2290                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2291                         mono_assembly_name_free (aname);
2292                         return FALSE;
2293                 }
2294
2295                 if (is_ecma) {
2296                         if (save_public_key)
2297                                 aname->public_key = (guint8*)pkey;
2298                         else
2299                                 g_free (pkey);
2300                         g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2301                         return TRUE;
2302                 }
2303                 
2304                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2305                 // We also need to generate the key token
2306                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2307                 encoded = encode_public_tok ((guchar*) tok, 8);
2308                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2309                 g_free (encoded);
2310
2311                 if (save_public_key)
2312                         aname->public_key = (guint8*) pkey;
2313                 else
2314                         g_free (pkey);
2315         }
2316
2317         return TRUE;
2318 }
2319
2320 static gboolean
2321 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2322 {
2323         gchar **parts;
2324         gboolean res;
2325         
2326         parts = g_strsplit (dirname, "_", 3);
2327         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2328                 g_strfreev (parts);
2329                 return FALSE;
2330         }
2331         
2332         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2333         g_strfreev (parts);
2334         return res;
2335 }
2336
2337 static gboolean
2338 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2339 {
2340         char *eqsign = strchr (pair, '=');
2341         if (!eqsign) {
2342                 *key = NULL;
2343                 *keylen = 0;
2344                 *value = NULL;
2345                 return FALSE;
2346         }
2347
2348         *key = (gchar*)pair;
2349         *keylen = eqsign - *key;
2350         while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2351                 (*keylen)--;
2352         *value = g_strstrip (eqsign + 1);
2353         return TRUE;
2354 }
2355
2356 gboolean
2357 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2358 {
2359         gchar *dllname;
2360         gchar *dllname_uq;
2361         gchar *version = NULL;
2362         gchar *version_uq;
2363         gchar *culture = NULL;
2364         gchar *culture_uq;
2365         gchar *token = NULL;
2366         gchar *token_uq;
2367         gchar *key = NULL;
2368         gchar *key_uq;
2369         gchar *retargetable = NULL;
2370         gchar *retargetable_uq;
2371         gchar *procarch;
2372         gchar *procarch_uq;
2373         gboolean res;
2374         gchar *value, *part_name;
2375         guint32 part_name_len;
2376         gchar **parts;
2377         gchar **tmp;
2378         gboolean version_defined;
2379         gboolean token_defined;
2380         guint32 flags = 0;
2381         guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2382
2383         if (!is_version_defined)
2384                 is_version_defined = &version_defined;
2385         *is_version_defined = FALSE;
2386         if (!is_token_defined)
2387                 is_token_defined = &token_defined;
2388         *is_token_defined = FALSE;
2389         
2390         parts = tmp = g_strsplit (name, ",", 6);
2391         if (!tmp || !*tmp) {
2392                 g_strfreev (tmp);
2393                 return FALSE;
2394         }
2395
2396         dllname = g_strstrip (*tmp);
2397         
2398         tmp++;
2399
2400         while (*tmp) {
2401                 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2402                         goto cleanup_and_fail;
2403
2404                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2405                         *is_version_defined = TRUE;
2406                         version = value;
2407                         if (strlen (version) == 0) {
2408                                 goto cleanup_and_fail;
2409                         }
2410                         tmp++;
2411                         continue;
2412                 }
2413
2414                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2415                         culture = value;
2416                         if (strlen (culture) == 0) {
2417                                 goto cleanup_and_fail;
2418                         }
2419                         tmp++;
2420                         continue;
2421                 }
2422
2423                 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2424                         *is_token_defined = TRUE;
2425                         token = value;
2426                         if (strlen (token) == 0) {
2427                                 goto cleanup_and_fail;
2428                         }
2429                         tmp++;
2430                         continue;
2431                 }
2432
2433                 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2434                         key = value;
2435                         if (strlen (key) == 0) {
2436                                 goto cleanup_and_fail;
2437                         }
2438                         tmp++;
2439                         continue;
2440                 }
2441
2442                 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2443                         retargetable = value;
2444                         retargetable_uq = unquote (retargetable);
2445                         if (retargetable_uq != NULL)
2446                                 retargetable = retargetable_uq;
2447
2448                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
2449                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2450                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
2451                                 g_free (retargetable_uq);
2452                                 goto cleanup_and_fail;
2453                         }
2454
2455                         g_free (retargetable_uq);
2456                         tmp++;
2457                         continue;
2458                 }
2459
2460                 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2461                         procarch = value;
2462                         procarch_uq = unquote (procarch);
2463                         if (procarch_uq != NULL)
2464                                 procarch = procarch_uq;
2465
2466                         if (!g_ascii_strcasecmp (procarch, "MSIL"))
2467                                 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2468                         else if (!g_ascii_strcasecmp (procarch, "X86"))
2469                                 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2470                         else if (!g_ascii_strcasecmp (procarch, "IA64"))
2471                                 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2472                         else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2473                                 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2474                         else {
2475                                 g_free (procarch_uq);
2476                                 goto cleanup_and_fail;
2477                         }
2478
2479                         g_free (procarch_uq);
2480                         tmp++;
2481                         continue;
2482                 }
2483
2484                 g_strfreev (parts);
2485                 return FALSE;
2486         }
2487
2488         /* if retargetable flag is set, then we must have a fully qualified name */
2489         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2490                 goto cleanup_and_fail;
2491         }
2492
2493         dllname_uq = unquote (dllname);
2494         version_uq = unquote (version);
2495         culture_uq = unquote (culture);
2496         token_uq = unquote (token);
2497         key_uq = unquote (key);
2498
2499         res = build_assembly_name (
2500                 dllname_uq == NULL ? dllname : dllname_uq,
2501                 version_uq == NULL ? version : version_uq,
2502                 culture_uq == NULL ? culture : culture_uq,
2503                 token_uq == NULL ? token : token_uq,
2504                 key_uq == NULL ? key : key_uq,
2505                 flags, arch, aname, save_public_key);
2506
2507         g_free (dllname_uq);
2508         g_free (version_uq);
2509         g_free (culture_uq);
2510         g_free (token_uq);
2511         g_free (key_uq);
2512
2513         g_strfreev (parts);
2514         return res;
2515
2516 cleanup_and_fail:
2517         g_strfreev (parts);
2518         return FALSE;
2519 }
2520
2521 static char*
2522 unquote (const char *str)
2523 {
2524         gint slen;
2525         const char *end;
2526
2527         if (str == NULL)
2528                 return NULL;
2529
2530         slen = strlen (str);
2531         if (slen < 2)
2532                 return NULL;
2533
2534         if (*str != '\'' && *str != '\"')
2535                 return NULL;
2536
2537         end = str + slen - 1;
2538         if (*str != *end)
2539                 return NULL;
2540
2541         return g_strndup (str + 1, slen - 2);
2542 }
2543
2544 /**
2545  * mono_assembly_name_parse:
2546  * @name: name to parse
2547  * @aname: the destination assembly name
2548  * 
2549  * Parses an assembly qualified type name and assigns the name,
2550  * version, culture and token to the provided assembly name object.
2551  *
2552  * Returns: TRUE if the name could be parsed.
2553  */
2554 gboolean
2555 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2556 {
2557         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2558 }
2559
2560 /**
2561  * mono_assembly_name_new:
2562  * @name: name to parse
2563  *
2564  * Allocate a new MonoAssemblyName and fill its values from the
2565  * passed @name.
2566  *
2567  * Returns: a newly allocated structure or NULL if there was any failure.
2568  */
2569 MonoAssemblyName*
2570 mono_assembly_name_new (const char *name)
2571 {
2572         MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2573         if (mono_assembly_name_parse (name, aname))
2574                 return aname;
2575         g_free (aname);
2576         return NULL;
2577 }
2578
2579 const char*
2580 mono_assembly_name_get_name (MonoAssemblyName *aname)
2581 {
2582         return aname->name;
2583 }
2584
2585 const char*
2586 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2587 {
2588         return aname->culture;
2589 }
2590
2591 mono_byte*
2592 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2593 {
2594         if (aname->public_key_token [0])
2595                 return aname->public_key_token;
2596         return NULL;
2597 }
2598
2599 uint16_t
2600 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2601 {
2602         if (minor)
2603                 *minor = aname->minor;
2604         if (build)
2605                 *build = aname->build;
2606         if (revision)
2607                 *revision = aname->revision;
2608         return aname->major;
2609 }
2610
2611 static MonoAssembly*
2612 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2613 {
2614         gchar *fullpath = NULL;
2615         GDir *dirhandle;
2616         const char* direntry;
2617         MonoAssemblyName gac_aname;
2618         gint major=-1, minor=0, build=0, revision=0;
2619         gboolean exact_version;
2620         
2621         dirhandle = g_dir_open (basepath, 0, NULL);
2622         if (!dirhandle)
2623                 return NULL;
2624                 
2625         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2626
2627         while ((direntry = g_dir_read_name (dirhandle))) {
2628                 gboolean match = TRUE;
2629                 
2630                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2631                         continue;
2632                 
2633                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2634                         match = FALSE;
2635                         
2636                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
2637                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2638                         match = FALSE;
2639                 
2640                 if (match) {
2641                         if (exact_version) {
2642                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2643                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
2644                         }
2645                         else if (gac_aname.major < major)
2646                                 match = FALSE;
2647                         else if (gac_aname.major == major) {
2648                                 if (gac_aname.minor < minor)
2649                                         match = FALSE;
2650                                 else if (gac_aname.minor == minor) {
2651                                         if (gac_aname.build < build)
2652                                                 match = FALSE;
2653                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
2654                                                 match = FALSE; 
2655                                 }
2656                         }
2657                 }
2658                 
2659                 if (match) {
2660                         major = gac_aname.major;
2661                         minor = gac_aname.minor;
2662                         build = gac_aname.build;
2663                         revision = gac_aname.revision;
2664                         g_free (fullpath);
2665                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2666                 }
2667
2668                 mono_assembly_name_free (&gac_aname);
2669         }
2670         
2671         g_dir_close (dirhandle);
2672         
2673         if (fullpath == NULL)
2674                 return NULL;
2675         else {
2676                 MonoAssembly *res = mono_assembly_open (fullpath, status);
2677                 g_free (fullpath);
2678                 return res;
2679         }
2680 }
2681
2682 /**
2683  * mono_assembly_load_with_partial_name:
2684  * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2685  * @status: return status code
2686  *
2687  * Loads a Mono Assembly from a name.  The name is parsed using `api:mono_assembly_name_parse`,
2688  * so it might contain a qualified type name, version, culture and token.
2689  *
2690  * This will load the assembly from the file whose name is derived from the assembly name
2691  * by appending the .dll extension.
2692  *
2693  * The assembly is loaded from either one of the extra Global Assembly Caches specified
2694  * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2695  * if that fails from the GAC.
2696  *
2697  * Returns: NULL on failure, or a pointer to a MonoAssembly on success.   
2698  */
2699 MonoAssembly*
2700 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2701 {
2702         MonoError error;
2703         MonoAssembly *res;
2704         MonoAssemblyName *aname, base_name;
2705         MonoAssemblyName mapped_aname;
2706         gchar *fullname, *gacpath;
2707         gchar **paths;
2708
2709         memset (&base_name, 0, sizeof (MonoAssemblyName));
2710         aname = &base_name;
2711
2712         if (!mono_assembly_name_parse (name, aname))
2713                 return NULL;
2714
2715         /* 
2716          * If no specific version has been requested, make sure we load the
2717          * correct version for system assemblies.
2718          */ 
2719         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2720                 aname = mono_assembly_remap_version (aname, &mapped_aname);
2721         
2722         res = mono_assembly_loaded (aname);
2723         if (res) {
2724                 mono_assembly_name_free (aname);
2725                 return res;
2726         }
2727
2728         res = invoke_assembly_preload_hook (aname, assemblies_path);
2729         if (res) {
2730                 res->in_gac = FALSE;
2731                 mono_assembly_name_free (aname);
2732                 return res;
2733         }
2734
2735         fullname = g_strdup_printf ("%s.dll", aname->name);
2736
2737         if (extra_gac_paths) {
2738                 paths = extra_gac_paths;
2739                 while (!res && *paths) {
2740                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2741                         res = probe_for_partial_name (gacpath, fullname, aname, status);
2742                         g_free (gacpath);
2743                         paths++;
2744                 }
2745         }
2746
2747         if (res) {
2748                 res->in_gac = TRUE;
2749                 g_free (fullname);
2750                 mono_assembly_name_free (aname);
2751                 return res;
2752         }
2753
2754         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2755         res = probe_for_partial_name (gacpath, fullname, aname, status);
2756         g_free (gacpath);
2757
2758         g_free (fullname);
2759         mono_assembly_name_free (aname);
2760
2761         if (res)
2762                 res->in_gac = TRUE;
2763         else {
2764                 MonoDomain *domain = mono_domain_get ();
2765
2766                 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2767                 if (!is_ok (&error)) {
2768                         mono_error_cleanup (&error);
2769                         if (*status == MONO_IMAGE_OK)
2770                                 *status = MONO_IMAGE_IMAGE_INVALID;
2771                 }
2772         }
2773
2774         return res;
2775 }
2776
2777 static MonoBoolean
2778 mono_assembly_is_in_gac (const gchar *filename)
2779 {
2780         const gchar *rootdir;
2781         gchar *gp;
2782         gchar **paths;
2783
2784         if (filename == NULL)
2785                 return FALSE;
2786
2787         for (paths = extra_gac_paths; paths && *paths; paths++) {
2788                 if (strstr (*paths, filename) != *paths)
2789                         continue;
2790
2791                 gp = (gchar *) (filename + strlen (*paths));
2792                 if (*gp != G_DIR_SEPARATOR)
2793                         continue;
2794                 gp++;
2795                 if (strncmp (gp, "lib", 3))
2796                         continue;
2797                 gp += 3;
2798                 if (*gp != G_DIR_SEPARATOR)
2799                         continue;
2800                 gp++;
2801                 if (strncmp (gp, "mono", 4))
2802                         continue;
2803                 gp += 4;
2804                 if (*gp != G_DIR_SEPARATOR)
2805                         continue;
2806                 gp++;
2807                 if (strncmp (gp, "gac", 3))
2808                         continue;
2809                 gp += 3;
2810                 if (*gp != G_DIR_SEPARATOR)
2811                         continue;
2812
2813                 return TRUE;
2814         }
2815
2816         rootdir = mono_assembly_getrootdir ();
2817         if (strstr (filename, rootdir) != filename)
2818                 return FALSE;
2819
2820         gp = (gchar *) (filename + strlen (rootdir));
2821         if (*gp != G_DIR_SEPARATOR)
2822                 return FALSE;
2823         gp++;
2824         if (strncmp (gp, "mono", 4))
2825                 return FALSE;
2826         gp += 4;
2827         if (*gp != G_DIR_SEPARATOR)
2828                 return FALSE;
2829         gp++;
2830         if (strncmp (gp, "gac", 3))
2831                 return FALSE;
2832         gp += 3;
2833         if (*gp != G_DIR_SEPARATOR)
2834                 return FALSE;
2835         return TRUE;
2836 }
2837
2838 static MonoImage*
2839 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2840 {
2841         MonoImage *image;
2842         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2843         gchar **paths;
2844         gint32 len;
2845
2846         if (strstr (aname->name, ".dll")) {
2847                 len = strlen (aname->name) - 4;
2848                 name = (gchar *)g_malloc (len + 1);
2849                 memcpy (name, aname->name, len);
2850                 name[len] = 0;
2851         } else
2852                 name = g_strdup (aname->name);
2853         
2854         if (aname->culture)
2855                 culture = g_utf8_strdown (aname->culture, -1);
2856         else
2857                 culture = g_strdup ("");
2858         
2859         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2860         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2861         g_free (name);
2862         g_free (culture);
2863         
2864         filename = g_strconcat (pname, ".dll", NULL);
2865         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2866         g_free (pname);
2867         g_free (version);
2868         g_free (filename);
2869
2870         image = NULL;
2871         if (extra_gac_paths) {
2872                 paths = extra_gac_paths;
2873                 while (!image && *paths) {
2874                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2875                                         "lib", "mono", "gac", subpath, NULL);
2876                         image = mono_image_open (fullpath, NULL);
2877                         g_free (fullpath);
2878                         paths++;
2879                 }
2880         }
2881
2882         if (image) {
2883                 g_free (subpath);
2884                 return image;
2885         }
2886
2887         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
2888                         "mono", "gac", subpath, NULL);
2889         image = mono_image_open (fullpath, NULL);
2890         g_free (subpath);
2891         g_free (fullpath);
2892         
2893         return image;
2894 }
2895
2896 static MonoAssemblyName*
2897 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2898 {
2899         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2900         dest_name->major = info->new_version.major;
2901         dest_name->minor = info->new_version.minor;
2902         dest_name->build = info->new_version.build;
2903         dest_name->revision = info->new_version.revision;
2904         
2905         return dest_name;
2906 }
2907
2908 /* LOCKING: assembly_binding lock must be held */
2909 static MonoAssemblyBindingInfo*
2910 search_binding_loaded (MonoAssemblyName *aname)
2911 {
2912         GSList *tmp;
2913
2914         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2915                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2916                 if (assembly_binding_maps_name (info, aname))
2917                         return info;
2918         }
2919
2920         return NULL;
2921 }
2922
2923 static inline gboolean
2924 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2925 {
2926         if (left->major != right->major || left->minor != right->minor ||
2927             left->build != right->build || left->revision != right->revision)
2928                 return FALSE;
2929
2930         return TRUE;
2931 }
2932
2933 static inline gboolean
2934 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2935 {
2936         if (left->has_old_version_bottom != right->has_old_version_bottom)
2937                 return FALSE;
2938
2939         if (left->has_old_version_top != right->has_old_version_top)
2940                 return FALSE;
2941
2942         if (left->has_new_version != right->has_new_version)
2943                 return FALSE;
2944
2945         if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2946                 return FALSE;
2947
2948         if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2949                 return FALSE;
2950
2951         if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2952                 return FALSE;
2953
2954         return TRUE;
2955 }
2956
2957 /* LOCKING: assumes all the necessary locks are held */
2958 static void
2959 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2960 {
2961         MonoAssemblyBindingInfo *info_copy;
2962         GSList *tmp;
2963         MonoAssemblyBindingInfo *info_tmp;
2964         MonoDomain *domain = (MonoDomain*)user_data;
2965
2966         if (!domain)
2967                 return;
2968
2969         for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2970                 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2971                 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2972                         return;
2973         }
2974
2975         info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2976         memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2977         if (info->name)
2978                 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2979         if (info->culture)
2980                 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2981
2982         domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2983 }
2984
2985 static int
2986 get_version_number (int major, int minor)
2987 {
2988         return major * 256 + minor;
2989 }
2990
2991 static inline gboolean
2992 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2993 {
2994         int aname_version_number = get_version_number (aname->major, aname->minor);
2995         if (!info->has_old_version_bottom)
2996                 return FALSE;
2997
2998         if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2999                 return FALSE;
3000
3001         if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3002                 return FALSE;
3003
3004         /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3005         info->major = aname->major;
3006         info->minor = aname->minor;
3007
3008         return TRUE;
3009 }
3010
3011 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3012 static MonoAssemblyBindingInfo*
3013 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3014 {
3015         MonoAssemblyBindingInfo *info;
3016         GSList *list;
3017
3018         if (!domain->assembly_bindings)
3019                 return NULL;
3020
3021         info = NULL;
3022         for (list = domain->assembly_bindings; list; list = list->next) {
3023                 info = (MonoAssemblyBindingInfo *)list->data;
3024                 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3025                         break;
3026                 info = NULL;
3027         }
3028
3029         if (info) {
3030                 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3031                     info->has_new_version && assembly_binding_maps_name (info, aname))
3032                         info->is_valid = TRUE;
3033                 else
3034                         info->is_valid = FALSE;
3035         }
3036
3037         return info;
3038 }
3039
3040 static MonoAssemblyName*
3041 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3042 {
3043         MonoError error;
3044         MonoAssemblyBindingInfo *info, *info2;
3045         MonoImage *ppimage;
3046         MonoDomain *domain;
3047
3048         if (aname->public_key_token [0] == 0)
3049                 return aname;
3050
3051         domain = mono_domain_get ();
3052
3053         mono_assembly_binding_lock ();
3054         info = search_binding_loaded (aname);
3055         mono_assembly_binding_unlock ();
3056
3057         if (!info) {
3058                 mono_domain_lock (domain);
3059                 info = get_per_domain_assembly_binding_info (domain, aname);
3060                 mono_domain_unlock (domain);
3061         }
3062
3063         if (info) {
3064                 if (!check_policy_versions (info, aname))
3065                         return aname;
3066                 
3067                 mono_assembly_bind_version (info, aname, dest_name);
3068                 return dest_name;
3069         }
3070
3071         if (domain && domain->setup && domain->setup->configuration_file) {
3072                 mono_domain_lock (domain);
3073                 if (!domain->assembly_bindings_parsed) {
3074                         gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3075                         /* expect this to succeed because mono_domain_set_options_from_config () did
3076                          * the same thing when the domain was created. */
3077                         mono_error_assert_ok (&error);
3078
3079                         gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3080
3081                         if (!domain_config_file_path)
3082                                 domain_config_file_path = domain_config_file_name;
3083                         
3084                         mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
3085                         domain->assembly_bindings_parsed = TRUE;
3086                         if (domain_config_file_name != domain_config_file_path)
3087                                 g_free (domain_config_file_name);
3088                         g_free (domain_config_file_path);
3089                 }
3090
3091                 info2 = get_per_domain_assembly_binding_info (domain, aname);
3092
3093                 if (info2) {
3094                         info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3095                         info->name = g_strdup (info2->name);
3096                         info->culture = g_strdup (info2->culture);
3097                         info->domain_id = domain->domain_id;
3098                 }
3099
3100                 mono_domain_unlock (domain);
3101         }
3102
3103         if (!info) {
3104                 info = g_new0 (MonoAssemblyBindingInfo, 1);
3105                 info->major = aname->major;
3106                 info->minor = aname->minor;
3107         }
3108
3109         if (!info->is_valid) {
3110                 ppimage = mono_assembly_load_publisher_policy (aname);
3111                 if (ppimage) {
3112                         get_publisher_policy_info (ppimage, aname, info);
3113                         mono_image_close (ppimage);
3114                 }
3115         }
3116
3117         /* Define default error value if needed */
3118         if (!info->is_valid) {
3119                 info->name = g_strdup (aname->name);
3120                 info->culture = g_strdup (aname->culture);
3121                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3122         }
3123         
3124         mono_assembly_binding_lock ();
3125         info2 = search_binding_loaded (aname);
3126         if (info2) {
3127                 /* This binding was added by another thread 
3128                  * before us */
3129                 mono_assembly_binding_info_free (info);
3130                 g_free (info);
3131                 
3132                 info = info2;
3133         } else
3134                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3135                 
3136         mono_assembly_binding_unlock ();
3137         
3138         if (!info->is_valid || !check_policy_versions (info, aname))
3139                 return aname;
3140
3141         mono_assembly_bind_version (info, aname, dest_name);
3142         return dest_name;
3143 }
3144
3145 /**
3146  * mono_assembly_load_from_gac
3147  *
3148  * @aname: The assembly name object
3149  */
3150 static MonoAssembly*
3151 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3152 {
3153         MonoAssembly *result = NULL;
3154         gchar *name, *version, *culture, *fullpath, *subpath;
3155         gint32 len;
3156         gchar **paths;
3157         char *pubtok;
3158
3159         if (aname->public_key_token [0] == 0) {
3160                 return NULL;
3161         }
3162
3163         if (strstr (aname->name, ".dll")) {
3164                 len = strlen (filename) - 4;
3165                 name = (gchar *)g_malloc (len + 1);
3166                 memcpy (name, aname->name, len);
3167                 name[len] = 0;
3168         } else {
3169                 name = g_strdup (aname->name);
3170         }
3171
3172         if (aname->culture) {
3173                 culture = g_utf8_strdown (aname->culture, -1);
3174         } else {
3175                 culture = g_strdup ("");
3176         }
3177
3178         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3179         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3180                         aname->minor, aname->build, aname->revision,
3181                         culture, pubtok);
3182         g_free (pubtok);
3183         
3184         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3185         g_free (name);
3186         g_free (version);
3187         g_free (culture);
3188
3189         if (extra_gac_paths) {
3190                 paths = extra_gac_paths;
3191                 while (!result && *paths) {
3192                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3193                         result = mono_assembly_open_full (fullpath, status, refonly);
3194                         g_free (fullpath);
3195                         paths++;
3196                 }
3197         }
3198
3199         if (result) {
3200                 result->in_gac = TRUE;
3201                 g_free (subpath);
3202                 return result;
3203         }
3204
3205         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3206                         "mono", "gac", subpath, NULL);
3207         result = mono_assembly_open_full (fullpath, status, refonly);
3208         g_free (fullpath);
3209
3210         if (result)
3211                 result->in_gac = TRUE;
3212         
3213         g_free (subpath);
3214
3215         return result;
3216 }
3217
3218 MonoAssembly*
3219 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3220 {
3221         char *corlib_file;
3222         MonoAssemblyName *aname;
3223
3224         if (corlib) {
3225                 /* g_print ("corlib already loaded\n"); */
3226                 return corlib;
3227         }
3228
3229         // In native client, Corlib is embedded in the executable as static variable corlibData
3230 #if defined(__native_client__)
3231         if (corlibData != NULL && corlibSize != 0) {
3232                 int status = 0;
3233                 /* First "FALSE" instructs mono not to make a copy. */
3234                 /* Second "FALSE" says this is not just a ref.      */
3235                 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3236                 if (image == NULL || status != 0)
3237                         g_print("mono_image_open_from_data_full failed: %d\n", status);
3238                 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3239                 if (corlib == NULL || status != 0)
3240                         g_print ("mono_assembly_load_from_full failed: %d\n", status);
3241                 if (corlib)
3242                         return corlib;
3243         }
3244 #endif
3245
3246         // A nonstandard preload hook may provide a special mscorlib assembly
3247         aname = mono_assembly_name_new ("mscorlib.dll");
3248         corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3249         mono_assembly_name_free (aname);
3250         g_free (aname);
3251         if (corlib != NULL)
3252                 goto return_corlib_and_facades;
3253
3254         // This unusual directory layout can occur if mono is being built and run out of its own source repo
3255         if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3256                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3257                 if (corlib)
3258                         goto return_corlib_and_facades;
3259         }
3260
3261         /* Normal case: Load corlib from mono/<version> */
3262         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3263         if (assemblies_path) { // Custom assemblies path
3264                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3265                 if (corlib) {
3266                         g_free (corlib_file);
3267                         goto return_corlib_and_facades;
3268                 }
3269         }
3270         corlib = load_in_path (corlib_file, default_path, status, FALSE);
3271         g_free (corlib_file);
3272
3273 return_corlib_and_facades:
3274         if (corlib && !strcmp (runtime->framework_version, "4.5"))  // FIXME: stop hardcoding 4.5 here
3275                 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3276                 
3277         return corlib;
3278 }
3279
3280 static MonoAssembly*
3281 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3282 {
3283         MonoError refasm_error;
3284         error_init (&refasm_error);
3285         if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3286                 candidate = NULL;
3287         }
3288         mono_error_cleanup (&refasm_error);
3289         return candidate;
3290 }
3291
3292
3293 MonoAssembly*
3294 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
3295                                                                   const char       *basedir, 
3296                                                                   MonoImageOpenStatus *status,
3297                                                                   gboolean refonly)
3298 {
3299         MonoAssembly *result;
3300         char *fullpath, *filename;
3301         MonoAssemblyName maped_aname;
3302         MonoAssemblyName maped_name_pp;
3303         int ext_index;
3304         const char *ext;
3305         int len;
3306
3307         aname = mono_assembly_remap_version (aname, &maped_aname);
3308         
3309         /* Reflection only assemblies don't get assembly binding */
3310         if (!refonly)
3311                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3312         
3313         result = mono_assembly_loaded_full (aname, refonly);
3314         if (result)
3315                 return result;
3316
3317         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3318         if (result) {
3319                 result->in_gac = FALSE;
3320                 return result;
3321         }
3322
3323         /* Currently we retrieve the loaded corlib for reflection 
3324          * only requests, like a common reflection only assembly 
3325          */
3326         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3327                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3328         }
3329
3330         len = strlen (aname->name);
3331         for (ext_index = 0; ext_index < 2; ext_index ++) {
3332                 ext = ext_index == 0 ? ".dll" : ".exe";
3333                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3334                         filename = g_strdup (aname->name);
3335                         /* Don't try appending .dll/.exe if it already has one of those extensions */
3336                         ext_index++;
3337                 } else {
3338                         filename = g_strconcat (aname->name, ext, NULL);
3339                 }
3340
3341                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3342                 if (result) {
3343                         g_free (filename);
3344                         return result;
3345                 }
3346
3347                 if (basedir) {
3348                         fullpath = g_build_filename (basedir, filename, NULL);
3349                         result = mono_assembly_open_full (fullpath, status, refonly);
3350                         g_free (fullpath);
3351                         if (result) {
3352                                 result->in_gac = FALSE;
3353                                 g_free (filename);
3354                                 return result;
3355                         }
3356                 }
3357
3358                 result = load_in_path (filename, default_path, status, refonly);
3359                 if (result)
3360                         result->in_gac = FALSE;
3361                 g_free (filename);
3362                 if (result)
3363                         return result;
3364         }
3365
3366         return result;
3367 }
3368
3369 MonoAssembly*
3370 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3371 {
3372         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3373
3374         if (!result) {
3375                 /* Try a postload search hook */
3376                 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3377                 result = prevent_reference_assembly_from_running (result, refonly);
3378         }
3379         return result;
3380 }
3381
3382 /**
3383  * mono_assembly_load_full:
3384  * @aname: A MonoAssemblyName with the assembly name to load.
3385  * @basedir: A directory to look up the assembly at.
3386  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3387  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3388  *
3389  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3390  * attempts to load the assembly from that directory before probing the standard locations.
3391  *
3392  * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
3393  * assembly binding takes place.
3394  *
3395  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3396  * value pointed by status is updated with an error code.
3397  */
3398 MonoAssembly*
3399 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3400 {
3401         return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3402 }
3403
3404 /**
3405  * mono_assembly_load:
3406  * @aname: A MonoAssemblyName with the assembly name to load.
3407  * @basedir: A directory to look up the assembly at.
3408  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3409  *
3410  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3411  * attempts to load the assembly from that directory before probing the standard locations.
3412  *
3413  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3414  * value pointed by status is updated with an error code.
3415  */
3416 MonoAssembly*
3417 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3418 {
3419         return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3420 }
3421
3422 /**
3423  * mono_assembly_loaded_full:
3424  * @aname: an assembly to look for.
3425  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3426  *
3427  * This is used to determine if the specified assembly has been loaded
3428  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3429  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3430  */
3431 MonoAssembly*
3432 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3433 {
3434         MonoAssembly *res;
3435         MonoAssemblyName maped_aname;
3436
3437         aname = mono_assembly_remap_version (aname, &maped_aname);
3438
3439         res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3440
3441         return res;
3442 }
3443
3444 /**
3445  * mono_assembly_loaded:
3446  * @aname: an assembly to look for.
3447  *
3448  * This is used to determine if the specified assembly has been loaded
3449  
3450  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3451  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3452  */
3453 MonoAssembly*
3454 mono_assembly_loaded (MonoAssemblyName *aname)
3455 {
3456         return mono_assembly_loaded_full (aname, FALSE);
3457 }
3458
3459 void
3460 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3461 {
3462         if (assembly == NULL || assembly == REFERENCE_MISSING)
3463                 return;
3464
3465         if (assembly_is_dynamic (assembly)) {
3466                 int i;
3467                 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3468                 for (i = 0; i < dynimg->image.module_count; ++i)
3469                         mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3470                 mono_dynamic_image_release_gc_roots (dynimg);
3471         }
3472 }
3473
3474 /*
3475  * Returns whether mono_assembly_close_finish() must be called as
3476  * well.  See comment for mono_image_close_except_pools() for why we
3477  * unload in two steps.
3478  */
3479 gboolean
3480 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3481 {
3482         GSList *tmp;
3483         g_return_val_if_fail (assembly != NULL, FALSE);
3484
3485         if (assembly == REFERENCE_MISSING)
3486                 return FALSE;
3487
3488         /* Might be 0 already */
3489         if (InterlockedDecrement (&assembly->ref_count) > 0)
3490                 return FALSE;
3491
3492         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3493
3494         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3495
3496         mono_debug_close_image (assembly->image);
3497
3498         mono_assemblies_lock ();
3499         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3500         mono_assemblies_unlock ();
3501
3502         assembly->image->assembly = NULL;
3503
3504         if (!mono_image_close_except_pools (assembly->image))
3505                 assembly->image = NULL;
3506
3507         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3508                 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3509                 mono_assembly_name_free (fname);
3510                 g_free (fname);
3511         }
3512         g_slist_free (assembly->friend_assembly_names);
3513         g_free (assembly->basedir);
3514
3515         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3516
3517         return TRUE;
3518 }
3519
3520 void
3521 mono_assembly_close_finish (MonoAssembly *assembly)
3522 {
3523         g_assert (assembly && assembly != REFERENCE_MISSING);
3524
3525         if (assembly->image)
3526                 mono_image_close_finish (assembly->image);
3527
3528         if (assembly_is_dynamic (assembly)) {
3529                 g_free ((char*)assembly->aname.culture);
3530         } else {
3531                 g_free (assembly);
3532         }
3533 }
3534
3535 /**
3536  * mono_assembly_close:
3537  * @assembly: the assembly to release.
3538  *
3539  * This method releases a reference to the @assembly.  The assembly is
3540  * only released when all the outstanding references to it are released.
3541  */
3542 void
3543 mono_assembly_close (MonoAssembly *assembly)
3544 {
3545         if (mono_assembly_close_except_image_pools (assembly))
3546                 mono_assembly_close_finish (assembly);
3547 }
3548
3549 MonoImage*
3550 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3551 {
3552         MonoError error;
3553         MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3554         mono_error_assert_ok (&error);
3555         return result;
3556 }
3557
3558 MONO_API MonoImage*
3559 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3560 {
3561         return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3562 }
3563
3564
3565 /**
3566  * mono_assembly_foreach:
3567  * @func: function to invoke for each assembly loaded
3568  * @user_data: data passed to the callback
3569  *
3570  * Invokes the provided @func callback for each assembly loaded into
3571  * the runtime.   The first parameter passed to the callback  is the
3572  * `MonoAssembly*`, and the second parameter is the @user_data.
3573  *
3574  * This is done for all assemblies loaded in the runtime, not just
3575  * those loaded in the current application domain.
3576  */
3577 void
3578 mono_assembly_foreach (GFunc func, gpointer user_data)
3579 {
3580         GList *copy;
3581
3582         /*
3583          * We make a copy of the list to avoid calling the callback inside the 
3584          * lock, which could lead to deadlocks.
3585          */
3586         mono_assemblies_lock ();
3587         copy = g_list_copy (loaded_assemblies);
3588         mono_assemblies_unlock ();
3589
3590         g_list_foreach (loaded_assemblies, func, user_data);
3591
3592         g_list_free (copy);
3593 }
3594
3595 /**
3596  * mono_assemblies_cleanup:
3597  *
3598  * Free all resources used by this module.
3599  */
3600 void
3601 mono_assemblies_cleanup (void)
3602 {
3603         GSList *l;
3604
3605         mono_os_mutex_destroy (&assemblies_mutex);
3606         mono_os_mutex_destroy (&assembly_binding_mutex);
3607
3608         for (l = loaded_assembly_bindings; l; l = l->next) {
3609                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3610
3611                 mono_assembly_binding_info_free (info);
3612                 g_free (info);
3613         }
3614         g_slist_free (loaded_assembly_bindings);
3615
3616         free_assembly_load_hooks ();
3617         free_assembly_search_hooks ();
3618         free_assembly_preload_hooks ();
3619 }
3620
3621 /*LOCKING takes the assembly_binding lock*/
3622 void
3623 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3624 {
3625         GSList **iter;
3626
3627         mono_assembly_binding_lock ();
3628         iter = &loaded_assembly_bindings;
3629         while (*iter) {
3630                 GSList *l = *iter;
3631                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3632
3633                 if (info->domain_id == domain_id) {
3634                         *iter = l->next;
3635                         mono_assembly_binding_info_free (info);
3636                         g_free (info);
3637                         g_slist_free_1 (l);
3638                 } else {
3639                         iter = &l->next;
3640                 }
3641         }
3642         mono_assembly_binding_unlock ();
3643 }
3644
3645 /*
3646  * Holds the assembly of the application, for
3647  * System.Diagnostics.Process::MainModule
3648  */
3649 static MonoAssembly *main_assembly=NULL;
3650
3651 void
3652 mono_assembly_set_main (MonoAssembly *assembly)
3653 {
3654         main_assembly = assembly;
3655 }
3656
3657 /**
3658  * mono_assembly_get_main:
3659  *
3660  * Returns: the assembly for the application, the first assembly that is loaded by the VM
3661  */
3662 MonoAssembly *
3663 mono_assembly_get_main (void)
3664 {
3665         return (main_assembly);
3666 }
3667
3668 /**
3669  * mono_assembly_get_image:
3670  * @assembly: The assembly to retrieve the image from
3671  *
3672  * Returns: the MonoImage associated with this assembly.
3673  */
3674 MonoImage*
3675 mono_assembly_get_image (MonoAssembly *assembly)
3676 {
3677         return assembly->image;
3678 }
3679
3680 /**
3681  * mono_assembly_get_name:
3682  * @assembly: The assembly to retrieve the name from
3683  *
3684  * The returned name's lifetime is the same as @assembly's.
3685  *
3686  * Returns: the MonoAssemblyName associated with this assembly.
3687  */
3688 MonoAssemblyName *
3689 mono_assembly_get_name (MonoAssembly *assembly)
3690 {
3691         return &assembly->aname;
3692 }
3693
3694 void
3695 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3696 {
3697         bundles = assemblies;
3698 }
3699
3700 #define MONO_DECLSEC_FORMAT_10          0x3C
3701 #define MONO_DECLSEC_FORMAT_20          0x2E
3702 #define MONO_DECLSEC_FIELD              0x53
3703 #define MONO_DECLSEC_PROPERTY           0x54
3704
3705 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3706 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3707 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3708 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3709 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3710
3711 static gboolean
3712 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3713 {
3714         int len;
3715         switch (*p++) {
3716         case MONO_DECLSEC_PROPERTY:
3717                 break;
3718         case MONO_DECLSEC_FIELD:
3719         default:
3720                 *abort_decoding = TRUE;
3721                 return FALSE;
3722                 break;
3723         }
3724
3725         if (*p++ != MONO_TYPE_BOOLEAN) {
3726                 *abort_decoding = TRUE;
3727                 return FALSE;
3728         }
3729                 
3730         /* property name length */
3731         len = mono_metadata_decode_value (p, &p);
3732
3733         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3734                 p += len;
3735                 return *p;
3736         }
3737         p += len + 1;
3738
3739         *resp = p;
3740         return FALSE;
3741 }
3742
3743 static gboolean
3744 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3745 {
3746         int i, j, num, len, params_len;
3747
3748         if (*p == MONO_DECLSEC_FORMAT_10) {
3749                 gsize read, written;
3750                 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3751                 if (res) {
3752                         gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3753                         g_free (res);
3754                         return found;
3755                 }
3756                 return FALSE;
3757         }
3758         if (*p++ != MONO_DECLSEC_FORMAT_20)
3759                 return FALSE;
3760
3761         /* number of encoded permission attributes */
3762         num = mono_metadata_decode_value (p, &p);
3763         for (i = 0; i < num; ++i) {
3764                 gboolean is_valid = FALSE;
3765                 gboolean abort_decoding = FALSE;
3766
3767                 /* attribute name length */
3768                 len =  mono_metadata_decode_value (p, &p);
3769
3770                 /* We don't really need to fully decode the type. Comparing the name is enough */
3771                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3772
3773                 p += len;
3774
3775                 /*size of the params table*/
3776                 params_len =  mono_metadata_decode_value (p, &p);
3777                 if (is_valid) {
3778                         const char *params_end = p + params_len;
3779                         
3780                         /* number of parameters */
3781                         len = mono_metadata_decode_value (p, &p);
3782         
3783                         for (j = 0; j < len; ++j) {
3784                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3785                                         return TRUE;
3786                                 if (abort_decoding)
3787                                         break;
3788                         }
3789                         p = params_end;
3790                 } else {
3791                         p += params_len;
3792                 }
3793         }
3794         
3795         return FALSE;
3796 }
3797
3798
3799 gboolean
3800 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3801 {
3802         MonoTableInfo *t;       
3803         guint32 cols [MONO_DECL_SECURITY_SIZE];
3804         const char *blob;
3805         int i, len;
3806
3807         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3808                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3809
3810         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3811
3812         for (i = 0; i < t->rows; ++i) {
3813                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3814                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3815                         continue;
3816                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3817                         continue;
3818
3819                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3820                 len = mono_metadata_decode_blob_size (blob, &blob);
3821                 if (!len)
3822                         continue;
3823
3824                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3825                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3826                         return TRUE;
3827                 }
3828         }
3829
3830         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
3831         return FALSE;
3832 }