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