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