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