Merge pull request #2903 from krytarowski/netbsd-support-4
[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 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
925
926 typedef struct {
927         const char *name;
928         const char *from;
929         const char *to;
930 } KeyRemapEntry;
931
932 static KeyRemapEntry key_remap_table[] = {
933         { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
934         { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
935         { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
936         { "System", SILVERLIGHT_KEY, ECMA_KEY },
937         { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
938         { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
939         { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
940         { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
941         { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
942         { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
943         { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
944         { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
945         { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
946         // FIXME: MS uses MSFINAL_KEY for .NET 4.5
947         { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
948         { "System.Numerics", WINFX_KEY, ECMA_KEY },
949         { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
950         { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
951         { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
952         { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
953         { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
954         { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
955         { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
956         { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
957         { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
958         { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
959         { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
960         { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
961         { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
962 };
963
964 static void
965 remap_keys (MonoAssemblyName *aname)
966 {
967         int i;
968         for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
969                 const KeyRemapEntry *entry = &key_remap_table [i];
970
971                 if (strcmp (aname->name, entry->name) ||
972                     !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
973                         continue;
974
975                 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
976                      
977                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
978                             "Remapped public key token of retargetable assembly %s from %s to %s",
979                             aname->name, entry->from, entry->to);
980                 return;
981         }
982 }
983
984 static MonoAssemblyName *
985 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
986 {
987         const MonoRuntimeInfo *current_runtime;
988         int pos, first, last;
989
990         if (aname->name == NULL) return aname;
991
992         current_runtime = mono_get_runtime_info ();
993
994         if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
995                 const AssemblyVersionSet* vset;
996
997                 /* Remap to current runtime */
998                 vset = &current_runtime->version_sets [0];
999
1000                 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1001                 dest_aname->major = vset->major;
1002                 dest_aname->minor = vset->minor;
1003                 dest_aname->build = vset->build;
1004                 dest_aname->revision = vset->revision;
1005                 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1006
1007                 /* Remap assembly name */
1008                 if (!strcmp (aname->name, "System.Net"))
1009                         dest_aname->name = g_strdup ("System");
1010                 
1011                 remap_keys (dest_aname);
1012
1013                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1014                                         "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1015                                         aname->name,
1016                                         aname->major, aname->minor, aname->build, aname->revision,
1017                                         dest_aname->name,
1018                                         vset->major, vset->minor, vset->build, vset->revision
1019                                         );
1020
1021                 return dest_aname;
1022         }
1023         
1024 #ifndef DISABLE_ASSEMBLY_REMAPPING
1025         first = 0;
1026         last = G_N_ELEMENTS (framework_assemblies) - 1;
1027         
1028         while (first <= last) {
1029                 int res;
1030                 pos = first + (last - first) / 2;
1031                 res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
1032                 if (res == 0) {
1033                         const AssemblyVersionSet* vset;
1034                         int index = framework_assemblies[pos].version_set_index;
1035                         g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1036                         vset = &current_runtime->version_sets [index];
1037
1038                         if (aname->major == vset->major && aname->minor == vset->minor &&
1039                                 aname->build == vset->build && aname->revision == vset->revision)
1040                                 return aname;
1041                 
1042                         if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
1043                                 return aname;
1044
1045                         if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1046                                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1047                                         "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1048                                                         aname->name,
1049                                                         aname->major, aname->minor, aname->build, aname->revision,
1050                                                         vset->major, vset->minor, vset->build, vset->revision
1051                                                         );
1052                         
1053                         memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1054                         dest_aname->major = vset->major;
1055                         dest_aname->minor = vset->minor;
1056                         dest_aname->build = vset->build;
1057                         dest_aname->revision = vset->revision;
1058                         if (framework_assemblies[pos].new_assembly_name != NULL) {
1059                                 dest_aname->name = framework_assemblies[pos].new_assembly_name;
1060                                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1061                                                         "The assembly name %s was remapped to %s",
1062                                                         aname->name,
1063                                                         dest_aname->name);
1064                         }
1065                         return dest_aname;
1066                 } else if (res < 0) {
1067                         last = pos - 1;
1068                 } else {
1069                         first = pos + 1;
1070                 }
1071         }
1072 #endif
1073
1074         return aname;
1075 }
1076
1077 /**
1078  * mono_assembly_get_assemblyref:
1079  * @image: pointer to the MonoImage to extract the information from.
1080  * @index: index to the assembly reference in the image.
1081  * @aname: pointer to a `MonoAssemblyName` that will hold the returned value.
1082  *
1083  * Fills out the @aname with the assembly name of the @index assembly reference in @image.
1084  */
1085 void
1086 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1087 {
1088         MonoTableInfo *t;
1089         guint32 cols [MONO_ASSEMBLYREF_SIZE];
1090         const char *hash;
1091
1092         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1093
1094         mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1095                 
1096         hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1097         aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1098         aname->hash_value = hash;
1099         aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1100         aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1101         aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1102         aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1103         aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1104         aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1105         aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1106
1107         if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1108                 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1109                 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1110                 g_free (token);
1111         } else {
1112                 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1113         }
1114 }
1115
1116 void
1117 mono_assembly_load_reference (MonoImage *image, int index)
1118 {
1119         MonoAssembly *reference;
1120         MonoAssemblyName aname;
1121         MonoImageOpenStatus status;
1122
1123         /*
1124          * image->references is shared between threads, so we need to access
1125          * it inside a critical section.
1126          */
1127         mono_assemblies_lock ();
1128         if (!image->references) {
1129                 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1130         
1131                 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1132                 image->nreferences = t->rows;
1133         }
1134         reference = image->references [index];
1135         mono_assemblies_unlock ();
1136         if (reference)
1137                 return;
1138
1139         mono_assembly_get_assemblyref (image, index, &aname);
1140
1141         if (image->assembly && image->assembly->ref_only) {
1142                 /* We use the loaded corlib */
1143                 if (!strcmp (aname.name, "mscorlib"))
1144                         reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1145                 else {
1146                         reference = mono_assembly_loaded_full (&aname, TRUE);
1147                         if (!reference)
1148                                 /* Try a postload search hook */
1149                                 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1150                 }
1151
1152                 /*
1153                  * Here we must advice that the error was due to
1154                  * a non loaded reference using the ReflectionOnly api
1155                 */
1156                 if (!reference)
1157                         reference = (MonoAssembly *)REFERENCE_MISSING;
1158         } else {
1159                 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1160                  * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1161                  * accordingly, it would fail on the MS runtime before).
1162                  * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1163                  * example bug-349190.2.cs and who knows how much more code in the wild.
1164                  */
1165                 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1166                 if (!reference && image->assembly)
1167                         reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1168         }
1169
1170         if (reference == NULL){
1171                 char *extra_msg;
1172
1173                 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1174                         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 : "" );
1175                 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1176                         extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1177                 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1178                         extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1179                 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1180                         extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1181                 } else {
1182                         extra_msg = g_strdup ("");
1183                 }
1184                 
1185                 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1186                                    "     Assembly:   %s    (assemblyref_index=%d)\n"
1187                                    "     Version:    %d.%d.%d.%d\n"
1188                                    "     Public Key: %s\n%s",
1189                                    image->name, aname.name, index,
1190                                    aname.major, aname.minor, aname.build, aname.revision,
1191                                    strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1192                 g_free (extra_msg);
1193         }
1194
1195         mono_assemblies_lock ();
1196         if (reference == NULL) {
1197                 /* Flag as not found */
1198                 reference = (MonoAssembly *)REFERENCE_MISSING;
1199         }       
1200
1201         if (!image->references [index]) {
1202                 if (reference != REFERENCE_MISSING){
1203                         mono_assembly_addref (reference);
1204                         if (image->assembly)
1205                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1206                                     image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1207                 } else {
1208                         if (image->assembly)
1209                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
1210                                     image->assembly->aname.name, image->assembly);
1211                 }
1212                 
1213                 image->references [index] = reference;
1214         }
1215         mono_assemblies_unlock ();
1216
1217         if (image->references [index] != reference) {
1218                 /* Somebody loaded it before us */
1219                 mono_assembly_close (reference);
1220         }
1221 }
1222
1223 /**
1224  * mono_assembly_load_references:
1225  * @image: 
1226  * @status:
1227  * @deprecated: There is no reason to use this method anymore, it does nothing
1228  *
1229  * This method is now a no-op, it does nothing other than setting the @status to #MONO_IMAGE_OK
1230  */
1231 void
1232 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1233 {
1234         /* This is a no-op now but it is part of the embedding API so we can't remove it */
1235         *status = MONO_IMAGE_OK;
1236 }
1237
1238 typedef struct AssemblyLoadHook AssemblyLoadHook;
1239 struct AssemblyLoadHook {
1240         AssemblyLoadHook *next;
1241         MonoAssemblyLoadFunc func;
1242         gpointer user_data;
1243 };
1244
1245 AssemblyLoadHook *assembly_load_hook = NULL;
1246
1247 void
1248 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1249 {
1250         AssemblyLoadHook *hook;
1251
1252         for (hook = assembly_load_hook; hook; hook = hook->next) {
1253                 hook->func (ass, hook->user_data);
1254         }
1255 }
1256
1257 void
1258 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1259 {
1260         AssemblyLoadHook *hook;
1261         
1262         g_return_if_fail (func != NULL);
1263
1264         hook = g_new0 (AssemblyLoadHook, 1);
1265         hook->func = func;
1266         hook->user_data = user_data;
1267         hook->next = assembly_load_hook;
1268         assembly_load_hook = hook;
1269 }
1270
1271 static void
1272 free_assembly_load_hooks (void)
1273 {
1274         AssemblyLoadHook *hook, *next;
1275
1276         for (hook = assembly_load_hook; hook; hook = next) {
1277                 next = hook->next;
1278                 g_free (hook);
1279         }
1280 }
1281
1282 typedef struct AssemblySearchHook AssemblySearchHook;
1283 struct AssemblySearchHook {
1284         AssemblySearchHook *next;
1285         MonoAssemblySearchFunc func;
1286         gboolean refonly;
1287         gboolean postload;
1288         gpointer user_data;
1289 };
1290
1291 AssemblySearchHook *assembly_search_hook = NULL;
1292
1293 static MonoAssembly*
1294 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1295 {
1296         AssemblySearchHook *hook;
1297
1298         for (hook = assembly_search_hook; hook; hook = hook->next) {
1299                 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1300                         MonoAssembly *ass;
1301                         /**
1302                           * A little explanation is in order here.
1303                           *
1304                           * The default postload search hook needs to know the requesting assembly to report it to managed code.
1305                           * The embedding API exposes a search hook that doesn't take such argument.
1306                           *
1307                           * The original fix would call the default search hook before all the registered ones and pass
1308                           * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1309                           * rely on. Which is the ordering between user hooks and the default runtime hook.
1310                           *
1311                           * Registering the hook after mono_jit_init would let your hook run before the default one and
1312                           * when using it to handle non standard app layouts this could save your app from a massive amount
1313                           * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1314                           * are all using this trick and if we broke this assumption they would be very disapointed at us.
1315                           *
1316                           * So what's the fix? We register the default hook using regular means and special case it when iterating
1317                           * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1318                           * assembly.
1319                           */
1320                         if (hook->func == (void*)mono_domain_assembly_postload_search)
1321                                 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1322                         else
1323                                 ass = hook->func (aname, hook->user_data);
1324                         if (ass)
1325                                 return ass;
1326                 }
1327         }
1328
1329         return NULL;
1330 }
1331
1332 MonoAssembly*
1333 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1334 {
1335         return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1336 }
1337
1338 static void
1339 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1340 {
1341         AssemblySearchHook *hook;
1342         
1343         g_return_if_fail (func != NULL);
1344
1345         hook = g_new0 (AssemblySearchHook, 1);
1346         hook->func = func;
1347         hook->user_data = user_data;
1348         hook->refonly = refonly;
1349         hook->postload = postload;
1350         hook->next = assembly_search_hook;
1351         assembly_search_hook = hook;
1352 }
1353
1354 void          
1355 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1356 {
1357         mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1358 }       
1359
1360 static void
1361 free_assembly_search_hooks (void)
1362 {
1363         AssemblySearchHook *hook, *next;
1364
1365         for (hook = assembly_search_hook; hook; hook = next) {
1366                 next = hook->next;
1367                 g_free (hook);
1368         }
1369 }
1370
1371 void
1372 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1373 {
1374         mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1375 }
1376
1377 void          
1378 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1379 {
1380         mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1381 }       
1382
1383 void
1384 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1385 {
1386         mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1387 }
1388
1389 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1390 struct AssemblyPreLoadHook {
1391         AssemblyPreLoadHook *next;
1392         MonoAssemblyPreLoadFunc func;
1393         gpointer user_data;
1394 };
1395
1396 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1397 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1398
1399 static MonoAssembly *
1400 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1401 {
1402         AssemblyPreLoadHook *hook;
1403         MonoAssembly *assembly;
1404
1405         for (hook = assembly_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 static MonoAssembly *
1415 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1416 {
1417         AssemblyPreLoadHook *hook;
1418         MonoAssembly *assembly;
1419
1420         for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1421                 assembly = hook->func (aname, assemblies_path, hook->user_data);
1422                 if (assembly != NULL)
1423                         return assembly;
1424         }
1425
1426         return NULL;
1427 }
1428
1429 void
1430 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1431 {
1432         AssemblyPreLoadHook *hook;
1433         
1434         g_return_if_fail (func != NULL);
1435
1436         hook = g_new0 (AssemblyPreLoadHook, 1);
1437         hook->func = func;
1438         hook->user_data = user_data;
1439         hook->next = assembly_preload_hook;
1440         assembly_preload_hook = hook;
1441 }
1442
1443 void
1444 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1445 {
1446         AssemblyPreLoadHook *hook;
1447         
1448         g_return_if_fail (func != NULL);
1449
1450         hook = g_new0 (AssemblyPreLoadHook, 1);
1451         hook->func = func;
1452         hook->user_data = user_data;
1453         hook->next = assembly_refonly_preload_hook;
1454         assembly_refonly_preload_hook = hook;
1455 }
1456
1457 static void
1458 free_assembly_preload_hooks (void)
1459 {
1460         AssemblyPreLoadHook *hook, *next;
1461
1462         for (hook = assembly_preload_hook; hook; hook = next) {
1463                 next = hook->next;
1464                 g_free (hook);
1465         }
1466
1467         for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1468                 next = hook->next;
1469                 g_free (hook);
1470         }
1471 }
1472
1473 static gchar *
1474 absolute_dir (const gchar *filename)
1475 {
1476         gchar *cwd;
1477         gchar *mixed;
1478         gchar **parts;
1479         gchar *part;
1480         GList *list, *tmp;
1481         GString *result;
1482         gchar *res;
1483         gint i;
1484
1485         if (g_path_is_absolute (filename)) {
1486                 part = g_path_get_dirname (filename);
1487                 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1488                 g_free (part);
1489                 return res;
1490         }
1491
1492         cwd = g_get_current_dir ();
1493         mixed = g_build_filename (cwd, filename, NULL);
1494         parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1495         g_free (mixed);
1496         g_free (cwd);
1497
1498         list = NULL;
1499         for (i = 0; (part = parts [i]) != NULL; i++) {
1500                 if (!strcmp (part, "."))
1501                         continue;
1502
1503                 if (!strcmp (part, "..")) {
1504                         if (list && list->next) /* Don't remove root */
1505                                 list = g_list_delete_link (list, list);
1506                 } else {
1507                         list = g_list_prepend (list, part);
1508                 }
1509         }
1510
1511         result = g_string_new ("");
1512         list = g_list_reverse (list);
1513
1514         /* Ignores last data pointer, which should be the filename */
1515         for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1516                 if (tmp->data)
1517                         g_string_append_printf (result, "%s%c", (char *) tmp->data,
1518                                                                 G_DIR_SEPARATOR);
1519         }
1520
1521         res = result->str;
1522         g_string_free (result, FALSE);
1523         g_list_free (list);
1524         g_strfreev (parts);
1525         if (*res == '\0') {
1526                 g_free (res);
1527                 return g_strdup (".");
1528         }
1529
1530         return res;
1531 }
1532
1533 /** 
1534  * mono_assembly_open_from_bundle:
1535  * @filename: Filename requested
1536  * @status: return status code
1537  *
1538  * This routine tries to open the assembly specified by `filename' from the
1539  * defined bundles, if found, returns the MonoImage for it, if not found
1540  * returns NULL
1541  */
1542 MonoImage *
1543 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1544 {
1545         int i;
1546         char *name;
1547         MonoImage *image = NULL;
1548
1549         /*
1550          * we do a very simple search for bundled assemblies: it's not a general 
1551          * purpose assembly loading mechanism.
1552          */
1553
1554         if (!bundles)
1555                 return NULL;
1556
1557         name = g_path_get_basename (filename);
1558
1559         mono_assemblies_lock ();
1560         for (i = 0; !image && bundles [i]; ++i) {
1561                 if (strcmp (bundles [i]->name, name) == 0) {
1562                         image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1563                         break;
1564                 }
1565         }
1566         mono_assemblies_unlock ();
1567         if (image) {
1568                 mono_image_addref (image);
1569                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
1570                 g_free (name);
1571                 return image;
1572         }
1573         g_free (name);
1574         return NULL;
1575 }
1576
1577 /**
1578  * mono_assemblies_open_full:
1579  * @filename: the file to load
1580  * @status: return status code 
1581  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1582
1583  * This loads an assembly from the specified @filename.   The @filename allows
1584  * a local URL (starting with a file:// prefix).  If a file prefix is used, the
1585  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
1586  * is treated as a local path.
1587  *
1588  * First, an attempt is made to load the assembly from the bundled executable (for those
1589  * deployments that have been done with the `mkbundle` tool or for scenarios where the
1590  * assembly has been registered as an embedded assembly).   If this is not the case, then
1591  * the assembly is loaded from disk using `api:mono_image_open_full`.
1592  *
1593  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1594  * the assembly is made.
1595  *
1596  * If @refonly is set to true, then the assembly is loaded purely for inspection with
1597  * the `System.Reflection` API.
1598  *
1599  * Returns: NULL on error, with the @status set to an error code, or a pointer
1600  * to the assembly.
1601  */
1602 MonoAssembly *
1603 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1604 {
1605         MonoImage *image;
1606         MonoAssembly *ass;
1607         MonoImageOpenStatus def_status;
1608         gchar *fname;
1609         gchar *new_fname;
1610         gboolean loaded_from_bundle;
1611         
1612         g_return_val_if_fail (filename != NULL, NULL);
1613
1614         if (!status)
1615                 status = &def_status;
1616         *status = MONO_IMAGE_OK;
1617
1618         if (strncmp (filename, "file://", 7) == 0) {
1619                 GError *error = NULL;
1620                 gchar *uri = (gchar *) filename;
1621                 gchar *tmpuri;
1622
1623                 /*
1624                  * MS allows file://c:/... and fails on file://localhost/c:/... 
1625                  * They also throw an IndexOutOfRangeException if "file://"
1626                  */
1627                 if (uri [7] != '/')
1628                         uri = g_strdup_printf ("file:///%s", uri + 7);
1629         
1630                 tmpuri = uri;
1631                 uri = mono_escape_uri_string (tmpuri);
1632                 fname = g_filename_from_uri (uri, NULL, &error);
1633                 g_free (uri);
1634
1635                 if (tmpuri != filename)
1636                         g_free (tmpuri);
1637
1638                 if (error != NULL) {
1639                         g_warning ("%s\n", error->message);
1640                         g_error_free (error);
1641                         fname = g_strdup (filename);
1642                 }
1643         } else {
1644                 fname = g_strdup (filename);
1645         }
1646
1647         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1648                         "Assembly Loader probing location: '%s'.", fname);
1649
1650         new_fname = NULL;
1651         if (!mono_assembly_is_in_gac (fname)) {
1652                 MonoError error;
1653                 new_fname = mono_make_shadow_copy (fname, &error);
1654                 if (!is_ok (&error)) {
1655                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1656                                     "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1657                         mono_error_cleanup (&error);
1658                         *status = MONO_IMAGE_IMAGE_INVALID;
1659                         g_free (fname);
1660                         return NULL;
1661                 }
1662         }
1663         if (new_fname && new_fname != fname) {
1664                 g_free (fname);
1665                 fname = new_fname;
1666                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1667                             "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1668         }
1669         
1670         image = NULL;
1671
1672         // If VM built with mkbundle
1673         loaded_from_bundle = FALSE;
1674         if (bundles != NULL) {
1675                 image = mono_assembly_open_from_bundle (fname, status, refonly);
1676                 loaded_from_bundle = image != NULL;
1677         }
1678
1679         if (!image)
1680                 image = mono_image_open_full (fname, status, refonly);
1681
1682         if (!image){
1683                 if (*status == MONO_IMAGE_OK)
1684                         *status = MONO_IMAGE_ERROR_ERRNO;
1685                 g_free (fname);
1686                 return NULL;
1687         }
1688
1689         if (image->assembly) {
1690                 /* Already loaded by another appdomain */
1691                 mono_assembly_invoke_load_hook (image->assembly);
1692                 mono_image_close (image);
1693                 g_free (fname);
1694                 return image->assembly;
1695         }
1696
1697         ass = mono_assembly_load_from_full (image, fname, status, refonly);
1698
1699         if (ass) {
1700                 if (!loaded_from_bundle)
1701                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1702                                 "Assembly Loader loaded assembly from location: '%s'.", filename);
1703                 if (!refonly)
1704                         mono_config_for_assembly (ass->image);
1705         }
1706
1707         /* Clear the reference added by mono_image_open */
1708         mono_image_close (image);
1709         
1710         g_free (fname);
1711
1712         return ass;
1713 }
1714
1715 static void
1716 free_item (gpointer val, gpointer user_data)
1717 {
1718         g_free (val);
1719 }
1720
1721 /**
1722  * mono_assembly_load_friends:
1723  * @ass: an assembly
1724  *
1725  * Load the list of friend assemblies that are allowed to access
1726  * the assembly's internal types and members. They are stored as assembly
1727  * names in custom attributes.
1728  *
1729  * This is an internal method, we need this because when we load mscorlib
1730  * we do not have the internals visible cattr loaded yet,
1731  * so we need to load these after we initialize the runtime. 
1732  *
1733  * LOCKING: Acquires the assemblies lock plus the loader lock.
1734  */
1735 void
1736 mono_assembly_load_friends (MonoAssembly* ass)
1737 {
1738         MonoError error;
1739         int i;
1740         MonoCustomAttrInfo* attrs;
1741         GSList *list;
1742
1743         if (ass->friend_assembly_names_inited)
1744                 return;
1745
1746         attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
1747         mono_error_assert_ok (&error);
1748         if (!attrs) {
1749                 mono_assemblies_lock ();
1750                 ass->friend_assembly_names_inited = TRUE;
1751                 mono_assemblies_unlock ();
1752                 return;
1753         }
1754
1755         mono_assemblies_lock ();
1756         if (ass->friend_assembly_names_inited) {
1757                 mono_assemblies_unlock ();
1758                 return;
1759         }
1760         mono_assemblies_unlock ();
1761
1762         list = NULL;
1763         /* 
1764          * We build the list outside the assemblies lock, the worse that can happen
1765          * is that we'll need to free the allocated list.
1766          */
1767         for (i = 0; i < attrs->num_attrs; ++i) {
1768                 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1769                 MonoAssemblyName *aname;
1770                 const gchar *data;
1771                 /* Do some sanity checking */
1772                 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
1773                         continue;
1774                 if (attr->data_size < 4)
1775                         continue;
1776                 data = (const char*)attr->data;
1777                 /* 0xFF means null string, see custom attr format */
1778                 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
1779                         continue;
1780                 mono_metadata_decode_value (data + 2, &data);
1781                 aname = g_new0 (MonoAssemblyName, 1);
1782                 /*g_print ("friend ass: %s\n", data);*/
1783                 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
1784                         list = g_slist_prepend (list, aname);
1785                 } else {
1786                         g_free (aname);
1787                 }
1788         }
1789         mono_custom_attrs_free (attrs);
1790
1791         mono_assemblies_lock ();
1792         if (ass->friend_assembly_names_inited) {
1793                 mono_assemblies_unlock ();
1794                 g_slist_foreach (list, free_item, NULL);
1795                 g_slist_free (list);
1796                 return;
1797         }
1798         ass->friend_assembly_names = list;
1799
1800         /* Because of the double checked locking pattern above */
1801         mono_memory_barrier ();
1802         ass->friend_assembly_names_inited = TRUE;
1803         mono_assemblies_unlock ();
1804 }
1805
1806 /**
1807  * mono_assembly_open:
1808  * @filename: Opens the assembly pointed out by this name
1809  * @status: return status code
1810  *
1811  * This loads an assembly from the specified @filename.   The @filename allows
1812  * a local URL (starting with a file:// prefix).  If a file prefix is used, the
1813  * filename is interpreted as a URL, and the filename is URL-decoded.   Otherwise the file
1814  * is treated as a local path.
1815  *
1816  * First, an attempt is made to load the assembly from the bundled executable (for those
1817  * deployments that have been done with the `mkbundle` tool or for scenarios where the
1818  * assembly has been registered as an embedded assembly).   If this is not the case, then
1819  * the assembly is loaded from disk using `api:mono_image_open_full`.
1820  *
1821  * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1822  * the assembly is made.
1823  *
1824  * Return: a pointer to the MonoAssembly if @filename contains a valid
1825  * assembly or NULL on error.  Details about the error are stored in the
1826  * @status variable.
1827  */
1828 MonoAssembly *
1829 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
1830 {
1831         return mono_assembly_open_full (filename, status, FALSE);
1832 }
1833
1834 /**
1835  * mono_assembly_load_from_full:
1836  * @image: Image to load the assembly from
1837  * @fname: assembly name to associate with the assembly
1838  * @status: returns the status condition
1839  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
1840  *
1841  * If the provided @image has an assembly reference, it will process the given
1842  * image as an assembly with the given name.
1843  *
1844  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1845  *
1846  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1847  * set to #MONO_IMAGE_OK;  or NULL on error.
1848  *
1849  * If there is an error loading the assembly the @status will indicate the
1850  * reason with @status being set to `MONO_IMAGE_INVALID` if the
1851  * image did not contain an assembly reference table.
1852  */
1853 MonoAssembly *
1854 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
1855                               MonoImageOpenStatus *status, gboolean refonly)
1856 {
1857         MonoAssembly *ass, *ass2;
1858         char *base_dir;
1859
1860         if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
1861                 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
1862                 *status = MONO_IMAGE_IMAGE_INVALID;
1863                 return NULL;
1864         }
1865
1866 #if defined (HOST_WIN32)
1867         {
1868                 gchar *tmp_fn;
1869                 int i;
1870
1871                 tmp_fn = g_strdup (fname);
1872                 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
1873                         if (tmp_fn [i] == '/')
1874                                 tmp_fn [i] = '\\';
1875                 }
1876
1877                 base_dir = absolute_dir (tmp_fn);
1878                 g_free (tmp_fn);
1879         }
1880 #else
1881         base_dir = absolute_dir (fname);
1882 #endif
1883
1884         /*
1885          * Create assembly struct, and enter it into the assembly cache
1886          */
1887         ass = g_new0 (MonoAssembly, 1);
1888         ass->basedir = base_dir;
1889         ass->ref_only = refonly;
1890         ass->image = image;
1891
1892         mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
1893
1894         mono_assembly_fill_assembly_name (image, &ass->aname);
1895
1896         if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
1897                 // MS.NET doesn't support loading other mscorlibs
1898                 g_free (ass);
1899                 g_free (base_dir);
1900                 mono_image_addref (mono_defaults.corlib);
1901                 *status = MONO_IMAGE_OK;
1902                 return mono_defaults.corlib->assembly;
1903         }
1904
1905         /* Add a non-temporary reference because of ass->image */
1906         mono_image_addref (image);
1907
1908         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);
1909
1910         /* 
1911          * The load hooks might take locks so we can't call them while holding the
1912          * assemblies lock.
1913          */
1914         if (ass->aname.name) {
1915                 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
1916                 if (ass2) {
1917                         g_free (ass);
1918                         g_free (base_dir);
1919                         mono_image_close (image);
1920                         *status = MONO_IMAGE_OK;
1921                         return ass2;
1922                 }
1923         }
1924
1925         mono_assemblies_lock ();
1926
1927         if (image->assembly) {
1928                 /* 
1929                  * This means another thread has already loaded the assembly, but not yet
1930                  * called the load hooks so the search hook can't find the assembly.
1931                  */
1932                 mono_assemblies_unlock ();
1933                 ass2 = image->assembly;
1934                 g_free (ass);
1935                 g_free (base_dir);
1936                 mono_image_close (image);
1937                 *status = MONO_IMAGE_OK;
1938                 return ass2;
1939         }
1940
1941         image->assembly = ass;
1942
1943         loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
1944         mono_assemblies_unlock ();
1945
1946 #ifdef HOST_WIN32
1947         if (image->is_module_handle)
1948                 mono_image_fixup_vtable (image);
1949 #endif
1950
1951         mono_assembly_invoke_load_hook (ass);
1952
1953         mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
1954         
1955         return ass;
1956 }
1957
1958 /**
1959  * mono_assembly_load_from:
1960  * @image: Image to load the assembly from
1961  * @fname: assembly name to associate with the assembly
1962  * @status: return status code
1963  *
1964  * If the provided @image has an assembly reference, it will process the given
1965  * image as an assembly with the given name.
1966  *
1967  * Most likely you want to use the `api:mono_assembly_load_full` method instead.
1968  *
1969  * This is equivalent to calling `api:mono_assembly_load_from_full` with the
1970  * @refonly parameter set to FALSE.
1971  * Returns: A valid pointer to a `MonoAssembly*` on success and the @status will be
1972  * set to #MONO_IMAGE_OK;  or NULL on error.
1973  *
1974  * If there is an error loading the assembly the @status will indicate the
1975  * reason with @status being set to `MONO_IMAGE_INVALID` if the
1976  * image did not contain an assembly reference table.
1977  
1978  */
1979 MonoAssembly *
1980 mono_assembly_load_from (MonoImage *image, const char *fname,
1981                          MonoImageOpenStatus *status)
1982 {
1983         return mono_assembly_load_from_full (image, fname, status, FALSE);
1984 }
1985
1986 /**
1987  * mono_assembly_name_free:
1988  * @aname: assembly name to free
1989  * 
1990  * Frees the provided assembly name object.
1991  * (it does not frees the object itself, only the name members).
1992  */
1993 void
1994 mono_assembly_name_free (MonoAssemblyName *aname)
1995 {
1996         if (aname == NULL)
1997                 return;
1998
1999         g_free ((void *) aname->name);
2000         g_free ((void *) aname->culture);
2001         g_free ((void *) aname->hash_value);
2002         g_free ((guint8*) aname->public_key);
2003 }
2004
2005 static gboolean
2006 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2007 {
2008         const gchar *pkey;
2009         gchar header [16], val, *arr;
2010         gint i, j, offset, bitlen, keylen, pkeylen;
2011         
2012         keylen = strlen (key) >> 1;
2013         if (keylen < 1)
2014                 return FALSE;
2015
2016         /* allow the ECMA standard key */
2017         if (strcmp (key, "00000000000000000400000000000000") == 0) {
2018                 if (pubkey) {
2019                         *pubkey = g_strdup (key);
2020                         *is_ecma = TRUE;
2021                 }
2022                 return TRUE;
2023         }
2024         *is_ecma = FALSE;
2025         val = g_ascii_xdigit_value (key [0]) << 4;
2026         val |= g_ascii_xdigit_value (key [1]);
2027         switch (val) {
2028                 case 0x00:
2029                         if (keylen < 13)
2030                                 return FALSE;
2031                         val = g_ascii_xdigit_value (key [24]);
2032                         val |= g_ascii_xdigit_value (key [25]);
2033                         if (val != 0x06)
2034                                 return FALSE;
2035                         pkey = key + 24;
2036                         break;
2037                 case 0x06:
2038                         pkey = key;
2039                         break;
2040                 default:
2041                         return FALSE;
2042         }
2043                 
2044         /* We need the first 16 bytes
2045         * to check whether this key is valid or not */
2046         pkeylen = strlen (pkey) >> 1;
2047         if (pkeylen < 16)
2048                 return FALSE;
2049                 
2050         for (i = 0, j = 0; i < 16; i++) {
2051                 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2052                 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2053         }
2054
2055         if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2056                         header [1] != 0x02 || /* Version (0x02) */
2057                         header [2] != 0x00 || /* Reserved (word) */
2058                         header [3] != 0x00 ||
2059                         (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2060                 return FALSE;
2061
2062         /* Based on this length, we _should_ be able to know if the length is right */
2063         bitlen = read32 (header + 12) >> 3;
2064         if ((bitlen + 16 + 4) != pkeylen)
2065                 return FALSE;
2066
2067         /* parsing is OK and the public key itself is not requested back */
2068         if (!pubkey)
2069                 return TRUE;
2070                 
2071         /* Encode the size of the blob */
2072         offset = 0;
2073         if (keylen <= 127) {
2074                 arr = (gchar *)g_malloc (keylen + 1);
2075                 arr [offset++] = keylen;
2076         } else {
2077                 arr = (gchar *)g_malloc (keylen + 2);
2078                 arr [offset++] = 0x80; /* 10bs */
2079                 arr [offset++] = keylen;
2080         }
2081                 
2082         for (i = offset, j = 0; i < keylen + offset; i++) {
2083                 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2084                 arr [i] |= g_ascii_xdigit_value (key [j++]);
2085         }
2086
2087         *pubkey = arr;
2088
2089         return TRUE;
2090 }
2091
2092 static gboolean
2093 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)
2094 {
2095         gint major, minor, build, revision;
2096         gint len;
2097         gint version_parts;
2098         gchar *pkey, *pkeyptr, *encoded, tok [8];
2099
2100         memset (aname, 0, sizeof (MonoAssemblyName));
2101
2102         if (version) {
2103                 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2104                 if (version_parts < 2 || version_parts > 4)
2105                         return FALSE;
2106
2107                 /* FIXME: we should set build & revision to -1 (instead of 0)
2108                 if these are not set in the version string. That way, later on,
2109                 we can still determine if these were specified. */
2110                 aname->major = major;
2111                 aname->minor = minor;
2112                 if (version_parts >= 3)
2113                         aname->build = build;
2114                 else
2115                         aname->build = 0;
2116                 if (version_parts == 4)
2117                         aname->revision = revision;
2118                 else
2119                         aname->revision = 0;
2120         }
2121         
2122         aname->flags = flags;
2123         aname->arch = arch;
2124         aname->name = g_strdup (name);
2125         
2126         if (culture) {
2127                 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2128                         aname->culture = g_strdup ("");
2129                 else
2130                         aname->culture = g_strdup (culture);
2131         }
2132         
2133         if (token && strncmp (token, "null", 4) != 0) {
2134                 char *lower;
2135
2136                 /* the constant includes the ending NULL, hence the -1 */
2137                 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2138                         mono_assembly_name_free (aname);
2139                         return FALSE;
2140                 }
2141                 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2142                 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2143                 g_free (lower);
2144         }
2145
2146         if (key) {
2147                 gboolean is_ecma;
2148                 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2149                         mono_assembly_name_free (aname);
2150                         return FALSE;
2151                 }
2152
2153                 if (is_ecma) {
2154                         if (save_public_key)
2155                                 aname->public_key = (guint8*)pkey;
2156                         else
2157                                 g_free (pkey);
2158                         g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2159                         return TRUE;
2160                 }
2161                 
2162                 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2163                 // We also need to generate the key token
2164                 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2165                 encoded = encode_public_tok ((guchar*) tok, 8);
2166                 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2167                 g_free (encoded);
2168
2169                 if (save_public_key)
2170                         aname->public_key = (guint8*) pkey;
2171                 else
2172                         g_free (pkey);
2173         }
2174
2175         return TRUE;
2176 }
2177
2178 static gboolean
2179 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2180 {
2181         gchar **parts;
2182         gboolean res;
2183         
2184         parts = g_strsplit (dirname, "_", 3);
2185         if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2186                 g_strfreev (parts);
2187                 return FALSE;
2188         }
2189         
2190         res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2191         g_strfreev (parts);
2192         return res;
2193 }
2194
2195 static gboolean
2196 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2197 {
2198         char *eqsign = strchr (pair, '=');
2199         if (!eqsign) {
2200                 *key = NULL;
2201                 *keylen = 0;
2202                 *value = NULL;
2203                 return FALSE;
2204         }
2205
2206         *key = (gchar*)pair;
2207         *keylen = eqsign - *key;
2208         while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2209                 (*keylen)--;
2210         *value = g_strstrip (eqsign + 1);
2211         return TRUE;
2212 }
2213
2214 gboolean
2215 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2216 {
2217         gchar *dllname;
2218         gchar *dllname_uq;
2219         gchar *version = NULL;
2220         gchar *version_uq;
2221         gchar *culture = NULL;
2222         gchar *culture_uq;
2223         gchar *token = NULL;
2224         gchar *token_uq;
2225         gchar *key = NULL;
2226         gchar *key_uq;
2227         gchar *retargetable = NULL;
2228         gchar *retargetable_uq;
2229         gchar *procarch;
2230         gchar *procarch_uq;
2231         gboolean res;
2232         gchar *value, *part_name;
2233         guint32 part_name_len;
2234         gchar **parts;
2235         gchar **tmp;
2236         gboolean version_defined;
2237         gboolean token_defined;
2238         guint32 flags = 0;
2239         guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2240
2241         if (!is_version_defined)
2242                 is_version_defined = &version_defined;
2243         *is_version_defined = FALSE;
2244         if (!is_token_defined)
2245                 is_token_defined = &token_defined;
2246         *is_token_defined = FALSE;
2247         
2248         parts = tmp = g_strsplit (name, ",", 6);
2249         if (!tmp || !*tmp) {
2250                 g_strfreev (tmp);
2251                 return FALSE;
2252         }
2253
2254         dllname = g_strstrip (*tmp);
2255         
2256         tmp++;
2257
2258         while (*tmp) {
2259                 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2260                         goto cleanup_and_fail;
2261
2262                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2263                         *is_version_defined = TRUE;
2264                         version = value;
2265                         if (strlen (version) == 0) {
2266                                 goto cleanup_and_fail;
2267                         }
2268                         tmp++;
2269                         continue;
2270                 }
2271
2272                 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2273                         culture = value;
2274                         if (strlen (culture) == 0) {
2275                                 goto cleanup_and_fail;
2276                         }
2277                         tmp++;
2278                         continue;
2279                 }
2280
2281                 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2282                         *is_token_defined = TRUE;
2283                         token = value;
2284                         if (strlen (token) == 0) {
2285                                 goto cleanup_and_fail;
2286                         }
2287                         tmp++;
2288                         continue;
2289                 }
2290
2291                 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2292                         key = value;
2293                         if (strlen (key) == 0) {
2294                                 goto cleanup_and_fail;
2295                         }
2296                         tmp++;
2297                         continue;
2298                 }
2299
2300                 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2301                         retargetable = value;
2302                         retargetable_uq = unquote (retargetable);
2303                         if (retargetable_uq != NULL)
2304                                 retargetable = retargetable_uq;
2305
2306                         if (!g_ascii_strcasecmp (retargetable, "yes")) {
2307                                 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2308                         } else if (g_ascii_strcasecmp (retargetable, "no")) {
2309                                 free (retargetable_uq);
2310                                 goto cleanup_and_fail;
2311                         }
2312
2313                         free (retargetable_uq);
2314                         tmp++;
2315                         continue;
2316                 }
2317
2318                 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2319                         procarch = value;
2320                         procarch_uq = unquote (procarch);
2321                         if (procarch_uq != NULL)
2322                                 procarch = procarch_uq;
2323
2324                         if (!g_ascii_strcasecmp (procarch, "MSIL"))
2325                                 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2326                         else if (!g_ascii_strcasecmp (procarch, "X86"))
2327                                 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2328                         else if (!g_ascii_strcasecmp (procarch, "IA64"))
2329                                 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2330                         else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2331                                 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2332                         else {
2333                                 free (procarch_uq);
2334                                 goto cleanup_and_fail;
2335                         }
2336
2337                         free (procarch_uq);
2338                         tmp++;
2339                         continue;
2340                 }
2341
2342                 g_strfreev (parts);
2343                 return FALSE;
2344         }
2345
2346         /* if retargetable flag is set, then we must have a fully qualified name */
2347         if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2348                 goto cleanup_and_fail;
2349         }
2350
2351         dllname_uq = unquote (dllname);
2352         version_uq = unquote (version);
2353         culture_uq = unquote (culture);
2354         token_uq = unquote (token);
2355         key_uq = unquote (key);
2356
2357         res = build_assembly_name (
2358                 dllname_uq == NULL ? dllname : dllname_uq,
2359                 version_uq == NULL ? version : version_uq,
2360                 culture_uq == NULL ? culture : culture_uq,
2361                 token_uq == NULL ? token : token_uq,
2362                 key_uq == NULL ? key : key_uq,
2363                 flags, arch, aname, save_public_key);
2364
2365         free (dllname_uq);
2366         free (version_uq);
2367         free (culture_uq);
2368         free (token_uq);
2369         free (key_uq);
2370
2371         g_strfreev (parts);
2372         return res;
2373
2374 cleanup_and_fail:
2375         g_strfreev (parts);
2376         return FALSE;
2377 }
2378
2379 static char*
2380 unquote (const char *str)
2381 {
2382         gint slen;
2383         const char *end;
2384
2385         if (str == NULL)
2386                 return NULL;
2387
2388         slen = strlen (str);
2389         if (slen < 2)
2390                 return NULL;
2391
2392         if (*str != '\'' && *str != '\"')
2393                 return NULL;
2394
2395         end = str + slen - 1;
2396         if (*str != *end)
2397                 return NULL;
2398
2399         return g_strndup (str + 1, slen - 2);
2400 }
2401
2402 /**
2403  * mono_assembly_name_parse:
2404  * @name: name to parse
2405  * @aname: the destination assembly name
2406  * 
2407  * Parses an assembly qualified type name and assigns the name,
2408  * version, culture and token to the provided assembly name object.
2409  *
2410  * Returns: TRUE if the name could be parsed.
2411  */
2412 gboolean
2413 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2414 {
2415         return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2416 }
2417
2418 /**
2419  * mono_assembly_name_new:
2420  * @name: name to parse
2421  *
2422  * Allocate a new MonoAssemblyName and fill its values from the
2423  * passed @name.
2424  *
2425  * Returns: a newly allocated structure or NULL if there was any failure.
2426  */
2427 MonoAssemblyName*
2428 mono_assembly_name_new (const char *name)
2429 {
2430         MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2431         if (mono_assembly_name_parse (name, aname))
2432                 return aname;
2433         g_free (aname);
2434         return NULL;
2435 }
2436
2437 const char*
2438 mono_assembly_name_get_name (MonoAssemblyName *aname)
2439 {
2440         return aname->name;
2441 }
2442
2443 const char*
2444 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2445 {
2446         return aname->culture;
2447 }
2448
2449 mono_byte*
2450 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2451 {
2452         if (aname->public_key_token [0])
2453                 return aname->public_key_token;
2454         return NULL;
2455 }
2456
2457 uint16_t
2458 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2459 {
2460         if (minor)
2461                 *minor = aname->minor;
2462         if (build)
2463                 *build = aname->build;
2464         if (revision)
2465                 *revision = aname->revision;
2466         return aname->major;
2467 }
2468
2469 static MonoAssembly*
2470 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2471 {
2472         gchar *fullpath = NULL;
2473         GDir *dirhandle;
2474         const char* direntry;
2475         MonoAssemblyName gac_aname;
2476         gint major=-1, minor=0, build=0, revision=0;
2477         gboolean exact_version;
2478         
2479         dirhandle = g_dir_open (basepath, 0, NULL);
2480         if (!dirhandle)
2481                 return NULL;
2482                 
2483         exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2484
2485         while ((direntry = g_dir_read_name (dirhandle))) {
2486                 gboolean match = TRUE;
2487                 
2488                 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2489                         continue;
2490                 
2491                 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2492                         match = FALSE;
2493                         
2494                 if (match && strlen ((char*)aname->public_key_token) > 0 && 
2495                                 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2496                         match = FALSE;
2497                 
2498                 if (match) {
2499                         if (exact_version) {
2500                                 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2501                                                  aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
2502                         }
2503                         else if (gac_aname.major < major)
2504                                 match = FALSE;
2505                         else if (gac_aname.major == major) {
2506                                 if (gac_aname.minor < minor)
2507                                         match = FALSE;
2508                                 else if (gac_aname.minor == minor) {
2509                                         if (gac_aname.build < build)
2510                                                 match = FALSE;
2511                                         else if (gac_aname.build == build && gac_aname.revision <= revision)
2512                                                 match = FALSE; 
2513                                 }
2514                         }
2515                 }
2516                 
2517                 if (match) {
2518                         major = gac_aname.major;
2519                         minor = gac_aname.minor;
2520                         build = gac_aname.build;
2521                         revision = gac_aname.revision;
2522                         g_free (fullpath);
2523                         fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2524                 }
2525
2526                 mono_assembly_name_free (&gac_aname);
2527         }
2528         
2529         g_dir_close (dirhandle);
2530         
2531         if (fullpath == NULL)
2532                 return NULL;
2533         else {
2534                 MonoAssembly *res = mono_assembly_open (fullpath, status);
2535                 g_free (fullpath);
2536                 return res;
2537         }
2538 }
2539
2540 /**
2541  * mono_assembly_load_with_partial_name:
2542  * @name: an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2543  * @status: return status code
2544  *
2545  * Loads a Mono Assembly from a name.  The name is parsed using `api:mono_assembly_name_parse`,
2546  * so it might contain a qualified type name, version, culture and token.
2547  *
2548  * This will load the assembly from the file whose name is derived from the assembly name
2549  * by appending the .dll extension.
2550  *
2551  * The assembly is loaded from either one of the extra Global Assembly Caches specified
2552  * by the extra GAC paths (specified by the `MONO_GAC_PREFIX` environment variable) or
2553  * if that fails from the GAC.
2554  *
2555  * Returns: NULL on failure, or a pointer to a MonoAssembly on success.   
2556  */
2557 MonoAssembly*
2558 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2559 {
2560         MonoError error;
2561         MonoAssembly *res;
2562         MonoAssemblyName *aname, base_name;
2563         MonoAssemblyName mapped_aname;
2564         gchar *fullname, *gacpath;
2565         gchar **paths;
2566
2567         memset (&base_name, 0, sizeof (MonoAssemblyName));
2568         aname = &base_name;
2569
2570         if (!mono_assembly_name_parse (name, aname))
2571                 return NULL;
2572
2573         /* 
2574          * If no specific version has been requested, make sure we load the
2575          * correct version for system assemblies.
2576          */ 
2577         if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2578                 aname = mono_assembly_remap_version (aname, &mapped_aname);
2579         
2580         res = mono_assembly_loaded (aname);
2581         if (res) {
2582                 mono_assembly_name_free (aname);
2583                 return res;
2584         }
2585
2586         res = invoke_assembly_preload_hook (aname, assemblies_path);
2587         if (res) {
2588                 res->in_gac = FALSE;
2589                 mono_assembly_name_free (aname);
2590                 return res;
2591         }
2592
2593         fullname = g_strdup_printf ("%s.dll", aname->name);
2594
2595         if (extra_gac_paths) {
2596                 paths = extra_gac_paths;
2597                 while (!res && *paths) {
2598                         gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2599                         res = probe_for_partial_name (gacpath, fullname, aname, status);
2600                         g_free (gacpath);
2601                         paths++;
2602                 }
2603         }
2604
2605         if (res) {
2606                 res->in_gac = TRUE;
2607                 g_free (fullname);
2608                 mono_assembly_name_free (aname);
2609                 return res;
2610         }
2611
2612         gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2613         res = probe_for_partial_name (gacpath, fullname, aname, status);
2614         g_free (gacpath);
2615
2616         if (res)
2617                 res->in_gac = TRUE;
2618         else {
2619                 MonoDomain *domain = mono_domain_get ();
2620                 MonoReflectionAssembly *refasm;
2621
2622                 refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
2623                 if (!is_ok (&error)) {
2624                         g_free (fullname);
2625                         mono_assembly_name_free (aname);
2626                         mono_error_cleanup (&error);
2627                         if (*status == MONO_IMAGE_OK)
2628                                 *status = MONO_IMAGE_IMAGE_INVALID;
2629                 }
2630
2631                 if (refasm)
2632                         res = refasm->assembly;
2633         }
2634         
2635         g_free (fullname);
2636         mono_assembly_name_free (aname);
2637
2638         return res;
2639 }
2640
2641 static MonoBoolean
2642 mono_assembly_is_in_gac (const gchar *filename)
2643 {
2644         const gchar *rootdir;
2645         gchar *gp;
2646         gchar **paths;
2647
2648         if (filename == NULL)
2649                 return FALSE;
2650
2651         for (paths = extra_gac_paths; paths && *paths; paths++) {
2652                 if (strstr (*paths, filename) != *paths)
2653                         continue;
2654
2655                 gp = (gchar *) (filename + strlen (*paths));
2656                 if (*gp != G_DIR_SEPARATOR)
2657                         continue;
2658                 gp++;
2659                 if (strncmp (gp, "lib", 3))
2660                         continue;
2661                 gp += 3;
2662                 if (*gp != G_DIR_SEPARATOR)
2663                         continue;
2664                 gp++;
2665                 if (strncmp (gp, "mono", 4))
2666                         continue;
2667                 gp += 4;
2668                 if (*gp != G_DIR_SEPARATOR)
2669                         continue;
2670                 gp++;
2671                 if (strncmp (gp, "gac", 3))
2672                         continue;
2673                 gp += 3;
2674                 if (*gp != G_DIR_SEPARATOR)
2675                         continue;
2676
2677                 return TRUE;
2678         }
2679
2680         rootdir = mono_assembly_getrootdir ();
2681         if (strstr (filename, rootdir) != filename)
2682                 return FALSE;
2683
2684         gp = (gchar *) (filename + strlen (rootdir));
2685         if (*gp != G_DIR_SEPARATOR)
2686                 return FALSE;
2687         gp++;
2688         if (strncmp (gp, "mono", 4))
2689                 return FALSE;
2690         gp += 4;
2691         if (*gp != G_DIR_SEPARATOR)
2692                 return FALSE;
2693         gp++;
2694         if (strncmp (gp, "gac", 3))
2695                 return FALSE;
2696         gp += 3;
2697         if (*gp != G_DIR_SEPARATOR)
2698                 return FALSE;
2699         return TRUE;
2700 }
2701
2702 static MonoImage*
2703 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
2704 {
2705         MonoImage *image;
2706         gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
2707         gchar **paths;
2708         gint32 len;
2709
2710         if (strstr (aname->name, ".dll")) {
2711                 len = strlen (aname->name) - 4;
2712                 name = (gchar *)g_malloc (len + 1);
2713                 strncpy (name, aname->name, len);
2714                 name[len] = 0;
2715         } else
2716                 name = g_strdup (aname->name);
2717         
2718         if (aname->culture)
2719                 culture = g_utf8_strdown (aname->culture, -1);
2720         else
2721                 culture = g_strdup ("");
2722         
2723         pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
2724         version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
2725         g_free (name);
2726         g_free (culture);
2727         
2728         filename = g_strconcat (pname, ".dll", NULL);
2729         subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
2730         g_free (pname);
2731         g_free (version);
2732         g_free (filename);
2733
2734         image = NULL;
2735         if (extra_gac_paths) {
2736                 paths = extra_gac_paths;
2737                 while (!image && *paths) {
2738                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
2739                                         "lib", "mono", "gac", subpath, NULL);
2740                         image = mono_image_open (fullpath, NULL);
2741                         g_free (fullpath);
2742                         paths++;
2743                 }
2744         }
2745
2746         if (image) {
2747                 g_free (subpath);
2748                 return image;
2749         }
2750
2751         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), 
2752                         "mono", "gac", subpath, NULL);
2753         image = mono_image_open (fullpath, NULL);
2754         g_free (subpath);
2755         g_free (fullpath);
2756         
2757         return image;
2758 }
2759
2760 static MonoAssemblyName*
2761 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2762 {
2763         memcpy (dest_name, aname, sizeof (MonoAssemblyName));
2764         dest_name->major = info->new_version.major;
2765         dest_name->minor = info->new_version.minor;
2766         dest_name->build = info->new_version.build;
2767         dest_name->revision = info->new_version.revision;
2768         
2769         return dest_name;
2770 }
2771
2772 /* LOCKING: assembly_binding lock must be held */
2773 static MonoAssemblyBindingInfo*
2774 search_binding_loaded (MonoAssemblyName *aname)
2775 {
2776         GSList *tmp;
2777
2778         for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
2779                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
2780                 if (assembly_binding_maps_name (info, aname))
2781                         return info;
2782         }
2783
2784         return NULL;
2785 }
2786
2787 static inline gboolean
2788 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
2789 {
2790         if (left->major != right->major || left->minor != right->minor ||
2791             left->build != right->build || left->revision != right->revision)
2792                 return FALSE;
2793
2794         return TRUE;
2795 }
2796
2797 static inline gboolean
2798 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
2799 {
2800         if (left->has_old_version_bottom != right->has_old_version_bottom)
2801                 return FALSE;
2802
2803         if (left->has_old_version_top != right->has_old_version_top)
2804                 return FALSE;
2805
2806         if (left->has_new_version != right->has_new_version)
2807                 return FALSE;
2808
2809         if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
2810                 return FALSE;
2811
2812         if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
2813                 return FALSE;
2814
2815         if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
2816                 return FALSE;
2817
2818         return TRUE;
2819 }
2820
2821 /* LOCKING: assumes all the necessary locks are held */
2822 static void
2823 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
2824 {
2825         MonoAssemblyBindingInfo *info_copy;
2826         GSList *tmp;
2827         MonoAssemblyBindingInfo *info_tmp;
2828         MonoDomain *domain = (MonoDomain*)user_data;
2829
2830         if (!domain)
2831                 return;
2832
2833         for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
2834                 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
2835                 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
2836                         return;
2837         }
2838
2839         info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
2840         memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
2841         if (info->name)
2842                 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
2843         if (info->culture)
2844                 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
2845
2846         domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
2847 }
2848
2849 static int
2850 get_version_number (int major, int minor)
2851 {
2852         return major * 256 + minor;
2853 }
2854
2855 static inline gboolean
2856 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
2857 {
2858         int aname_version_number = get_version_number (aname->major, aname->minor);
2859         if (!info->has_old_version_bottom)
2860                 return FALSE;
2861
2862         if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
2863                 return FALSE;
2864
2865         if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
2866                 return FALSE;
2867
2868         /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
2869         info->major = aname->major;
2870         info->minor = aname->minor;
2871
2872         return TRUE;
2873 }
2874
2875 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
2876 static MonoAssemblyBindingInfo*
2877 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
2878 {
2879         MonoAssemblyBindingInfo *info;
2880         GSList *list;
2881
2882         if (!domain->assembly_bindings)
2883                 return NULL;
2884
2885         info = NULL;
2886         for (list = domain->assembly_bindings; list; list = list->next) {
2887                 info = (MonoAssemblyBindingInfo *)list->data;
2888                 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
2889                         break;
2890                 info = NULL;
2891         }
2892
2893         if (info) {
2894                 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
2895                     info->has_new_version && assembly_binding_maps_name (info, aname))
2896                         info->is_valid = TRUE;
2897                 else
2898                         info->is_valid = FALSE;
2899         }
2900
2901         return info;
2902 }
2903
2904 static MonoAssemblyName*
2905 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
2906 {
2907         MonoError error;
2908         MonoAssemblyBindingInfo *info, *info2;
2909         MonoImage *ppimage;
2910         MonoDomain *domain;
2911
2912         if (aname->public_key_token [0] == 0)
2913                 return aname;
2914
2915         domain = mono_domain_get ();
2916
2917         mono_assembly_binding_lock ();
2918         info = search_binding_loaded (aname);
2919         mono_assembly_binding_unlock ();
2920
2921         if (!info) {
2922                 mono_domain_lock (domain);
2923                 info = get_per_domain_assembly_binding_info (domain, aname);
2924                 mono_domain_unlock (domain);
2925         }
2926
2927         if (info) {
2928                 if (!check_policy_versions (info, aname))
2929                         return aname;
2930                 
2931                 mono_assembly_bind_version (info, aname, dest_name);
2932                 return dest_name;
2933         }
2934
2935         if (domain && domain->setup && domain->setup->configuration_file) {
2936                 mono_domain_lock (domain);
2937                 if (!domain->assembly_bindings_parsed) {
2938                         gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
2939                         /* expect this to succeed because mono_domain_set_options_from_config () did
2940                          * the same thing when the domain was created. */
2941                         mono_error_assert_ok (&error);
2942
2943                         gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
2944
2945                         if (!domain_config_file_path)
2946                                 domain_config_file_path = domain_config_file_name;
2947                         
2948                         mono_config_parse_assembly_bindings (domain_config_file_path, aname->major, aname->minor, domain, assembly_binding_info_parsed);
2949                         domain->assembly_bindings_parsed = TRUE;
2950                         if (domain_config_file_name != domain_config_file_path)
2951                                 g_free (domain_config_file_name);
2952                         g_free (domain_config_file_path);
2953                 }
2954
2955                 info2 = get_per_domain_assembly_binding_info (domain, aname);
2956
2957                 if (info2) {
2958                         info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
2959                         info->name = g_strdup (info2->name);
2960                         info->culture = g_strdup (info2->culture);
2961                         info->domain_id = domain->domain_id;
2962                 }
2963
2964                 mono_domain_unlock (domain);
2965         }
2966
2967         if (!info) {
2968                 info = g_new0 (MonoAssemblyBindingInfo, 1);
2969                 info->major = aname->major;
2970                 info->minor = aname->minor;
2971         }
2972
2973         if (!info->is_valid) {
2974                 ppimage = mono_assembly_load_publisher_policy (aname);
2975                 if (ppimage) {
2976                         get_publisher_policy_info (ppimage, aname, info);
2977                         mono_image_close (ppimage);
2978                 }
2979         }
2980
2981         /* Define default error value if needed */
2982         if (!info->is_valid) {
2983                 info->name = g_strdup (aname->name);
2984                 info->culture = g_strdup (aname->culture);
2985                 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2986         }
2987         
2988         mono_assembly_binding_lock ();
2989         info2 = search_binding_loaded (aname);
2990         if (info2) {
2991                 /* This binding was added by another thread 
2992                  * before us */
2993                 mono_assembly_binding_info_free (info);
2994                 g_free (info);
2995                 
2996                 info = info2;
2997         } else
2998                 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
2999                 
3000         mono_assembly_binding_unlock ();
3001         
3002         if (!info->is_valid || !check_policy_versions (info, aname))
3003                 return aname;
3004
3005         mono_assembly_bind_version (info, aname, dest_name);
3006         return dest_name;
3007 }
3008
3009 /**
3010  * mono_assembly_load_from_gac
3011  *
3012  * @aname: The assembly name object
3013  */
3014 static MonoAssembly*
3015 mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3016 {
3017         MonoAssembly *result = NULL;
3018         gchar *name, *version, *culture, *fullpath, *subpath;
3019         gint32 len;
3020         gchar **paths;
3021         char *pubtok;
3022
3023         if (aname->public_key_token [0] == 0) {
3024                 return NULL;
3025         }
3026
3027         if (strstr (aname->name, ".dll")) {
3028                 len = strlen (filename) - 4;
3029                 name = (gchar *)g_malloc (len + 1);
3030                 strncpy (name, aname->name, len);
3031                 name[len] = 0;
3032         } else {
3033                 name = g_strdup (aname->name);
3034         }
3035
3036         if (aname->culture) {
3037                 culture = g_utf8_strdown (aname->culture, -1);
3038         } else {
3039                 culture = g_strdup ("");
3040         }
3041
3042         pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3043         version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3044                         aname->minor, aname->build, aname->revision,
3045                         culture, pubtok);
3046         g_free (pubtok);
3047         
3048         subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3049         g_free (name);
3050         g_free (version);
3051         g_free (culture);
3052
3053         if (extra_gac_paths) {
3054                 paths = extra_gac_paths;
3055                 while (!result && *paths) {
3056                         fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3057                         result = mono_assembly_open_full (fullpath, status, refonly);
3058                         g_free (fullpath);
3059                         paths++;
3060                 }
3061         }
3062
3063         if (result) {
3064                 result->in_gac = TRUE;
3065                 g_free (subpath);
3066                 return result;
3067         }
3068
3069         fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3070                         "mono", "gac", subpath, NULL);
3071         result = mono_assembly_open_full (fullpath, status, refonly);
3072         g_free (fullpath);
3073
3074         if (result)
3075                 result->in_gac = TRUE;
3076         
3077         g_free (subpath);
3078
3079         return result;
3080 }
3081
3082 MonoAssembly*
3083 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3084 {
3085         char *corlib_file;
3086         MonoAssemblyName *aname;
3087
3088         if (corlib) {
3089                 /* g_print ("corlib already loaded\n"); */
3090                 return corlib;
3091         }
3092
3093         // In native client, Corlib is embedded in the executable as static variable corlibData
3094 #if defined(__native_client__)
3095         if (corlibData != NULL && corlibSize != 0) {
3096                 int status = 0;
3097                 /* First "FALSE" instructs mono not to make a copy. */
3098                 /* Second "FALSE" says this is not just a ref.      */
3099                 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3100                 if (image == NULL || status != 0)
3101                         g_print("mono_image_open_from_data_full failed: %d\n", status);
3102                 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3103                 if (corlib == NULL || status != 0)
3104                         g_print ("mono_assembly_load_from_full failed: %d\n", status);
3105                 if (corlib)
3106                         return corlib;
3107         }
3108 #endif
3109
3110         // A nonstandard preload hook may provide a special mscorlib assembly
3111         aname = mono_assembly_name_new ("mscorlib.dll");
3112         corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3113         mono_assembly_name_free (aname);
3114         g_free (aname);
3115         if (corlib != NULL)
3116                 goto return_corlib_and_facades;
3117
3118         // This unusual directory layout can occur if mono is being built and run out of its own source repo
3119         if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3120                 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
3121                 if (corlib)
3122                         goto return_corlib_and_facades;
3123         }
3124
3125         /* Normal case: Load corlib from mono/<version> */
3126         corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3127         if (assemblies_path) { // Custom assemblies path
3128                 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
3129                 if (corlib) {
3130                         g_free (corlib_file);
3131                         goto return_corlib_and_facades;
3132                 }
3133         }
3134         corlib = load_in_path (corlib_file, default_path, status, FALSE);
3135         g_free (corlib_file);
3136
3137 return_corlib_and_facades:
3138         if (corlib && !strcmp (runtime->framework_version, "4.5"))  // FIXME: stop hardcoding 4.5 here
3139                 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3140                 
3141         return corlib;
3142 }
3143
3144 MonoAssembly*
3145 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
3146                                                                   const char       *basedir, 
3147                                                                   MonoImageOpenStatus *status,
3148                                                                   gboolean refonly)
3149 {
3150         MonoAssembly *result;
3151         char *fullpath, *filename;
3152         MonoAssemblyName maped_aname;
3153         MonoAssemblyName maped_name_pp;
3154         int ext_index;
3155         const char *ext;
3156         int len;
3157
3158         aname = mono_assembly_remap_version (aname, &maped_aname);
3159         
3160         /* Reflection only assemblies don't get assembly binding */
3161         if (!refonly)
3162                 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3163         
3164         result = mono_assembly_loaded_full (aname, refonly);
3165         if (result)
3166                 return result;
3167
3168         result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3169         if (result) {
3170                 result->in_gac = FALSE;
3171                 return result;
3172         }
3173
3174         /* Currently we retrieve the loaded corlib for reflection 
3175          * only requests, like a common reflection only assembly 
3176          */
3177         if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3178                 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3179         }
3180
3181         len = strlen (aname->name);
3182         for (ext_index = 0; ext_index < 2; ext_index ++) {
3183                 ext = ext_index == 0 ? ".dll" : ".exe";
3184                 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3185                         filename = g_strdup (aname->name);
3186                         /* Don't try appending .dll/.exe if it already has one of those extensions */
3187                         ext_index++;
3188                 } else {
3189                         filename = g_strconcat (aname->name, ext, NULL);
3190                 }
3191
3192                 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3193                 if (result) {
3194                         g_free (filename);
3195                         return result;
3196                 }
3197
3198                 if (basedir) {
3199                         fullpath = g_build_filename (basedir, filename, NULL);
3200                         result = mono_assembly_open_full (fullpath, status, refonly);
3201                         g_free (fullpath);
3202                         if (result) {
3203                                 result->in_gac = FALSE;
3204                                 g_free (filename);
3205                                 return result;
3206                         }
3207                 }
3208
3209                 result = load_in_path (filename, default_path, status, refonly);
3210                 if (result)
3211                         result->in_gac = FALSE;
3212                 g_free (filename);
3213                 if (result)
3214                         return result;
3215         }
3216
3217         return result;
3218 }
3219
3220 MonoAssembly*
3221 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3222 {
3223         MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3224
3225         if (!result)
3226                 /* Try a postload search hook */
3227                 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3228         return result;
3229 }
3230
3231 /**
3232  * mono_assembly_load_full:
3233  * @aname: A MonoAssemblyName with the assembly name to load.
3234  * @basedir: A directory to look up the assembly at.
3235  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3236  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3237  *
3238  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3239  * attempts to load the assembly from that directory before probing the standard locations.
3240  *
3241  * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
3242  * assembly binding takes place.
3243  *
3244  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3245  * value pointed by status is updated with an error code.
3246  */
3247 MonoAssembly*
3248 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3249 {
3250         return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3251 }
3252
3253 /**
3254  * mono_assembly_load:
3255  * @aname: A MonoAssemblyName with the assembly name to load.
3256  * @basedir: A directory to look up the assembly at.
3257  * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
3258  *
3259  * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
3260  * attempts to load the assembly from that directory before probing the standard locations.
3261  *
3262  * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
3263  * value pointed by status is updated with an error code.
3264  */
3265 MonoAssembly*
3266 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3267 {
3268         return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3269 }
3270
3271 /**
3272  * mono_assembly_loaded_full:
3273  * @aname: an assembly to look for.
3274  * @refonly: Whether this assembly is being opened in "reflection-only" mode.
3275  *
3276  * This is used to determine if the specified assembly has been loaded
3277  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3278  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3279  */
3280 MonoAssembly*
3281 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3282 {
3283         MonoAssembly *res;
3284         MonoAssemblyName maped_aname;
3285
3286         aname = mono_assembly_remap_version (aname, &maped_aname);
3287
3288         res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3289
3290         return res;
3291 }
3292
3293 /**
3294  * mono_assembly_loaded:
3295  * @aname: an assembly to look for.
3296  *
3297  * This is used to determine if the specified assembly has been loaded
3298  
3299  * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
3300  * a `MonoAssembly` that matches the `MonoAssemblyName` specified.
3301  */
3302 MonoAssembly*
3303 mono_assembly_loaded (MonoAssemblyName *aname)
3304 {
3305         return mono_assembly_loaded_full (aname, FALSE);
3306 }
3307
3308 void
3309 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3310 {
3311         if (assembly == NULL || assembly == REFERENCE_MISSING)
3312                 return;
3313
3314         if (assembly_is_dynamic (assembly)) {
3315                 int i;
3316                 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3317                 for (i = 0; i < dynimg->image.module_count; ++i)
3318                         mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3319                 mono_dynamic_image_release_gc_roots (dynimg);
3320         }
3321 }
3322
3323 /*
3324  * Returns whether mono_assembly_close_finish() must be called as
3325  * well.  See comment for mono_image_close_except_pools() for why we
3326  * unload in two steps.
3327  */
3328 gboolean
3329 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3330 {
3331         GSList *tmp;
3332         g_return_val_if_fail (assembly != NULL, FALSE);
3333
3334         if (assembly == REFERENCE_MISSING)
3335                 return FALSE;
3336
3337         /* Might be 0 already */
3338         if (InterlockedDecrement (&assembly->ref_count) > 0)
3339                 return FALSE;
3340
3341         mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3342
3343         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3344
3345         mono_debug_close_image (assembly->image);
3346
3347         mono_assemblies_lock ();
3348         loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3349         mono_assemblies_unlock ();
3350
3351         assembly->image->assembly = NULL;
3352
3353         if (!mono_image_close_except_pools (assembly->image))
3354                 assembly->image = NULL;
3355
3356         for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3357                 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3358                 mono_assembly_name_free (fname);
3359                 g_free (fname);
3360         }
3361         g_slist_free (assembly->friend_assembly_names);
3362         g_free (assembly->basedir);
3363
3364         mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3365
3366         return TRUE;
3367 }
3368
3369 void
3370 mono_assembly_close_finish (MonoAssembly *assembly)
3371 {
3372         g_assert (assembly && assembly != REFERENCE_MISSING);
3373
3374         if (assembly->image)
3375                 mono_image_close_finish (assembly->image);
3376
3377         if (assembly_is_dynamic (assembly)) {
3378                 g_free ((char*)assembly->aname.culture);
3379         } else {
3380                 g_free (assembly);
3381         }
3382 }
3383
3384 /**
3385  * mono_assembly_close:
3386  * @assembly: the assembly to release.
3387  *
3388  * This method releases a reference to the @assembly.  The assembly is
3389  * only released when all the outstanding references to it are released.
3390  */
3391 void
3392 mono_assembly_close (MonoAssembly *assembly)
3393 {
3394         if (mono_assembly_close_except_image_pools (assembly))
3395                 mono_assembly_close_finish (assembly);
3396 }
3397
3398 MonoImage*
3399 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3400 {
3401         return mono_image_load_file_for_image (assembly->image, idx);
3402 }
3403
3404 /**
3405  * mono_assembly_foreach:
3406  * @func: function to invoke for each assembly loaded
3407  * @user_data: data passed to the callback
3408  *
3409  * Invokes the provided @func callback for each assembly loaded into
3410  * the runtime.   The first parameter passed to the callback  is the
3411  * `MonoAssembly*`, and the second parameter is the @user_data.
3412  *
3413  * This is done for all assemblies loaded in the runtime, not just
3414  * those loaded in the current application domain.
3415  */
3416 void
3417 mono_assembly_foreach (GFunc func, gpointer user_data)
3418 {
3419         GList *copy;
3420
3421         /*
3422          * We make a copy of the list to avoid calling the callback inside the 
3423          * lock, which could lead to deadlocks.
3424          */
3425         mono_assemblies_lock ();
3426         copy = g_list_copy (loaded_assemblies);
3427         mono_assemblies_unlock ();
3428
3429         g_list_foreach (loaded_assemblies, func, user_data);
3430
3431         g_list_free (copy);
3432 }
3433
3434 /**
3435  * mono_assemblies_cleanup:
3436  *
3437  * Free all resources used by this module.
3438  */
3439 void
3440 mono_assemblies_cleanup (void)
3441 {
3442         GSList *l;
3443
3444         mono_os_mutex_destroy (&assemblies_mutex);
3445         mono_os_mutex_destroy (&assembly_binding_mutex);
3446
3447         for (l = loaded_assembly_bindings; l; l = l->next) {
3448                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3449
3450                 mono_assembly_binding_info_free (info);
3451                 g_free (info);
3452         }
3453         g_slist_free (loaded_assembly_bindings);
3454
3455         free_assembly_load_hooks ();
3456         free_assembly_search_hooks ();
3457         free_assembly_preload_hooks ();
3458 }
3459
3460 /*LOCKING takes the assembly_binding lock*/
3461 void
3462 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3463 {
3464         GSList **iter;
3465
3466         mono_assembly_binding_lock ();
3467         iter = &loaded_assembly_bindings;
3468         while (*iter) {
3469                 GSList *l = *iter;
3470                 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3471
3472                 if (info->domain_id == domain_id) {
3473                         *iter = l->next;
3474                         mono_assembly_binding_info_free (info);
3475                         g_free (info);
3476                         g_slist_free_1 (l);
3477                 } else {
3478                         iter = &l->next;
3479                 }
3480         }
3481         mono_assembly_binding_unlock ();
3482 }
3483
3484 /*
3485  * Holds the assembly of the application, for
3486  * System.Diagnostics.Process::MainModule
3487  */
3488 static MonoAssembly *main_assembly=NULL;
3489
3490 void
3491 mono_assembly_set_main (MonoAssembly *assembly)
3492 {
3493         main_assembly = assembly;
3494 }
3495
3496 /**
3497  * mono_assembly_get_main:
3498  *
3499  * Returns: the assembly for the application, the first assembly that is loaded by the VM
3500  */
3501 MonoAssembly *
3502 mono_assembly_get_main (void)
3503 {
3504         return (main_assembly);
3505 }
3506
3507 /**
3508  * mono_assembly_get_image:
3509  * @assembly: The assembly to retrieve the image from
3510  *
3511  * Returns: the MonoImage associated with this assembly.
3512  */
3513 MonoImage*
3514 mono_assembly_get_image (MonoAssembly *assembly)
3515 {
3516         return assembly->image;
3517 }
3518
3519 /**
3520  * mono_assembly_get_name:
3521  * @assembly: The assembly to retrieve the name from
3522  *
3523  * The returned name's lifetime is the same as @assembly's.
3524  *
3525  * Returns: the MonoAssemblyName associated with this assembly.
3526  */
3527 MonoAssemblyName *
3528 mono_assembly_get_name (MonoAssembly *assembly)
3529 {
3530         return &assembly->aname;
3531 }
3532
3533 void
3534 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
3535 {
3536         bundles = assemblies;
3537 }
3538
3539 #define MONO_DECLSEC_FORMAT_10          0x3C
3540 #define MONO_DECLSEC_FORMAT_20          0x2E
3541 #define MONO_DECLSEC_FIELD              0x53
3542 #define MONO_DECLSEC_PROPERTY           0x54
3543
3544 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
3545 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
3546 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
3547 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
3548 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
3549
3550 static gboolean
3551 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
3552 {
3553         int len;
3554         switch (*p++) {
3555         case MONO_DECLSEC_PROPERTY:
3556                 break;
3557         case MONO_DECLSEC_FIELD:
3558         default:
3559                 *abort_decoding = TRUE;
3560                 return FALSE;
3561                 break;
3562         }
3563
3564         if (*p++ != MONO_TYPE_BOOLEAN) {
3565                 *abort_decoding = TRUE;
3566                 return FALSE;
3567         }
3568                 
3569         /* property name length */
3570         len = mono_metadata_decode_value (p, &p);
3571
3572         if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
3573                 p += len;
3574                 return *p;
3575         }
3576         p += len + 1;
3577
3578         *resp = p;
3579         return FALSE;
3580 }
3581
3582 static gboolean
3583 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
3584 {
3585         int i, j, num, len, params_len;
3586
3587         if (*p == MONO_DECLSEC_FORMAT_10) {
3588                 gsize read, written;
3589                 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
3590                 if (res) {
3591                         gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
3592                         g_free (res);
3593                         return found;
3594                 }
3595                 return FALSE;
3596         }
3597         if (*p++ != MONO_DECLSEC_FORMAT_20)
3598                 return FALSE;
3599
3600         /* number of encoded permission attributes */
3601         num = mono_metadata_decode_value (p, &p);
3602         for (i = 0; i < num; ++i) {
3603                 gboolean is_valid = FALSE;
3604                 gboolean abort_decoding = FALSE;
3605
3606                 /* attribute name length */
3607                 len =  mono_metadata_decode_value (p, &p);
3608
3609                 /* We don't really need to fully decode the type. Comparing the name is enough */
3610                 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
3611
3612                 p += len;
3613
3614                 /*size of the params table*/
3615                 params_len =  mono_metadata_decode_value (p, &p);
3616                 if (is_valid) {
3617                         const char *params_end = p + params_len;
3618                         
3619                         /* number of parameters */
3620                         len = mono_metadata_decode_value (p, &p);
3621         
3622                         for (j = 0; j < len; ++j) {
3623                                 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
3624                                         return TRUE;
3625                                 if (abort_decoding)
3626                                         break;
3627                         }
3628                         p = params_end;
3629                 } else {
3630                         p += params_len;
3631                 }
3632         }
3633         
3634         return FALSE;
3635 }
3636
3637
3638 gboolean
3639 mono_assembly_has_skip_verification (MonoAssembly *assembly)
3640 {
3641         MonoTableInfo *t;       
3642         guint32 cols [MONO_DECL_SECURITY_SIZE];
3643         const char *blob;
3644         int i, len;
3645
3646         if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
3647                 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
3648
3649         t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
3650
3651         for (i = 0; i < t->rows; ++i) {
3652                 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
3653                 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
3654                         continue;
3655                 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
3656                         continue;
3657
3658                 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
3659                 len = mono_metadata_decode_blob_size (blob, &blob);
3660                 if (!len)
3661                         continue;
3662
3663                 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
3664                         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
3665                         return TRUE;
3666                 }
3667         }
3668
3669         MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);
3670         return FALSE;
3671 }