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>
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(HOST_DARWIN) && !defined(TARGET_ARM))
844 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
847 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
851 * _NSGetExecutablePath may return -1 to indicate buf is not large
852 * enough, but we ignore that case to avoid having to do extra dynamic
853 * allocation for the path and hope that 4096 is enough - this is
854 * ok in the Linux/Solaris case below at least...
858 guint buf_size = sizeof (buf);
861 if (_NSGetExecutablePath (buf, &buf_size) == 0)
862 name = g_strdup (buf);
871 resolvedname = mono_path_resolve_symlinks (name);
873 bindir = g_path_get_dirname (resolvedname);
874 installdir = g_path_get_dirname (bindir);
875 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
877 config = g_build_filename (root, "..", "etc", NULL);
879 mono_set_dirs (root, config);
881 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
882 mono_set_dirs (root, config);
892 g_free (resolvedname);
893 #elif defined(DISABLE_MONO_AUTODETECTION)
901 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
909 /* Solaris 10 style */
910 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
911 s = readlink (str, buf, sizeof (buf)-1);
923 * mono_assemblies_init:
925 * Initialize global variables used by this module.
928 mono_assemblies_init (void)
931 * Initialize our internal paths if we have not been initialized yet.
932 * This happens when embedders use Mono.
934 if (mono_assembly_getrootdir () == NULL)
938 check_extra_gac_path_env ();
940 mono_os_mutex_init_recursive (&assemblies_mutex);
941 mono_os_mutex_init (&assembly_binding_mutex);
943 #ifndef DISABLE_DESKTOP_LOADER
944 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
947 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
948 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
954 mono_assembly_binding_lock (void)
956 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
960 mono_assembly_binding_unlock (void)
962 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
966 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
968 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
969 guint32 cols [MONO_ASSEMBLY_SIZE];
970 gint32 machine, flags;
975 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
978 aname->hash_value = NULL;
979 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
981 aname->name = g_strdup (aname->name);
982 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
984 aname->culture = g_strdup (aname->culture);
985 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
986 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
987 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
988 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
989 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
990 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
991 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
992 guchar* token = (guchar *)g_malloc (8);
997 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
998 len = mono_metadata_decode_blob_size (pkey, &pkey);
999 aname->public_key = (guchar*)pkey;
1001 mono_digest_get_public_token (token, aname->public_key, len);
1002 encoded = encode_public_tok (token, 8);
1003 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1009 aname->public_key = NULL;
1010 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1013 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
1014 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
1016 const gchar *pkey_end;
1017 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
1018 pkey_end += len; /* move to end */
1019 size_t size = pkey_end - (const gchar*)aname->public_key;
1020 guchar *tmp = g_new (guchar, size);
1021 memcpy (tmp, aname->public_key, size);
1022 aname->public_key = tmp;
1027 aname->public_key = 0;
1029 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
1030 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
1032 case COFF_MACHINE_I386:
1033 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1034 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
1035 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
1036 else if ((flags & 0x70) == 0x70)
1037 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
1039 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
1041 case COFF_MACHINE_IA64:
1042 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
1044 case COFF_MACHINE_AMD64:
1045 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
1047 case COFF_MACHINE_ARM:
1048 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
1058 * mono_assembly_fill_assembly_name:
1059 * \param image Image
1061 * \returns TRUE if successful
1064 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
1066 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
1070 * mono_stringify_assembly_name:
1071 * \param aname the assembly name.
1073 * Convert \p aname into its string format. The returned string is dynamically
1074 * allocated and should be freed by the caller.
1076 * \returns a newly allocated string with a string representation of
1077 * the assembly name.
1080 mono_stringify_assembly_name (MonoAssemblyName *aname)
1082 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
1084 return g_strdup_printf (
1085 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1086 quote, aname->name, quote,
1087 aname->major, aname->minor, aname->build, aname->revision,
1088 aname->culture && *aname->culture? aname->culture: "neutral",
1089 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
1090 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
1094 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
1096 const gchar *public_tok;
1099 public_tok = mono_metadata_blob_heap (image, key_index);
1100 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
1102 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
1104 mono_digest_get_public_token (token, (guchar*)public_tok, len);
1105 return encode_public_tok (token, 8);
1108 return encode_public_tok ((guchar*)public_tok, len);
1112 * mono_assembly_addref:
1113 * \param assembly the assembly to reference
1115 * This routine increments the reference count on a MonoAssembly.
1116 * The reference count is reduced every time the method mono_assembly_close() is
1120 mono_assembly_addref (MonoAssembly *assembly)
1122 InterlockedIncrement (&assembly->ref_count);
1126 * CAUTION: This table must be kept in sync with
1127 * ivkm/reflect/Fusion.cs
1130 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1131 #define WINFX_KEY "31bf3856ad364e35"
1132 #define ECMA_KEY "b77a5c561934e089"
1133 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1134 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1142 static KeyRemapEntry key_remap_table[] = {
1143 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1144 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1145 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1146 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1147 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1148 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1149 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1150 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1151 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1152 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1153 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1154 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1155 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1156 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1157 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1158 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1159 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1160 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1161 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1162 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1163 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1164 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1165 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1166 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1167 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1168 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1169 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1170 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1171 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1175 remap_keys (MonoAssemblyName *aname)
1178 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1179 const KeyRemapEntry *entry = &key_remap_table [i];
1181 if (strcmp (aname->name, entry->name) ||
1182 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1185 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1187 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1188 "Remapped public key token of retargetable assembly %s from %s to %s",
1189 aname->name, entry->from, entry->to);
1194 static MonoAssemblyName *
1195 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1197 const MonoRuntimeInfo *current_runtime;
1199 if (aname->name == NULL) return aname;
1201 current_runtime = mono_get_runtime_info ();
1203 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1204 const AssemblyVersionSet* vset;
1206 /* Remap to current runtime */
1207 vset = ¤t_runtime->version_sets [0];
1209 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1210 dest_aname->major = vset->major;
1211 dest_aname->minor = vset->minor;
1212 dest_aname->build = vset->build;
1213 dest_aname->revision = vset->revision;
1214 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1216 /* Remap assembly name */
1217 if (!strcmp (aname->name, "System.Net"))
1218 dest_aname->name = g_strdup ("System");
1220 remap_keys (dest_aname);
1222 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1223 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1225 aname->major, aname->minor, aname->build, aname->revision,
1227 vset->major, vset->minor, vset->build, vset->revision
1233 #ifndef DISABLE_DESKTOP_LOADER
1234 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1236 const AssemblyVersionSet* vset;
1237 int index = vmap->version_set_index;
1238 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1239 vset = ¤t_runtime->version_sets [index];
1241 if (vmap->framework_facade_assembly) {
1242 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s is a framework Facade asseembly",
1247 if (aname->major == vset->major && aname->minor == vset->minor &&
1248 aname->build == vset->build && aname->revision == vset->revision) {
1249 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1251 aname->major, aname->minor, aname->build, aname->revision);
1255 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1256 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1257 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1259 aname->major, aname->minor, aname->build, aname->revision,
1260 vset->major, vset->minor, vset->build, vset->revision
1265 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1266 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1267 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1269 aname->major, aname->minor, aname->build, aname->revision,
1270 vset->major, vset->minor, vset->build, vset->revision
1273 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1274 dest_aname->major = vset->major;
1275 dest_aname->minor = vset->minor;
1276 dest_aname->build = vset->build;
1277 dest_aname->revision = vset->revision;
1278 if (vmap->new_assembly_name != NULL) {
1279 dest_aname->name = vmap->new_assembly_name;
1280 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1281 "The assembly name %s was remapped to %s",
1293 * mono_assembly_get_assemblyref:
1294 * \param image pointer to the \c MonoImage to extract the information from.
1295 * \param index index to the assembly reference in the image.
1296 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1298 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1301 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1304 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1307 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1309 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1311 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1312 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1313 aname->hash_value = hash;
1314 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1315 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1316 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1317 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1318 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1319 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1320 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1322 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1323 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1324 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1327 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1332 * mono_assembly_load_reference:
1335 mono_assembly_load_reference (MonoImage *image, int index)
1337 MonoAssembly *reference;
1338 MonoAssemblyName aname;
1339 MonoImageOpenStatus status;
1342 * image->references is shared between threads, so we need to access
1343 * it inside a critical section.
1345 mono_assemblies_lock ();
1346 if (!image->references) {
1347 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1349 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1350 image->nreferences = t->rows;
1352 reference = image->references [index];
1353 mono_assemblies_unlock ();
1357 mono_assembly_get_assemblyref (image, index, &aname);
1359 if (image->assembly && image->assembly->ref_only) {
1360 /* We use the loaded corlib */
1361 if (!strcmp (aname.name, "mscorlib"))
1362 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1364 reference = mono_assembly_loaded_full (&aname, TRUE);
1366 /* Try a postload search hook */
1367 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1371 * Here we must advice that the error was due to
1372 * a non loaded reference using the ReflectionOnly api
1375 reference = (MonoAssembly *)REFERENCE_MISSING;
1377 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1378 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1379 * accordingly, it would fail on the MS runtime before).
1380 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1381 * example bug-349190.2.cs and who knows how much more code in the wild.
1383 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1384 if (!reference && image->assembly)
1385 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1388 if (reference == NULL){
1391 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1392 extra_msg = g_strdup_printf ("The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (%s).\n", image->assembly != NULL ? image->assembly->basedir : "" );
1393 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1394 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1395 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1396 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1397 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1398 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1400 extra_msg = g_strdup ("");
1403 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1404 " Assembly: %s (assemblyref_index=%d)\n"
1405 " Version: %d.%d.%d.%d\n"
1406 " Public Key: %s\n%s",
1407 image->name, aname.name, index,
1408 aname.major, aname.minor, aname.build, aname.revision,
1409 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1414 mono_assemblies_lock ();
1415 if (reference == NULL) {
1416 /* Flag as not found */
1417 reference = (MonoAssembly *)REFERENCE_MISSING;
1420 if (!image->references [index]) {
1421 if (reference != REFERENCE_MISSING){
1422 mono_assembly_addref (reference);
1423 if (image->assembly)
1424 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1425 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1427 if (image->assembly)
1428 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1429 image->assembly->aname.name, image->assembly);
1432 image->references [index] = reference;
1434 mono_assemblies_unlock ();
1436 if (image->references [index] != reference) {
1437 /* Somebody loaded it before us */
1438 mono_assembly_close (reference);
1443 * mono_assembly_load_references:
1446 * \deprecated There is no reason to use this method anymore, it does nothing
1448 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1451 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1453 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1454 *status = MONO_IMAGE_OK;
1457 typedef struct AssemblyLoadHook AssemblyLoadHook;
1458 struct AssemblyLoadHook {
1459 AssemblyLoadHook *next;
1460 MonoAssemblyLoadFunc func;
1464 AssemblyLoadHook *assembly_load_hook = NULL;
1467 * mono_assembly_invoke_load_hook:
1470 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1472 AssemblyLoadHook *hook;
1474 for (hook = assembly_load_hook; hook; hook = hook->next) {
1475 hook->func (ass, hook->user_data);
1480 * mono_install_assembly_load_hook:
1483 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1485 AssemblyLoadHook *hook;
1487 g_return_if_fail (func != NULL);
1489 hook = g_new0 (AssemblyLoadHook, 1);
1491 hook->user_data = user_data;
1492 hook->next = assembly_load_hook;
1493 assembly_load_hook = hook;
1497 free_assembly_load_hooks (void)
1499 AssemblyLoadHook *hook, *next;
1501 for (hook = assembly_load_hook; hook; hook = next) {
1507 typedef struct AssemblySearchHook AssemblySearchHook;
1508 struct AssemblySearchHook {
1509 AssemblySearchHook *next;
1510 MonoAssemblySearchFunc func;
1516 AssemblySearchHook *assembly_search_hook = NULL;
1518 static MonoAssembly*
1519 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1521 AssemblySearchHook *hook;
1523 for (hook = assembly_search_hook; hook; hook = hook->next) {
1524 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1527 * A little explanation is in order here.
1529 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1530 * The embedding API exposes a search hook that doesn't take such argument.
1532 * The original fix would call the default search hook before all the registered ones and pass
1533 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1534 * rely on. Which is the ordering between user hooks and the default runtime hook.
1536 * Registering the hook after mono_jit_init would let your hook run before the default one and
1537 * when using it to handle non standard app layouts this could save your app from a massive amount
1538 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1539 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1541 * So what's the fix? We register the default hook using regular means and special case it when iterating
1542 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1545 if (hook->func == (void*)mono_domain_assembly_postload_search)
1546 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1548 ass = hook->func (aname, hook->user_data);
1558 * mono_assembly_invoke_search_hook:
1561 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1563 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1567 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1569 AssemblySearchHook *hook;
1571 g_return_if_fail (func != NULL);
1573 hook = g_new0 (AssemblySearchHook, 1);
1575 hook->user_data = user_data;
1576 hook->refonly = refonly;
1577 hook->postload = postload;
1578 hook->next = assembly_search_hook;
1579 assembly_search_hook = hook;
1583 * mono_install_assembly_search_hook:
1586 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1588 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1592 free_assembly_search_hooks (void)
1594 AssemblySearchHook *hook, *next;
1596 for (hook = assembly_search_hook; hook; hook = next) {
1603 * mono_install_assembly_refonly_search_hook:
1606 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1608 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1612 * mono_install_assembly_postload_search_hook:
1615 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1617 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1621 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1623 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1626 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1627 struct AssemblyPreLoadHook {
1628 AssemblyPreLoadHook *next;
1629 MonoAssemblyPreLoadFunc func;
1633 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1634 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1636 static MonoAssembly *
1637 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1639 AssemblyPreLoadHook *hook;
1640 MonoAssembly *assembly;
1642 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1643 assembly = hook->func (aname, assemblies_path, hook->user_data);
1644 if (assembly != NULL)
1651 static MonoAssembly *
1652 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1654 AssemblyPreLoadHook *hook;
1655 MonoAssembly *assembly;
1657 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1658 assembly = hook->func (aname, assemblies_path, hook->user_data);
1659 if (assembly != NULL)
1667 * mono_install_assembly_preload_hook:
1670 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1672 AssemblyPreLoadHook *hook;
1674 g_return_if_fail (func != NULL);
1676 hook = g_new0 (AssemblyPreLoadHook, 1);
1678 hook->user_data = user_data;
1679 hook->next = assembly_preload_hook;
1680 assembly_preload_hook = hook;
1684 * mono_install_assembly_refonly_preload_hook:
1687 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1689 AssemblyPreLoadHook *hook;
1691 g_return_if_fail (func != NULL);
1693 hook = g_new0 (AssemblyPreLoadHook, 1);
1695 hook->user_data = user_data;
1696 hook->next = assembly_refonly_preload_hook;
1697 assembly_refonly_preload_hook = hook;
1701 free_assembly_preload_hooks (void)
1703 AssemblyPreLoadHook *hook, *next;
1705 for (hook = assembly_preload_hook; hook; hook = next) {
1710 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1717 absolute_dir (const gchar *filename)
1728 if (g_path_is_absolute (filename)) {
1729 part = g_path_get_dirname (filename);
1730 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1735 cwd = g_get_current_dir ();
1736 mixed = g_build_filename (cwd, filename, NULL);
1737 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1742 for (i = 0; (part = parts [i]) != NULL; i++) {
1743 if (!strcmp (part, "."))
1746 if (!strcmp (part, "..")) {
1747 if (list && list->next) /* Don't remove root */
1748 list = g_list_delete_link (list, list);
1750 list = g_list_prepend (list, part);
1754 result = g_string_new ("");
1755 list = g_list_reverse (list);
1757 /* Ignores last data pointer, which should be the filename */
1758 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1760 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1765 g_string_free (result, FALSE);
1770 return g_strdup (".");
1777 * mono_assembly_open_from_bundle:
1778 * \param filename Filename requested
1779 * \param status return status code
1781 * This routine tries to open the assembly specified by \p filename from the
1782 * defined bundles, if found, returns the MonoImage for it, if not found
1786 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1790 gchar *lowercase_filename;
1791 MonoImage *image = NULL;
1792 gboolean is_satellite = FALSE;
1794 * we do a very simple search for bundled assemblies: it's not a general
1795 * purpose assembly loading mechanism.
1801 lowercase_filename = g_utf8_strdown (filename, -1);
1802 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1803 g_free (lowercase_filename);
1804 name = g_path_get_basename (filename);
1805 mono_assemblies_lock ();
1806 for (i = 0; !image && bundles [i]; ++i) {
1807 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1808 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1812 mono_assemblies_unlock ();
1814 mono_image_addref (image);
1815 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1824 * mono_assembly_open_full:
1825 * \param filename the file to load
1826 * \param status return status code
1827 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1829 * This loads an assembly from the specified \p filename. The \p filename allows
1830 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1831 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1832 * is treated as a local path.
1834 * First, an attempt is made to load the assembly from the bundled executable (for those
1835 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1836 * assembly has been registered as an embedded assembly). If this is not the case, then
1837 * the assembly is loaded from disk using `api:mono_image_open_full`.
1839 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1840 * the assembly is made.
1842 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1843 * the \c System.Reflection API.
1845 * \returns NULL on error, with the \p status set to an error code, or a pointer
1849 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1851 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1855 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1857 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1861 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1862 gboolean load_from_context,
1863 MonoAssemblyCandidatePredicate predicate,
1865 MonoImageOpenStatus *status)
1869 MonoImageOpenStatus def_status;
1872 gboolean loaded_from_bundle;
1874 g_return_val_if_fail (filename != NULL, NULL);
1877 status = &def_status;
1878 *status = MONO_IMAGE_OK;
1880 if (strncmp (filename, "file://", 7) == 0) {
1881 GError *error = NULL;
1882 gchar *uri = (gchar *) filename;
1886 * MS allows file://c:/... and fails on file://localhost/c:/...
1887 * They also throw an IndexOutOfRangeException if "file://"
1890 uri = g_strdup_printf ("file:///%s", uri + 7);
1893 uri = mono_escape_uri_string (tmpuri);
1894 fname = g_filename_from_uri (uri, NULL, &error);
1897 if (tmpuri != filename)
1900 if (error != NULL) {
1901 g_warning ("%s\n", error->message);
1902 g_error_free (error);
1903 fname = g_strdup (filename);
1906 fname = g_strdup (filename);
1909 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1910 "Assembly Loader probing location: '%s'.", fname);
1913 if (!mono_assembly_is_in_gac (fname)) {
1915 new_fname = mono_make_shadow_copy (fname, &error);
1916 if (!is_ok (&error)) {
1917 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1918 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1919 mono_error_cleanup (&error);
1920 *status = MONO_IMAGE_IMAGE_INVALID;
1925 if (new_fname && new_fname != fname) {
1928 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1929 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1934 // If VM built with mkbundle
1935 loaded_from_bundle = FALSE;
1936 if (bundles != NULL) {
1937 image = mono_assembly_open_from_bundle (fname, status, refonly);
1938 loaded_from_bundle = image != NULL;
1942 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1945 if (*status == MONO_IMAGE_OK)
1946 *status = MONO_IMAGE_ERROR_ERRNO;
1951 if (image->assembly) {
1952 /* We want to return the MonoAssembly that's already loaded,
1953 * but if we're using the strict assembly loader, we also need
1954 * to check that the previously loaded assembly matches the
1955 * predicate. It could be that we previously loaded a
1956 * different version that happens to have the filename that
1957 * we're currently probing. */
1958 if (mono_loader_get_strict_strong_names () &&
1959 predicate && !predicate (image->assembly, user_data)) {
1960 mono_image_close (image);
1964 /* Already loaded by another appdomain */
1965 mono_assembly_invoke_load_hook (image->assembly);
1966 mono_image_close (image);
1968 return image->assembly;
1972 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1975 if (!loaded_from_bundle)
1976 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1977 "Assembly Loader loaded assembly from location: '%s'.", filename);
1979 mono_config_for_assembly (ass->image);
1982 /* Clear the reference added by mono_image_open */
1983 mono_image_close (image);
1991 free_item (gpointer val, gpointer user_data)
1997 * mono_assembly_load_friends:
1998 * \param ass an assembly
2000 * Load the list of friend assemblies that are allowed to access
2001 * the assembly's internal types and members. They are stored as assembly
2002 * names in custom attributes.
2004 * This is an internal method, we need this because when we load mscorlib
2005 * we do not have the internals visible cattr loaded yet,
2006 * so we need to load these after we initialize the runtime.
2008 * LOCKING: Acquires the assemblies lock plus the loader lock.
2011 mono_assembly_load_friends (MonoAssembly* ass)
2015 MonoCustomAttrInfo* attrs;
2018 if (ass->friend_assembly_names_inited)
2021 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
2022 mono_error_assert_ok (&error);
2024 mono_assemblies_lock ();
2025 ass->friend_assembly_names_inited = TRUE;
2026 mono_assemblies_unlock ();
2030 mono_assemblies_lock ();
2031 if (ass->friend_assembly_names_inited) {
2032 mono_assemblies_unlock ();
2035 mono_assemblies_unlock ();
2039 * We build the list outside the assemblies lock, the worse that can happen
2040 * is that we'll need to free the allocated list.
2042 for (i = 0; i < attrs->num_attrs; ++i) {
2043 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2044 MonoAssemblyName *aname;
2046 /* Do some sanity checking */
2047 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
2049 if (attr->data_size < 4)
2051 data = (const char*)attr->data;
2052 /* 0xFF means null string, see custom attr format */
2053 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
2055 mono_metadata_decode_value (data + 2, &data);
2056 aname = g_new0 (MonoAssemblyName, 1);
2057 /*g_print ("friend ass: %s\n", data);*/
2058 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
2059 list = g_slist_prepend (list, aname);
2064 mono_custom_attrs_free (attrs);
2066 mono_assemblies_lock ();
2067 if (ass->friend_assembly_names_inited) {
2068 mono_assemblies_unlock ();
2069 g_slist_foreach (list, free_item, NULL);
2070 g_slist_free (list);
2073 ass->friend_assembly_names = list;
2075 /* Because of the double checked locking pattern above */
2076 mono_memory_barrier ();
2077 ass->friend_assembly_names_inited = TRUE;
2078 mono_assemblies_unlock ();
2081 struct HasReferenceAssemblyAttributeIterData {
2086 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
2088 gboolean stop_scanning = FALSE;
2089 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
2091 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
2092 /* Note we don't check the assembly name, same as coreCLR. */
2093 iter_data->has_attr = TRUE;
2094 stop_scanning = TRUE;
2097 return stop_scanning;
2101 * mono_assembly_has_reference_assembly_attribute:
2102 * \param assembly a MonoAssembly
2103 * \param error set on error.
2105 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2106 * On error returns FALSE and sets \p error.
2109 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
2111 g_assert (assembly && assembly->image);
2112 /* .NET Framework appears to ignore the attribute on dynamic
2113 * assemblies, so don't call this function for dynamic assemblies. */
2114 g_assert (!image_is_dynamic (assembly->image));
2118 * This might be called during assembly loading, so do everything using the low-level
2122 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
2124 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
2126 return iter_data.has_attr;
2130 * mono_assembly_open:
2131 * \param filename Opens the assembly pointed out by this name
2132 * \param status return status code
2134 * This loads an assembly from the specified \p filename. The \p filename allows
2135 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2136 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2137 * is treated as a local path.
2139 * First, an attempt is made to load the assembly from the bundled executable (for those
2140 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2141 * assembly has been registered as an embedded assembly). If this is not the case, then
2142 * the assembly is loaded from disk using `api:mono_image_open_full`.
2144 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2145 * the assembly is made.
2147 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2148 * assembly or NULL on error. Details about the error are stored in the
2149 * \p status variable.
2152 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2154 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2158 * mono_assembly_load_from_full:
2159 * \param image Image to load the assembly from
2160 * \param fname assembly name to associate with the assembly
2161 * \param status returns the status condition
2162 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2164 * If the provided \p image has an assembly reference, it will process the given
2165 * image as an assembly with the given name.
2167 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2169 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2170 * set to \c MONO_IMAGE_OK; or NULL on error.
2172 * If there is an error loading the assembly the \p status will indicate the
2173 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2174 * image did not contain an assembly reference table.
2177 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2178 MonoImageOpenStatus *status, gboolean refonly)
2180 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2184 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2186 MonoAssemblyCandidatePredicate predicate,
2188 MonoImageOpenStatus *status)
2190 MonoAssembly *ass, *ass2;
2193 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2194 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2195 *status = MONO_IMAGE_IMAGE_INVALID;
2199 #if defined (HOST_WIN32)
2204 tmp_fn = g_strdup (fname);
2205 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2206 if (tmp_fn [i] == '/')
2210 base_dir = absolute_dir (tmp_fn);
2214 base_dir = absolute_dir (fname);
2218 * Create assembly struct, and enter it into the assembly cache
2220 ass = g_new0 (MonoAssembly, 1);
2221 ass->basedir = base_dir;
2222 ass->ref_only = refonly;
2225 MONO_PROFILER_RAISE (assembly_loading, (ass));
2227 mono_assembly_fill_assembly_name (image, &ass->aname);
2229 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2230 // MS.NET doesn't support loading other mscorlibs
2233 mono_image_addref (mono_defaults.corlib);
2234 *status = MONO_IMAGE_OK;
2235 return mono_defaults.corlib->assembly;
2238 /* Add a non-temporary reference because of ass->image */
2239 mono_image_addref (image);
2241 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s[%p] -> %s[%p]: %d", ass->aname.name, ass, image->name, image, image->ref_count);
2244 * The load hooks might take locks so we can't call them while holding the
2247 if (ass->aname.name) {
2248 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2252 mono_image_close (image);
2253 *status = MONO_IMAGE_OK;
2258 /* We need to check for ReferenceAssmeblyAttribute before we
2259 * mark the assembly as loaded and before we fire the load
2260 * hook. Otherwise mono_domain_fire_assembly_load () in
2261 * appdomain.c will cache a mapping from the assembly name to
2262 * this image and we won't be able to look for a different
2266 MonoError refasm_error;
2267 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2268 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2271 mono_image_close (image);
2272 *status = MONO_IMAGE_IMAGE_INVALID;
2275 mono_error_cleanup (&refasm_error);
2278 if (predicate && !predicate (ass, user_data)) {
2279 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2282 mono_image_close (image);
2283 *status = MONO_IMAGE_IMAGE_INVALID;
2287 mono_assemblies_lock ();
2289 if (image->assembly) {
2291 * This means another thread has already loaded the assembly, but not yet
2292 * called the load hooks so the search hook can't find the assembly.
2294 mono_assemblies_unlock ();
2295 ass2 = image->assembly;
2298 mono_image_close (image);
2299 *status = MONO_IMAGE_OK;
2303 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2305 image->assembly = ass;
2307 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2308 mono_assemblies_unlock ();
2311 if (image->is_module_handle)
2312 mono_image_fixup_vtable (image);
2315 mono_assembly_invoke_load_hook (ass);
2317 MONO_PROFILER_RAISE (assembly_loaded, (ass));
2323 * mono_assembly_load_from:
2324 * \param image Image to load the assembly from
2325 * \param fname assembly name to associate with the assembly
2326 * \param status return status code
2328 * If the provided \p image has an assembly reference, it will process the given
2329 * image as an assembly with the given name.
2331 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2333 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2334 * \p refonly parameter set to FALSE.
2335 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2336 * set to \c MONO_IMAGE_OK; or NULL on error.
2338 * If there is an error loading the assembly the \p status will indicate the
2339 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2340 * image did not contain an assembly reference table.
2344 mono_assembly_load_from (MonoImage *image, const char *fname,
2345 MonoImageOpenStatus *status)
2347 return mono_assembly_load_from_full (image, fname, status, FALSE);
2351 * mono_assembly_name_free:
2352 * \param aname assembly name to free
2354 * Frees the provided assembly name object.
2355 * (it does not frees the object itself, only the name members).
2358 mono_assembly_name_free (MonoAssemblyName *aname)
2363 g_free ((void *) aname->name);
2364 g_free ((void *) aname->culture);
2365 g_free ((void *) aname->hash_value);
2366 g_free ((guint8*) aname->public_key);
2370 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2373 gchar header [16], val, *arr, *endp;
2374 gint i, j, offset, bitlen, keylen, pkeylen;
2376 //both pubkey and is_ecma are required arguments
2377 g_assert (pubkey && is_ecma);
2379 keylen = strlen (key) >> 1;
2383 /* allow the ECMA standard key */
2384 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2390 val = g_ascii_xdigit_value (key [0]) << 4;
2391 val |= g_ascii_xdigit_value (key [1]);
2396 val = g_ascii_xdigit_value (key [24]);
2397 val |= g_ascii_xdigit_value (key [25]);
2409 /* We need the first 16 bytes
2410 * to check whether this key is valid or not */
2411 pkeylen = strlen (pkey) >> 1;
2415 for (i = 0, j = 0; i < 16; i++) {
2416 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2417 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2420 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2421 header [1] != 0x02 || /* Version (0x02) */
2422 header [2] != 0x00 || /* Reserved (word) */
2423 header [3] != 0x00 ||
2424 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2427 /* Based on this length, we _should_ be able to know if the length is right */
2428 bitlen = read32 (header + 12) >> 3;
2429 if ((bitlen + 16 + 4) != pkeylen)
2432 arr = (gchar *)g_malloc (keylen + 4);
2433 /* Encode the size of the blob */
2434 mono_metadata_encode_value (keylen, &arr[0], &endp);
2435 offset = (gint)(endp-arr);
2437 for (i = offset, j = 0; i < keylen + offset; i++) {
2438 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2439 arr [i] |= g_ascii_xdigit_value (key [j++]);
2448 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)
2450 gint major, minor, build, revision;
2453 gchar *pkeyptr, *encoded, tok [8];
2455 memset (aname, 0, sizeof (MonoAssemblyName));
2458 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2459 if (version_parts < 2 || version_parts > 4)
2462 /* FIXME: we should set build & revision to -1 (instead of 0)
2463 if these are not set in the version string. That way, later on,
2464 we can still determine if these were specified. */
2465 aname->major = major;
2466 aname->minor = minor;
2467 if (version_parts >= 3)
2468 aname->build = build;
2471 if (version_parts == 4)
2472 aname->revision = revision;
2474 aname->revision = 0;
2477 aname->flags = flags;
2479 aname->name = g_strdup (name);
2482 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2483 aname->culture = g_strdup ("");
2485 aname->culture = g_strdup (culture);
2488 if (token && strncmp (token, "null", 4) != 0) {
2491 /* the constant includes the ending NULL, hence the -1 */
2492 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2493 mono_assembly_name_free (aname);
2496 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2497 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2502 gboolean is_ecma = FALSE;
2504 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2505 mono_assembly_name_free (aname);
2510 g_assert (pkey == NULL);
2511 aname->public_key = NULL;
2512 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2516 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2517 // We also need to generate the key token
2518 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2519 encoded = encode_public_tok ((guchar*) tok, 8);
2520 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2523 if (save_public_key)
2524 aname->public_key = (guint8*) pkey;
2533 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2538 parts = g_strsplit (dirname, "_", 3);
2539 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2544 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2550 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2552 char *eqsign = strchr (pair, '=');
2560 *key = (gchar*)pair;
2561 *keylen = eqsign - *key;
2562 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2564 *value = g_strstrip (eqsign + 1);
2569 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2573 gchar *version = NULL;
2575 gchar *culture = NULL;
2577 gchar *token = NULL;
2581 gchar *retargetable = NULL;
2582 gchar *retargetable_uq;
2586 gchar *value, *part_name;
2587 guint32 part_name_len;
2590 gboolean version_defined;
2591 gboolean token_defined;
2593 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2595 if (!is_version_defined)
2596 is_version_defined = &version_defined;
2597 *is_version_defined = FALSE;
2598 if (!is_token_defined)
2599 is_token_defined = &token_defined;
2600 *is_token_defined = FALSE;
2602 parts = tmp = g_strsplit (name, ",", 6);
2603 if (!tmp || !*tmp) {
2608 dllname = g_strstrip (*tmp);
2613 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2614 goto cleanup_and_fail;
2616 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2617 *is_version_defined = TRUE;
2619 if (strlen (version) == 0) {
2620 goto cleanup_and_fail;
2626 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2628 if (strlen (culture) == 0) {
2629 goto cleanup_and_fail;
2635 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2636 *is_token_defined = TRUE;
2638 if (strlen (token) == 0) {
2639 goto cleanup_and_fail;
2645 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2647 if (strlen (key) == 0) {
2648 goto cleanup_and_fail;
2654 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2655 retargetable = value;
2656 retargetable_uq = unquote (retargetable);
2657 if (retargetable_uq != NULL)
2658 retargetable = retargetable_uq;
2660 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2661 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2662 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2663 g_free (retargetable_uq);
2664 goto cleanup_and_fail;
2667 g_free (retargetable_uq);
2672 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2674 procarch_uq = unquote (procarch);
2675 if (procarch_uq != NULL)
2676 procarch = procarch_uq;
2678 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2679 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2680 else if (!g_ascii_strcasecmp (procarch, "X86"))
2681 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2682 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2683 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2684 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2685 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2687 g_free (procarch_uq);
2688 goto cleanup_and_fail;
2691 g_free (procarch_uq);
2700 /* if retargetable flag is set, then we must have a fully qualified name */
2701 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2702 goto cleanup_and_fail;
2705 dllname_uq = unquote (dllname);
2706 version_uq = unquote (version);
2707 culture_uq = unquote (culture);
2708 token_uq = unquote (token);
2709 key_uq = unquote (key);
2711 res = build_assembly_name (
2712 dllname_uq == NULL ? dllname : dllname_uq,
2713 version_uq == NULL ? version : version_uq,
2714 culture_uq == NULL ? culture : culture_uq,
2715 token_uq == NULL ? token : token_uq,
2716 key_uq == NULL ? key : key_uq,
2717 flags, arch, aname, save_public_key);
2719 g_free (dllname_uq);
2720 g_free (version_uq);
2721 g_free (culture_uq);
2734 unquote (const char *str)
2742 slen = strlen (str);
2746 if (*str != '\'' && *str != '\"')
2749 end = str + slen - 1;
2753 return g_strndup (str + 1, slen - 2);
2757 * mono_assembly_name_parse:
2758 * \param name name to parse
2759 * \param aname the destination assembly name
2761 * Parses an assembly qualified type name and assigns the name,
2762 * version, culture and token to the provided assembly name object.
2764 * \returns TRUE if the name could be parsed.
2767 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2769 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2773 * mono_assembly_name_new:
2774 * \param name name to parse
2776 * Allocate a new \c MonoAssemblyName and fill its values from the
2779 * \returns a newly allocated structure or NULL if there was any failure.
2782 mono_assembly_name_new (const char *name)
2784 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2785 if (mono_assembly_name_parse (name, aname))
2792 * mono_assembly_name_get_name:
2795 mono_assembly_name_get_name (MonoAssemblyName *aname)
2801 * mono_assembly_name_get_culture:
2804 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2806 return aname->culture;
2810 * mono_assembly_name_get_pubkeytoken:
2813 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2815 if (aname->public_key_token [0])
2816 return aname->public_key_token;
2821 * mono_assembly_name_get_version:
2824 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2827 *minor = aname->minor;
2829 *build = aname->build;
2831 *revision = aname->revision;
2832 return aname->major;
2835 static MonoAssembly*
2836 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2838 gchar *fullpath = NULL;
2840 const char* direntry;
2841 MonoAssemblyName gac_aname;
2842 gint major=-1, minor=0, build=0, revision=0;
2843 gboolean exact_version;
2845 dirhandle = g_dir_open (basepath, 0, NULL);
2849 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2851 while ((direntry = g_dir_read_name (dirhandle))) {
2852 gboolean match = TRUE;
2854 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2857 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2860 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2861 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2865 if (exact_version) {
2866 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2867 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2869 else if (gac_aname.major < major)
2871 else if (gac_aname.major == major) {
2872 if (gac_aname.minor < minor)
2874 else if (gac_aname.minor == minor) {
2875 if (gac_aname.build < build)
2877 else if (gac_aname.build == build && gac_aname.revision <= revision)
2884 major = gac_aname.major;
2885 minor = gac_aname.minor;
2886 build = gac_aname.build;
2887 revision = gac_aname.revision;
2889 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2892 mono_assembly_name_free (&gac_aname);
2895 g_dir_close (dirhandle);
2897 if (fullpath == NULL)
2900 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2907 * mono_assembly_load_with_partial_name:
2908 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2909 * \param status return status code
2911 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2912 * so it might contain a qualified type name, version, culture and token.
2914 * This will load the assembly from the file whose name is derived from the assembly name
2915 * by appending the \c .dll extension.
2917 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2918 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2919 * if that fails from the GAC.
2921 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2924 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2928 MonoAssemblyName *aname, base_name;
2929 MonoAssemblyName mapped_aname;
2930 gchar *fullname, *gacpath;
2933 memset (&base_name, 0, sizeof (MonoAssemblyName));
2936 if (!mono_assembly_name_parse (name, aname))
2940 * If no specific version has been requested, make sure we load the
2941 * correct version for system assemblies.
2943 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2944 aname = mono_assembly_remap_version (aname, &mapped_aname);
2946 res = mono_assembly_loaded (aname);
2948 mono_assembly_name_free (aname);
2952 res = invoke_assembly_preload_hook (aname, assemblies_path);
2954 res->in_gac = FALSE;
2955 mono_assembly_name_free (aname);
2959 fullname = g_strdup_printf ("%s.dll", aname->name);
2961 if (extra_gac_paths) {
2962 paths = extra_gac_paths;
2963 while (!res && *paths) {
2964 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2965 res = probe_for_partial_name (gacpath, fullname, aname, status);
2974 mono_assembly_name_free (aname);
2978 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2979 res = probe_for_partial_name (gacpath, fullname, aname, status);
2983 mono_assembly_name_free (aname);
2988 MonoDomain *domain = mono_domain_get ();
2990 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2991 if (!is_ok (&error)) {
2992 mono_error_cleanup (&error);
2993 if (*status == MONO_IMAGE_OK)
2994 *status = MONO_IMAGE_IMAGE_INVALID;
3002 mono_assembly_is_in_gac (const gchar *filename)
3004 const gchar *rootdir;
3008 if (filename == NULL)
3011 for (paths = extra_gac_paths; paths && *paths; paths++) {
3012 if (strstr (*paths, filename) != *paths)
3015 gp = (gchar *) (filename + strlen (*paths));
3016 if (*gp != G_DIR_SEPARATOR)
3019 if (strncmp (gp, "lib", 3))
3022 if (*gp != G_DIR_SEPARATOR)
3025 if (strncmp (gp, "mono", 4))
3028 if (*gp != G_DIR_SEPARATOR)
3031 if (strncmp (gp, "gac", 3))
3034 if (*gp != G_DIR_SEPARATOR)
3040 rootdir = mono_assembly_getrootdir ();
3041 if (strstr (filename, rootdir) != filename)
3044 gp = (gchar *) (filename + strlen (rootdir));
3045 if (*gp != G_DIR_SEPARATOR)
3048 if (strncmp (gp, "mono", 4))
3051 if (*gp != G_DIR_SEPARATOR)
3054 if (strncmp (gp, "gac", 3))
3057 if (*gp != G_DIR_SEPARATOR)
3063 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3066 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
3070 if (strstr (aname->name, ".dll")) {
3071 len = strlen (aname->name) - 4;
3072 name = (gchar *)g_malloc (len + 1);
3073 memcpy (name, aname->name, len);
3076 name = g_strdup (aname->name);
3079 culture = g_utf8_strdown (aname->culture, -1);
3081 culture = g_strdup ("");
3083 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
3084 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
3088 filename = g_strconcat (pname, ".dll", NULL);
3089 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
3095 if (extra_gac_paths) {
3096 paths = extra_gac_paths;
3097 while (!image && *paths) {
3098 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
3099 "lib", "mono", "gac", subpath, NULL);
3100 image = mono_image_open (fullpath, NULL);
3111 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3112 "mono", "gac", subpath, NULL);
3113 image = mono_image_open (fullpath, NULL);
3120 static MonoAssemblyName*
3121 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3123 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3124 dest_name->major = info->new_version.major;
3125 dest_name->minor = info->new_version.minor;
3126 dest_name->build = info->new_version.build;
3127 dest_name->revision = info->new_version.revision;
3132 /* LOCKING: assembly_binding lock must be held */
3133 static MonoAssemblyBindingInfo*
3134 search_binding_loaded (MonoAssemblyName *aname)
3138 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3139 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3140 if (assembly_binding_maps_name (info, aname))
3147 static inline gboolean
3148 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3150 if (left->major != right->major || left->minor != right->minor ||
3151 left->build != right->build || left->revision != right->revision)
3157 static inline gboolean
3158 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3160 if (left->has_old_version_bottom != right->has_old_version_bottom)
3163 if (left->has_old_version_top != right->has_old_version_top)
3166 if (left->has_new_version != right->has_new_version)
3169 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3172 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3175 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3181 /* LOCKING: assumes all the necessary locks are held */
3183 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3185 MonoAssemblyBindingInfo *info_copy;
3187 MonoAssemblyBindingInfo *info_tmp;
3188 MonoDomain *domain = (MonoDomain*)user_data;
3193 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)) {
3194 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3195 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3199 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3200 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3201 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3205 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3206 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3208 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3210 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3212 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3216 get_version_number (int major, int minor)
3218 return major * 256 + minor;
3221 static inline gboolean
3222 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3224 int aname_version_number = get_version_number (aname->major, aname->minor);
3225 if (!info->has_old_version_bottom)
3228 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3231 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3234 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3235 info->major = aname->major;
3236 info->minor = aname->minor;
3241 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3242 static MonoAssemblyBindingInfo*
3243 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3245 MonoAssemblyBindingInfo *info;
3248 if (!domain->assembly_bindings)
3252 for (list = domain->assembly_bindings; list; list = list->next) {
3253 info = (MonoAssemblyBindingInfo *)list->data;
3254 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3260 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3261 info->has_new_version && assembly_binding_maps_name (info, aname))
3262 info->is_valid = TRUE;
3264 info->is_valid = FALSE;
3271 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3273 if (domain->assembly_bindings_parsed)
3275 mono_domain_lock (domain);
3276 if (!domain->assembly_bindings_parsed) {
3278 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3280 if (!domain_config_file_path)
3281 domain_config_file_path = domain_config_file_name;
3283 mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3284 domain->assembly_bindings_parsed = TRUE;
3285 if (domain_config_file_name != domain_config_file_path)
3286 g_free (domain_config_file_path);
3289 mono_domain_unlock (domain);
3292 static MonoAssemblyName*
3293 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3296 MonoAssemblyBindingInfo *info, *info2;
3300 if (aname->public_key_token [0] == 0)
3303 domain = mono_domain_get ();
3305 mono_assembly_binding_lock ();
3306 info = search_binding_loaded (aname);
3307 mono_assembly_binding_unlock ();
3310 mono_domain_lock (domain);
3311 info = get_per_domain_assembly_binding_info (domain, aname);
3312 mono_domain_unlock (domain);
3316 if (!check_policy_versions (info, aname))
3319 mono_assembly_bind_version (info, aname, dest_name);
3323 if (domain && domain->setup && domain->setup->configuration_file) {
3324 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3325 /* expect this to succeed because mono_domain_set_options_from_config () did
3326 * the same thing when the domain was created. */
3327 mono_error_assert_ok (&error);
3328 mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3329 g_free (domain_config_file_name);
3331 mono_domain_lock (domain);
3332 info2 = get_per_domain_assembly_binding_info (domain, aname);
3335 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3336 info->name = g_strdup (info2->name);
3337 info->culture = g_strdup (info2->culture);
3338 info->domain_id = domain->domain_id;
3341 mono_domain_unlock (domain);
3346 info = g_new0 (MonoAssemblyBindingInfo, 1);
3347 info->major = aname->major;
3348 info->minor = aname->minor;
3351 if (!info->is_valid) {
3352 ppimage = mono_assembly_load_publisher_policy (aname);
3354 get_publisher_policy_info (ppimage, aname, info);
3355 mono_image_close (ppimage);
3359 /* Define default error value if needed */
3360 if (!info->is_valid) {
3361 info->name = g_strdup (aname->name);
3362 info->culture = g_strdup (aname->culture);
3363 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3366 mono_assembly_binding_lock ();
3367 info2 = search_binding_loaded (aname);
3369 /* This binding was added by another thread
3371 mono_assembly_binding_info_free (info);
3376 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3378 mono_assembly_binding_unlock ();
3380 if (!info->is_valid || !check_policy_versions (info, aname))
3383 mono_assembly_bind_version (info, aname, dest_name);
3388 * mono_assembly_load_from_gac
3390 * \param aname The assembly name object
3392 static MonoAssembly*
3393 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3395 MonoAssembly *result = NULL;
3396 gchar *name, *version, *culture, *fullpath, *subpath;
3401 if (aname->public_key_token [0] == 0) {
3405 if (strstr (aname->name, ".dll")) {
3406 len = strlen (filename) - 4;
3407 name = (gchar *)g_malloc (len + 1);
3408 memcpy (name, aname->name, len);
3411 name = g_strdup (aname->name);
3414 if (aname->culture) {
3415 culture = g_utf8_strdown (aname->culture, -1);
3417 culture = g_strdup ("");
3420 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3421 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3422 aname->minor, aname->build, aname->revision,
3426 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3431 if (extra_gac_paths) {
3432 paths = extra_gac_paths;
3433 while (!result && *paths) {
3434 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3435 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3442 result->in_gac = TRUE;
3447 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3448 "mono", "gac", subpath, NULL);
3449 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3453 result->in_gac = TRUE;
3461 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3464 MonoAssemblyName *aname;
3467 /* g_print ("corlib already loaded\n"); */
3471 // A nonstandard preload hook may provide a special mscorlib assembly
3472 aname = mono_assembly_name_new ("mscorlib.dll");
3473 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3474 mono_assembly_name_free (aname);
3477 goto return_corlib_and_facades;
3479 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3480 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3481 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3483 goto return_corlib_and_facades;
3486 /* Normal case: Load corlib from mono/<version> */
3487 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3488 if (assemblies_path) { // Custom assemblies path
3489 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3491 g_free (corlib_file);
3492 goto return_corlib_and_facades;
3495 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3496 g_free (corlib_file);
3498 return_corlib_and_facades:
3499 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3500 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3505 static MonoAssembly*
3506 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3508 MonoError refasm_error;
3509 error_init (&refasm_error);
3510 if (candidate && !refonly) {
3511 /* .NET Framework seems to not check for ReferenceAssemblyAttribute on dynamic assemblies */
3512 if (!image_is_dynamic (candidate->image) &&
3513 mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error))
3516 mono_error_cleanup (&refasm_error);
3521 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3523 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3524 MonoAssemblyName *candidate_name = &candidate->aname;
3526 g_assert (wanted_name != NULL);
3527 g_assert (candidate_name != NULL);
3529 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3530 char * s = mono_stringify_assembly_name (wanted_name);
3531 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3533 s = mono_stringify_assembly_name (candidate_name);
3534 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3539 /* Wanted name has no token, not strongly named: always matches. */
3540 if (0 == wanted_name->public_key_token [0]) {
3541 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3545 /* Candidate name has no token, not strongly named: never matches */
3546 if (0 == candidate_name->public_key_token [0]) {
3547 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3551 return exact_sn_match (wanted_name, candidate_name) ||
3552 framework_assembly_sn_match (wanted_name, candidate_name);
3556 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3558 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3560 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3561 result ? "match, returning TRUE" : "don't match, returning FALSE");
3567 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3569 #ifndef DISABLE_DESKTOP_LOADER
3570 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3572 if (!vmap->framework_facade_assembly) {
3573 /* 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. */
3574 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3575 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");
3578 /* For facades, the name and public key token should
3579 * match, but the version doesn't matter. */
3580 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3581 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");
3590 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3591 const char *basedir,
3592 MonoImageOpenStatus *status,
3595 MonoAssembly *result;
3596 char *fullpath, *filename;
3597 MonoAssemblyName maped_aname;
3598 MonoAssemblyName maped_name_pp;
3603 aname = mono_assembly_remap_version (aname, &maped_aname);
3605 /* Reflection only assemblies don't get assembly binding */
3607 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3609 result = mono_assembly_loaded_full (aname, refonly);
3613 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3615 result->in_gac = FALSE;
3619 /* Currently we retrieve the loaded corlib for reflection
3620 * only requests, like a common reflection only assembly
3622 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3623 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3626 MonoAssemblyCandidatePredicate predicate = NULL;
3627 void* predicate_ud = NULL;
3628 #if !defined(DISABLE_DESKTOP_LOADER)
3629 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
3630 predicate = &mono_assembly_candidate_predicate_sn_same_name;
3631 predicate_ud = aname;
3635 len = strlen (aname->name);
3636 for (ext_index = 0; ext_index < 2; ext_index ++) {
3637 ext = ext_index == 0 ? ".dll" : ".exe";
3638 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3639 filename = g_strdup (aname->name);
3640 /* Don't try appending .dll/.exe if it already has one of those extensions */
3643 filename = g_strconcat (aname->name, ext, NULL);
3646 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3653 fullpath = g_build_filename (basedir, filename, NULL);
3654 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, predicate_ud, status);
3657 result->in_gac = FALSE;
3663 result = load_in_path (filename, default_path, status, refonly, predicate, predicate_ud);
3665 result->in_gac = FALSE;
3675 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3677 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3680 /* Try a postload search hook */
3681 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3682 result = prevent_reference_assembly_from_running (result, refonly);
3688 * mono_assembly_load_full:
3689 * \param aname A MonoAssemblyName with the assembly name to load.
3690 * \param basedir A directory to look up the assembly at.
3691 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3692 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3694 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3695 * attempts to load the assembly from that directory before probing the standard locations.
3697 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3698 * assembly binding takes place.
3700 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3701 * value pointed by \p status is updated with an error code.
3704 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3706 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3710 * mono_assembly_load:
3711 * \param aname A MonoAssemblyName with the assembly name to load.
3712 * \param basedir A directory to look up the assembly at.
3713 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3715 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3716 * attempts to load the assembly from that directory before probing the standard locations.
3718 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3719 * value pointed by \p status is updated with an error code.
3722 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3724 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3728 * mono_assembly_loaded_full:
3729 * \param aname an assembly to look for.
3730 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3732 * This is used to determine if the specified assembly has been loaded
3733 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3734 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3737 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3740 MonoAssemblyName maped_aname;
3742 aname = mono_assembly_remap_version (aname, &maped_aname);
3744 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3750 * mono_assembly_loaded:
3751 * \param aname an assembly to look for.
3753 * This is used to determine if the specified assembly has been loaded
3755 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3756 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3759 mono_assembly_loaded (MonoAssemblyName *aname)
3761 return mono_assembly_loaded_full (aname, FALSE);
3765 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3767 if (assembly == NULL || assembly == REFERENCE_MISSING)
3770 if (assembly_is_dynamic (assembly)) {
3772 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3773 for (i = 0; i < dynimg->image.module_count; ++i)
3774 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3775 mono_dynamic_image_release_gc_roots (dynimg);
3780 * Returns whether mono_assembly_close_finish() must be called as
3781 * well. See comment for mono_image_close_except_pools() for why we
3782 * unload in two steps.
3785 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3788 g_return_val_if_fail (assembly != NULL, FALSE);
3790 if (assembly == REFERENCE_MISSING)
3793 /* Might be 0 already */
3794 if (InterlockedDecrement (&assembly->ref_count) > 0)
3797 MONO_PROFILER_RAISE (assembly_unloading, (assembly));
3799 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3801 mono_debug_close_image (assembly->image);
3803 mono_assemblies_lock ();
3804 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3805 mono_assemblies_unlock ();
3807 assembly->image->assembly = NULL;
3809 if (!mono_image_close_except_pools (assembly->image))
3810 assembly->image = NULL;
3812 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3813 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3814 mono_assembly_name_free (fname);
3817 g_slist_free (assembly->friend_assembly_names);
3818 g_free (assembly->basedir);
3820 MONO_PROFILER_RAISE (assembly_unloaded, (assembly));
3826 mono_assembly_close_finish (MonoAssembly *assembly)
3828 g_assert (assembly && assembly != REFERENCE_MISSING);
3830 if (assembly->image)
3831 mono_image_close_finish (assembly->image);
3833 if (assembly_is_dynamic (assembly)) {
3834 g_free ((char*)assembly->aname.culture);
3841 * mono_assembly_close:
3842 * \param assembly the assembly to release.
3844 * This method releases a reference to the \p assembly. The assembly is
3845 * only released when all the outstanding references to it are released.
3848 mono_assembly_close (MonoAssembly *assembly)
3850 if (mono_assembly_close_except_image_pools (assembly))
3851 mono_assembly_close_finish (assembly);
3855 * mono_assembly_load_module:
3858 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3861 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3862 mono_error_assert_ok (&error);
3867 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3869 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3874 * mono_assembly_foreach:
3875 * \param func function to invoke for each assembly loaded
3876 * \param user_data data passed to the callback
3878 * Invokes the provided \p func callback for each assembly loaded into
3879 * the runtime. The first parameter passed to the callback is the
3880 * \c MonoAssembly*, and the second parameter is the \p user_data.
3882 * This is done for all assemblies loaded in the runtime, not just
3883 * those loaded in the current application domain.
3886 mono_assembly_foreach (GFunc func, gpointer user_data)
3891 * We make a copy of the list to avoid calling the callback inside the
3892 * lock, which could lead to deadlocks.
3894 mono_assemblies_lock ();
3895 copy = g_list_copy (loaded_assemblies);
3896 mono_assemblies_unlock ();
3898 g_list_foreach (loaded_assemblies, func, user_data);
3904 * mono_assemblies_cleanup:
3906 * Free all resources used by this module.
3909 mono_assemblies_cleanup (void)
3913 mono_os_mutex_destroy (&assemblies_mutex);
3914 mono_os_mutex_destroy (&assembly_binding_mutex);
3916 for (l = loaded_assembly_bindings; l; l = l->next) {
3917 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3919 mono_assembly_binding_info_free (info);
3922 g_slist_free (loaded_assembly_bindings);
3924 free_assembly_load_hooks ();
3925 free_assembly_search_hooks ();
3926 free_assembly_preload_hooks ();
3929 /*LOCKING takes the assembly_binding lock*/
3931 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3935 mono_assembly_binding_lock ();
3936 iter = &loaded_assembly_bindings;
3939 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3941 if (info->domain_id == domain_id) {
3943 mono_assembly_binding_info_free (info);
3950 mono_assembly_binding_unlock ();
3954 * Holds the assembly of the application, for
3955 * System.Diagnostics.Process::MainModule
3957 static MonoAssembly *main_assembly=NULL;
3960 * mono_assembly_set_main:
3963 mono_assembly_set_main (MonoAssembly *assembly)
3965 main_assembly = assembly;
3969 * mono_assembly_get_main:
3971 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3974 mono_assembly_get_main (void)
3976 return (main_assembly);
3980 * mono_assembly_get_image:
3981 * \param assembly The assembly to retrieve the image from
3983 * \returns the \c MonoImage associated with this assembly.
3986 mono_assembly_get_image (MonoAssembly *assembly)
3988 return assembly->image;
3992 * mono_assembly_get_name:
3993 * \param assembly The assembly to retrieve the name from
3995 * The returned name's lifetime is the same as \p assembly's.
3997 * \returns the \c MonoAssemblyName associated with this assembly.
4000 mono_assembly_get_name (MonoAssembly *assembly)
4002 return &assembly->aname;
4006 * mono_register_bundled_assemblies:
4009 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4011 bundles = assemblies;
4014 #define MONO_DECLSEC_FORMAT_10 0x3C
4015 #define MONO_DECLSEC_FORMAT_20 0x2E
4016 #define MONO_DECLSEC_FIELD 0x53
4017 #define MONO_DECLSEC_PROPERTY 0x54
4019 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4020 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4021 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4022 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4023 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4026 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4030 case MONO_DECLSEC_PROPERTY:
4032 case MONO_DECLSEC_FIELD:
4034 *abort_decoding = TRUE;
4039 if (*p++ != MONO_TYPE_BOOLEAN) {
4040 *abort_decoding = TRUE;
4044 /* property name length */
4045 len = mono_metadata_decode_value (p, &p);
4047 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4058 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4060 int i, j, num, len, params_len;
4062 if (*p == MONO_DECLSEC_FORMAT_10) {
4063 gsize read, written;
4064 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4066 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4072 if (*p++ != MONO_DECLSEC_FORMAT_20)
4075 /* number of encoded permission attributes */
4076 num = mono_metadata_decode_value (p, &p);
4077 for (i = 0; i < num; ++i) {
4078 gboolean is_valid = FALSE;
4079 gboolean abort_decoding = FALSE;
4081 /* attribute name length */
4082 len = mono_metadata_decode_value (p, &p);
4084 /* We don't really need to fully decode the type. Comparing the name is enough */
4085 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4089 /*size of the params table*/
4090 params_len = mono_metadata_decode_value (p, &p);
4092 const char *params_end = p + params_len;
4094 /* number of parameters */
4095 len = mono_metadata_decode_value (p, &p);
4097 for (j = 0; j < len; ++j) {
4098 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4114 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4117 guint32 cols [MONO_DECL_SECURITY_SIZE];
4121 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4122 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4124 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4126 for (i = 0; i < t->rows; ++i) {
4127 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4128 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4130 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4133 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4134 len = mono_metadata_decode_blob_size (blob, &blob);
4138 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4139 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4144 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);