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)
2111 g_assert (assembly && assembly->image);
2112 /* .NET Framework appears to ignore the attribute on dynamic
2113 * assemblies, so don't call this function for dynamic assemblies. */
2114 g_assert (!image_is_dynamic (assembly->image));
2118 * This might be called during assembly loading, so do everything using the low-level
2122 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
2124 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
2126 return iter_data.has_attr;
2130 * mono_assembly_open:
2131 * \param filename Opens the assembly pointed out by this name
2132 * \param status return status code
2134 * This loads an assembly from the specified \p filename. The \p filename allows
2135 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2136 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2137 * is treated as a local path.
2139 * First, an attempt is made to load the assembly from the bundled executable (for those
2140 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2141 * assembly has been registered as an embedded assembly). If this is not the case, then
2142 * the assembly is loaded from disk using `api:mono_image_open_full`.
2144 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2145 * the assembly is made.
2147 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2148 * assembly or NULL on error. Details about the error are stored in the
2149 * \p status variable.
2152 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2154 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2158 * mono_assembly_load_from_full:
2159 * \param image Image to load the assembly from
2160 * \param fname assembly name to associate with the assembly
2161 * \param status returns the status condition
2162 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2164 * If the provided \p image has an assembly reference, it will process the given
2165 * image as an assembly with the given name.
2167 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2169 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2170 * set to \c MONO_IMAGE_OK; or NULL on error.
2172 * If there is an error loading the assembly the \p status will indicate the
2173 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2174 * image did not contain an assembly reference table.
2177 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2178 MonoImageOpenStatus *status, gboolean refonly)
2180 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2184 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2186 MonoAssemblyCandidatePredicate predicate,
2188 MonoImageOpenStatus *status)
2190 MonoAssembly *ass, *ass2;
2193 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2194 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2195 *status = MONO_IMAGE_IMAGE_INVALID;
2199 #if defined (HOST_WIN32)
2204 tmp_fn = g_strdup (fname);
2205 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2206 if (tmp_fn [i] == '/')
2210 base_dir = absolute_dir (tmp_fn);
2214 base_dir = absolute_dir (fname);
2218 * Create assembly struct, and enter it into the assembly cache
2220 ass = g_new0 (MonoAssembly, 1);
2221 ass->basedir = base_dir;
2222 ass->ref_only = refonly;
2225 MONO_PROFILER_RAISE (assembly_loading, (ass));
2227 mono_assembly_fill_assembly_name (image, &ass->aname);
2229 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2230 // MS.NET doesn't support loading other mscorlibs
2233 mono_image_addref (mono_defaults.corlib);
2234 *status = MONO_IMAGE_OK;
2235 return mono_defaults.corlib->assembly;
2238 /* Add a non-temporary reference because of ass->image */
2239 mono_image_addref (image);
2241 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);
2244 * The load hooks might take locks so we can't call them while holding the
2247 if (ass->aname.name) {
2248 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2252 mono_image_close (image);
2253 *status = MONO_IMAGE_OK;
2258 /* We need to check for ReferenceAssmeblyAttribute before we
2259 * mark the assembly as loaded and before we fire the load
2260 * hook. Otherwise mono_domain_fire_assembly_load () in
2261 * appdomain.c will cache a mapping from the assembly name to
2262 * this image and we won't be able to look for a different
2266 MonoError refasm_error;
2267 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2268 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2271 mono_image_close (image);
2272 *status = MONO_IMAGE_IMAGE_INVALID;
2275 mono_error_cleanup (&refasm_error);
2278 if (predicate && !predicate (ass, user_data)) {
2279 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2282 mono_image_close (image);
2283 *status = MONO_IMAGE_IMAGE_INVALID;
2287 mono_assemblies_lock ();
2289 if (image->assembly) {
2291 * This means another thread has already loaded the assembly, but not yet
2292 * called the load hooks so the search hook can't find the assembly.
2294 mono_assemblies_unlock ();
2295 ass2 = image->assembly;
2298 mono_image_close (image);
2299 *status = MONO_IMAGE_OK;
2303 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2305 image->assembly = ass;
2307 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2308 mono_assemblies_unlock ();
2311 if (image->is_module_handle)
2312 mono_image_fixup_vtable (image);
2315 mono_assembly_invoke_load_hook (ass);
2317 MONO_PROFILER_RAISE (assembly_loaded, (ass));
2323 * mono_assembly_load_from:
2324 * \param image Image to load the assembly from
2325 * \param fname assembly name to associate with the assembly
2326 * \param status return status code
2328 * If the provided \p image has an assembly reference, it will process the given
2329 * image as an assembly with the given name.
2331 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2333 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2334 * \p refonly parameter set to FALSE.
2335 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2336 * set to \c MONO_IMAGE_OK; or NULL on error.
2338 * If there is an error loading the assembly the \p status will indicate the
2339 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2340 * image did not contain an assembly reference table.
2344 mono_assembly_load_from (MonoImage *image, const char *fname,
2345 MonoImageOpenStatus *status)
2347 return mono_assembly_load_from_full (image, fname, status, FALSE);
2351 * mono_assembly_name_free:
2352 * \param aname assembly name to free
2354 * Frees the provided assembly name object.
2355 * (it does not frees the object itself, only the name members).
2358 mono_assembly_name_free (MonoAssemblyName *aname)
2363 g_free ((void *) aname->name);
2364 g_free ((void *) aname->culture);
2365 g_free ((void *) aname->hash_value);
2366 g_free ((guint8*) aname->public_key);
2370 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2373 gchar header [16], val, *arr, *endp;
2374 gint i, j, offset, bitlen, keylen, pkeylen;
2376 keylen = strlen (key) >> 1;
2380 /* allow the ECMA standard key */
2381 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2383 *pubkey = g_strdup (key);
2389 val = g_ascii_xdigit_value (key [0]) << 4;
2390 val |= g_ascii_xdigit_value (key [1]);
2395 val = g_ascii_xdigit_value (key [24]);
2396 val |= g_ascii_xdigit_value (key [25]);
2408 /* We need the first 16 bytes
2409 * to check whether this key is valid or not */
2410 pkeylen = strlen (pkey) >> 1;
2414 for (i = 0, j = 0; i < 16; i++) {
2415 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2416 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2419 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2420 header [1] != 0x02 || /* Version (0x02) */
2421 header [2] != 0x00 || /* Reserved (word) */
2422 header [3] != 0x00 ||
2423 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2426 /* Based on this length, we _should_ be able to know if the length is right */
2427 bitlen = read32 (header + 12) >> 3;
2428 if ((bitlen + 16 + 4) != pkeylen)
2431 /* parsing is OK and the public key itself is not requested back */
2435 arr = (gchar *)g_malloc (keylen + 4);
2436 /* Encode the size of the blob */
2437 mono_metadata_encode_value (keylen, &arr[0], &endp);
2438 offset = (gint)(endp-arr);
2440 for (i = offset, j = 0; i < keylen + offset; i++) {
2441 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2442 arr [i] |= g_ascii_xdigit_value (key [j++]);
2451 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)
2453 gint major, minor, build, revision;
2456 gchar *pkey, *pkeyptr, *encoded, tok [8];
2458 memset (aname, 0, sizeof (MonoAssemblyName));
2461 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2462 if (version_parts < 2 || version_parts > 4)
2465 /* FIXME: we should set build & revision to -1 (instead of 0)
2466 if these are not set in the version string. That way, later on,
2467 we can still determine if these were specified. */
2468 aname->major = major;
2469 aname->minor = minor;
2470 if (version_parts >= 3)
2471 aname->build = build;
2474 if (version_parts == 4)
2475 aname->revision = revision;
2477 aname->revision = 0;
2480 aname->flags = flags;
2482 aname->name = g_strdup (name);
2485 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2486 aname->culture = g_strdup ("");
2488 aname->culture = g_strdup (culture);
2491 if (token && strncmp (token, "null", 4) != 0) {
2494 /* the constant includes the ending NULL, hence the -1 */
2495 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2496 mono_assembly_name_free (aname);
2499 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2500 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2506 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2507 mono_assembly_name_free (aname);
2512 if (save_public_key)
2513 aname->public_key = (guint8*)pkey;
2516 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2520 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2521 // We also need to generate the key token
2522 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2523 encoded = encode_public_tok ((guchar*) tok, 8);
2524 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2527 if (save_public_key)
2528 aname->public_key = (guint8*) pkey;
2537 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2542 parts = g_strsplit (dirname, "_", 3);
2543 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2548 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2554 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2556 char *eqsign = strchr (pair, '=');
2564 *key = (gchar*)pair;
2565 *keylen = eqsign - *key;
2566 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2568 *value = g_strstrip (eqsign + 1);
2573 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2577 gchar *version = NULL;
2579 gchar *culture = NULL;
2581 gchar *token = NULL;
2585 gchar *retargetable = NULL;
2586 gchar *retargetable_uq;
2590 gchar *value, *part_name;
2591 guint32 part_name_len;
2594 gboolean version_defined;
2595 gboolean token_defined;
2597 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2599 if (!is_version_defined)
2600 is_version_defined = &version_defined;
2601 *is_version_defined = FALSE;
2602 if (!is_token_defined)
2603 is_token_defined = &token_defined;
2604 *is_token_defined = FALSE;
2606 parts = tmp = g_strsplit (name, ",", 6);
2607 if (!tmp || !*tmp) {
2612 dllname = g_strstrip (*tmp);
2617 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2618 goto cleanup_and_fail;
2620 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2621 *is_version_defined = TRUE;
2623 if (strlen (version) == 0) {
2624 goto cleanup_and_fail;
2630 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2632 if (strlen (culture) == 0) {
2633 goto cleanup_and_fail;
2639 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2640 *is_token_defined = TRUE;
2642 if (strlen (token) == 0) {
2643 goto cleanup_and_fail;
2649 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2651 if (strlen (key) == 0) {
2652 goto cleanup_and_fail;
2658 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2659 retargetable = value;
2660 retargetable_uq = unquote (retargetable);
2661 if (retargetable_uq != NULL)
2662 retargetable = retargetable_uq;
2664 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2665 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2666 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2667 g_free (retargetable_uq);
2668 goto cleanup_and_fail;
2671 g_free (retargetable_uq);
2676 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2678 procarch_uq = unquote (procarch);
2679 if (procarch_uq != NULL)
2680 procarch = procarch_uq;
2682 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2683 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2684 else if (!g_ascii_strcasecmp (procarch, "X86"))
2685 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2686 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2687 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2688 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2689 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2691 g_free (procarch_uq);
2692 goto cleanup_and_fail;
2695 g_free (procarch_uq);
2704 /* if retargetable flag is set, then we must have a fully qualified name */
2705 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2706 goto cleanup_and_fail;
2709 dllname_uq = unquote (dllname);
2710 version_uq = unquote (version);
2711 culture_uq = unquote (culture);
2712 token_uq = unquote (token);
2713 key_uq = unquote (key);
2715 res = build_assembly_name (
2716 dllname_uq == NULL ? dllname : dllname_uq,
2717 version_uq == NULL ? version : version_uq,
2718 culture_uq == NULL ? culture : culture_uq,
2719 token_uq == NULL ? token : token_uq,
2720 key_uq == NULL ? key : key_uq,
2721 flags, arch, aname, save_public_key);
2723 g_free (dllname_uq);
2724 g_free (version_uq);
2725 g_free (culture_uq);
2738 unquote (const char *str)
2746 slen = strlen (str);
2750 if (*str != '\'' && *str != '\"')
2753 end = str + slen - 1;
2757 return g_strndup (str + 1, slen - 2);
2761 * mono_assembly_name_parse:
2762 * \param name name to parse
2763 * \param aname the destination assembly name
2765 * Parses an assembly qualified type name and assigns the name,
2766 * version, culture and token to the provided assembly name object.
2768 * \returns TRUE if the name could be parsed.
2771 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2773 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2777 * mono_assembly_name_new:
2778 * \param name name to parse
2780 * Allocate a new \c MonoAssemblyName and fill its values from the
2783 * \returns a newly allocated structure or NULL if there was any failure.
2786 mono_assembly_name_new (const char *name)
2788 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2789 if (mono_assembly_name_parse (name, aname))
2796 * mono_assembly_name_get_name:
2799 mono_assembly_name_get_name (MonoAssemblyName *aname)
2805 * mono_assembly_name_get_culture:
2808 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2810 return aname->culture;
2814 * mono_assembly_name_get_pubkeytoken:
2817 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2819 if (aname->public_key_token [0])
2820 return aname->public_key_token;
2825 * mono_assembly_name_get_version:
2828 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2831 *minor = aname->minor;
2833 *build = aname->build;
2835 *revision = aname->revision;
2836 return aname->major;
2839 static MonoAssembly*
2840 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2842 gchar *fullpath = NULL;
2844 const char* direntry;
2845 MonoAssemblyName gac_aname;
2846 gint major=-1, minor=0, build=0, revision=0;
2847 gboolean exact_version;
2849 dirhandle = g_dir_open (basepath, 0, NULL);
2853 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2855 while ((direntry = g_dir_read_name (dirhandle))) {
2856 gboolean match = TRUE;
2858 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2861 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2864 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2865 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2869 if (exact_version) {
2870 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2871 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2873 else if (gac_aname.major < major)
2875 else if (gac_aname.major == major) {
2876 if (gac_aname.minor < minor)
2878 else if (gac_aname.minor == minor) {
2879 if (gac_aname.build < build)
2881 else if (gac_aname.build == build && gac_aname.revision <= revision)
2888 major = gac_aname.major;
2889 minor = gac_aname.minor;
2890 build = gac_aname.build;
2891 revision = gac_aname.revision;
2893 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2896 mono_assembly_name_free (&gac_aname);
2899 g_dir_close (dirhandle);
2901 if (fullpath == NULL)
2904 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2911 * mono_assembly_load_with_partial_name:
2912 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2913 * \param status return status code
2915 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2916 * so it might contain a qualified type name, version, culture and token.
2918 * This will load the assembly from the file whose name is derived from the assembly name
2919 * by appending the \c .dll extension.
2921 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2922 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2923 * if that fails from the GAC.
2925 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2928 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2932 MonoAssemblyName *aname, base_name;
2933 MonoAssemblyName mapped_aname;
2934 gchar *fullname, *gacpath;
2937 memset (&base_name, 0, sizeof (MonoAssemblyName));
2940 if (!mono_assembly_name_parse (name, aname))
2944 * If no specific version has been requested, make sure we load the
2945 * correct version for system assemblies.
2947 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2948 aname = mono_assembly_remap_version (aname, &mapped_aname);
2950 res = mono_assembly_loaded (aname);
2952 mono_assembly_name_free (aname);
2956 res = invoke_assembly_preload_hook (aname, assemblies_path);
2958 res->in_gac = FALSE;
2959 mono_assembly_name_free (aname);
2963 fullname = g_strdup_printf ("%s.dll", aname->name);
2965 if (extra_gac_paths) {
2966 paths = extra_gac_paths;
2967 while (!res && *paths) {
2968 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2969 res = probe_for_partial_name (gacpath, fullname, aname, status);
2978 mono_assembly_name_free (aname);
2982 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2983 res = probe_for_partial_name (gacpath, fullname, aname, status);
2987 mono_assembly_name_free (aname);
2992 MonoDomain *domain = mono_domain_get ();
2994 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2995 if (!is_ok (&error)) {
2996 mono_error_cleanup (&error);
2997 if (*status == MONO_IMAGE_OK)
2998 *status = MONO_IMAGE_IMAGE_INVALID;
3006 mono_assembly_is_in_gac (const gchar *filename)
3008 const gchar *rootdir;
3012 if (filename == NULL)
3015 for (paths = extra_gac_paths; paths && *paths; paths++) {
3016 if (strstr (*paths, filename) != *paths)
3019 gp = (gchar *) (filename + strlen (*paths));
3020 if (*gp != G_DIR_SEPARATOR)
3023 if (strncmp (gp, "lib", 3))
3026 if (*gp != G_DIR_SEPARATOR)
3029 if (strncmp (gp, "mono", 4))
3032 if (*gp != G_DIR_SEPARATOR)
3035 if (strncmp (gp, "gac", 3))
3038 if (*gp != G_DIR_SEPARATOR)
3044 rootdir = mono_assembly_getrootdir ();
3045 if (strstr (filename, rootdir) != filename)
3048 gp = (gchar *) (filename + strlen (rootdir));
3049 if (*gp != G_DIR_SEPARATOR)
3052 if (strncmp (gp, "mono", 4))
3055 if (*gp != G_DIR_SEPARATOR)
3058 if (strncmp (gp, "gac", 3))
3061 if (*gp != G_DIR_SEPARATOR)
3067 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3070 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
3074 if (strstr (aname->name, ".dll")) {
3075 len = strlen (aname->name) - 4;
3076 name = (gchar *)g_malloc (len + 1);
3077 memcpy (name, aname->name, len);
3080 name = g_strdup (aname->name);
3083 culture = g_utf8_strdown (aname->culture, -1);
3085 culture = g_strdup ("");
3087 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
3088 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
3092 filename = g_strconcat (pname, ".dll", NULL);
3093 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
3099 if (extra_gac_paths) {
3100 paths = extra_gac_paths;
3101 while (!image && *paths) {
3102 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
3103 "lib", "mono", "gac", subpath, NULL);
3104 image = mono_image_open (fullpath, NULL);
3115 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3116 "mono", "gac", subpath, NULL);
3117 image = mono_image_open (fullpath, NULL);
3124 static MonoAssemblyName*
3125 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3127 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3128 dest_name->major = info->new_version.major;
3129 dest_name->minor = info->new_version.minor;
3130 dest_name->build = info->new_version.build;
3131 dest_name->revision = info->new_version.revision;
3136 /* LOCKING: assembly_binding lock must be held */
3137 static MonoAssemblyBindingInfo*
3138 search_binding_loaded (MonoAssemblyName *aname)
3142 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3143 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3144 if (assembly_binding_maps_name (info, aname))
3151 static inline gboolean
3152 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3154 if (left->major != right->major || left->minor != right->minor ||
3155 left->build != right->build || left->revision != right->revision)
3161 static inline gboolean
3162 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3164 if (left->has_old_version_bottom != right->has_old_version_bottom)
3167 if (left->has_old_version_top != right->has_old_version_top)
3170 if (left->has_new_version != right->has_new_version)
3173 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3176 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3179 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3185 /* LOCKING: assumes all the necessary locks are held */
3187 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3189 MonoAssemblyBindingInfo *info_copy;
3191 MonoAssemblyBindingInfo *info_tmp;
3192 MonoDomain *domain = (MonoDomain*)user_data;
3197 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)) {
3198 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3199 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3203 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3204 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3205 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3209 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3210 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3212 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3214 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3216 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3220 get_version_number (int major, int minor)
3222 return major * 256 + minor;
3225 static inline gboolean
3226 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3228 int aname_version_number = get_version_number (aname->major, aname->minor);
3229 if (!info->has_old_version_bottom)
3232 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3235 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3238 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3239 info->major = aname->major;
3240 info->minor = aname->minor;
3245 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3246 static MonoAssemblyBindingInfo*
3247 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3249 MonoAssemblyBindingInfo *info;
3252 if (!domain->assembly_bindings)
3256 for (list = domain->assembly_bindings; list; list = list->next) {
3257 info = (MonoAssemblyBindingInfo *)list->data;
3258 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3264 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3265 info->has_new_version && assembly_binding_maps_name (info, aname))
3266 info->is_valid = TRUE;
3268 info->is_valid = FALSE;
3275 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3277 if (domain->assembly_bindings_parsed)
3279 mono_domain_lock (domain);
3280 if (!domain->assembly_bindings_parsed) {
3282 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3284 if (!domain_config_file_path)
3285 domain_config_file_path = domain_config_file_name;
3287 mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3288 domain->assembly_bindings_parsed = TRUE;
3289 if (domain_config_file_name != domain_config_file_path)
3290 g_free (domain_config_file_path);
3293 mono_domain_unlock (domain);
3296 static MonoAssemblyName*
3297 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3300 MonoAssemblyBindingInfo *info, *info2;
3304 if (aname->public_key_token [0] == 0)
3307 domain = mono_domain_get ();
3309 mono_assembly_binding_lock ();
3310 info = search_binding_loaded (aname);
3311 mono_assembly_binding_unlock ();
3314 mono_domain_lock (domain);
3315 info = get_per_domain_assembly_binding_info (domain, aname);
3316 mono_domain_unlock (domain);
3320 if (!check_policy_versions (info, aname))
3323 mono_assembly_bind_version (info, aname, dest_name);
3327 if (domain && domain->setup && domain->setup->configuration_file) {
3328 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3329 /* expect this to succeed because mono_domain_set_options_from_config () did
3330 * the same thing when the domain was created. */
3331 mono_error_assert_ok (&error);
3332 mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3333 g_free (domain_config_file_name);
3335 mono_domain_lock (domain);
3336 info2 = get_per_domain_assembly_binding_info (domain, aname);
3339 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3340 info->name = g_strdup (info2->name);
3341 info->culture = g_strdup (info2->culture);
3342 info->domain_id = domain->domain_id;
3345 mono_domain_unlock (domain);
3350 info = g_new0 (MonoAssemblyBindingInfo, 1);
3351 info->major = aname->major;
3352 info->minor = aname->minor;
3355 if (!info->is_valid) {
3356 ppimage = mono_assembly_load_publisher_policy (aname);
3358 get_publisher_policy_info (ppimage, aname, info);
3359 mono_image_close (ppimage);
3363 /* Define default error value if needed */
3364 if (!info->is_valid) {
3365 info->name = g_strdup (aname->name);
3366 info->culture = g_strdup (aname->culture);
3367 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3370 mono_assembly_binding_lock ();
3371 info2 = search_binding_loaded (aname);
3373 /* This binding was added by another thread
3375 mono_assembly_binding_info_free (info);
3380 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3382 mono_assembly_binding_unlock ();
3384 if (!info->is_valid || !check_policy_versions (info, aname))
3387 mono_assembly_bind_version (info, aname, dest_name);
3392 * mono_assembly_load_from_gac
3394 * \param aname The assembly name object
3396 static MonoAssembly*
3397 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3399 MonoAssembly *result = NULL;
3400 gchar *name, *version, *culture, *fullpath, *subpath;
3405 if (aname->public_key_token [0] == 0) {
3409 if (strstr (aname->name, ".dll")) {
3410 len = strlen (filename) - 4;
3411 name = (gchar *)g_malloc (len + 1);
3412 memcpy (name, aname->name, len);
3415 name = g_strdup (aname->name);
3418 if (aname->culture) {
3419 culture = g_utf8_strdown (aname->culture, -1);
3421 culture = g_strdup ("");
3424 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3425 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3426 aname->minor, aname->build, aname->revision,
3430 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3435 if (extra_gac_paths) {
3436 paths = extra_gac_paths;
3437 while (!result && *paths) {
3438 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3439 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3446 result->in_gac = TRUE;
3451 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3452 "mono", "gac", subpath, NULL);
3453 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3457 result->in_gac = TRUE;
3465 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3468 MonoAssemblyName *aname;
3471 /* g_print ("corlib already loaded\n"); */
3475 // A nonstandard preload hook may provide a special mscorlib assembly
3476 aname = mono_assembly_name_new ("mscorlib.dll");
3477 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3478 mono_assembly_name_free (aname);
3481 goto return_corlib_and_facades;
3483 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3484 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3485 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3487 goto return_corlib_and_facades;
3490 /* Normal case: Load corlib from mono/<version> */
3491 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3492 if (assemblies_path) { // Custom assemblies path
3493 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3495 g_free (corlib_file);
3496 goto return_corlib_and_facades;
3499 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3500 g_free (corlib_file);
3502 return_corlib_and_facades:
3503 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3504 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3509 static MonoAssembly*
3510 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3512 MonoError refasm_error;
3513 error_init (&refasm_error);
3514 if (candidate && !refonly) {
3515 /* .NET Framework seems to not check for ReferenceAssemblyAttribute on dynamic assemblies */
3516 if (!image_is_dynamic (candidate->image) &&
3517 mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error))
3520 mono_error_cleanup (&refasm_error);
3525 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3527 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3528 MonoAssemblyName *candidate_name = &candidate->aname;
3530 g_assert (wanted_name != NULL);
3531 g_assert (candidate_name != NULL);
3533 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3534 char * s = mono_stringify_assembly_name (wanted_name);
3535 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3537 s = mono_stringify_assembly_name (candidate_name);
3538 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3543 /* Wanted name has no token, not strongly named: always matches. */
3544 if (0 == wanted_name->public_key_token [0]) {
3545 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3549 /* Candidate name has no token, not strongly named: never matches */
3550 if (0 == candidate_name->public_key_token [0]) {
3551 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3555 return exact_sn_match (wanted_name, candidate_name) ||
3556 framework_assembly_sn_match (wanted_name, candidate_name);
3560 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3562 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3564 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3565 result ? "match, returning TRUE" : "don't match, returning FALSE");
3571 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3573 #ifndef DISABLE_DESKTOP_LOADER
3574 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3576 if (!vmap->framework_facade_assembly) {
3577 /* 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. */
3578 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3579 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s (ignoring the public key token)", result ? "match, returning TRUE" : "don't match, returning FALSE");
3582 /* For facades, the name and public key token should
3583 * match, but the version doesn't matter. */
3584 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3585 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");
3594 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3595 const char *basedir,
3596 MonoImageOpenStatus *status,
3599 MonoAssembly *result;
3600 char *fullpath, *filename;
3601 MonoAssemblyName maped_aname;
3602 MonoAssemblyName maped_name_pp;
3607 aname = mono_assembly_remap_version (aname, &maped_aname);
3609 /* Reflection only assemblies don't get assembly binding */
3611 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3613 result = mono_assembly_loaded_full (aname, refonly);
3617 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3619 result->in_gac = FALSE;
3623 /* Currently we retrieve the loaded corlib for reflection
3624 * only requests, like a common reflection only assembly
3626 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3627 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3630 MonoAssemblyCandidatePredicate predicate = NULL;
3631 void* predicate_ud = NULL;
3632 #if !defined(DISABLE_DESKTOP_LOADER)
3633 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
3634 predicate = &mono_assembly_candidate_predicate_sn_same_name;
3635 predicate_ud = aname;
3639 len = strlen (aname->name);
3640 for (ext_index = 0; ext_index < 2; ext_index ++) {
3641 ext = ext_index == 0 ? ".dll" : ".exe";
3642 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3643 filename = g_strdup (aname->name);
3644 /* Don't try appending .dll/.exe if it already has one of those extensions */
3647 filename = g_strconcat (aname->name, ext, NULL);
3650 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3657 fullpath = g_build_filename (basedir, filename, NULL);
3658 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, predicate_ud, status);
3661 result->in_gac = FALSE;
3667 result = load_in_path (filename, default_path, status, refonly, predicate, predicate_ud);
3669 result->in_gac = FALSE;
3679 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3681 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3684 /* Try a postload search hook */
3685 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3686 result = prevent_reference_assembly_from_running (result, refonly);
3692 * mono_assembly_load_full:
3693 * \param aname A MonoAssemblyName with the assembly name to load.
3694 * \param basedir A directory to look up the assembly at.
3695 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3696 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3698 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3699 * attempts to load the assembly from that directory before probing the standard locations.
3701 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3702 * assembly binding takes place.
3704 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3705 * value pointed by \p status is updated with an error code.
3708 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3710 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3714 * mono_assembly_load:
3715 * \param aname A MonoAssemblyName with the assembly name to load.
3716 * \param basedir A directory to look up the assembly at.
3717 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3719 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3720 * attempts to load the assembly from that directory before probing the standard locations.
3722 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3723 * value pointed by \p status is updated with an error code.
3726 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3728 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3732 * mono_assembly_loaded_full:
3733 * \param aname an assembly to look for.
3734 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3736 * This is used to determine if the specified assembly has been loaded
3737 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3738 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3741 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3744 MonoAssemblyName maped_aname;
3746 aname = mono_assembly_remap_version (aname, &maped_aname);
3748 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3754 * mono_assembly_loaded:
3755 * \param aname an assembly to look for.
3757 * This is used to determine if the specified assembly has been loaded
3759 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3760 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3763 mono_assembly_loaded (MonoAssemblyName *aname)
3765 return mono_assembly_loaded_full (aname, FALSE);
3769 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3771 if (assembly == NULL || assembly == REFERENCE_MISSING)
3774 if (assembly_is_dynamic (assembly)) {
3776 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3777 for (i = 0; i < dynimg->image.module_count; ++i)
3778 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3779 mono_dynamic_image_release_gc_roots (dynimg);
3784 * Returns whether mono_assembly_close_finish() must be called as
3785 * well. See comment for mono_image_close_except_pools() for why we
3786 * unload in two steps.
3789 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3792 g_return_val_if_fail (assembly != NULL, FALSE);
3794 if (assembly == REFERENCE_MISSING)
3797 /* Might be 0 already */
3798 if (InterlockedDecrement (&assembly->ref_count) > 0)
3801 MONO_PROFILER_RAISE (assembly_unloading, (assembly));
3803 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3805 mono_debug_close_image (assembly->image);
3807 mono_assemblies_lock ();
3808 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3809 mono_assemblies_unlock ();
3811 assembly->image->assembly = NULL;
3813 if (!mono_image_close_except_pools (assembly->image))
3814 assembly->image = NULL;
3816 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3817 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3818 mono_assembly_name_free (fname);
3821 g_slist_free (assembly->friend_assembly_names);
3822 g_free (assembly->basedir);
3824 MONO_PROFILER_RAISE (assembly_unloaded, (assembly));
3830 mono_assembly_close_finish (MonoAssembly *assembly)
3832 g_assert (assembly && assembly != REFERENCE_MISSING);
3834 if (assembly->image)
3835 mono_image_close_finish (assembly->image);
3837 if (assembly_is_dynamic (assembly)) {
3838 g_free ((char*)assembly->aname.culture);
3845 * mono_assembly_close:
3846 * \param assembly the assembly to release.
3848 * This method releases a reference to the \p assembly. The assembly is
3849 * only released when all the outstanding references to it are released.
3852 mono_assembly_close (MonoAssembly *assembly)
3854 if (mono_assembly_close_except_image_pools (assembly))
3855 mono_assembly_close_finish (assembly);
3859 * mono_assembly_load_module:
3862 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3865 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3866 mono_error_assert_ok (&error);
3871 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3873 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3878 * mono_assembly_foreach:
3879 * \param func function to invoke for each assembly loaded
3880 * \param user_data data passed to the callback
3882 * Invokes the provided \p func callback for each assembly loaded into
3883 * the runtime. The first parameter passed to the callback is the
3884 * \c MonoAssembly*, and the second parameter is the \p user_data.
3886 * This is done for all assemblies loaded in the runtime, not just
3887 * those loaded in the current application domain.
3890 mono_assembly_foreach (GFunc func, gpointer user_data)
3895 * We make a copy of the list to avoid calling the callback inside the
3896 * lock, which could lead to deadlocks.
3898 mono_assemblies_lock ();
3899 copy = g_list_copy (loaded_assemblies);
3900 mono_assemblies_unlock ();
3902 g_list_foreach (loaded_assemblies, func, user_data);
3908 * mono_assemblies_cleanup:
3910 * Free all resources used by this module.
3913 mono_assemblies_cleanup (void)
3917 mono_os_mutex_destroy (&assemblies_mutex);
3918 mono_os_mutex_destroy (&assembly_binding_mutex);
3920 for (l = loaded_assembly_bindings; l; l = l->next) {
3921 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3923 mono_assembly_binding_info_free (info);
3926 g_slist_free (loaded_assembly_bindings);
3928 free_assembly_load_hooks ();
3929 free_assembly_search_hooks ();
3930 free_assembly_preload_hooks ();
3933 /*LOCKING takes the assembly_binding lock*/
3935 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3939 mono_assembly_binding_lock ();
3940 iter = &loaded_assembly_bindings;
3943 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3945 if (info->domain_id == domain_id) {
3947 mono_assembly_binding_info_free (info);
3954 mono_assembly_binding_unlock ();
3958 * Holds the assembly of the application, for
3959 * System.Diagnostics.Process::MainModule
3961 static MonoAssembly *main_assembly=NULL;
3964 * mono_assembly_set_main:
3967 mono_assembly_set_main (MonoAssembly *assembly)
3969 main_assembly = assembly;
3973 * mono_assembly_get_main:
3975 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3978 mono_assembly_get_main (void)
3980 return (main_assembly);
3984 * mono_assembly_get_image:
3985 * \param assembly The assembly to retrieve the image from
3987 * \returns the \c MonoImage associated with this assembly.
3990 mono_assembly_get_image (MonoAssembly *assembly)
3992 return assembly->image;
3996 * mono_assembly_get_name:
3997 * \param assembly The assembly to retrieve the name from
3999 * The returned name's lifetime is the same as \p assembly's.
4001 * \returns the \c MonoAssemblyName associated with this assembly.
4004 mono_assembly_get_name (MonoAssembly *assembly)
4006 return &assembly->aname;
4010 * mono_register_bundled_assemblies:
4013 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4015 bundles = assemblies;
4018 #define MONO_DECLSEC_FORMAT_10 0x3C
4019 #define MONO_DECLSEC_FORMAT_20 0x2E
4020 #define MONO_DECLSEC_FIELD 0x53
4021 #define MONO_DECLSEC_PROPERTY 0x54
4023 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4024 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4025 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4026 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4027 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4030 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4034 case MONO_DECLSEC_PROPERTY:
4036 case MONO_DECLSEC_FIELD:
4038 *abort_decoding = TRUE;
4043 if (*p++ != MONO_TYPE_BOOLEAN) {
4044 *abort_decoding = TRUE;
4048 /* property name length */
4049 len = mono_metadata_decode_value (p, &p);
4051 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4062 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4064 int i, j, num, len, params_len;
4066 if (*p == MONO_DECLSEC_FORMAT_10) {
4067 gsize read, written;
4068 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4070 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4076 if (*p++ != MONO_DECLSEC_FORMAT_20)
4079 /* number of encoded permission attributes */
4080 num = mono_metadata_decode_value (p, &p);
4081 for (i = 0; i < num; ++i) {
4082 gboolean is_valid = FALSE;
4083 gboolean abort_decoding = FALSE;
4085 /* attribute name length */
4086 len = mono_metadata_decode_value (p, &p);
4088 /* We don't really need to fully decode the type. Comparing the name is enough */
4089 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4093 /*size of the params table*/
4094 params_len = mono_metadata_decode_value (p, &p);
4096 const char *params_end = p + params_len;
4098 /* number of parameters */
4099 len = mono_metadata_decode_value (p, &p);
4101 for (j = 0; j < len; ++j) {
4102 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4118 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4121 guint32 cols [MONO_DECL_SECURITY_SIZE];
4125 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4126 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4128 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4130 for (i = 0; i < t->rows; ++i) {
4131 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4132 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4134 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4137 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4138 len = mono_metadata_decode_blob_size (blob, &blob);
4142 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4143 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4148 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);