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