[sgen] Don't reallocate mod_union at each major
[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                 mono_error_raise_exception (&error); /* FIXME don't raise here */
1640         }
1641         if (new_fname && new_fname != fname) {
1642                 g_free (fname);
1643                 fname = new_fname;
1644                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1645                             "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1646         }
1647         
1648         image = NULL;
1649
1650         // If VM built with mkbundle
1651         loaded_from_bundle = FALSE;
1652         if (bundles != NULL) {
1653                 image = mono_assembly_open_from_bundle (fname, status, refonly);
1654                 loaded_from_bundle = image != NULL;
1655         }
1656
1657         if (!image)
1658                 image = mono_image_open_full (fname, status, refonly);
1659
1660         if (!image){
1661                 if (*status == MONO_IMAGE_OK)
1662                         *status = MONO_IMAGE_ERROR_ERRNO;
1663                 g_free (fname);
1664                 return NULL;
1665         }
1666
1667         if (image->assembly) {
1668                 /* Already loaded by another appdomain */
1669                 mono_assembly_invoke_load_hook (image->assembly);
1670                 mono_image_close (image);
1671                 g_free (fname);
1672                 return image->assembly;
1673         }
1674
1675         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1676
1677         if (ass) {
1678                 if (!loaded_from_bundle)
1679                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1680                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1681                 if (!refonly)
1682                         mono_config_for_assembly (ass->image);
1683         }
1684
1685         /* Clear the reference added by mono_image_open */
1686         mono_image_close (image);
1687         
1688         g_free (fname);
1689
1690         return ass;
1691 }
1692
1693 static void
1694 free_item (gpointer val, gpointer user_data)
1695 {
1696         g_free (val);
1697 }
1698
1699 /**
1700  * mono_assembly_load_friends:
1701  * @ass: an assembly
1702  *
1703  * Load the list of friend assemblies that are allowed to access
1704  * the assembly's internal types and members. They are stored as assembly
1705  * names in custom attributes.
1706  *
1707  * This is an internal method, we need this because when we load mscorlib
1708  * we do not have the internals visible cattr loaded yet,
1709  * so we need to load these after we initialize the runtime. 
1710  *
1711  * LOCKING: Acquires the assemblies lock plus the loader lock.
1712  */
1713 void
1714 mono_assembly_load_friends (MonoAssembly* ass)
1715 {
1716         MonoError error;
1717         int i;
1718         MonoCustomAttrInfo* attrs;
1719         GSList *list;
1720
1721         if (ass->friend_assembly_names_inited)
1722                 return;
1723
1724         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1725         mono_error_assert_ok (&error);
1726         if (!attrs) {
1727                 mono_assemblies_lock ();
1728                 ass->friend_assembly_names_inited = TRUE;
1729                 mono_assemblies_unlock ();
1730                 return;
1731         }
1732
1733         mono_assemblies_lock ();
1734         if (ass->friend_assembly_names_inited) {
1735                 mono_assemblies_unlock ();
1736                 return;
1737         }
1738         mono_assemblies_unlock ();
1739
1740         list = NULL;
1741         /* 
1742          * We build the list outside the assemblies lock, the worse that can happen
1743          * is that we'll need to free the allocated list.
1744          */
1745         for (i = 0; i < attrs->num_attrs; ++i) {
1746                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1747                 MonoAssemblyName *aname;
1748                 const gchar *data;
1749                 /* Do some sanity checking */
1750                 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1751                         continue;
1752                 if (attr->data_size < 4)
1753                         continue;
1754                 data = (const char*)attr->data;
1755                 /* 0xFF means null string, see custom attr format */
1756                 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1757                         continue;
1758                 mono_metadata_decode_value (data + 2, &data);
1759                 aname = g_new0 (MonoAssemblyName, 1);
1760                 /*g_print ("friend ass: %s\n", data);*/
1761                 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1762                         list = g_slist_prepend (list, aname);
1763                 } else {
1764                         g_free (aname);
1765                 }
1766         }
1767         mono_custom_attrs_free (attrs);
1768
1769         mono_assemblies_lock ();
1770         if (ass->friend_assembly_names_inited) {
1771                 mono_assemblies_unlock ();
1772                 g_slist_foreach (list, free_item, NULL);
1773                 g_slist_free (list);
1774                 return;
1775         }
1776         ass->friend_assembly_names = list;
1777
1778         /* Because of the double checked locking pattern above */
1779         mono_memory_barrier ();
1780         ass->friend_assembly_names_inited = TRUE;
1781         mono_assemblies_unlock ();
1782 }
1783
1784 /**
1785  * mono_assembly_open:
1786  * @filename: Opens the assembly pointed out by this name
1787  * @status: return status code
1788  *
1789  * This loads an assembly from the specified @filename.   The @filename allows
1790  * a local URL (starting with a file:// prefix).  If a file prefix is used, the
1791  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
1792  * is treated as a local path.
1793  *
1794  * First, an attempt is made to load the assembly from the bundled executable (for those
1795  * deployments that have been done with the `mkbundle` tool or for scenarios where the
1796  * assembly has been registered as an embedded assembly).   If this is not the case, then
1797  * the assembly is loaded from disk using `api:mono_image_open_full`.
1798  *
1799  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1800  * the assembly is made.
1801  *
1802  * Return: a pointer to the MonoAssembly if @filename contains a valid
1803  * assembly or NULL on error.  Details about the error are stored in the
1804  * @status variable.
1805  */
1806 MonoAssembly *
1807 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1808 {
1809         return mono_assembly_open_full (filename, status, FALSE);
1810 }
1811
1812 /**
1813  * mono_assembly_load_from_full:
1814  * @image: Image to load the assembly from
1815  * @fname: assembly name to associate with the assembly
1816  * @status: returns the status condition
1817  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1818  *
1819  * If the provided @image has an assembly reference, it will process the given
1820  * image as an assembly with the given name.
1821  *
1822  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1823  *
1824  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1825  * set to #MONO_IMAGE_OK;  or NULL on error.
1826  *
1827  * If there is an error loading the assembly the @status will indicate the
1828  * reason with @status being set to `MONO_IMAGE_INVALID` if the
1829  * image did not contain an assembly reference table.
1830  */
1831 MonoAssembly *
1832 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1833                               MonoImageOpenStatus *status, gboolean refonly)
1834 {
1835         MonoAssembly *ass, *ass2;
1836         char *base_dir;
1837
1838         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1839                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1840                 *status = MONO_IMAGE_IMAGE_INVALID;
1841                 return NULL;
1842         }
1843
1844 #if defined (HOST_WIN32)
1845         {
1846                 gchar *tmp_fn;
1847                 int i;
1848
1849                 tmp_fn = g_strdup (fname);
1850                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1851                         if (tmp_fn [i] == '/')
1852                                 tmp_fn [i] = '\\';
1853                 }
1854
1855                 base_dir = absolute_dir (tmp_fn);
1856                 g_free (tmp_fn);
1857         }
1858 #else
1859         base_dir = absolute_dir (fname);
1860 #endif
1861
1862         /*
1863          * Create assembly struct, and enter it into the assembly cache
1864          */
1865         ass = g_new0 (MonoAssembly, 1);
1866         ass->basedir = base_dir;
1867         ass->ref_only = refonly;
1868         ass->image = image;
1869
1870         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1871
1872         mono_assembly_fill_assembly_name (image, &ass->aname);
1873
1874         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1875                 // MS.NET doesn't support loading other mscorlibs
1876                 g_free (ass);
1877                 g_free (base_dir);
1878                 mono_image_addref (mono_defaults.corlib);
1879                 *status = MONO_IMAGE_OK;
1880                 return mono_defaults.corlib->assembly;
1881         }
1882
1883         /* Add a non-temporary reference because of ass->image */
1884         mono_image_addref (image);
1885
1886         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);
1887
1888         /* 
1889          * The load hooks might take locks so we can't call them while holding the
1890          * assemblies lock.
1891          */
1892         if (ass->aname.name) {
1893                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1894                 if (ass2) {
1895                         g_free (ass);
1896                         g_free (base_dir);
1897                         mono_image_close (image);
1898                         *status = MONO_IMAGE_OK;
1899                         return ass2;
1900                 }
1901         }
1902
1903         mono_assemblies_lock ();
1904
1905         if (image->assembly) {
1906                 /* 
1907                  * This means another thread has already loaded the assembly, but not yet
1908                  * called the load hooks so the search hook can't find the assembly.
1909                  */
1910                 mono_assemblies_unlock ();
1911                 ass2 = image->assembly;
1912                 g_free (ass);
1913                 g_free (base_dir);
1914                 mono_image_close (image);
1915                 *status = MONO_IMAGE_OK;
1916                 return ass2;
1917         }
1918
1919         image->assembly = ass;
1920
1921         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1922         mono_assemblies_unlock ();
1923
1924 #ifdef HOST_WIN32
1925         if (image->is_module_handle)
1926                 mono_image_fixup_vtable (image);
1927 #endif
1928
1929         mono_assembly_invoke_load_hook (ass);
1930
1931         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1932         
1933         return ass;
1934 }
1935
1936 /**
1937  * mono_assembly_load_from:
1938  * @image: Image to load the assembly from
1939  * @fname: assembly name to associate with the assembly
1940  * @status: return status code
1941  *
1942  * If the provided @image has an assembly reference, it will process the given
1943  * image as an assembly with the given name.
1944  *
1945  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1946  *
1947  * This is equivalent to calling `api:mono_assembly_load_from_full` with the
1948  * @refonly parameter set to FALSE.
1949  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1950  * set to #MONO_IMAGE_OK;  or NULL on error.
1951  *
1952  * If there is an error loading the assembly the @status will indicate the
1953  * reason with @status being set to `MONO_IMAGE_INVALID` if the
1954  * image did not contain an assembly reference table.
1955  
1956  */
1957 MonoAssembly *
1958 mono_assembly_load_from (MonoImage *image, const char *fname,
1959                          MonoImageOpenStatus *status)
1960 {
1961         return mono_assembly_load_from_full (image, fname, status, FALSE);
1962 }
1963
1964 /**
1965  * mono_assembly_name_free:
1966  * @aname: assembly name to free
1967  * 
1968  * Frees the provided assembly name object.
1969  * (it does not frees the object itself, only the name members).
1970  */
1971 void
1972 mono_assembly_name_free (MonoAssemblyName *aname)
1973 {
1974         if (aname == NULL)
1975                 return;
1976
1977         g_free ((void *) aname->name);
1978         g_free ((void *) aname->culture);
1979         g_free ((void *) aname->hash_value);
1980 }
1981
1982 static gboolean
1983 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
1984 {
1985         const gchar *pkey;
1986         gchar header [16], val, *arr;
1987         gint i, j, offset, bitlen, keylen, pkeylen;
1988         
1989         keylen = strlen (key) >> 1;
1990         if (keylen < 1)
1991                 return FALSE;
1992
1993         /* allow the ECMA standard key */
1994         if (strcmp (key, "00000000000000000400000000000000") == 0) {
1995                 if (pubkey) {
1996                         *pubkey = g_strdup (key);
1997                         *is_ecma = TRUE;
1998                 }
1999                 return TRUE;
2000         }
2001         *is_ecma = FALSE;
2002         val = g_ascii_xdigit_value (key [0]) << 4;
2003         val |= g_ascii_xdigit_value (key [1]);
2004         switch (val) {
2005                 case 0x00:
2006                         if (keylen < 13)
2007                                 return FALSE;
2008                         val = g_ascii_xdigit_value (key [24]);
2009                         val |= g_ascii_xdigit_value (key [25]);
2010                         if (val != 0x06)
2011                                 return FALSE;
2012                         pkey = key + 24;
2013                         break;
2014                 case 0x06:
2015                         pkey = key;
2016                         break;
2017                 default:
2018                         return FALSE;
2019         }
2020                 
2021         /* We need the first 16 bytes
2022         * to check whether this key is valid or not */
2023         pkeylen = strlen (pkey) >> 1;
2024         if (pkeylen < 16)
2025                 return FALSE;
2026                 
2027         for (i = 0, j = 0; i < 16; i++) {
2028                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2029                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2030         }
2031
2032         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2033                         header [1] != 0x02 || /* Version (0x02) */
2034                         header [2] != 0x00 || /* Reserved (word) */
2035                         header [3] != 0x00 ||
2036                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2037                 return FALSE;
2038
2039         /* Based on this length, we _should_ be able to know if the length is right */
2040         bitlen = read32 (header + 12) >> 3;
2041         if ((bitlen + 16 + 4) != pkeylen)
2042                 return FALSE;
2043
2044         /* parsing is OK and the public key itself is not requested back */
2045         if (!pubkey)
2046                 return TRUE;
2047                 
2048         /* Encode the size of the blob */
2049         offset = 0;
2050         if (keylen <= 127) {
2051                 arr = (gchar *)g_malloc (keylen + 1);
2052                 arr [offset++] = keylen;
2053         } else {
2054                 arr = (gchar *)g_malloc (keylen + 2);
2055                 arr [offset++] = 0x80; /* 10bs */
2056                 arr [offset++] = keylen;
2057         }
2058                 
2059         for (i = offset, j = 0; i < keylen + offset; i++) {
2060                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2061                 arr [i] |= g_ascii_xdigit_value (key [j++]);
2062         }
2063
2064         *pubkey = arr;
2065
2066         return TRUE;
2067 }
2068
2069 static gboolean
2070 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)
2071 {
2072         gint major, minor, build, revision;
2073         gint len;
2074         gint version_parts;
2075         gchar *pkey, *pkeyptr, *encoded, tok [8];
2076
2077         memset (aname, 0, sizeof (MonoAssemblyName));
2078
2079         if (version) {
2080                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2081                 if (version_parts < 2 || version_parts > 4)
2082                         return FALSE;
2083
2084                 /* FIXME: we should set build & revision to -1 (instead of 0)
2085                 if these are not set in the version string. That way, later on,
2086                 we can still determine if these were specified. */
2087                 aname->major = major;
2088                 aname->minor = minor;
2089                 if (version_parts >= 3)
2090                         aname->build = build;
2091                 else
2092                         aname->build = 0;
2093                 if (version_parts == 4)
2094                         aname->revision = revision;
2095                 else
2096                         aname->revision = 0;
2097         }
2098         
2099         aname->flags = flags;
2100         aname->arch = arch;
2101         aname->name = g_strdup (name);
2102         
2103         if (culture) {
2104                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2105                         aname->culture = g_strdup ("");
2106                 else
2107                         aname->culture = g_strdup (culture);
2108         }
2109         
2110         if (token && strncmp (token, "null", 4) != 0) {
2111                 char *lower;
2112
2113                 /* the constant includes the ending NULL, hence the -1 */
2114                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2115                         mono_assembly_name_free (aname);
2116                         return FALSE;
2117                 }
2118                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2119                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2120                 g_free (lower);
2121         }
2122
2123         if (key) {
2124                 gboolean is_ecma;
2125                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2126                         mono_assembly_name_free (aname);
2127                         return FALSE;
2128                 }
2129
2130                 if (is_ecma) {
2131                         if (save_public_key)
2132                                 aname->public_key = (guint8*)pkey;
2133                         else
2134                                 g_free (pkey);
2135                         g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2136                         return TRUE;
2137                 }
2138                 
2139                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2140                 // We also need to generate the key token
2141                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2142                 encoded = encode_public_tok ((guchar*) tok, 8);
2143                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2144                 g_free (encoded);
2145
2146                 if (save_public_key)
2147                         aname->public_key = (guint8*) pkey;
2148                 else
2149                         g_free (pkey);
2150         }
2151
2152         return TRUE;
2153 }
2154
2155 static gboolean
2156 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2157 {
2158         gchar **parts;
2159         gboolean res;
2160         
2161         parts = g_strsplit (dirname, "_", 3);
2162         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2163                 g_strfreev (parts);
2164                 return FALSE;
2165         }
2166         
2167         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2168         g_strfreev (parts);
2169         return res;
2170 }
2171
2172 static gboolean
2173 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2174 {
2175         char *eqsign = strchr (pair, '=');
2176         if (!eqsign) {
2177                 *key = NULL;
2178                 *keylen = 0;
2179                 *value = NULL;
2180                 return FALSE;
2181         }
2182
2183         *key = (gchar*)pair;
2184         *keylen = eqsign - *key;
2185         while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2186                 (*keylen)--;
2187         *value = g_strstrip (eqsign + 1);
2188         return TRUE;
2189 }
2190
2191 gboolean
2192 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2193 {
2194         gchar *dllname;
2195         gchar *dllname_uq;
2196         gchar *version = NULL;
2197         gchar *version_uq;
2198         gchar *culture = NULL;
2199         gchar *culture_uq;
2200         gchar *token = NULL;
2201         gchar *token_uq;
2202         gchar *key = NULL;
2203         gchar *key_uq;
2204         gchar *retargetable = NULL;
2205         gchar *retargetable_uq;
2206         gchar *procarch;
2207         gchar *procarch_uq;
2208         gboolean res;
2209         gchar *value, *part_name;
2210         guint32 part_name_len;
2211         gchar **parts;
2212         gchar **tmp;
2213         gboolean version_defined;
2214         gboolean token_defined;
2215         guint32 flags = 0;
2216         guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2217
2218         if (!is_version_defined)
2219                 is_version_defined = &version_defined;
2220         *is_version_defined = FALSE;
2221         if (!is_token_defined)
2222                 is_token_defined = &token_defined;
2223         *is_token_defined = FALSE;
2224         
2225         parts = tmp = g_strsplit (name, ",", 6);
2226         if (!tmp || !*tmp) {
2227                 g_strfreev (tmp);
2228                 return FALSE;
2229         }
2230
2231         dllname = g_strstrip (*tmp);
2232         
2233         tmp++;
2234
2235         while (*tmp) {
2236                 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2237                         goto cleanup_and_fail;
2238
2239                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2240                         *is_version_defined = TRUE;
2241                         version = value;
2242                         if (strlen (version) == 0) {
2243                                 goto cleanup_and_fail;
2244                         }
2245                         tmp++;
2246                         continue;
2247                 }
2248
2249                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2250                         culture = value;
2251                         if (strlen (culture) == 0) {
2252                                 goto cleanup_and_fail;
2253                         }
2254                         tmp++;
2255                         continue;
2256                 }
2257
2258                 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2259                         *is_token_defined = TRUE;
2260                         token = value;
2261                         if (strlen (token) == 0) {
2262                                 goto cleanup_and_fail;
2263                         }
2264                         tmp++;
2265                         continue;
2266                 }
2267
2268                 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2269                         key = value;
2270                         if (strlen (key) == 0) {
2271                                 goto cleanup_and_fail;
2272                         }
2273                         tmp++;
2274                         continue;
2275                 }
2276
2277                 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2278                         retargetable = value;
2279                         retargetable_uq = unquote (retargetable);
2280                         if (retargetable_uq != NULL)
2281                                 retargetable = retargetable_uq;
2282
2283                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
2284                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2285                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
2286                                 free (retargetable_uq);
2287                                 goto cleanup_and_fail;
2288                         }
2289
2290                         free (retargetable_uq);
2291                         tmp++;
2292                         continue;
2293                 }
2294
2295                 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2296                         procarch = value;
2297                         procarch_uq = unquote (procarch);
2298                         if (procarch_uq != NULL)
2299                                 procarch = procarch_uq;
2300
2301                         if (!g_ascii_strcasecmp (procarch, "MSIL"))
2302                                 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2303                         else if (!g_ascii_strcasecmp (procarch, "X86"))
2304                                 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2305                         else if (!g_ascii_strcasecmp (procarch, "IA64"))
2306                                 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2307                         else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2308                                 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2309                         else {
2310                                 free (procarch_uq);
2311                                 goto cleanup_and_fail;
2312                         }
2313
2314                         free (procarch_uq);
2315                         tmp++;
2316                         continue;
2317                 }
2318
2319                 g_strfreev (parts);
2320                 return FALSE;
2321         }
2322
2323         /* if retargetable flag is set, then we must have a fully qualified name */
2324         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2325                 goto cleanup_and_fail;
2326         }
2327
2328         dllname_uq = unquote (dllname);
2329         version_uq = unquote (version);
2330         culture_uq = unquote (culture);
2331         token_uq = unquote (token);
2332         key_uq = unquote (key);
2333
2334         res = build_assembly_name (
2335                 dllname_uq == NULL ? dllname : dllname_uq,
2336                 version_uq == NULL ? version : version_uq,
2337                 culture_uq == NULL ? culture : culture_uq,
2338                 token_uq == NULL ? token : token_uq,
2339                 key_uq == NULL ? key : key_uq,
2340                 flags, arch, aname, save_public_key);
2341
2342         free (dllname_uq);
2343         free (version_uq);
2344         free (culture_uq);
2345         free (token_uq);
2346         free (key_uq);
2347
2348         g_strfreev (parts);
2349         return res;
2350
2351 cleanup_and_fail:
2352         g_strfreev (parts);
2353         return FALSE;
2354 }
2355
2356 static char*
2357 unquote (const char *str)
2358 {
2359         gint slen;
2360         const char *end;
2361
2362         if (str == NULL)
2363                 return NULL;
2364
2365         slen = strlen (str);
2366         if (slen < 2)
2367                 return NULL;
2368
2369         if (*str != '\'' && *str != '\"')
2370                 return NULL;
2371
2372         end = str + slen - 1;
2373         if (*str != *end)
2374                 return NULL;
2375
2376         return g_strndup (str + 1, slen - 2);
2377 }
2378
2379 /**
2380  * mono_assembly_name_parse:
2381  * @name: name to parse
2382  * @aname: the destination assembly name
2383  * 
2384  * Parses an assembly qualified type name and assigns the name,
2385  * version, culture and token to the provided assembly name object.
2386  *
2387  * Returns: TRUE if the name could be parsed.
2388  */
2389 gboolean
2390 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2391 {
2392         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2393 }
2394
2395 /**
2396  * mono_assembly_name_new:
2397  * @name: name to parse
2398  *
2399  * Allocate a new MonoAssemblyName and fill its values from the
2400  * passed @name.
2401  *
2402  * Returns: a newly allocated structure or NULL if there was any failure.
2403  */
2404 MonoAssemblyName*
2405 mono_assembly_name_new (const char *name)
2406 {
2407         MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2408         if (mono_assembly_name_parse (name, aname))
2409                 return aname;
2410         g_free (aname);
2411         return NULL;
2412 }
2413
2414 const char*
2415 mono_assembly_name_get_name (MonoAssemblyName *aname)
2416 {
2417         return aname->name;
2418 }
2419
2420 const char*
2421 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2422 {
2423         return aname->culture;
2424 }
2425
2426 mono_byte*
2427 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2428 {
2429         if (aname->public_key_token [0])
2430                 return aname->public_key_token;
2431         return NULL;
2432 }
2433
2434 uint16_t
2435 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2436 {
2437         if (minor)
2438                 *minor = aname->minor;
2439         if (build)
2440                 *build = aname->build;
2441         if (revision)
2442                 *revision = aname->revision;
2443         return aname->major;
2444 }
2445
2446 static MonoAssembly*
2447 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2448 {
2449         gchar *fullpath = NULL;
2450         GDir *dirhandle;
2451         const char* direntry;
2452         MonoAssemblyName gac_aname;
2453         gint major=-1, minor=0, build=0, revision=0;
2454         gboolean exact_version;
2455         
2456         dirhandle = g_dir_open (basepath, 0, NULL);
2457         if (!dirhandle)
2458                 return NULL;
2459                 
2460         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2461
2462         while ((direntry = g_dir_read_name (dirhandle))) {
2463                 gboolean match = TRUE;
2464                 
2465                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2466                         continue;
2467                 
2468                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2469                         match = FALSE;
2470                         
2471                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
2472                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2473                         match = FALSE;
2474                 
2475                 if (match) {
2476                         if (exact_version) {
2477                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2478                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
2479                         }
2480                         else if (gac_aname.major < major)
2481                                 match = FALSE;
2482                         else if (gac_aname.major == major) {
2483                                 if (gac_aname.minor < minor)
2484                                         match = FALSE;
2485                                 else if (gac_aname.minor == minor) {
2486                                         if (gac_aname.build < build)
2487                                                 match = FALSE;
2488                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
2489                                                 match = FALSE; 
2490                                 }
2491                         }
2492                 }
2493                 
2494                 if (match) {
2495                         major = gac_aname.major;
2496                         minor = gac_aname.minor;
2497                         build = gac_aname.build;
2498                         revision = gac_aname.revision;
2499                         g_free (fullpath);
2500                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2501                 }
2502
2503                 mono_assembly_name_free (&gac_aname);
2504         }
2505         
2506         g_dir_close (dirhandle);
2507         
2508         if (fullpath == NULL)
2509                 return NULL;
2510         else {
2511                 MonoAssembly *res = mono_assembly_open (fullpath, status);
2512                 g_free (fullpath);
2513                 return res;
2514         }
2515 }
2516
2517 /**
2518  * mono_assembly_load_with_partial_name:
2519  * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2520  * @status: return status code
2521  *
2522  * Loads a Mono Assembly from a name.  The name is parsed using `api:mono_assembly_name_parse`,
2523  * so it might contain a qualified type name, version, culture and token.
2524  *
2525  * This will load the assembly from the file whose name is derived from the assembly name
2526  * by appending the .dll extension.
2527  *
2528  * The assembly is loaded from either one of the extra Global Assembly Caches specified
2529  * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2530  * if that fails from the GAC.
2531  *
2532  * Returns: NULL on failure, or a pointer to a MonoAssembly on success.   
2533  */
2534 MonoAssembly*
2535 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2536 {
2537         MonoError error;
2538         MonoAssembly *res;
2539         MonoAssemblyName *aname, base_name;
2540         MonoAssemblyName mapped_aname;
2541         gchar *fullname, *gacpath;
2542         gchar **paths;
2543
2544         memset (&base_name, 0, sizeof (MonoAssemblyName));
2545         aname = &base_name;
2546
2547         if (!mono_assembly_name_parse (name, aname))
2548                 return NULL;
2549
2550         /* 
2551          * If no specific version has been requested, make sure we load the
2552          * correct version for system assemblies.
2553          */ 
2554         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2555                 aname = mono_assembly_remap_version (aname, &mapped_aname);
2556         
2557         res = mono_assembly_loaded (aname);
2558         if (res) {
2559                 mono_assembly_name_free (aname);
2560                 return res;
2561         }
2562
2563         res = invoke_assembly_preload_hook (aname, assemblies_path);
2564         if (res) {
2565                 res->in_gac = FALSE;
2566                 mono_assembly_name_free (aname);
2567                 return res;
2568         }
2569
2570         fullname = g_strdup_printf ("%s.dll", aname->name);
2571
2572         if (extra_gac_paths) {
2573                 paths = extra_gac_paths;
2574                 while (!res && *paths) {
2575                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2576                         res = probe_for_partial_name (gacpath, fullname, aname, status);
2577                         g_free (gacpath);
2578                         paths++;
2579                 }
2580         }
2581
2582         if (res) {
2583                 res->in_gac = TRUE;
2584                 g_free (fullname);
2585                 mono_assembly_name_free (aname);
2586                 return res;
2587         }
2588
2589         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2590         res = probe_for_partial_name (gacpath, fullname, aname, status);
2591         g_free (gacpath);
2592
2593         if (res)
2594                 res->in_gac = TRUE;
2595         else {
2596                 MonoDomain *domain = mono_domain_get ();
2597                 MonoReflectionAssembly *refasm;
2598
2599                 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2600                 if (!mono_error_ok (&error)) {
2601                         g_free (fullname);
2602                         mono_assembly_name_free (aname);
2603                         mono_error_raise_exception (&error); /* FIXME don't raise here */
2604                 }
2605
2606                 if (refasm)
2607                         res = refasm->assembly;
2608         }
2609         
2610         g_free (fullname);
2611         mono_assembly_name_free (aname);
2612
2613         return res;
2614 }
2615
2616 static MonoBoolean
2617 mono_assembly_is_in_gac (const gchar *filename)
2618 {
2619         const gchar *rootdir;
2620         gchar *gp;
2621         gchar **paths;
2622
2623         if (filename == NULL)
2624                 return FALSE;
2625
2626         for (paths = extra_gac_paths; paths && *paths; paths++) {
2627                 if (strstr (*paths, filename) != *paths)
2628                         continue;
2629
2630                 gp = (gchar *) (filename + strlen (*paths));
2631                 if (*gp != G_DIR_SEPARATOR)
2632                         continue;
2633                 gp++;
2634                 if (strncmp (gp, "lib", 3))
2635                         continue;
2636                 gp += 3;
2637                 if (*gp != G_DIR_SEPARATOR)
2638                         continue;
2639                 gp++;
2640                 if (strncmp (gp, "mono", 4))
2641                         continue;
2642                 gp += 4;
2643                 if (*gp != G_DIR_SEPARATOR)
2644                         continue;
2645                 gp++;
2646                 if (strncmp (gp, "gac", 3))
2647                         continue;
2648                 gp += 3;
2649                 if (*gp != G_DIR_SEPARATOR)
2650                         continue;
2651
2652                 return TRUE;
2653         }
2654
2655         rootdir = mono_assembly_getrootdir ();
2656         if (strstr (filename, rootdir) != filename)
2657                 return FALSE;
2658
2659         gp = (gchar *) (filename + strlen (rootdir));
2660         if (*gp != G_DIR_SEPARATOR)
2661                 return FALSE;
2662         gp++;
2663         if (strncmp (gp, "mono", 4))
2664                 return FALSE;
2665         gp += 4;
2666         if (*gp != G_DIR_SEPARATOR)
2667                 return FALSE;
2668         gp++;
2669         if (strncmp (gp, "gac", 3))
2670                 return FALSE;
2671         gp += 3;
2672         if (*gp != G_DIR_SEPARATOR)
2673                 return FALSE;
2674         return TRUE;
2675 }
2676
2677 static MonoImage*
2678 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2679 {
2680         MonoImage *image;
2681         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2682         gchar **paths;
2683         gint32 len;
2684
2685         if (strstr (aname->name, ".dll")) {
2686                 len = strlen (aname->name) - 4;
2687                 name = (gchar *)g_malloc (len + 1);
2688                 strncpy (name, aname->name, len);
2689                 name[len] = 0;
2690         } else
2691                 name = g_strdup (aname->name);
2692         
2693         if (aname->culture)
2694                 culture = g_utf8_strdown (aname->culture, -1);
2695         else
2696                 culture = g_strdup ("");
2697         
2698         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2699         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2700         g_free (name);
2701         g_free (culture);
2702         
2703         filename = g_strconcat (pname, ".dll", NULL);
2704         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2705         g_free (pname);
2706         g_free (version);
2707         g_free (filename);
2708
2709         image = NULL;
2710         if (extra_gac_paths) {
2711                 paths = extra_gac_paths;
2712                 while (!image && *paths) {
2713                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2714                                         "lib", "mono", "gac", subpath, NULL);
2715                         image = mono_image_open (fullpath, NULL);
2716                         g_free (fullpath);
2717                         paths++;
2718                 }
2719         }
2720
2721         if (image) {
2722                 g_free (subpath);
2723                 return image;
2724         }
2725
2726         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
2727                         "mono", "gac", subpath, NULL);
2728         image = mono_image_open (fullpath, NULL);
2729         g_free (subpath);
2730         g_free (fullpath);
2731         
2732         return image;
2733 }
2734
2735 static MonoAssemblyName*
2736 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2737 {
2738         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2739         dest_name->major = info->new_version.major;
2740         dest_name->minor = info->new_version.minor;
2741         dest_name->build = info->new_version.build;
2742         dest_name->revision = info->new_version.revision;
2743         
2744         return dest_name;
2745 }
2746
2747 /* LOCKING: assembly_binding lock must be held */
2748 static MonoAssemblyBindingInfo*
2749 search_binding_loaded (MonoAssemblyName *aname)
2750 {
2751         GSList *tmp;
2752
2753         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2754                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2755                 if (assembly_binding_maps_name (info, aname))
2756                         return info;
2757         }
2758
2759         return NULL;
2760 }
2761
2762 static inline gboolean
2763 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2764 {
2765         if (left->major != right->major || left->minor != right->minor ||
2766             left->build != right->build || left->revision != right->revision)
2767                 return FALSE;
2768
2769         return TRUE;
2770 }
2771
2772 static inline gboolean
2773 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2774 {
2775         if (left->has_old_version_bottom != right->has_old_version_bottom)
2776                 return FALSE;
2777
2778         if (left->has_old_version_top != right->has_old_version_top)
2779                 return FALSE;
2780
2781         if (left->has_new_version != right->has_new_version)
2782                 return FALSE;
2783
2784         if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2785                 return FALSE;
2786
2787         if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2788                 return FALSE;
2789
2790         if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2791                 return FALSE;
2792
2793         return TRUE;
2794 }
2795
2796 /* LOCKING: assumes all the necessary locks are held */
2797 static void
2798 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2799 {
2800         MonoAssemblyBindingInfo *info_copy;
2801         GSList *tmp;
2802         MonoAssemblyBindingInfo *info_tmp;
2803         MonoDomain *domain = (MonoDomain*)user_data;
2804
2805         if (!domain)
2806                 return;
2807
2808         for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2809                 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2810                 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2811                         return;
2812         }
2813
2814         info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2815         memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2816         if (info->name)
2817                 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2818         if (info->culture)
2819                 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2820
2821         domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2822 }
2823
2824 static int
2825 get_version_number (int major, int minor)
2826 {
2827         return major * 256 + minor;
2828 }
2829
2830 static inline gboolean
2831 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2832 {
2833         int aname_version_number = get_version_number (aname->major, aname->minor);
2834         if (!info->has_old_version_bottom)
2835                 return FALSE;
2836
2837         if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2838                 return FALSE;
2839
2840         if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2841                 return FALSE;
2842
2843         /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2844         info->major = aname->major;
2845         info->minor = aname->minor;
2846
2847         return TRUE;
2848 }
2849
2850 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2851 static MonoAssemblyBindingInfo*
2852 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2853 {
2854         MonoAssemblyBindingInfo *info;
2855         GSList *list;
2856
2857         if (!domain->assembly_bindings)
2858                 return NULL;
2859
2860         info = NULL;
2861         for (list = domain->assembly_bindings; list; list = list->next) {
2862                 info = (MonoAssemblyBindingInfo *)list->data;
2863                 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2864                         break;
2865                 info = NULL;
2866         }
2867
2868         if (info) {
2869                 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2870                     info->has_new_version && assembly_binding_maps_name (info, aname))
2871                         info->is_valid = TRUE;
2872                 else
2873                         info->is_valid = FALSE;
2874         }
2875
2876         return info;
2877 }
2878
2879 static MonoAssemblyName*
2880 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2881 {
2882         MonoAssemblyBindingInfo *info, *info2;
2883         MonoImage *ppimage;
2884         MonoDomain *domain;
2885
2886         if (aname->public_key_token [0] == 0)
2887                 return aname;
2888
2889         domain = mono_domain_get ();
2890
2891         mono_assembly_binding_lock ();
2892         info = search_binding_loaded (aname);
2893         mono_assembly_binding_unlock ();
2894
2895         if (!info) {
2896                 mono_domain_lock (domain);
2897                 info = get_per_domain_assembly_binding_info (domain, aname);
2898                 mono_domain_unlock (domain);
2899         }
2900
2901         if (info) {
2902                 if (!check_policy_versions (info, aname))
2903                         return aname;
2904                 
2905                 mono_assembly_bind_version (info, aname, dest_name);
2906                 return dest_name;
2907         }
2908
2909         if (domain && domain->setup && domain->setup->configuration_file) {
2910                 mono_domain_lock (domain);
2911                 if (!domain->assembly_bindings_parsed) {
2912                         gchar *domain_config_file_name = mono_string_to_utf8 (domain->setup->configuration_file);
2913                         gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2914
2915                         if (!domain_config_file_path)
2916                                 domain_config_file_path = domain_config_file_name;
2917                         
2918                         mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2919                         domain->assembly_bindings_parsed = TRUE;
2920                         if (domain_config_file_name != domain_config_file_path)
2921                                 g_free (domain_config_file_name);
2922                         g_free (domain_config_file_path);
2923                 }
2924
2925                 info2 = get_per_domain_assembly_binding_info (domain, aname);
2926
2927                 if (info2) {
2928                         info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2929                         info->name = g_strdup (info2->name);
2930                         info->culture = g_strdup (info2->culture);
2931                         info->domain_id = domain->domain_id;
2932                 }
2933
2934                 mono_domain_unlock (domain);
2935         }
2936
2937         if (!info) {
2938                 info = g_new0 (MonoAssemblyBindingInfo, 1);
2939                 info->major = aname->major;
2940                 info->minor = aname->minor;
2941         }
2942
2943         if (!info->is_valid) {
2944                 ppimage = mono_assembly_load_publisher_policy (aname);
2945                 if (ppimage) {
2946                         get_publisher_policy_info (ppimage, aname, info);
2947                         mono_image_close (ppimage);
2948                 }
2949         }
2950
2951         /* Define default error value if needed */
2952         if (!info->is_valid) {
2953                 info->name = g_strdup (aname->name);
2954                 info->culture = g_strdup (aname->culture);
2955                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2956         }
2957         
2958         mono_assembly_binding_lock ();
2959         info2 = search_binding_loaded (aname);
2960         if (info2) {
2961                 /* This binding was added by another thread 
2962                  * before us */
2963                 mono_assembly_binding_info_free (info);
2964                 g_free (info);
2965                 
2966                 info = info2;
2967         } else
2968                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2969                 
2970         mono_assembly_binding_unlock ();
2971         
2972         if (!info->is_valid || !check_policy_versions (info, aname))
2973                 return aname;
2974
2975         mono_assembly_bind_version (info, aname, dest_name);
2976         return dest_name;
2977 }
2978
2979 /**
2980  * mono_assembly_load_from_gac
2981  *
2982  * @aname: The assembly name object
2983  */
2984 static MonoAssembly*
2985 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
2986 {
2987         MonoAssembly *result = NULL;
2988         gchar *name, *version, *culture, *fullpath, *subpath;
2989         gint32 len;
2990         gchar **paths;
2991         char *pubtok;
2992
2993         if (aname->public_key_token [0] == 0) {
2994                 return NULL;
2995         }
2996
2997         if (strstr (aname->name, ".dll")) {
2998                 len = strlen (filename) - 4;
2999                 name = (gchar *)g_malloc (len + 1);
3000                 strncpy (name, aname->name, len);
3001                 name[len] = 0;
3002         } else {
3003                 name = g_strdup (aname->name);
3004         }
3005
3006         if (aname->culture) {
3007                 culture = g_utf8_strdown (aname->culture, -1);
3008         } else {
3009                 culture = g_strdup ("");
3010         }
3011
3012         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3013         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3014                         aname->minor, aname->build, aname->revision,
3015                         culture, pubtok);
3016         g_free (pubtok);
3017         
3018         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3019         g_free (name);
3020         g_free (version);
3021         g_free (culture);
3022
3023         if (extra_gac_paths) {
3024                 paths = extra_gac_paths;
3025                 while (!result && *paths) {
3026                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3027                         result = mono_assembly_open_full (fullpath, status, refonly);
3028                         g_free (fullpath);
3029                         paths++;
3030                 }
3031         }
3032
3033         if (result) {
3034                 result->in_gac = TRUE;
3035                 g_free (subpath);
3036                 return result;
3037         }
3038
3039         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3040                         "mono", "gac", subpath, NULL);
3041         result = mono_assembly_open_full (fullpath, status, refonly);
3042         g_free (fullpath);
3043
3044         if (result)
3045                 result->in_gac = TRUE;
3046         
3047         g_free (subpath);
3048
3049         return result;
3050 }
3051
3052 MonoAssembly*
3053 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3054 {
3055         char *corlib_file;
3056         MonoAssemblyName *aname;
3057
3058         if (corlib) {
3059                 /* g_print ("corlib already loaded\n"); */
3060                 return corlib;
3061         }
3062
3063         // In native client, Corlib is embedded in the executable as static variable corlibData
3064 #if defined(__native_client__)
3065         if (corlibData != NULL && corlibSize != 0) {
3066                 int status = 0;
3067                 /* First "FALSE" instructs mono not to make a copy. */
3068                 /* Second "FALSE" says this is not just a ref.      */
3069                 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3070                 if (image == NULL || status != 0)
3071                         g_print("mono_image_open_from_data_full failed: %d\n", status);
3072                 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3073                 if (corlib == NULL || status != 0)
3074                         g_print ("mono_assembly_load_from_full failed: %d\n", status);
3075                 if (corlib)
3076                         return corlib;
3077         }
3078 #endif
3079
3080         // A nonstandard preload hook may provide a special mscorlib assembly
3081         aname = mono_assembly_name_new ("mscorlib.dll");
3082         corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3083         mono_assembly_name_free (aname);
3084         g_free (aname);
3085         if (corlib != NULL)
3086                 goto return_corlib_and_facades;
3087
3088         // This unusual directory layout can occur if mono is being built and run out of its own source repo
3089         if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3090                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3091                 if (corlib)
3092                         goto return_corlib_and_facades;
3093         }
3094
3095         /* Normal case: Load corlib from mono/<version> */
3096         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3097         if (assemblies_path) { // Custom assemblies path
3098                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3099                 if (corlib) {
3100                         g_free (corlib_file);
3101                         goto return_corlib_and_facades;
3102                 }
3103         }
3104         corlib = load_in_path (corlib_file, default_path, status, FALSE);
3105         g_free (corlib_file);
3106
3107 return_corlib_and_facades:
3108         if (corlib && !strcmp (runtime->framework_version, "4.5"))  // FIXME: stop hardcoding 4.5 here
3109                 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3110                 
3111         return corlib;
3112 }
3113
3114 MonoAssembly*
3115 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
3116                                                                   const char       *basedir, 
3117                                                                   MonoImageOpenStatus *status,
3118                                                                   gboolean refonly)
3119 {
3120         MonoAssembly *result;
3121         char *fullpath, *filename;
3122         MonoAssemblyName maped_aname;
3123         MonoAssemblyName maped_name_pp;
3124         int ext_index;
3125         const char *ext;
3126         int len;
3127
3128         aname = mono_assembly_remap_version (aname, &maped_aname);
3129         
3130         /* Reflection only assemblies don't get assembly binding */
3131         if (!refonly)
3132                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3133         
3134         result = mono_assembly_loaded_full (aname, refonly);
3135         if (result)
3136                 return result;
3137
3138         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3139         if (result) {
3140                 result->in_gac = FALSE;
3141                 return result;
3142         }
3143
3144         /* Currently we retrieve the loaded corlib for reflection 
3145          * only requests, like a common reflection only assembly 
3146          */
3147         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3148                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3149         }
3150
3151         len = strlen (aname->name);
3152         for (ext_index = 0; ext_index < 2; ext_index ++) {
3153                 ext = ext_index == 0 ? ".dll" : ".exe";
3154                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3155                         filename = g_strdup (aname->name);
3156                         /* Don't try appending .dll/.exe if it already has one of those extensions */
3157                         ext_index++;
3158                 } else {
3159                         filename = g_strconcat (aname->name, ext, NULL);
3160                 }
3161
3162                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3163                 if (result) {
3164                         g_free (filename);
3165                         return result;
3166                 }
3167
3168                 if (basedir) {
3169                         fullpath = g_build_filename (basedir, filename, NULL);
3170                         result = mono_assembly_open_full (fullpath, status, refonly);
3171                         g_free (fullpath);
3172                         if (result) {
3173                                 result->in_gac = FALSE;
3174                                 g_free (filename);
3175                                 return result;
3176                         }
3177                 }
3178
3179                 result = load_in_path (filename, default_path, status, refonly);
3180                 if (result)
3181                         result->in_gac = FALSE;
3182                 g_free (filename);
3183                 if (result)
3184                         return result;
3185         }
3186
3187         return result;
3188 }
3189
3190 MonoAssembly*
3191 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3192 {
3193         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3194
3195         if (!result)
3196                 /* Try a postload search hook */
3197                 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3198         return result;
3199 }
3200
3201 /**
3202  * mono_assembly_load_full:
3203  * @aname: A MonoAssemblyName with the assembly name to load.
3204  * @basedir: A directory to look up the assembly at.
3205  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3206  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3207  *
3208  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3209  * attempts to load the assembly from that directory before probing the standard locations.
3210  *
3211  * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
3212  * assembly binding takes place.
3213  *
3214  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3215  * value pointed by status is updated with an error code.
3216  */
3217 MonoAssembly*
3218 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3219 {
3220         return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3221 }
3222
3223 /**
3224  * mono_assembly_load:
3225  * @aname: A MonoAssemblyName with the assembly name to load.
3226  * @basedir: A directory to look up the assembly at.
3227  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3228  *
3229  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3230  * attempts to load the assembly from that directory before probing the standard locations.
3231  *
3232  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3233  * value pointed by status is updated with an error code.
3234  */
3235 MonoAssembly*
3236 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3237 {
3238         return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3239 }
3240
3241 /**
3242  * mono_assembly_loaded_full:
3243  * @aname: an assembly to look for.
3244  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3245  *
3246  * This is used to determine if the specified assembly has been loaded
3247  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3248  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3249  */
3250 MonoAssembly*
3251 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3252 {
3253         MonoAssembly *res;
3254         MonoAssemblyName maped_aname;
3255
3256         aname = mono_assembly_remap_version (aname, &maped_aname);
3257
3258         res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3259
3260         return res;
3261 }
3262
3263 /**
3264  * mono_assembly_loaded:
3265  * @aname: an assembly to look for.
3266  *
3267  * This is used to determine if the specified assembly has been loaded
3268  
3269  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3270  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3271  */
3272 MonoAssembly*
3273 mono_assembly_loaded (MonoAssemblyName *aname)
3274 {
3275         return mono_assembly_loaded_full (aname, FALSE);
3276 }
3277
3278 void
3279 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3280 {
3281         if (assembly == NULL || assembly == REFERENCE_MISSING)
3282                 return;
3283
3284         if (assembly_is_dynamic (assembly)) {
3285                 int i;
3286                 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3287                 for (i = 0; i < dynimg->image.module_count; ++i)
3288                         mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3289                 mono_dynamic_image_release_gc_roots (dynimg);
3290         }
3291 }
3292
3293 /*
3294  * Returns whether mono_assembly_close_finish() must be called as
3295  * well.  See comment for mono_image_close_except_pools() for why we
3296  * unload in two steps.
3297  */
3298 gboolean
3299 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3300 {
3301         GSList *tmp;
3302         g_return_val_if_fail (assembly != NULL, FALSE);
3303
3304         if (assembly == REFERENCE_MISSING)
3305                 return FALSE;
3306
3307         /* Might be 0 already */
3308         if (InterlockedDecrement (&assembly->ref_count) > 0)
3309                 return FALSE;
3310
3311         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3312
3313         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3314
3315         mono_debug_close_image (assembly->image);
3316
3317         mono_assemblies_lock ();
3318         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3319         mono_assemblies_unlock ();
3320
3321         assembly->image->assembly = NULL;
3322
3323         if (!mono_image_close_except_pools (assembly->image))
3324                 assembly->image = NULL;
3325
3326         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3327                 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3328                 mono_assembly_name_free (fname);
3329                 g_free (fname);
3330         }
3331         g_slist_free (assembly->friend_assembly_names);
3332         g_free (assembly->basedir);
3333
3334         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3335
3336         return TRUE;
3337 }
3338
3339 void
3340 mono_assembly_close_finish (MonoAssembly *assembly)
3341 {
3342         g_assert (assembly && assembly != REFERENCE_MISSING);
3343
3344         if (assembly->image)
3345                 mono_image_close_finish (assembly->image);
3346
3347         if (assembly_is_dynamic (assembly)) {
3348                 g_free ((char*)assembly->aname.culture);
3349         } else {
3350                 g_free (assembly);
3351         }
3352 }
3353
3354 /**
3355  * mono_assembly_close:
3356  * @assembly: the assembly to release.
3357  *
3358  * This method releases a reference to the @assembly.  The assembly is
3359  * only released when all the outstanding references to it are released.
3360  */
3361 void
3362 mono_assembly_close (MonoAssembly *assembly)
3363 {
3364         if (mono_assembly_close_except_image_pools (assembly))
3365                 mono_assembly_close_finish (assembly);
3366 }
3367
3368 MonoImage*
3369 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3370 {
3371         return mono_image_load_file_for_image (assembly->image, idx);
3372 }
3373
3374 /**
3375  * mono_assembly_foreach:
3376  * @func: function to invoke for each assembly loaded
3377  * @user_data: data passed to the callback
3378  *
3379  * Invokes the provided @func callback for each assembly loaded into
3380  * the runtime.   The first parameter passed to the callback  is the
3381  * `MonoAssembly*`, and the second parameter is the @user_data.
3382  *
3383  * This is done for all assemblies loaded in the runtime, not just
3384  * those loaded in the current application domain.
3385  */
3386 void
3387 mono_assembly_foreach (GFunc func, gpointer user_data)
3388 {
3389         GList *copy;
3390
3391         /*
3392          * We make a copy of the list to avoid calling the callback inside the 
3393          * lock, which could lead to deadlocks.
3394          */
3395         mono_assemblies_lock ();
3396         copy = g_list_copy (loaded_assemblies);
3397         mono_assemblies_unlock ();
3398
3399         g_list_foreach (loaded_assemblies, func, user_data);
3400
3401         g_list_free (copy);
3402 }
3403
3404 /**
3405  * mono_assemblies_cleanup:
3406  *
3407  * Free all resources used by this module.
3408  */
3409 void
3410 mono_assemblies_cleanup (void)
3411 {
3412         GSList *l;
3413
3414         mono_os_mutex_destroy (&assemblies_mutex);
3415         mono_os_mutex_destroy (&assembly_binding_mutex);
3416
3417         for (l = loaded_assembly_bindings; l; l = l->next) {
3418                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3419
3420                 mono_assembly_binding_info_free (info);
3421                 g_free (info);
3422         }
3423         g_slist_free (loaded_assembly_bindings);
3424
3425         free_assembly_load_hooks ();
3426         free_assembly_search_hooks ();
3427         free_assembly_preload_hooks ();
3428 }
3429
3430 /*LOCKING takes the assembly_binding lock*/
3431 void
3432 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3433 {
3434         GSList **iter;
3435
3436         mono_assembly_binding_lock ();
3437         iter = &loaded_assembly_bindings;
3438         while (*iter) {
3439                 GSList *l = *iter;
3440                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3441
3442                 if (info->domain_id == domain_id) {
3443                         *iter = l->next;
3444                         mono_assembly_binding_info_free (info);
3445                         g_free (info);
3446                         g_slist_free_1 (l);
3447                 } else {
3448                         iter = &l->next;
3449                 }
3450         }
3451         mono_assembly_binding_unlock ();
3452 }
3453
3454 /*
3455  * Holds the assembly of the application, for
3456  * System.Diagnostics.Process::MainModule
3457  */
3458 static MonoAssembly *main_assembly=NULL;
3459
3460 void
3461 mono_assembly_set_main (MonoAssembly *assembly)
3462 {
3463         main_assembly = assembly;
3464 }
3465
3466 /**
3467  * mono_assembly_get_main:
3468  *
3469  * Returns: the assembly for the application, the first assembly that is loaded by the VM
3470  */
3471 MonoAssembly *
3472 mono_assembly_get_main (void)
3473 {
3474         return (main_assembly);
3475 }
3476
3477 /**
3478  * mono_assembly_get_image:
3479  * @assembly: The assembly to retrieve the image from
3480  *
3481  * Returns: the MonoImage associated with this assembly.
3482  */
3483 MonoImage*
3484 mono_assembly_get_image (MonoAssembly *assembly)
3485 {
3486         return assembly->image;
3487 }
3488
3489 /**
3490  * mono_assembly_get_name:
3491  * @assembly: The assembly to retrieve the name from
3492  *
3493  * The returned name's lifetime is the same as @assembly's.
3494  *
3495  * Returns: the MonoAssemblyName associated with this assembly.
3496  */
3497 MonoAssemblyName *
3498 mono_assembly_get_name (MonoAssembly *assembly)
3499 {
3500         return &assembly->aname;
3501 }
3502
3503 void
3504 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3505 {
3506         bundles = assemblies;
3507 }
3508
3509 #define MONO_DECLSEC_FORMAT_10          0x3C
3510 #define MONO_DECLSEC_FORMAT_20          0x2E
3511 #define MONO_DECLSEC_FIELD              0x53
3512 #define MONO_DECLSEC_PROPERTY           0x54
3513
3514 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3515 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3516 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3517 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3518 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3519
3520 static gboolean
3521 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3522 {
3523         int len;
3524         switch (*p++) {
3525         case MONO_DECLSEC_PROPERTY:
3526                 break;
3527         case MONO_DECLSEC_FIELD:
3528         default:
3529                 *abort_decoding = TRUE;
3530                 return FALSE;
3531                 break;
3532         }
3533
3534         if (*p++ != MONO_TYPE_BOOLEAN) {
3535                 *abort_decoding = TRUE;
3536                 return FALSE;
3537         }
3538                 
3539         /* property name length */
3540         len = mono_metadata_decode_value (p, &p);
3541
3542         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3543                 p += len;
3544                 return *p;
3545         }
3546         p += len + 1;
3547
3548         *resp = p;
3549         return FALSE;
3550 }
3551
3552 static gboolean
3553 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3554 {
3555         int i, j, num, len, params_len;
3556
3557         if (*p == MONO_DECLSEC_FORMAT_10) {
3558                 gsize read, written;
3559                 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3560                 if (res) {
3561                         gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3562                         g_free (res);
3563                         return found;
3564                 }
3565                 return FALSE;
3566         }
3567         if (*p++ != MONO_DECLSEC_FORMAT_20)
3568                 return FALSE;
3569
3570         /* number of encoded permission attributes */
3571         num = mono_metadata_decode_value (p, &p);
3572         for (i = 0; i < num; ++i) {
3573                 gboolean is_valid = FALSE;
3574                 gboolean abort_decoding = FALSE;
3575
3576                 /* attribute name length */
3577                 len =  mono_metadata_decode_value (p, &p);
3578
3579                 /* We don't really need to fully decode the type. Comparing the name is enough */
3580                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3581
3582                 p += len;
3583
3584                 /*size of the params table*/
3585                 params_len =  mono_metadata_decode_value (p, &p);
3586                 if (is_valid) {
3587                         const char *params_end = p + params_len;
3588                         
3589                         /* number of parameters */
3590                         len = mono_metadata_decode_value (p, &p);
3591         
3592                         for (j = 0; j < len; ++j) {
3593                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3594                                         return TRUE;
3595                                 if (abort_decoding)
3596                                         break;
3597                         }
3598                         p = params_end;
3599                 } else {
3600                         p += params_len;
3601                 }
3602         }
3603         
3604         return FALSE;
3605 }
3606
3607
3608 gboolean
3609 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3610 {
3611         MonoTableInfo *t;       
3612         guint32 cols [MONO_DECL_SECURITY_SIZE];
3613         const char *blob;
3614         int i, len;
3615
3616         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3617                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3618
3619         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3620
3621         for (i = 0; i < t->rows; ++i) {
3622                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3623                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3624                         continue;
3625                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3626                         continue;
3627
3628                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3629                 len = mono_metadata_decode_blob_size (blob, &blob);
3630                 if (!len)
3631                         continue;
3632
3633                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3634                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3635                         return TRUE;
3636                 }
3637         }
3638
3639         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
3640         return FALSE;
3641 }