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