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