3 * Routines for loading assemblies.
6 * Miguel de Icaza (miguel@ximian.com)
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.
20 #include "assembly-internals.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>
48 #include <sys/types.h>
53 #ifdef PLATFORM_MACOSX
54 #include <mach-o/dyld.h>
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 */
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;
66 /* Flag bits for assembly_names_equal_flags (). */
68 /* Default comparison: all fields must match */
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,
76 } AssemblyNameEqFlags;
78 /* the default search path is empty, the first slot is replaced with the computed value */
86 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
87 static char **assemblies_path = NULL;
89 /* Contains the list of directories that point to auxiliary GACs */
90 static char **extra_gac_paths = NULL;
92 #ifndef DISABLE_DESKTOP_LOADER
94 #define FACADE_ASSEMBLY(str) {str, 0, NULL, FALSE, TRUE}
96 static GHashTable* assembly_remapping_table;
97 /* The list of system assemblies what will be remapped to the running
99 * This list is stored in @assembly_remapping_table during initialization.
100 * Keep it sorted just to make maintenance easier.
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.
106 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
109 static const AssemblyVersionMap framework_assemblies [] = {
110 {"Accessibility", 0},
111 {"Commons.Xml.Relaxng", 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"),
130 {"Mono.CompilerServices.SymbolWriter", 0},
132 {"Mono.Data.SybaseClient", 0},
133 {"Mono.Data.Tds", 0},
134 {"Mono.Data.TdsClient", 0},
135 {"Mono.GetOptions", 0},
138 {"Mono.Security", 0},
139 {"Mono.Security.Win32", 0},
141 {"Novell.Directory.Ldap", 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"),
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},
210 FACADE_ASSEMBLY ("System.Net.AuthenticationManager"),
211 FACADE_ASSEMBLY ("System.Net.Cache"),
212 {"System.Net.Http", 4},
213 {"System.Net.Http.Rtc", 0},
214 FACADE_ASSEMBLY ("System.Net.HttpListener"),
215 FACADE_ASSEMBLY ("System.Net.Mail"),
216 FACADE_ASSEMBLY ("System.Net.NameResolution"),
217 FACADE_ASSEMBLY ("System.Net.NetworkInformation"),
218 FACADE_ASSEMBLY ("System.Net.Ping"),
219 FACADE_ASSEMBLY ("System.Net.Primitives"),
220 FACADE_ASSEMBLY ("System.Net.Requests"),
221 FACADE_ASSEMBLY ("System.Net.Security"),
222 FACADE_ASSEMBLY ("System.Net.ServicePoint"),
223 FACADE_ASSEMBLY ("System.Net.Sockets"),
224 FACADE_ASSEMBLY ("System.Net.Utilities"),
225 FACADE_ASSEMBLY ("System.Net.WebHeaderCollection"),
226 FACADE_ASSEMBLY ("System.Net.WebSockets"),
227 FACADE_ASSEMBLY ("System.Net.WebSockets.Client"),
228 {"System.Numerics.Vectors", 3},
229 FACADE_ASSEMBLY ("System.ObjectModel"),
230 FACADE_ASSEMBLY ("System.Reflection"),
231 FACADE_ASSEMBLY ("System.Reflection.DispatchProxy"),
232 FACADE_ASSEMBLY ("System.Reflection.Emit"),
233 FACADE_ASSEMBLY ("System.Reflection.Emit.ILGeneration"),
234 FACADE_ASSEMBLY ("System.Reflection.Emit.Lightweight"),
235 FACADE_ASSEMBLY ("System.Reflection.Extensions"),
236 FACADE_ASSEMBLY ("System.Reflection.Primitives"),
237 FACADE_ASSEMBLY ("System.Reflection.TypeExtensions"),
238 FACADE_ASSEMBLY ("System.Resources.ReaderWriter"),
239 FACADE_ASSEMBLY ("System.Resources.ResourceManager"),
240 FACADE_ASSEMBLY ("System.Runtime"),
241 FACADE_ASSEMBLY ("System.Runtime.CompilerServices.VisualC"),
242 FACADE_ASSEMBLY ("System.Runtime.Extensions"),
243 FACADE_ASSEMBLY ("System.Runtime.Handles"),
244 FACADE_ASSEMBLY ("System.Runtime.InteropServices"),
245 FACADE_ASSEMBLY ("System.Runtime.InteropServices.RuntimeInformation"),
246 FACADE_ASSEMBLY ("System.Runtime.InteropServices.WindowsRuntime"),
247 FACADE_ASSEMBLY ("System.Runtime.Loader"),
248 FACADE_ASSEMBLY ("System.Runtime.Numerics"),
249 {"System.Runtime.Remoting", 0},
250 {"System.Runtime.Serialization", 3},
251 FACADE_ASSEMBLY ("System.Runtime.Serialization.Formatters"),
252 {"System.Runtime.Serialization.Formatters.Soap", 0},
253 FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"),
254 FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"),
255 FACADE_ASSEMBLY ("System.Runtime.Serialization.Xml"),
256 {"System.Security", 0},
257 FACADE_ASSEMBLY ("System.Security.AccessControl"),
258 FACADE_ASSEMBLY ("System.Security.Claims"),
259 FACADE_ASSEMBLY ("System.Security.Cryptography.Algorithms"),
260 FACADE_ASSEMBLY ("System.Security.Cryptography.Cng"),
261 FACADE_ASSEMBLY ("System.Security.Cryptography.Csp"),
262 FACADE_ASSEMBLY ("System.Security.Cryptography.DeriveBytes"),
263 FACADE_ASSEMBLY ("System.Security.Cryptography.Encoding"),
264 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption"),
265 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Aes"),
266 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDiffieHellman"),
267 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDsa"),
268 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing"),
269 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing.Algorithms"),
270 FACADE_ASSEMBLY ("System.Security.Cryptography.OpenSsl"),
271 FACADE_ASSEMBLY ("System.Security.Cryptography.Pkcs"),
272 FACADE_ASSEMBLY ("System.Security.Cryptography.Primitives"),
273 FACADE_ASSEMBLY ("System.Security.Cryptography.ProtectedData"),
274 FACADE_ASSEMBLY ("System.Security.Cryptography.RSA"),
275 FACADE_ASSEMBLY ("System.Security.Cryptography.RandomNumberGenerator"),
276 FACADE_ASSEMBLY ("System.Security.Cryptography.X509Certificates"),
277 FACADE_ASSEMBLY ("System.Security.Principal"),
278 FACADE_ASSEMBLY ("System.Security.Principal.Windows"),
279 FACADE_ASSEMBLY ("System.Security.SecureString"),
280 {"System.ServiceModel", 3},
281 FACADE_ASSEMBLY ("System.ServiceModel.Duplex"),
282 FACADE_ASSEMBLY ("System.ServiceModel.Http"),
283 FACADE_ASSEMBLY ("System.ServiceModel.NetTcp"),
284 FACADE_ASSEMBLY ("System.ServiceModel.Primitives"),
285 FACADE_ASSEMBLY ("System.ServiceModel.Security"),
286 {"System.ServiceModel.Web", 2},
287 {"System.ServiceProcess", 0},
288 FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"),
289 FACADE_ASSEMBLY ("System.Text.Encoding"),
290 FACADE_ASSEMBLY ("System.Text.Encoding.CodePages"),
291 FACADE_ASSEMBLY ("System.Text.Encoding.Extensions"),
292 FACADE_ASSEMBLY ("System.Text.RegularExpressions"),
293 FACADE_ASSEMBLY ("System.Threading"),
294 FACADE_ASSEMBLY ("System.Threading.AccessControl"),
295 FACADE_ASSEMBLY ("System.Threading.Overlapped"),
296 FACADE_ASSEMBLY ("System.Threading.Tasks"),
297 FACADE_ASSEMBLY ("System.Threading.Tasks.Parallel"),
298 FACADE_ASSEMBLY ("System.Threading.Thread"),
299 FACADE_ASSEMBLY ("System.Threading.ThreadPool"),
300 FACADE_ASSEMBLY ("System.Threading.Timer"),
301 {"System.Transactions", 0},
302 FACADE_ASSEMBLY ("System.ValueTuple"),
304 {"System.Web.Abstractions", 2},
305 {"System.Web.DynamicData", 2},
306 {"System.Web.Extensions", 2},
307 {"System.Web.Mobile", 0},
308 {"System.Web.Routing", 2},
309 {"System.Web.Services", 0},
310 {"System.Windows", 0},
311 {"System.Windows.Forms", 0},
313 {"System.Xml.Linq", 2},
314 FACADE_ASSEMBLY ("System.Xml.ReaderWriter"),
315 {"System.Xml.Serialization", 0},
316 FACADE_ASSEMBLY ("System.Xml.XDocument"),
317 FACADE_ASSEMBLY ("System.Xml.XPath"),
318 FACADE_ASSEMBLY ("System.Xml.XPath.XmlDocument"),
319 FACADE_ASSEMBLY ("System.Xml.XPath.XDocument"),
320 FACADE_ASSEMBLY ("System.Xml.XmlDocument"),
321 FACADE_ASSEMBLY ("System.Xml.XmlSerializer"),
322 FACADE_ASSEMBLY ("System.Xml.Xsl.Primitives"),
325 FACADE_ASSEMBLY ("netstandard"),
330 * keeps track of loaded assemblies
332 static GList *loaded_assemblies = NULL;
333 static MonoAssembly *corlib;
335 static char* unquote (const char *str);
337 /* This protects loaded_assemblies and image->references */
338 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
339 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
340 static mono_mutex_t assemblies_mutex;
342 /* If defined, points to the bundled assembly information */
343 const MonoBundledAssembly **bundles;
345 static mono_mutex_t assembly_binding_mutex;
347 /* Loaded assembly binding info */
348 static GSList *loaded_assembly_bindings = NULL;
350 /* Class lazy loading functions */
351 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
353 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
355 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
357 mono_assembly_is_in_gac (const gchar *filanem);
360 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
363 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags);
365 /* Assembly name matching */
367 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
369 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
372 encode_public_tok (const guchar *token, gint32 len)
374 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
378 res = (gchar *)g_malloc (len * 2 + 1);
379 for (i = 0; i < len; i++) {
380 res [i * 2] = allowed [token [i] >> 4];
381 res [i * 2 + 1] = allowed [token [i] & 0xF];
388 * mono_public_tokens_are_equal:
389 * \param pubt1 first public key token
390 * \param pubt2 second public key token
392 * Compare two public key tokens and return TRUE is they are equal and FALSE
396 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
398 return memcmp (pubt1, pubt2, 16) == 0;
402 * mono_set_assemblies_path:
403 * \param path list of paths that contain directories where Mono will look for assemblies
405 * Use this method to override the standard assembly lookup system and
406 * override any assemblies coming from the GAC. This is the method
407 * that supports the \c MONO_PATH variable.
409 * Notice that \c MONO_PATH and this method are really a very bad idea as
410 * it prevents the GAC from working and it prevents the standard
411 * resolution mechanisms from working. Nonetheless, for some debugging
412 * situations and bootstrapping setups, this is useful to have.
415 mono_set_assemblies_path (const char* path)
417 char **splitted, **dest;
419 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
421 g_strfreev (assemblies_path);
422 assemblies_path = dest = splitted;
424 char *tmp = *splitted;
426 *dest++ = mono_path_canonicalize (tmp);
432 if (g_hasenv ("MONO_DEBUG"))
435 splitted = assemblies_path;
437 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
438 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
445 check_path_env (void)
447 if (assemblies_path != NULL)
450 char* path = g_getenv ("MONO_PATH");
454 mono_set_assemblies_path(path);
459 check_extra_gac_path_env (void)
462 char **splitted, **dest;
464 path = g_getenv ("MONO_GAC_PREFIX");
468 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
472 g_strfreev (extra_gac_paths);
473 extra_gac_paths = dest = splitted;
481 if (!g_hasenv ("MONO_DEBUG"))
485 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
486 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
493 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
495 if (!info || !info->name)
498 if (strcmp (info->name, aname->name))
501 if (info->major != aname->major || info->minor != aname->minor)
504 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
507 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
510 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
517 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
523 g_free (info->culture);
527 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
530 guint32 cols [MONO_MANIFEST_SIZE];
531 const gchar *filename;
532 gchar *subpath, *fullpath;
534 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
535 /* MS Impl. accepts policy assemblies with more than
536 * one manifest resource, and only takes the first one */
538 binding_info->is_valid = FALSE;
542 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
543 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
544 binding_info->is_valid = FALSE;
548 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
549 g_assert (filename != NULL);
551 subpath = g_path_get_dirname (image->name);
552 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
553 mono_config_parse_publisher_policy (fullpath, binding_info);
557 /* Define the optional elements/attributes before checking */
558 if (!binding_info->culture)
559 binding_info->culture = g_strdup ("");
561 /* Check that the most important elements/attributes exist */
562 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
563 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
564 mono_assembly_binding_info_free (binding_info);
565 binding_info->is_valid = FALSE;
569 binding_info->is_valid = TRUE;
573 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
575 if (v->major > aname->major)
577 else if (v->major < aname->major)
580 if (v->minor > aname->minor)
582 else if (v->minor < aname->minor)
585 if (v->build > aname->build)
587 else if (v->build < aname->build)
590 if (v->revision > aname->revision)
592 else if (v->revision < aname->revision)
599 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
604 /* If has_old_version_top doesn't exist, we don't have an interval */
605 if (!info->has_old_version_top) {
606 if (compare_versions (&info->old_version_bottom, name) == 0)
612 /* Check that the version defined by name is valid for the interval */
613 if (compare_versions (&info->old_version_top, name) < 0)
616 /* We should be greater or equal than the small version */
617 if (compare_versions (&info->old_version_bottom, name) > 0)
624 * mono_assembly_names_equal:
625 * \param l first assembly
626 * \param r second assembly.
628 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
630 * This compares the names, the cultures, the release version and their
633 * \returns TRUE if both assembly names are equal.
636 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
638 return assembly_names_equal_flags (l, r, ANAME_EQ_NONE);
642 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags)
644 if (!l->name || !r->name)
647 if (strcmp (l->name, r->name))
650 if (l->culture && r->culture && strcmp (l->culture, r->culture))
653 if ((l->major != r->major || l->minor != r->minor ||
654 l->build != r->build || l->revision != r->revision) &&
655 (flags & ANAME_EQ_IGNORE_VERSION) == 0)
656 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)))
659 if (!l->public_key_token [0] || !r->public_key_token [0] || (flags & ANAME_EQ_IGNORE_PUBKEY) != 0)
662 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
668 static MonoAssembly *
669 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
673 MonoAssembly *result;
675 for (i = 0; search_path [i]; ++i) {
676 fullpath = g_build_filename (search_path [i], basename, NULL);
677 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
686 * mono_assembly_setrootdir:
687 * \param root_dir The pathname of the root directory where we will locate assemblies
689 * This routine sets the internal default root directory for looking up
692 * This is used by Windows installations to compute dynamically the
693 * place where the Mono assemblies are located.
697 mono_assembly_setrootdir (const char *root_dir)
700 * Override the MONO_ASSEMBLIES directory configured at compile time.
702 /* Leak if called more than once */
703 default_path [0] = g_strdup (root_dir);
707 * mono_assembly_getrootdir:
709 * Obtains the root directory used for looking up assemblies.
711 * Returns: a string with the directory, this string should not be freed.
713 G_CONST_RETURN gchar *
714 mono_assembly_getrootdir (void)
716 return default_path [0];
720 * mono_native_getrootdir:
722 * Obtains the root directory used for looking up native libs (.so, .dylib).
724 * Returns: a string with the directory, this string should be freed by
728 mono_native_getrootdir (void)
730 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
736 * \param assembly_dir the base directory for assemblies
737 * \param config_dir the base directory for configuration files
739 * This routine is used internally and by developers embedding
740 * the runtime into their own applications.
742 * There are a number of cases to consider: Mono as a system-installed
743 * package that is available on the location preconfigured or Mono in
744 * a relocated location.
746 * If you are using a system-installed Mono, you can pass NULL
747 * to both parameters. If you are not, you should compute both
748 * directory values and call this routine.
750 * The values for a given PREFIX are:
752 * assembly_dir: PREFIX/lib
753 * config_dir: PREFIX/etc
755 * Notice that embedders that use Mono in a relocated way must
756 * compute the location at runtime, as they will be in control
757 * of where Mono is installed.
760 mono_set_dirs (const char *assembly_dir, const char *config_dir)
762 if (assembly_dir == NULL)
763 assembly_dir = mono_config_get_assemblies_dir ();
764 if (config_dir == NULL)
765 config_dir = mono_config_get_cfg_dir ();
766 mono_assembly_setrootdir (assembly_dir);
767 mono_set_config_dir (config_dir);
773 compute_base (char *path)
775 char *p = strrchr (path, '/');
779 /* Not a well known Mono executable, we are embedded, cant guess the base */
780 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
784 p = strrchr (path, '/');
788 if (strcmp (p, "/bin") != 0)
797 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
800 static G_GNUC_UNUSED void
804 char *config, *lib, *mono;
809 * Only /usr prefix is treated specially
811 bindir = mono_config_get_bin_dir ();
813 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
818 config = g_build_filename (base, "etc", NULL);
819 lib = g_build_filename (base, "lib", NULL);
820 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
821 if (stat (mono, &buf) == -1)
824 mono_set_dirs (lib, config);
832 #endif /* HOST_WIN32 */
837 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
838 * this auto-detects the prefix where Mono was installed.
841 mono_set_rootdir (void)
843 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
844 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
847 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
851 * _NSGetExecutablePath may return -1 to indicate buf is not large
852 * enough, but we ignore that case to avoid having to do extra dynamic
853 * allocation for the path and hope that 4096 is enough - this is
854 * ok in the Linux/Solaris case below at least...
858 guint buf_size = sizeof (buf);
861 if (_NSGetExecutablePath (buf, &buf_size) == 0)
862 name = g_strdup (buf);
871 resolvedname = mono_path_resolve_symlinks (name);
873 bindir = g_path_get_dirname (resolvedname);
874 installdir = g_path_get_dirname (bindir);
875 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
877 config = g_build_filename (root, "..", "etc", NULL);
879 mono_set_dirs (root, config);
881 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
882 mono_set_dirs (root, config);
892 g_free (resolvedname);
893 #elif defined(DISABLE_MONO_AUTODETECTION)
901 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
909 /* Solaris 10 style */
910 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
911 s = readlink (str, buf, sizeof (buf)-1);
923 * mono_assemblies_init:
925 * Initialize global variables used by this module.
928 mono_assemblies_init (void)
931 * Initialize our internal paths if we have not been initialized yet.
932 * This happens when embedders use Mono.
934 if (mono_assembly_getrootdir () == NULL)
938 check_extra_gac_path_env ();
940 mono_os_mutex_init_recursive (&assemblies_mutex);
941 mono_os_mutex_init (&assembly_binding_mutex);
943 #ifndef DISABLE_DESKTOP_LOADER
944 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
947 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
948 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
954 mono_assembly_binding_lock (void)
956 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
960 mono_assembly_binding_unlock (void)
962 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
966 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
968 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
969 guint32 cols [MONO_ASSEMBLY_SIZE];
970 gint32 machine, flags;
975 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
978 aname->hash_value = NULL;
979 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
981 aname->name = g_strdup (aname->name);
982 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
984 aname->culture = g_strdup (aname->culture);
985 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
986 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
987 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
988 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
989 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
990 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
991 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
992 guchar* token = (guchar *)g_malloc (8);
997 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
998 len = mono_metadata_decode_blob_size (pkey, &pkey);
999 aname->public_key = (guchar*)pkey;
1001 mono_digest_get_public_token (token, aname->public_key, len);
1002 encoded = encode_public_tok (token, 8);
1003 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1009 aname->public_key = NULL;
1010 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1013 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
1014 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
1016 const gchar *pkey_end;
1017 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
1018 pkey_end += len; /* move to end */
1019 size_t size = pkey_end - (const gchar*)aname->public_key;
1020 guchar *tmp = g_new (guchar, size);
1021 memcpy (tmp, aname->public_key, size);
1022 aname->public_key = tmp;
1027 aname->public_key = 0;
1029 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
1030 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
1032 case COFF_MACHINE_I386:
1033 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1034 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
1035 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
1036 else if ((flags & 0x70) == 0x70)
1037 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
1039 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
1041 case COFF_MACHINE_IA64:
1042 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
1044 case COFF_MACHINE_AMD64:
1045 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
1047 case COFF_MACHINE_ARM:
1048 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
1058 * mono_assembly_fill_assembly_name:
1059 * \param image Image
1061 * \returns TRUE if successful
1064 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
1066 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
1070 * mono_stringify_assembly_name:
1071 * \param aname the assembly name.
1073 * Convert \p aname into its string format. The returned string is dynamically
1074 * allocated and should be freed by the caller.
1076 * \returns a newly allocated string with a string representation of
1077 * the assembly name.
1080 mono_stringify_assembly_name (MonoAssemblyName *aname)
1082 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
1084 return g_strdup_printf (
1085 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1086 quote, aname->name, quote,
1087 aname->major, aname->minor, aname->build, aname->revision,
1088 aname->culture && *aname->culture? aname->culture: "neutral",
1089 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
1090 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
1094 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
1096 const gchar *public_tok;
1099 public_tok = mono_metadata_blob_heap (image, key_index);
1100 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
1102 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
1104 mono_digest_get_public_token (token, (guchar*)public_tok, len);
1105 return encode_public_tok (token, 8);
1108 return encode_public_tok ((guchar*)public_tok, len);
1112 * mono_assembly_addref:
1113 * \param assembly the assembly to reference
1115 * This routine increments the reference count on a MonoAssembly.
1116 * The reference count is reduced every time the method mono_assembly_close() is
1120 mono_assembly_addref (MonoAssembly *assembly)
1122 InterlockedIncrement (&assembly->ref_count);
1126 * CAUTION: This table must be kept in sync with
1127 * ivkm/reflect/Fusion.cs
1130 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1131 #define WINFX_KEY "31bf3856ad364e35"
1132 #define ECMA_KEY "b77a5c561934e089"
1133 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1134 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1142 static KeyRemapEntry key_remap_table[] = {
1143 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1144 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1145 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1146 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1147 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1148 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1149 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1150 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1151 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1152 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1153 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1154 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1155 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1156 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1157 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1158 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1159 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1160 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1161 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1162 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1163 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1164 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1165 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1166 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1167 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1168 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1169 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1170 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1171 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1175 remap_keys (MonoAssemblyName *aname)
1178 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1179 const KeyRemapEntry *entry = &key_remap_table [i];
1181 if (strcmp (aname->name, entry->name) ||
1182 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1185 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1187 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1188 "Remapped public key token of retargetable assembly %s from %s to %s",
1189 aname->name, entry->from, entry->to);
1194 static MonoAssemblyName *
1195 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1197 const MonoRuntimeInfo *current_runtime;
1199 if (aname->name == NULL) return aname;
1201 current_runtime = mono_get_runtime_info ();
1203 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1204 const AssemblyVersionSet* vset;
1206 /* Remap to current runtime */
1207 vset = ¤t_runtime->version_sets [0];
1209 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1210 dest_aname->major = vset->major;
1211 dest_aname->minor = vset->minor;
1212 dest_aname->build = vset->build;
1213 dest_aname->revision = vset->revision;
1214 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1216 /* Remap assembly name */
1217 if (!strcmp (aname->name, "System.Net"))
1218 dest_aname->name = g_strdup ("System");
1220 remap_keys (dest_aname);
1222 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1223 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1225 aname->major, aname->minor, aname->build, aname->revision,
1227 vset->major, vset->minor, vset->build, vset->revision
1233 #ifndef DISABLE_DESKTOP_LOADER
1234 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1236 const AssemblyVersionSet* vset;
1237 int index = vmap->version_set_index;
1238 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1239 vset = ¤t_runtime->version_sets [index];
1241 if (vmap->framework_facade_assembly) {
1242 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s is a framework Facade asseembly",
1247 if (aname->major == vset->major && aname->minor == vset->minor &&
1248 aname->build == vset->build && aname->revision == vset->revision) {
1249 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->major, aname->minor, aname->build, aname->revision);
1255 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1256 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1257 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1259 aname->major, aname->minor, aname->build, aname->revision,
1260 vset->major, vset->minor, vset->build, vset->revision
1265 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1266 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1267 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1269 aname->major, aname->minor, aname->build, aname->revision,
1270 vset->major, vset->minor, vset->build, vset->revision
1273 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1274 dest_aname->major = vset->major;
1275 dest_aname->minor = vset->minor;
1276 dest_aname->build = vset->build;
1277 dest_aname->revision = vset->revision;
1278 if (vmap->new_assembly_name != NULL) {
1279 dest_aname->name = vmap->new_assembly_name;
1280 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1281 "The assembly name %s was remapped to %s",
1293 * mono_assembly_get_assemblyref:
1294 * \param image pointer to the \c MonoImage to extract the information from.
1295 * \param index index to the assembly reference in the image.
1296 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1298 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1301 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1304 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1307 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1309 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1311 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1312 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1313 aname->hash_value = hash;
1314 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1315 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1316 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1317 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1318 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1319 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1320 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1322 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1323 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1324 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1327 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1332 * mono_assembly_load_reference:
1335 mono_assembly_load_reference (MonoImage *image, int index)
1337 MonoAssembly *reference;
1338 MonoAssemblyName aname;
1339 MonoImageOpenStatus status;
1342 * image->references is shared between threads, so we need to access
1343 * it inside a critical section.
1345 mono_assemblies_lock ();
1346 if (!image->references) {
1347 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1349 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1350 image->nreferences = t->rows;
1352 reference = image->references [index];
1353 mono_assemblies_unlock ();
1357 mono_assembly_get_assemblyref (image, index, &aname);
1359 if (image->assembly && image->assembly->ref_only) {
1360 /* We use the loaded corlib */
1361 if (!strcmp (aname.name, "mscorlib"))
1362 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1364 reference = mono_assembly_loaded_full (&aname, TRUE);
1366 /* Try a postload search hook */
1367 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1371 * Here we must advice that the error was due to
1372 * a non loaded reference using the ReflectionOnly api
1375 reference = (MonoAssembly *)REFERENCE_MISSING;
1377 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1378 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1379 * accordingly, it would fail on the MS runtime before).
1380 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1381 * example bug-349190.2.cs and who knows how much more code in the wild.
1383 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1384 if (!reference && image->assembly)
1385 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1388 if (reference == NULL){
1391 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1392 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 : "" );
1393 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1394 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1395 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1396 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1397 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1398 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1400 extra_msg = g_strdup ("");
1403 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1404 " Assembly: %s (assemblyref_index=%d)\n"
1405 " Version: %d.%d.%d.%d\n"
1406 " Public Key: %s\n%s",
1407 image->name, aname.name, index,
1408 aname.major, aname.minor, aname.build, aname.revision,
1409 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1414 mono_assemblies_lock ();
1415 if (reference == NULL) {
1416 /* Flag as not found */
1417 reference = (MonoAssembly *)REFERENCE_MISSING;
1420 if (!image->references [index]) {
1421 if (reference != REFERENCE_MISSING){
1422 mono_assembly_addref (reference);
1423 if (image->assembly)
1424 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1425 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1427 if (image->assembly)
1428 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1429 image->assembly->aname.name, image->assembly);
1432 image->references [index] = reference;
1434 mono_assemblies_unlock ();
1436 if (image->references [index] != reference) {
1437 /* Somebody loaded it before us */
1438 mono_assembly_close (reference);
1443 * mono_assembly_load_references:
1446 * \deprecated There is no reason to use this method anymore, it does nothing
1448 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1451 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1453 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1454 *status = MONO_IMAGE_OK;
1457 typedef struct AssemblyLoadHook AssemblyLoadHook;
1458 struct AssemblyLoadHook {
1459 AssemblyLoadHook *next;
1460 MonoAssemblyLoadFunc func;
1464 AssemblyLoadHook *assembly_load_hook = NULL;
1467 * mono_assembly_invoke_load_hook:
1470 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1472 AssemblyLoadHook *hook;
1474 for (hook = assembly_load_hook; hook; hook = hook->next) {
1475 hook->func (ass, hook->user_data);
1480 * mono_install_assembly_load_hook:
1483 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1485 AssemblyLoadHook *hook;
1487 g_return_if_fail (func != NULL);
1489 hook = g_new0 (AssemblyLoadHook, 1);
1491 hook->user_data = user_data;
1492 hook->next = assembly_load_hook;
1493 assembly_load_hook = hook;
1497 free_assembly_load_hooks (void)
1499 AssemblyLoadHook *hook, *next;
1501 for (hook = assembly_load_hook; hook; hook = next) {
1507 typedef struct AssemblySearchHook AssemblySearchHook;
1508 struct AssemblySearchHook {
1509 AssemblySearchHook *next;
1510 MonoAssemblySearchFunc func;
1516 AssemblySearchHook *assembly_search_hook = NULL;
1518 static MonoAssembly*
1519 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1521 AssemblySearchHook *hook;
1523 for (hook = assembly_search_hook; hook; hook = hook->next) {
1524 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1527 * A little explanation is in order here.
1529 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1530 * The embedding API exposes a search hook that doesn't take such argument.
1532 * The original fix would call the default search hook before all the registered ones and pass
1533 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1534 * rely on. Which is the ordering between user hooks and the default runtime hook.
1536 * Registering the hook after mono_jit_init would let your hook run before the default one and
1537 * when using it to handle non standard app layouts this could save your app from a massive amount
1538 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1539 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1541 * So what's the fix? We register the default hook using regular means and special case it when iterating
1542 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1545 if (hook->func == (void*)mono_domain_assembly_postload_search)
1546 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1548 ass = hook->func (aname, hook->user_data);
1558 * mono_assembly_invoke_search_hook:
1561 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1563 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1567 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1569 AssemblySearchHook *hook;
1571 g_return_if_fail (func != NULL);
1573 hook = g_new0 (AssemblySearchHook, 1);
1575 hook->user_data = user_data;
1576 hook->refonly = refonly;
1577 hook->postload = postload;
1578 hook->next = assembly_search_hook;
1579 assembly_search_hook = hook;
1583 * mono_install_assembly_search_hook:
1586 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1588 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1592 free_assembly_search_hooks (void)
1594 AssemblySearchHook *hook, *next;
1596 for (hook = assembly_search_hook; hook; hook = next) {
1603 * mono_install_assembly_refonly_search_hook:
1606 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1608 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1612 * mono_install_assembly_postload_search_hook:
1615 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1617 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1621 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1623 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1626 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1627 struct AssemblyPreLoadHook {
1628 AssemblyPreLoadHook *next;
1629 MonoAssemblyPreLoadFunc func;
1633 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1634 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1636 static MonoAssembly *
1637 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1639 AssemblyPreLoadHook *hook;
1640 MonoAssembly *assembly;
1642 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1643 assembly = hook->func (aname, assemblies_path, hook->user_data);
1644 if (assembly != NULL)
1651 static MonoAssembly *
1652 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1654 AssemblyPreLoadHook *hook;
1655 MonoAssembly *assembly;
1657 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1658 assembly = hook->func (aname, assemblies_path, hook->user_data);
1659 if (assembly != NULL)
1667 * mono_install_assembly_preload_hook:
1670 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1672 AssemblyPreLoadHook *hook;
1674 g_return_if_fail (func != NULL);
1676 hook = g_new0 (AssemblyPreLoadHook, 1);
1678 hook->user_data = user_data;
1679 hook->next = assembly_preload_hook;
1680 assembly_preload_hook = hook;
1684 * mono_install_assembly_refonly_preload_hook:
1687 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1689 AssemblyPreLoadHook *hook;
1691 g_return_if_fail (func != NULL);
1693 hook = g_new0 (AssemblyPreLoadHook, 1);
1695 hook->user_data = user_data;
1696 hook->next = assembly_refonly_preload_hook;
1697 assembly_refonly_preload_hook = hook;
1701 free_assembly_preload_hooks (void)
1703 AssemblyPreLoadHook *hook, *next;
1705 for (hook = assembly_preload_hook; hook; hook = next) {
1710 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1717 absolute_dir (const gchar *filename)
1728 if (g_path_is_absolute (filename)) {
1729 part = g_path_get_dirname (filename);
1730 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1735 cwd = g_get_current_dir ();
1736 mixed = g_build_filename (cwd, filename, NULL);
1737 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1742 for (i = 0; (part = parts [i]) != NULL; i++) {
1743 if (!strcmp (part, "."))
1746 if (!strcmp (part, "..")) {
1747 if (list && list->next) /* Don't remove root */
1748 list = g_list_delete_link (list, list);
1750 list = g_list_prepend (list, part);
1754 result = g_string_new ("");
1755 list = g_list_reverse (list);
1757 /* Ignores last data pointer, which should be the filename */
1758 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1760 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1765 g_string_free (result, FALSE);
1770 return g_strdup (".");
1777 * mono_assembly_open_from_bundle:
1778 * \param filename Filename requested
1779 * \param status return status code
1781 * This routine tries to open the assembly specified by \p filename from the
1782 * defined bundles, if found, returns the MonoImage for it, if not found
1786 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1790 gchar *lowercase_filename;
1791 MonoImage *image = NULL;
1792 gboolean is_satellite = FALSE;
1794 * we do a very simple search for bundled assemblies: it's not a general
1795 * purpose assembly loading mechanism.
1801 lowercase_filename = g_utf8_strdown (filename, -1);
1802 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1803 g_free (lowercase_filename);
1804 name = g_path_get_basename (filename);
1805 mono_assemblies_lock ();
1806 for (i = 0; !image && bundles [i]; ++i) {
1807 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1808 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1812 mono_assemblies_unlock ();
1814 mono_image_addref (image);
1815 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1824 * mono_assembly_open_full:
1825 * \param filename the file to load
1826 * \param status return status code
1827 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1829 * This loads an assembly from the specified \p filename. The \p filename allows
1830 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1831 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1832 * is treated as a local path.
1834 * First, an attempt is made to load the assembly from the bundled executable (for those
1835 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1836 * assembly has been registered as an embedded assembly). If this is not the case, then
1837 * the assembly is loaded from disk using `api:mono_image_open_full`.
1839 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1840 * the assembly is made.
1842 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1843 * the \c System.Reflection API.
1845 * \returns NULL on error, with the \p status set to an error code, or a pointer
1849 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1851 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1855 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1857 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1861 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1862 gboolean load_from_context,
1863 MonoAssemblyCandidatePredicate predicate,
1865 MonoImageOpenStatus *status)
1869 MonoImageOpenStatus def_status;
1872 gboolean loaded_from_bundle;
1874 g_return_val_if_fail (filename != NULL, NULL);
1877 status = &def_status;
1878 *status = MONO_IMAGE_OK;
1880 if (strncmp (filename, "file://", 7) == 0) {
1881 GError *error = NULL;
1882 gchar *uri = (gchar *) filename;
1886 * MS allows file://c:/... and fails on file://localhost/c:/...
1887 * They also throw an IndexOutOfRangeException if "file://"
1890 uri = g_strdup_printf ("file:///%s", uri + 7);
1893 uri = mono_escape_uri_string (tmpuri);
1894 fname = g_filename_from_uri (uri, NULL, &error);
1897 if (tmpuri != filename)
1900 if (error != NULL) {
1901 g_warning ("%s\n", error->message);
1902 g_error_free (error);
1903 fname = g_strdup (filename);
1906 fname = g_strdup (filename);
1909 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1910 "Assembly Loader probing location: '%s'.", fname);
1913 if (!mono_assembly_is_in_gac (fname)) {
1915 new_fname = mono_make_shadow_copy (fname, &error);
1916 if (!is_ok (&error)) {
1917 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1918 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1919 mono_error_cleanup (&error);
1920 *status = MONO_IMAGE_IMAGE_INVALID;
1925 if (new_fname && new_fname != fname) {
1928 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1929 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1934 // If VM built with mkbundle
1935 loaded_from_bundle = FALSE;
1936 if (bundles != NULL) {
1937 image = mono_assembly_open_from_bundle (fname, status, refonly);
1938 loaded_from_bundle = image != NULL;
1942 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1945 if (*status == MONO_IMAGE_OK)
1946 *status = MONO_IMAGE_ERROR_ERRNO;
1951 if (image->assembly) {
1952 /* We want to return the MonoAssembly that's already loaded,
1953 * but if we're using the strict assembly loader, we also need
1954 * to check that the previously loaded assembly matches the
1955 * predicate. It could be that we previously loaded a
1956 * different version that happens to have the filename that
1957 * we're currently probing. */
1958 if (mono_loader_get_strict_strong_names () &&
1959 predicate && !predicate (image->assembly, user_data)) {
1960 mono_image_close (image);
1964 /* Already loaded by another appdomain */
1965 mono_assembly_invoke_load_hook (image->assembly);
1966 mono_image_close (image);
1968 return image->assembly;
1972 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1975 if (!loaded_from_bundle)
1976 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1977 "Assembly Loader loaded assembly from location: '%s'.", filename);
1979 mono_config_for_assembly (ass->image);
1982 /* Clear the reference added by mono_image_open */
1983 mono_image_close (image);
1991 free_item (gpointer val, gpointer user_data)
1997 * mono_assembly_load_friends:
1998 * \param ass an assembly
2000 * Load the list of friend assemblies that are allowed to access
2001 * the assembly's internal types and members. They are stored as assembly
2002 * names in custom attributes.
2004 * This is an internal method, we need this because when we load mscorlib
2005 * we do not have the internals visible cattr loaded yet,
2006 * so we need to load these after we initialize the runtime.
2008 * LOCKING: Acquires the assemblies lock plus the loader lock.
2011 mono_assembly_load_friends (MonoAssembly* ass)
2015 MonoCustomAttrInfo* attrs;
2018 if (ass->friend_assembly_names_inited)
2021 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
2022 mono_error_assert_ok (&error);
2024 mono_assemblies_lock ();
2025 ass->friend_assembly_names_inited = TRUE;
2026 mono_assemblies_unlock ();
2030 mono_assemblies_lock ();
2031 if (ass->friend_assembly_names_inited) {
2032 mono_assemblies_unlock ();
2035 mono_assemblies_unlock ();
2039 * We build the list outside the assemblies lock, the worse that can happen
2040 * is that we'll need to free the allocated list.
2042 for (i = 0; i < attrs->num_attrs; ++i) {
2043 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2044 MonoAssemblyName *aname;
2046 /* Do some sanity checking */
2047 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
2049 if (attr->data_size < 4)
2051 data = (const char*)attr->data;
2052 /* 0xFF means null string, see custom attr format */
2053 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
2055 mono_metadata_decode_value (data + 2, &data);
2056 aname = g_new0 (MonoAssemblyName, 1);
2057 /*g_print ("friend ass: %s\n", data);*/
2058 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
2059 list = g_slist_prepend (list, aname);
2064 mono_custom_attrs_free (attrs);
2066 mono_assemblies_lock ();
2067 if (ass->friend_assembly_names_inited) {
2068 mono_assemblies_unlock ();
2069 g_slist_foreach (list, free_item, NULL);
2070 g_slist_free (list);
2073 ass->friend_assembly_names = list;
2075 /* Because of the double checked locking pattern above */
2076 mono_memory_barrier ();
2077 ass->friend_assembly_names_inited = TRUE;
2078 mono_assemblies_unlock ();
2081 struct HasReferenceAssemblyAttributeIterData {
2086 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
2088 gboolean stop_scanning = FALSE;
2089 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
2091 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
2092 /* Note we don't check the assembly name, same as coreCLR. */
2093 iter_data->has_attr = TRUE;
2094 stop_scanning = TRUE;
2097 return stop_scanning;
2101 * mono_assembly_has_reference_assembly_attribute:
2102 * \param assembly a MonoAssembly
2103 * \param error set on error.
2105 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2106 * On error returns FALSE and sets \p error.
2109 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
2114 * This might be called during assembly loading, so do everything using the low-level
2118 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
2120 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
2122 return iter_data.has_attr;
2126 * mono_assembly_open:
2127 * \param filename Opens the assembly pointed out by this name
2128 * \param status return status code
2130 * This loads an assembly from the specified \p filename. The \p filename allows
2131 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2132 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2133 * is treated as a local path.
2135 * First, an attempt is made to load the assembly from the bundled executable (for those
2136 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2137 * assembly has been registered as an embedded assembly). If this is not the case, then
2138 * the assembly is loaded from disk using `api:mono_image_open_full`.
2140 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2141 * the assembly is made.
2143 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2144 * assembly or NULL on error. Details about the error are stored in the
2145 * \p status variable.
2148 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2150 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2154 * mono_assembly_load_from_full:
2155 * \param image Image to load the assembly from
2156 * \param fname assembly name to associate with the assembly
2157 * \param status returns the status condition
2158 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2160 * If the provided \p image has an assembly reference, it will process the given
2161 * image as an assembly with the given name.
2163 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2165 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2166 * set to \c MONO_IMAGE_OK; or NULL on error.
2168 * If there is an error loading the assembly the \p status will indicate the
2169 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2170 * image did not contain an assembly reference table.
2173 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2174 MonoImageOpenStatus *status, gboolean refonly)
2176 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2180 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2182 MonoAssemblyCandidatePredicate predicate,
2184 MonoImageOpenStatus *status)
2186 MonoAssembly *ass, *ass2;
2189 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2190 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2191 *status = MONO_IMAGE_IMAGE_INVALID;
2195 #if defined (HOST_WIN32)
2200 tmp_fn = g_strdup (fname);
2201 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2202 if (tmp_fn [i] == '/')
2206 base_dir = absolute_dir (tmp_fn);
2210 base_dir = absolute_dir (fname);
2214 * Create assembly struct, and enter it into the assembly cache
2216 ass = g_new0 (MonoAssembly, 1);
2217 ass->basedir = base_dir;
2218 ass->ref_only = refonly;
2221 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2223 mono_assembly_fill_assembly_name (image, &ass->aname);
2225 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2226 // MS.NET doesn't support loading other mscorlibs
2229 mono_image_addref (mono_defaults.corlib);
2230 *status = MONO_IMAGE_OK;
2231 return mono_defaults.corlib->assembly;
2234 /* Add a non-temporary reference because of ass->image */
2235 mono_image_addref (image);
2237 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);
2240 * The load hooks might take locks so we can't call them while holding the
2243 if (ass->aname.name) {
2244 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2248 mono_image_close (image);
2249 *status = MONO_IMAGE_OK;
2254 /* We need to check for ReferenceAssmeblyAttribute before we
2255 * mark the assembly as loaded and before we fire the load
2256 * hook. Otherwise mono_domain_fire_assembly_load () in
2257 * appdomain.c will cache a mapping from the assembly name to
2258 * this image and we won't be able to look for a different
2262 MonoError refasm_error;
2263 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2264 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2267 mono_image_close (image);
2268 *status = MONO_IMAGE_IMAGE_INVALID;
2271 mono_error_cleanup (&refasm_error);
2274 if (predicate && !predicate (ass, user_data)) {
2275 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2278 mono_image_close (image);
2279 *status = MONO_IMAGE_IMAGE_INVALID;
2283 mono_assemblies_lock ();
2285 if (image->assembly) {
2287 * This means another thread has already loaded the assembly, but not yet
2288 * called the load hooks so the search hook can't find the assembly.
2290 mono_assemblies_unlock ();
2291 ass2 = image->assembly;
2294 mono_image_close (image);
2295 *status = MONO_IMAGE_OK;
2299 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2301 image->assembly = ass;
2303 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2304 mono_assemblies_unlock ();
2307 if (image->is_module_handle)
2308 mono_image_fixup_vtable (image);
2311 mono_assembly_invoke_load_hook (ass);
2313 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2319 * mono_assembly_load_from:
2320 * \param image Image to load the assembly from
2321 * \param fname assembly name to associate with the assembly
2322 * \param status return status code
2324 * If the provided \p image has an assembly reference, it will process the given
2325 * image as an assembly with the given name.
2327 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2329 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2330 * \p refonly parameter set to FALSE.
2331 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2332 * set to \c MONO_IMAGE_OK; or NULL on error.
2334 * If there is an error loading the assembly the \p status will indicate the
2335 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2336 * image did not contain an assembly reference table.
2340 mono_assembly_load_from (MonoImage *image, const char *fname,
2341 MonoImageOpenStatus *status)
2343 return mono_assembly_load_from_full (image, fname, status, FALSE);
2347 * mono_assembly_name_free:
2348 * \param aname assembly name to free
2350 * Frees the provided assembly name object.
2351 * (it does not frees the object itself, only the name members).
2354 mono_assembly_name_free (MonoAssemblyName *aname)
2359 g_free ((void *) aname->name);
2360 g_free ((void *) aname->culture);
2361 g_free ((void *) aname->hash_value);
2362 g_free ((guint8*) aname->public_key);
2366 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2369 gchar header [16], val, *arr;
2370 gint i, j, offset, bitlen, keylen, pkeylen;
2372 keylen = strlen (key) >> 1;
2376 /* allow the ECMA standard key */
2377 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2379 *pubkey = g_strdup (key);
2385 val = g_ascii_xdigit_value (key [0]) << 4;
2386 val |= g_ascii_xdigit_value (key [1]);
2391 val = g_ascii_xdigit_value (key [24]);
2392 val |= g_ascii_xdigit_value (key [25]);
2404 /* We need the first 16 bytes
2405 * to check whether this key is valid or not */
2406 pkeylen = strlen (pkey) >> 1;
2410 for (i = 0, j = 0; i < 16; i++) {
2411 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2412 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2415 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2416 header [1] != 0x02 || /* Version (0x02) */
2417 header [2] != 0x00 || /* Reserved (word) */
2418 header [3] != 0x00 ||
2419 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2422 /* Based on this length, we _should_ be able to know if the length is right */
2423 bitlen = read32 (header + 12) >> 3;
2424 if ((bitlen + 16 + 4) != pkeylen)
2427 /* parsing is OK and the public key itself is not requested back */
2431 /* Encode the size of the blob */
2433 if (keylen <= 127) {
2434 arr = (gchar *)g_malloc (keylen + 1);
2435 arr [offset++] = keylen;
2437 arr = (gchar *)g_malloc (keylen + 2);
2438 arr [offset++] = 0x80; /* 10bs */
2439 arr [offset++] = keylen;
2442 for (i = offset, j = 0; i < keylen + offset; i++) {
2443 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2444 arr [i] |= g_ascii_xdigit_value (key [j++]);
2453 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 gint major, minor, build, revision;
2458 gchar *pkey, *pkeyptr, *encoded, tok [8];
2460 memset (aname, 0, sizeof (MonoAssemblyName));
2463 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2464 if (version_parts < 2 || version_parts > 4)
2467 /* FIXME: we should set build & revision to -1 (instead of 0)
2468 if these are not set in the version string. That way, later on,
2469 we can still determine if these were specified. */
2470 aname->major = major;
2471 aname->minor = minor;
2472 if (version_parts >= 3)
2473 aname->build = build;
2476 if (version_parts == 4)
2477 aname->revision = revision;
2479 aname->revision = 0;
2482 aname->flags = flags;
2484 aname->name = g_strdup (name);
2487 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2488 aname->culture = g_strdup ("");
2490 aname->culture = g_strdup (culture);
2493 if (token && strncmp (token, "null", 4) != 0) {
2496 /* the constant includes the ending NULL, hence the -1 */
2497 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2498 mono_assembly_name_free (aname);
2501 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2502 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2508 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2509 mono_assembly_name_free (aname);
2514 if (save_public_key)
2515 aname->public_key = (guint8*)pkey;
2518 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
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);
2529 if (save_public_key)
2530 aname->public_key = (guint8*) pkey;
2539 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2544 parts = g_strsplit (dirname, "_", 3);
2545 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2550 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2556 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2558 char *eqsign = strchr (pair, '=');
2566 *key = (gchar*)pair;
2567 *keylen = eqsign - *key;
2568 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2570 *value = g_strstrip (eqsign + 1);
2575 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2579 gchar *version = NULL;
2581 gchar *culture = NULL;
2583 gchar *token = NULL;
2587 gchar *retargetable = NULL;
2588 gchar *retargetable_uq;
2592 gchar *value, *part_name;
2593 guint32 part_name_len;
2596 gboolean version_defined;
2597 gboolean token_defined;
2599 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
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;
2608 parts = tmp = g_strsplit (name, ",", 6);
2609 if (!tmp || !*tmp) {
2614 dllname = g_strstrip (*tmp);
2619 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2620 goto cleanup_and_fail;
2622 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2623 *is_version_defined = TRUE;
2625 if (strlen (version) == 0) {
2626 goto cleanup_and_fail;
2632 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2634 if (strlen (culture) == 0) {
2635 goto cleanup_and_fail;
2641 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2642 *is_token_defined = TRUE;
2644 if (strlen (token) == 0) {
2645 goto cleanup_and_fail;
2651 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2653 if (strlen (key) == 0) {
2654 goto cleanup_and_fail;
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;
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;
2673 g_free (retargetable_uq);
2678 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2680 procarch_uq = unquote (procarch);
2681 if (procarch_uq != NULL)
2682 procarch = procarch_uq;
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;
2693 g_free (procarch_uq);
2694 goto cleanup_and_fail;
2697 g_free (procarch_uq);
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;
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);
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);
2725 g_free (dllname_uq);
2726 g_free (version_uq);
2727 g_free (culture_uq);
2740 unquote (const char *str)
2748 slen = strlen (str);
2752 if (*str != '\'' && *str != '\"')
2755 end = str + slen - 1;
2759 return g_strndup (str + 1, slen - 2);
2763 * mono_assembly_name_parse:
2764 * \param name name to parse
2765 * \param aname the destination assembly name
2767 * Parses an assembly qualified type name and assigns the name,
2768 * version, culture and token to the provided assembly name object.
2770 * \returns TRUE if the name could be parsed.
2773 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2775 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2779 * mono_assembly_name_new:
2780 * \param name name to parse
2782 * Allocate a new \c MonoAssemblyName and fill its values from the
2785 * \returns a newly allocated structure or NULL if there was any failure.
2788 mono_assembly_name_new (const char *name)
2790 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2791 if (mono_assembly_name_parse (name, aname))
2798 * mono_assembly_name_get_name:
2801 mono_assembly_name_get_name (MonoAssemblyName *aname)
2807 * mono_assembly_name_get_culture:
2810 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2812 return aname->culture;
2816 * mono_assembly_name_get_pubkeytoken:
2819 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2821 if (aname->public_key_token [0])
2822 return aname->public_key_token;
2827 * mono_assembly_name_get_version:
2830 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2833 *minor = aname->minor;
2835 *build = aname->build;
2837 *revision = aname->revision;
2838 return aname->major;
2841 static MonoAssembly*
2842 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2844 gchar *fullpath = NULL;
2846 const char* direntry;
2847 MonoAssemblyName gac_aname;
2848 gint major=-1, minor=0, build=0, revision=0;
2849 gboolean exact_version;
2851 dirhandle = g_dir_open (basepath, 0, NULL);
2855 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2857 while ((direntry = g_dir_read_name (dirhandle))) {
2858 gboolean match = TRUE;
2860 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2863 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
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))
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);
2875 else if (gac_aname.major < major)
2877 else if (gac_aname.major == major) {
2878 if (gac_aname.minor < minor)
2880 else if (gac_aname.minor == minor) {
2881 if (gac_aname.build < build)
2883 else if (gac_aname.build == build && gac_aname.revision <= revision)
2890 major = gac_aname.major;
2891 minor = gac_aname.minor;
2892 build = gac_aname.build;
2893 revision = gac_aname.revision;
2895 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2898 mono_assembly_name_free (&gac_aname);
2901 g_dir_close (dirhandle);
2903 if (fullpath == NULL)
2906 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
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
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.
2920 * This will load the assembly from the file whose name is derived from the assembly name
2921 * by appending the \c .dll extension.
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.
2927 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2930 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2934 MonoAssemblyName *aname, base_name;
2935 MonoAssemblyName mapped_aname;
2936 gchar *fullname, *gacpath;
2939 memset (&base_name, 0, sizeof (MonoAssemblyName));
2942 if (!mono_assembly_name_parse (name, aname))
2946 * If no specific version has been requested, make sure we load the
2947 * correct version for system assemblies.
2949 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2950 aname = mono_assembly_remap_version (aname, &mapped_aname);
2952 res = mono_assembly_loaded (aname);
2954 mono_assembly_name_free (aname);
2958 res = invoke_assembly_preload_hook (aname, assemblies_path);
2960 res->in_gac = FALSE;
2961 mono_assembly_name_free (aname);
2965 fullname = g_strdup_printf ("%s.dll", aname->name);
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);
2980 mono_assembly_name_free (aname);
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);
2989 mono_assembly_name_free (aname);
2994 MonoDomain *domain = mono_domain_get ();
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;
3008 mono_assembly_is_in_gac (const gchar *filename)
3010 const gchar *rootdir;
3014 if (filename == NULL)
3017 for (paths = extra_gac_paths; paths && *paths; paths++) {
3018 if (strstr (*paths, filename) != *paths)
3021 gp = (gchar *) (filename + strlen (*paths));
3022 if (*gp != G_DIR_SEPARATOR)
3025 if (strncmp (gp, "lib", 3))
3028 if (*gp != G_DIR_SEPARATOR)
3031 if (strncmp (gp, "mono", 4))
3034 if (*gp != G_DIR_SEPARATOR)
3037 if (strncmp (gp, "gac", 3))
3040 if (*gp != G_DIR_SEPARATOR)
3046 rootdir = mono_assembly_getrootdir ();
3047 if (strstr (filename, rootdir) != filename)
3050 gp = (gchar *) (filename + strlen (rootdir));
3051 if (*gp != G_DIR_SEPARATOR)
3054 if (strncmp (gp, "mono", 4))
3057 if (*gp != G_DIR_SEPARATOR)
3060 if (strncmp (gp, "gac", 3))
3063 if (*gp != G_DIR_SEPARATOR)
3069 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3072 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
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);
3082 name = g_strdup (aname->name);
3085 culture = g_utf8_strdown (aname->culture, -1);
3087 culture = g_strdup ("");
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);
3094 filename = g_strconcat (pname, ".dll", NULL);
3095 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, 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);
3117 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3118 "mono", "gac", subpath, NULL);
3119 image = mono_image_open (fullpath, NULL);
3126 static MonoAssemblyName*
3127 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
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;
3138 /* LOCKING: assembly_binding lock must be held */
3139 static MonoAssemblyBindingInfo*
3140 search_binding_loaded (MonoAssemblyName *aname)
3144 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3145 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3146 if (assembly_binding_maps_name (info, aname))
3153 static inline gboolean
3154 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3156 if (left->major != right->major || left->minor != right->minor ||
3157 left->build != right->build || left->revision != right->revision)
3163 static inline gboolean
3164 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3166 if (left->has_old_version_bottom != right->has_old_version_bottom)
3169 if (left->has_old_version_top != right->has_old_version_top)
3172 if (left->has_new_version != right->has_new_version)
3175 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3178 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3181 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3187 /* LOCKING: assumes all the necessary locks are held */
3189 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3191 MonoAssemblyBindingInfo *info_copy;
3193 MonoAssemblyBindingInfo *info_tmp;
3194 MonoDomain *domain = (MonoDomain*)user_data;
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);
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))
3211 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3212 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3214 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3216 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3218 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3222 get_version_number (int major, int minor)
3224 return major * 256 + minor;
3227 static inline gboolean
3228 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3230 int aname_version_number = get_version_number (aname->major, aname->minor);
3231 if (!info->has_old_version_bottom)
3234 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3237 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
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;
3247 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3248 static MonoAssemblyBindingInfo*
3249 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3251 MonoAssemblyBindingInfo *info;
3254 if (!domain->assembly_bindings)
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))
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;
3270 info->is_valid = FALSE;
3277 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3279 if (domain->assembly_bindings_parsed)
3281 mono_domain_lock (domain);
3282 if (!domain->assembly_bindings_parsed) {
3284 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3286 if (!domain_config_file_path)
3287 domain_config_file_path = domain_config_file_name;
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);
3295 mono_domain_unlock (domain);
3298 static MonoAssemblyName*
3299 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3302 MonoAssemblyBindingInfo *info, *info2;
3306 if (aname->public_key_token [0] == 0)
3309 domain = mono_domain_get ();
3311 mono_assembly_binding_lock ();
3312 info = search_binding_loaded (aname);
3313 mono_assembly_binding_unlock ();
3316 mono_domain_lock (domain);
3317 info = get_per_domain_assembly_binding_info (domain, aname);
3318 mono_domain_unlock (domain);
3322 if (!check_policy_versions (info, aname))
3325 mono_assembly_bind_version (info, aname, dest_name);
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);
3337 mono_domain_lock (domain);
3338 info2 = get_per_domain_assembly_binding_info (domain, aname);
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;
3347 mono_domain_unlock (domain);
3352 info = g_new0 (MonoAssemblyBindingInfo, 1);
3353 info->major = aname->major;
3354 info->minor = aname->minor;
3357 if (!info->is_valid) {
3358 ppimage = mono_assembly_load_publisher_policy (aname);
3360 get_publisher_policy_info (ppimage, aname, info);
3361 mono_image_close (ppimage);
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);
3372 mono_assembly_binding_lock ();
3373 info2 = search_binding_loaded (aname);
3375 /* This binding was added by another thread
3377 mono_assembly_binding_info_free (info);
3382 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3384 mono_assembly_binding_unlock ();
3386 if (!info->is_valid || !check_policy_versions (info, aname))
3389 mono_assembly_bind_version (info, aname, dest_name);
3394 * mono_assembly_load_from_gac
3396 * \param aname The assembly name object
3398 static MonoAssembly*
3399 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3401 MonoAssembly *result = NULL;
3402 gchar *name, *version, *culture, *fullpath, *subpath;
3407 if (aname->public_key_token [0] == 0) {
3411 if (strstr (aname->name, ".dll")) {
3412 len = strlen (filename) - 4;
3413 name = (gchar *)g_malloc (len + 1);
3414 memcpy (name, aname->name, len);
3417 name = g_strdup (aname->name);
3420 if (aname->culture) {
3421 culture = g_utf8_strdown (aname->culture, -1);
3423 culture = g_strdup ("");
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,
3432 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
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);
3448 result->in_gac = TRUE;
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);
3459 result->in_gac = TRUE;
3467 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3470 MonoAssemblyName *aname;
3473 /* g_print ("corlib already loaded\n"); */
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);
3483 goto return_corlib_and_facades;
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);
3489 goto return_corlib_and_facades;
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);
3497 g_free (corlib_file);
3498 goto return_corlib_and_facades;
3501 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3502 g_free (corlib_file);
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);
3511 static MonoAssembly*
3512 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3514 MonoError refasm_error;
3515 error_init (&refasm_error);
3516 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3519 mono_error_cleanup (&refasm_error);
3524 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3526 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3527 MonoAssemblyName *candidate_name = &candidate->aname;
3529 g_assert (wanted_name != NULL);
3530 g_assert (candidate_name != NULL);
3532 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3533 char * s = mono_stringify_assembly_name (wanted_name);
3534 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3536 s = mono_stringify_assembly_name (candidate_name);
3537 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3542 /* Wanted name has no token, not strongly named: always matches. */
3543 if (0 == wanted_name->public_key_token [0]) {
3544 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3548 /* Candidate name has no token, not strongly named: never matches */
3549 if (0 == candidate_name->public_key_token [0]) {
3550 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3554 return exact_sn_match (wanted_name, candidate_name) ||
3555 framework_assembly_sn_match (wanted_name, candidate_name);
3559 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3561 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3563 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3564 result ? "match, returning TRUE" : "don't match, returning FALSE");
3570 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3572 #ifndef DISABLE_DESKTOP_LOADER
3573 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3575 if (!vmap->framework_facade_assembly) {
3576 /* 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. */
3577 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3578 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");
3581 /* For facades, the name and public key token should
3582 * match, but the version doesn't matter. */
3583 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3584 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");
3593 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3594 const char *basedir,
3595 MonoImageOpenStatus *status,
3598 MonoAssembly *result;
3599 char *fullpath, *filename;
3600 MonoAssemblyName maped_aname;
3601 MonoAssemblyName maped_name_pp;
3606 aname = mono_assembly_remap_version (aname, &maped_aname);
3608 /* Reflection only assemblies don't get assembly binding */
3610 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3612 result = mono_assembly_loaded_full (aname, refonly);
3616 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3618 result->in_gac = FALSE;
3622 /* Currently we retrieve the loaded corlib for reflection
3623 * only requests, like a common reflection only assembly
3625 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3626 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3629 MonoAssemblyCandidatePredicate predicate = NULL;
3630 void* predicate_ud = NULL;
3631 #if !defined(DISABLE_DESKTOP_LOADER)
3632 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
3633 predicate = &mono_assembly_candidate_predicate_sn_same_name;
3634 predicate_ud = aname;
3638 len = strlen (aname->name);
3639 for (ext_index = 0; ext_index < 2; ext_index ++) {
3640 ext = ext_index == 0 ? ".dll" : ".exe";
3641 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3642 filename = g_strdup (aname->name);
3643 /* Don't try appending .dll/.exe if it already has one of those extensions */
3646 filename = g_strconcat (aname->name, ext, NULL);
3649 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3656 fullpath = g_build_filename (basedir, filename, NULL);
3657 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, predicate_ud, status);
3660 result->in_gac = FALSE;
3666 result = load_in_path (filename, default_path, status, refonly, predicate, predicate_ud);
3668 result->in_gac = FALSE;
3678 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3680 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3683 /* Try a postload search hook */
3684 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3685 result = prevent_reference_assembly_from_running (result, refonly);
3691 * mono_assembly_load_full:
3692 * \param aname A MonoAssemblyName with the assembly name to load.
3693 * \param basedir A directory to look up the assembly at.
3694 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3695 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3697 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3698 * attempts to load the assembly from that directory before probing the standard locations.
3700 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3701 * assembly binding takes place.
3703 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3704 * value pointed by \p status is updated with an error code.
3707 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3709 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3713 * mono_assembly_load:
3714 * \param aname A MonoAssemblyName with the assembly name to load.
3715 * \param basedir A directory to look up the assembly at.
3716 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3718 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3719 * attempts to load the assembly from that directory before probing the standard locations.
3721 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3722 * value pointed by \p status is updated with an error code.
3725 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3727 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3731 * mono_assembly_loaded_full:
3732 * \param aname an assembly to look for.
3733 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3735 * This is used to determine if the specified assembly has been loaded
3736 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3737 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3740 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3743 MonoAssemblyName maped_aname;
3745 aname = mono_assembly_remap_version (aname, &maped_aname);
3747 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3753 * mono_assembly_loaded:
3754 * \param aname an assembly to look for.
3756 * This is used to determine if the specified assembly has been loaded
3758 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3759 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3762 mono_assembly_loaded (MonoAssemblyName *aname)
3764 return mono_assembly_loaded_full (aname, FALSE);
3768 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3770 if (assembly == NULL || assembly == REFERENCE_MISSING)
3773 if (assembly_is_dynamic (assembly)) {
3775 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3776 for (i = 0; i < dynimg->image.module_count; ++i)
3777 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3778 mono_dynamic_image_release_gc_roots (dynimg);
3783 * Returns whether mono_assembly_close_finish() must be called as
3784 * well. See comment for mono_image_close_except_pools() for why we
3785 * unload in two steps.
3788 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3791 g_return_val_if_fail (assembly != NULL, FALSE);
3793 if (assembly == REFERENCE_MISSING)
3796 /* Might be 0 already */
3797 if (InterlockedDecrement (&assembly->ref_count) > 0)
3800 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3802 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3804 mono_debug_close_image (assembly->image);
3806 mono_assemblies_lock ();
3807 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3808 mono_assemblies_unlock ();
3810 assembly->image->assembly = NULL;
3812 if (!mono_image_close_except_pools (assembly->image))
3813 assembly->image = NULL;
3815 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3816 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3817 mono_assembly_name_free (fname);
3820 g_slist_free (assembly->friend_assembly_names);
3821 g_free (assembly->basedir);
3823 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3829 mono_assembly_close_finish (MonoAssembly *assembly)
3831 g_assert (assembly && assembly != REFERENCE_MISSING);
3833 if (assembly->image)
3834 mono_image_close_finish (assembly->image);
3836 if (assembly_is_dynamic (assembly)) {
3837 g_free ((char*)assembly->aname.culture);
3844 * mono_assembly_close:
3845 * \param assembly the assembly to release.
3847 * This method releases a reference to the \p assembly. The assembly is
3848 * only released when all the outstanding references to it are released.
3851 mono_assembly_close (MonoAssembly *assembly)
3853 if (mono_assembly_close_except_image_pools (assembly))
3854 mono_assembly_close_finish (assembly);
3858 * mono_assembly_load_module:
3861 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3864 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3865 mono_error_assert_ok (&error);
3870 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3872 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3877 * mono_assembly_foreach:
3878 * \param func function to invoke for each assembly loaded
3879 * \param user_data data passed to the callback
3881 * Invokes the provided \p func callback for each assembly loaded into
3882 * the runtime. The first parameter passed to the callback is the
3883 * \c MonoAssembly*, and the second parameter is the \p user_data.
3885 * This is done for all assemblies loaded in the runtime, not just
3886 * those loaded in the current application domain.
3889 mono_assembly_foreach (GFunc func, gpointer user_data)
3894 * We make a copy of the list to avoid calling the callback inside the
3895 * lock, which could lead to deadlocks.
3897 mono_assemblies_lock ();
3898 copy = g_list_copy (loaded_assemblies);
3899 mono_assemblies_unlock ();
3901 g_list_foreach (loaded_assemblies, func, user_data);
3907 * mono_assemblies_cleanup:
3909 * Free all resources used by this module.
3912 mono_assemblies_cleanup (void)
3916 mono_os_mutex_destroy (&assemblies_mutex);
3917 mono_os_mutex_destroy (&assembly_binding_mutex);
3919 for (l = loaded_assembly_bindings; l; l = l->next) {
3920 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3922 mono_assembly_binding_info_free (info);
3925 g_slist_free (loaded_assembly_bindings);
3927 free_assembly_load_hooks ();
3928 free_assembly_search_hooks ();
3929 free_assembly_preload_hooks ();
3932 /*LOCKING takes the assembly_binding lock*/
3934 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3938 mono_assembly_binding_lock ();
3939 iter = &loaded_assembly_bindings;
3942 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3944 if (info->domain_id == domain_id) {
3946 mono_assembly_binding_info_free (info);
3953 mono_assembly_binding_unlock ();
3957 * Holds the assembly of the application, for
3958 * System.Diagnostics.Process::MainModule
3960 static MonoAssembly *main_assembly=NULL;
3963 * mono_assembly_set_main:
3966 mono_assembly_set_main (MonoAssembly *assembly)
3968 main_assembly = assembly;
3972 * mono_assembly_get_main:
3974 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3977 mono_assembly_get_main (void)
3979 return (main_assembly);
3983 * mono_assembly_get_image:
3984 * \param assembly The assembly to retrieve the image from
3986 * \returns the \c MonoImage associated with this assembly.
3989 mono_assembly_get_image (MonoAssembly *assembly)
3991 return assembly->image;
3995 * mono_assembly_get_name:
3996 * \param assembly The assembly to retrieve the name from
3998 * The returned name's lifetime is the same as \p assembly's.
4000 * \returns the \c MonoAssemblyName associated with this assembly.
4003 mono_assembly_get_name (MonoAssembly *assembly)
4005 return &assembly->aname;
4009 * mono_register_bundled_assemblies:
4012 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4014 bundles = assemblies;
4017 #define MONO_DECLSEC_FORMAT_10 0x3C
4018 #define MONO_DECLSEC_FORMAT_20 0x2E
4019 #define MONO_DECLSEC_FIELD 0x53
4020 #define MONO_DECLSEC_PROPERTY 0x54
4022 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4023 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4024 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4025 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4026 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4029 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4033 case MONO_DECLSEC_PROPERTY:
4035 case MONO_DECLSEC_FIELD:
4037 *abort_decoding = TRUE;
4042 if (*p++ != MONO_TYPE_BOOLEAN) {
4043 *abort_decoding = TRUE;
4047 /* property name length */
4048 len = mono_metadata_decode_value (p, &p);
4050 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4061 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4063 int i, j, num, len, params_len;
4065 if (*p == MONO_DECLSEC_FORMAT_10) {
4066 gsize read, written;
4067 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4069 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4075 if (*p++ != MONO_DECLSEC_FORMAT_20)
4078 /* number of encoded permission attributes */
4079 num = mono_metadata_decode_value (p, &p);
4080 for (i = 0; i < num; ++i) {
4081 gboolean is_valid = FALSE;
4082 gboolean abort_decoding = FALSE;
4084 /* attribute name length */
4085 len = mono_metadata_decode_value (p, &p);
4087 /* We don't really need to fully decode the type. Comparing the name is enough */
4088 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4092 /*size of the params table*/
4093 params_len = mono_metadata_decode_value (p, &p);
4095 const char *params_end = p + params_len;
4097 /* number of parameters */
4098 len = mono_metadata_decode_value (p, &p);
4100 for (j = 0; j < len; ++j) {
4101 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4117 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4120 guint32 cols [MONO_DECL_SECURITY_SIZE];
4124 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4125 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4127 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4129 for (i = 0; i < t->rows; ++i) {
4130 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4131 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4133 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4136 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4137 len = mono_metadata_decode_blob_size (blob, &blob);
4141 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4142 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4147 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);