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_assembly_event (ass, MONO_PROFILE_START_LOAD);
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_assembly_loaded (ass, MONO_PROFILE_OK);
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;
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 /* Encode the size of the blob */
2437 if (keylen <= 127) {
2438 arr = (gchar *)g_malloc (keylen + 1);
2439 arr [offset++] = keylen;
2441 arr = (gchar *)g_malloc (keylen + 2);
2442 arr [offset++] = 0x80; /* 10bs */
2443 arr [offset++] = keylen;
2446 for (i = offset, j = 0; i < keylen + offset; i++) {
2447 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2448 arr [i] |= g_ascii_xdigit_value (key [j++]);
2457 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)
2459 gint major, minor, build, revision;
2462 gchar *pkey, *pkeyptr, *encoded, tok [8];
2464 memset (aname, 0, sizeof (MonoAssemblyName));
2467 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2468 if (version_parts < 2 || version_parts > 4)
2471 /* FIXME: we should set build & revision to -1 (instead of 0)
2472 if these are not set in the version string. That way, later on,
2473 we can still determine if these were specified. */
2474 aname->major = major;
2475 aname->minor = minor;
2476 if (version_parts >= 3)
2477 aname->build = build;
2480 if (version_parts == 4)
2481 aname->revision = revision;
2483 aname->revision = 0;
2486 aname->flags = flags;
2488 aname->name = g_strdup (name);
2491 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2492 aname->culture = g_strdup ("");
2494 aname->culture = g_strdup (culture);
2497 if (token && strncmp (token, "null", 4) != 0) {
2500 /* the constant includes the ending NULL, hence the -1 */
2501 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2502 mono_assembly_name_free (aname);
2505 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2506 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2512 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2513 mono_assembly_name_free (aname);
2518 if (save_public_key)
2519 aname->public_key = (guint8*)pkey;
2522 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2526 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2527 // We also need to generate the key token
2528 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2529 encoded = encode_public_tok ((guchar*) tok, 8);
2530 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2533 if (save_public_key)
2534 aname->public_key = (guint8*) pkey;
2543 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2548 parts = g_strsplit (dirname, "_", 3);
2549 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2554 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2560 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2562 char *eqsign = strchr (pair, '=');
2570 *key = (gchar*)pair;
2571 *keylen = eqsign - *key;
2572 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2574 *value = g_strstrip (eqsign + 1);
2579 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2583 gchar *version = NULL;
2585 gchar *culture = NULL;
2587 gchar *token = NULL;
2591 gchar *retargetable = NULL;
2592 gchar *retargetable_uq;
2596 gchar *value, *part_name;
2597 guint32 part_name_len;
2600 gboolean version_defined;
2601 gboolean token_defined;
2603 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2605 if (!is_version_defined)
2606 is_version_defined = &version_defined;
2607 *is_version_defined = FALSE;
2608 if (!is_token_defined)
2609 is_token_defined = &token_defined;
2610 *is_token_defined = FALSE;
2612 parts = tmp = g_strsplit (name, ",", 6);
2613 if (!tmp || !*tmp) {
2618 dllname = g_strstrip (*tmp);
2623 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2624 goto cleanup_and_fail;
2626 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2627 *is_version_defined = TRUE;
2629 if (strlen (version) == 0) {
2630 goto cleanup_and_fail;
2636 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2638 if (strlen (culture) == 0) {
2639 goto cleanup_and_fail;
2645 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2646 *is_token_defined = TRUE;
2648 if (strlen (token) == 0) {
2649 goto cleanup_and_fail;
2655 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2657 if (strlen (key) == 0) {
2658 goto cleanup_and_fail;
2664 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2665 retargetable = value;
2666 retargetable_uq = unquote (retargetable);
2667 if (retargetable_uq != NULL)
2668 retargetable = retargetable_uq;
2670 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2671 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2672 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2673 g_free (retargetable_uq);
2674 goto cleanup_and_fail;
2677 g_free (retargetable_uq);
2682 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2684 procarch_uq = unquote (procarch);
2685 if (procarch_uq != NULL)
2686 procarch = procarch_uq;
2688 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2689 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2690 else if (!g_ascii_strcasecmp (procarch, "X86"))
2691 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2692 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2693 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2694 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2695 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2697 g_free (procarch_uq);
2698 goto cleanup_and_fail;
2701 g_free (procarch_uq);
2710 /* if retargetable flag is set, then we must have a fully qualified name */
2711 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2712 goto cleanup_and_fail;
2715 dllname_uq = unquote (dllname);
2716 version_uq = unquote (version);
2717 culture_uq = unquote (culture);
2718 token_uq = unquote (token);
2719 key_uq = unquote (key);
2721 res = build_assembly_name (
2722 dllname_uq == NULL ? dllname : dllname_uq,
2723 version_uq == NULL ? version : version_uq,
2724 culture_uq == NULL ? culture : culture_uq,
2725 token_uq == NULL ? token : token_uq,
2726 key_uq == NULL ? key : key_uq,
2727 flags, arch, aname, save_public_key);
2729 g_free (dllname_uq);
2730 g_free (version_uq);
2731 g_free (culture_uq);
2744 unquote (const char *str)
2752 slen = strlen (str);
2756 if (*str != '\'' && *str != '\"')
2759 end = str + slen - 1;
2763 return g_strndup (str + 1, slen - 2);
2767 * mono_assembly_name_parse:
2768 * \param name name to parse
2769 * \param aname the destination assembly name
2771 * Parses an assembly qualified type name and assigns the name,
2772 * version, culture and token to the provided assembly name object.
2774 * \returns TRUE if the name could be parsed.
2777 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2779 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2783 * mono_assembly_name_new:
2784 * \param name name to parse
2786 * Allocate a new \c MonoAssemblyName and fill its values from the
2789 * \returns a newly allocated structure or NULL if there was any failure.
2792 mono_assembly_name_new (const char *name)
2794 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2795 if (mono_assembly_name_parse (name, aname))
2802 * mono_assembly_name_get_name:
2805 mono_assembly_name_get_name (MonoAssemblyName *aname)
2811 * mono_assembly_name_get_culture:
2814 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2816 return aname->culture;
2820 * mono_assembly_name_get_pubkeytoken:
2823 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2825 if (aname->public_key_token [0])
2826 return aname->public_key_token;
2831 * mono_assembly_name_get_version:
2834 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2837 *minor = aname->minor;
2839 *build = aname->build;
2841 *revision = aname->revision;
2842 return aname->major;
2845 static MonoAssembly*
2846 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2848 gchar *fullpath = NULL;
2850 const char* direntry;
2851 MonoAssemblyName gac_aname;
2852 gint major=-1, minor=0, build=0, revision=0;
2853 gboolean exact_version;
2855 dirhandle = g_dir_open (basepath, 0, NULL);
2859 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2861 while ((direntry = g_dir_read_name (dirhandle))) {
2862 gboolean match = TRUE;
2864 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2867 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2870 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2871 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2875 if (exact_version) {
2876 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2877 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2879 else if (gac_aname.major < major)
2881 else if (gac_aname.major == major) {
2882 if (gac_aname.minor < minor)
2884 else if (gac_aname.minor == minor) {
2885 if (gac_aname.build < build)
2887 else if (gac_aname.build == build && gac_aname.revision <= revision)
2894 major = gac_aname.major;
2895 minor = gac_aname.minor;
2896 build = gac_aname.build;
2897 revision = gac_aname.revision;
2899 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2902 mono_assembly_name_free (&gac_aname);
2905 g_dir_close (dirhandle);
2907 if (fullpath == NULL)
2910 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2917 * mono_assembly_load_with_partial_name:
2918 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2919 * \param status return status code
2921 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2922 * so it might contain a qualified type name, version, culture and token.
2924 * This will load the assembly from the file whose name is derived from the assembly name
2925 * by appending the \c .dll extension.
2927 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2928 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2929 * if that fails from the GAC.
2931 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2934 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2938 MonoAssemblyName *aname, base_name;
2939 MonoAssemblyName mapped_aname;
2940 gchar *fullname, *gacpath;
2943 memset (&base_name, 0, sizeof (MonoAssemblyName));
2946 if (!mono_assembly_name_parse (name, aname))
2950 * If no specific version has been requested, make sure we load the
2951 * correct version for system assemblies.
2953 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2954 aname = mono_assembly_remap_version (aname, &mapped_aname);
2956 res = mono_assembly_loaded (aname);
2958 mono_assembly_name_free (aname);
2962 res = invoke_assembly_preload_hook (aname, assemblies_path);
2964 res->in_gac = FALSE;
2965 mono_assembly_name_free (aname);
2969 fullname = g_strdup_printf ("%s.dll", aname->name);
2971 if (extra_gac_paths) {
2972 paths = extra_gac_paths;
2973 while (!res && *paths) {
2974 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2975 res = probe_for_partial_name (gacpath, fullname, aname, status);
2984 mono_assembly_name_free (aname);
2988 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2989 res = probe_for_partial_name (gacpath, fullname, aname, status);
2993 mono_assembly_name_free (aname);
2998 MonoDomain *domain = mono_domain_get ();
3000 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
3001 if (!is_ok (&error)) {
3002 mono_error_cleanup (&error);
3003 if (*status == MONO_IMAGE_OK)
3004 *status = MONO_IMAGE_IMAGE_INVALID;
3012 mono_assembly_is_in_gac (const gchar *filename)
3014 const gchar *rootdir;
3018 if (filename == NULL)
3021 for (paths = extra_gac_paths; paths && *paths; paths++) {
3022 if (strstr (*paths, filename) != *paths)
3025 gp = (gchar *) (filename + strlen (*paths));
3026 if (*gp != G_DIR_SEPARATOR)
3029 if (strncmp (gp, "lib", 3))
3032 if (*gp != G_DIR_SEPARATOR)
3035 if (strncmp (gp, "mono", 4))
3038 if (*gp != G_DIR_SEPARATOR)
3041 if (strncmp (gp, "gac", 3))
3044 if (*gp != G_DIR_SEPARATOR)
3050 rootdir = mono_assembly_getrootdir ();
3051 if (strstr (filename, rootdir) != filename)
3054 gp = (gchar *) (filename + strlen (rootdir));
3055 if (*gp != G_DIR_SEPARATOR)
3058 if (strncmp (gp, "mono", 4))
3061 if (*gp != G_DIR_SEPARATOR)
3064 if (strncmp (gp, "gac", 3))
3067 if (*gp != G_DIR_SEPARATOR)
3073 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3076 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
3080 if (strstr (aname->name, ".dll")) {
3081 len = strlen (aname->name) - 4;
3082 name = (gchar *)g_malloc (len + 1);
3083 memcpy (name, aname->name, len);
3086 name = g_strdup (aname->name);
3089 culture = g_utf8_strdown (aname->culture, -1);
3091 culture = g_strdup ("");
3093 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
3094 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
3098 filename = g_strconcat (pname, ".dll", NULL);
3099 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
3105 if (extra_gac_paths) {
3106 paths = extra_gac_paths;
3107 while (!image && *paths) {
3108 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
3109 "lib", "mono", "gac", subpath, NULL);
3110 image = mono_image_open (fullpath, NULL);
3121 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3122 "mono", "gac", subpath, NULL);
3123 image = mono_image_open (fullpath, NULL);
3130 static MonoAssemblyName*
3131 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3133 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3134 dest_name->major = info->new_version.major;
3135 dest_name->minor = info->new_version.minor;
3136 dest_name->build = info->new_version.build;
3137 dest_name->revision = info->new_version.revision;
3142 /* LOCKING: assembly_binding lock must be held */
3143 static MonoAssemblyBindingInfo*
3144 search_binding_loaded (MonoAssemblyName *aname)
3148 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3149 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3150 if (assembly_binding_maps_name (info, aname))
3157 static inline gboolean
3158 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3160 if (left->major != right->major || left->minor != right->minor ||
3161 left->build != right->build || left->revision != right->revision)
3167 static inline gboolean
3168 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3170 if (left->has_old_version_bottom != right->has_old_version_bottom)
3173 if (left->has_old_version_top != right->has_old_version_top)
3176 if (left->has_new_version != right->has_new_version)
3179 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3182 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3185 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3191 /* LOCKING: assumes all the necessary locks are held */
3193 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3195 MonoAssemblyBindingInfo *info_copy;
3197 MonoAssemblyBindingInfo *info_tmp;
3198 MonoDomain *domain = (MonoDomain*)user_data;
3203 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)) {
3204 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3205 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3209 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3210 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3211 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3215 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3216 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3218 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3220 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3222 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3226 get_version_number (int major, int minor)
3228 return major * 256 + minor;
3231 static inline gboolean
3232 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3234 int aname_version_number = get_version_number (aname->major, aname->minor);
3235 if (!info->has_old_version_bottom)
3238 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3241 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3244 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3245 info->major = aname->major;
3246 info->minor = aname->minor;
3251 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3252 static MonoAssemblyBindingInfo*
3253 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3255 MonoAssemblyBindingInfo *info;
3258 if (!domain->assembly_bindings)
3262 for (list = domain->assembly_bindings; list; list = list->next) {
3263 info = (MonoAssemblyBindingInfo *)list->data;
3264 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3270 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3271 info->has_new_version && assembly_binding_maps_name (info, aname))
3272 info->is_valid = TRUE;
3274 info->is_valid = FALSE;
3281 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3283 if (domain->assembly_bindings_parsed)
3285 mono_domain_lock (domain);
3286 if (!domain->assembly_bindings_parsed) {
3288 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3290 if (!domain_config_file_path)
3291 domain_config_file_path = domain_config_file_name;
3293 mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3294 domain->assembly_bindings_parsed = TRUE;
3295 if (domain_config_file_name != domain_config_file_path)
3296 g_free (domain_config_file_path);
3299 mono_domain_unlock (domain);
3302 static MonoAssemblyName*
3303 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3306 MonoAssemblyBindingInfo *info, *info2;
3310 if (aname->public_key_token [0] == 0)
3313 domain = mono_domain_get ();
3315 mono_assembly_binding_lock ();
3316 info = search_binding_loaded (aname);
3317 mono_assembly_binding_unlock ();
3320 mono_domain_lock (domain);
3321 info = get_per_domain_assembly_binding_info (domain, aname);
3322 mono_domain_unlock (domain);
3326 if (!check_policy_versions (info, aname))
3329 mono_assembly_bind_version (info, aname, dest_name);
3333 if (domain && domain->setup && domain->setup->configuration_file) {
3334 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3335 /* expect this to succeed because mono_domain_set_options_from_config () did
3336 * the same thing when the domain was created. */
3337 mono_error_assert_ok (&error);
3338 mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3339 g_free (domain_config_file_name);
3341 mono_domain_lock (domain);
3342 info2 = get_per_domain_assembly_binding_info (domain, aname);
3345 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3346 info->name = g_strdup (info2->name);
3347 info->culture = g_strdup (info2->culture);
3348 info->domain_id = domain->domain_id;
3351 mono_domain_unlock (domain);
3356 info = g_new0 (MonoAssemblyBindingInfo, 1);
3357 info->major = aname->major;
3358 info->minor = aname->minor;
3361 if (!info->is_valid) {
3362 ppimage = mono_assembly_load_publisher_policy (aname);
3364 get_publisher_policy_info (ppimage, aname, info);
3365 mono_image_close (ppimage);
3369 /* Define default error value if needed */
3370 if (!info->is_valid) {
3371 info->name = g_strdup (aname->name);
3372 info->culture = g_strdup (aname->culture);
3373 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3376 mono_assembly_binding_lock ();
3377 info2 = search_binding_loaded (aname);
3379 /* This binding was added by another thread
3381 mono_assembly_binding_info_free (info);
3386 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3388 mono_assembly_binding_unlock ();
3390 if (!info->is_valid || !check_policy_versions (info, aname))
3393 mono_assembly_bind_version (info, aname, dest_name);
3398 * mono_assembly_load_from_gac
3400 * \param aname The assembly name object
3402 static MonoAssembly*
3403 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3405 MonoAssembly *result = NULL;
3406 gchar *name, *version, *culture, *fullpath, *subpath;
3411 if (aname->public_key_token [0] == 0) {
3415 if (strstr (aname->name, ".dll")) {
3416 len = strlen (filename) - 4;
3417 name = (gchar *)g_malloc (len + 1);
3418 memcpy (name, aname->name, len);
3421 name = g_strdup (aname->name);
3424 if (aname->culture) {
3425 culture = g_utf8_strdown (aname->culture, -1);
3427 culture = g_strdup ("");
3430 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3431 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3432 aname->minor, aname->build, aname->revision,
3436 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3441 if (extra_gac_paths) {
3442 paths = extra_gac_paths;
3443 while (!result && *paths) {
3444 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3445 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3452 result->in_gac = TRUE;
3457 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3458 "mono", "gac", subpath, NULL);
3459 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3463 result->in_gac = TRUE;
3471 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3474 MonoAssemblyName *aname;
3477 /* g_print ("corlib already loaded\n"); */
3481 // A nonstandard preload hook may provide a special mscorlib assembly
3482 aname = mono_assembly_name_new ("mscorlib.dll");
3483 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3484 mono_assembly_name_free (aname);
3487 goto return_corlib_and_facades;
3489 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3490 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3491 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3493 goto return_corlib_and_facades;
3496 /* Normal case: Load corlib from mono/<version> */
3497 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3498 if (assemblies_path) { // Custom assemblies path
3499 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3501 g_free (corlib_file);
3502 goto return_corlib_and_facades;
3505 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3506 g_free (corlib_file);
3508 return_corlib_and_facades:
3509 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3510 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3515 static MonoAssembly*
3516 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3518 MonoError refasm_error;
3519 error_init (&refasm_error);
3520 if (candidate && !refonly) {
3521 /* .NET Framework seems to not check for ReferenceAssemblyAttribute on dynamic assemblies */
3522 if (!image_is_dynamic (candidate->image) &&
3523 mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error))
3526 mono_error_cleanup (&refasm_error);
3531 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3533 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3534 MonoAssemblyName *candidate_name = &candidate->aname;
3536 g_assert (wanted_name != NULL);
3537 g_assert (candidate_name != NULL);
3539 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3540 char * s = mono_stringify_assembly_name (wanted_name);
3541 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3543 s = mono_stringify_assembly_name (candidate_name);
3544 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3549 /* Wanted name has no token, not strongly named: always matches. */
3550 if (0 == wanted_name->public_key_token [0]) {
3551 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3555 /* Candidate name has no token, not strongly named: never matches */
3556 if (0 == candidate_name->public_key_token [0]) {
3557 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3561 return exact_sn_match (wanted_name, candidate_name) ||
3562 framework_assembly_sn_match (wanted_name, candidate_name);
3566 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3568 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3570 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3571 result ? "match, returning TRUE" : "don't match, returning FALSE");
3577 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3579 #ifndef DISABLE_DESKTOP_LOADER
3580 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3582 if (!vmap->framework_facade_assembly) {
3583 /* 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. */
3584 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3585 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");
3588 /* For facades, the name and public key token should
3589 * match, but the version doesn't matter. */
3590 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3591 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");
3600 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3601 const char *basedir,
3602 MonoImageOpenStatus *status,
3605 MonoAssembly *result;
3606 char *fullpath, *filename;
3607 MonoAssemblyName maped_aname;
3608 MonoAssemblyName maped_name_pp;
3613 aname = mono_assembly_remap_version (aname, &maped_aname);
3615 /* Reflection only assemblies don't get assembly binding */
3617 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3619 result = mono_assembly_loaded_full (aname, refonly);
3623 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3625 result->in_gac = FALSE;
3629 /* Currently we retrieve the loaded corlib for reflection
3630 * only requests, like a common reflection only assembly
3632 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3633 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3636 MonoAssemblyCandidatePredicate predicate = NULL;
3637 void* predicate_ud = NULL;
3638 #if !defined(DISABLE_DESKTOP_LOADER)
3639 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
3640 predicate = &mono_assembly_candidate_predicate_sn_same_name;
3641 predicate_ud = aname;
3645 len = strlen (aname->name);
3646 for (ext_index = 0; ext_index < 2; ext_index ++) {
3647 ext = ext_index == 0 ? ".dll" : ".exe";
3648 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3649 filename = g_strdup (aname->name);
3650 /* Don't try appending .dll/.exe if it already has one of those extensions */
3653 filename = g_strconcat (aname->name, ext, NULL);
3656 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3663 fullpath = g_build_filename (basedir, filename, NULL);
3664 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, predicate_ud, status);
3667 result->in_gac = FALSE;
3673 result = load_in_path (filename, default_path, status, refonly, predicate, predicate_ud);
3675 result->in_gac = FALSE;
3685 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3687 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3690 /* Try a postload search hook */
3691 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3692 result = prevent_reference_assembly_from_running (result, refonly);
3698 * mono_assembly_load_full:
3699 * \param aname A MonoAssemblyName with the assembly name to load.
3700 * \param basedir A directory to look up the assembly at.
3701 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3702 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3704 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3705 * attempts to load the assembly from that directory before probing the standard locations.
3707 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3708 * assembly binding takes place.
3710 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3711 * value pointed by \p status is updated with an error code.
3714 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3716 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3720 * mono_assembly_load:
3721 * \param aname A MonoAssemblyName with the assembly name to load.
3722 * \param basedir A directory to look up the assembly at.
3723 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3725 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3726 * attempts to load the assembly from that directory before probing the standard locations.
3728 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3729 * value pointed by \p status is updated with an error code.
3732 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3734 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3738 * mono_assembly_loaded_full:
3739 * \param aname an assembly to look for.
3740 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3742 * This is used to determine if the specified assembly has been loaded
3743 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3744 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3747 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3750 MonoAssemblyName maped_aname;
3752 aname = mono_assembly_remap_version (aname, &maped_aname);
3754 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3760 * mono_assembly_loaded:
3761 * \param aname an assembly to look for.
3763 * This is used to determine if the specified assembly has been loaded
3765 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3766 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3769 mono_assembly_loaded (MonoAssemblyName *aname)
3771 return mono_assembly_loaded_full (aname, FALSE);
3775 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3777 if (assembly == NULL || assembly == REFERENCE_MISSING)
3780 if (assembly_is_dynamic (assembly)) {
3782 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3783 for (i = 0; i < dynimg->image.module_count; ++i)
3784 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3785 mono_dynamic_image_release_gc_roots (dynimg);
3790 * Returns whether mono_assembly_close_finish() must be called as
3791 * well. See comment for mono_image_close_except_pools() for why we
3792 * unload in two steps.
3795 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3798 g_return_val_if_fail (assembly != NULL, FALSE);
3800 if (assembly == REFERENCE_MISSING)
3803 /* Might be 0 already */
3804 if (InterlockedDecrement (&assembly->ref_count) > 0)
3807 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3809 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3811 mono_debug_close_image (assembly->image);
3813 mono_assemblies_lock ();
3814 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3815 mono_assemblies_unlock ();
3817 assembly->image->assembly = NULL;
3819 if (!mono_image_close_except_pools (assembly->image))
3820 assembly->image = NULL;
3822 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3823 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3824 mono_assembly_name_free (fname);
3827 g_slist_free (assembly->friend_assembly_names);
3828 g_free (assembly->basedir);
3830 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3836 mono_assembly_close_finish (MonoAssembly *assembly)
3838 g_assert (assembly && assembly != REFERENCE_MISSING);
3840 if (assembly->image)
3841 mono_image_close_finish (assembly->image);
3843 if (assembly_is_dynamic (assembly)) {
3844 g_free ((char*)assembly->aname.culture);
3851 * mono_assembly_close:
3852 * \param assembly the assembly to release.
3854 * This method releases a reference to the \p assembly. The assembly is
3855 * only released when all the outstanding references to it are released.
3858 mono_assembly_close (MonoAssembly *assembly)
3860 if (mono_assembly_close_except_image_pools (assembly))
3861 mono_assembly_close_finish (assembly);
3865 * mono_assembly_load_module:
3868 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3871 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3872 mono_error_assert_ok (&error);
3877 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3879 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3884 * mono_assembly_foreach:
3885 * \param func function to invoke for each assembly loaded
3886 * \param user_data data passed to the callback
3888 * Invokes the provided \p func callback for each assembly loaded into
3889 * the runtime. The first parameter passed to the callback is the
3890 * \c MonoAssembly*, and the second parameter is the \p user_data.
3892 * This is done for all assemblies loaded in the runtime, not just
3893 * those loaded in the current application domain.
3896 mono_assembly_foreach (GFunc func, gpointer user_data)
3901 * We make a copy of the list to avoid calling the callback inside the
3902 * lock, which could lead to deadlocks.
3904 mono_assemblies_lock ();
3905 copy = g_list_copy (loaded_assemblies);
3906 mono_assemblies_unlock ();
3908 g_list_foreach (loaded_assemblies, func, user_data);
3914 * mono_assemblies_cleanup:
3916 * Free all resources used by this module.
3919 mono_assemblies_cleanup (void)
3923 mono_os_mutex_destroy (&assemblies_mutex);
3924 mono_os_mutex_destroy (&assembly_binding_mutex);
3926 for (l = loaded_assembly_bindings; l; l = l->next) {
3927 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3929 mono_assembly_binding_info_free (info);
3932 g_slist_free (loaded_assembly_bindings);
3934 free_assembly_load_hooks ();
3935 free_assembly_search_hooks ();
3936 free_assembly_preload_hooks ();
3939 /*LOCKING takes the assembly_binding lock*/
3941 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3945 mono_assembly_binding_lock ();
3946 iter = &loaded_assembly_bindings;
3949 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3951 if (info->domain_id == domain_id) {
3953 mono_assembly_binding_info_free (info);
3960 mono_assembly_binding_unlock ();
3964 * Holds the assembly of the application, for
3965 * System.Diagnostics.Process::MainModule
3967 static MonoAssembly *main_assembly=NULL;
3970 * mono_assembly_set_main:
3973 mono_assembly_set_main (MonoAssembly *assembly)
3975 main_assembly = assembly;
3979 * mono_assembly_get_main:
3981 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3984 mono_assembly_get_main (void)
3986 return (main_assembly);
3990 * mono_assembly_get_image:
3991 * \param assembly The assembly to retrieve the image from
3993 * \returns the \c MonoImage associated with this assembly.
3996 mono_assembly_get_image (MonoAssembly *assembly)
3998 return assembly->image;
4002 * mono_assembly_get_name:
4003 * \param assembly The assembly to retrieve the name from
4005 * The returned name's lifetime is the same as \p assembly's.
4007 * \returns the \c MonoAssemblyName associated with this assembly.
4010 mono_assembly_get_name (MonoAssembly *assembly)
4012 return &assembly->aname;
4016 * mono_register_bundled_assemblies:
4019 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4021 bundles = assemblies;
4024 #define MONO_DECLSEC_FORMAT_10 0x3C
4025 #define MONO_DECLSEC_FORMAT_20 0x2E
4026 #define MONO_DECLSEC_FIELD 0x53
4027 #define MONO_DECLSEC_PROPERTY 0x54
4029 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4030 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4031 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4032 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4033 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4036 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4040 case MONO_DECLSEC_PROPERTY:
4042 case MONO_DECLSEC_FIELD:
4044 *abort_decoding = TRUE;
4049 if (*p++ != MONO_TYPE_BOOLEAN) {
4050 *abort_decoding = TRUE;
4054 /* property name length */
4055 len = mono_metadata_decode_value (p, &p);
4057 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4068 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4070 int i, j, num, len, params_len;
4072 if (*p == MONO_DECLSEC_FORMAT_10) {
4073 gsize read, written;
4074 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4076 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4082 if (*p++ != MONO_DECLSEC_FORMAT_20)
4085 /* number of encoded permission attributes */
4086 num = mono_metadata_decode_value (p, &p);
4087 for (i = 0; i < num; ++i) {
4088 gboolean is_valid = FALSE;
4089 gboolean abort_decoding = FALSE;
4091 /* attribute name length */
4092 len = mono_metadata_decode_value (p, &p);
4094 /* We don't really need to fully decode the type. Comparing the name is enough */
4095 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4099 /*size of the params table*/
4100 params_len = mono_metadata_decode_value (p, &p);
4102 const char *params_end = p + params_len;
4104 /* number of parameters */
4105 len = mono_metadata_decode_value (p, &p);
4107 for (j = 0; j < len; ++j) {
4108 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4124 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4127 guint32 cols [MONO_DECL_SECURITY_SIZE];
4131 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4132 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4134 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4136 for (i = 0; i < t->rows; ++i) {
4137 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4138 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4140 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4143 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4144 len = mono_metadata_decode_blob_size (blob, &blob);
4148 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4149 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4154 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);