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