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