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