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) {
2385 *pubkey = g_strdup (key);
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 *pkey, *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);
2503 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2504 mono_assembly_name_free (aname);
2509 aname->public_key = NULL;
2511 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2515 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2516 // We also need to generate the key token
2517 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2518 encoded = encode_public_tok ((guchar*) tok, 8);
2519 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2522 if (save_public_key)
2523 aname->public_key = (guint8*) pkey;
2532 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2537 parts = g_strsplit (dirname, "_", 3);
2538 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2543 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2549 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2551 char *eqsign = strchr (pair, '=');
2559 *key = (gchar*)pair;
2560 *keylen = eqsign - *key;
2561 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2563 *value = g_strstrip (eqsign + 1);
2568 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2572 gchar *version = NULL;
2574 gchar *culture = NULL;
2576 gchar *token = NULL;
2580 gchar *retargetable = NULL;
2581 gchar *retargetable_uq;
2585 gchar *value, *part_name;
2586 guint32 part_name_len;
2589 gboolean version_defined;
2590 gboolean token_defined;
2592 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2594 if (!is_version_defined)
2595 is_version_defined = &version_defined;
2596 *is_version_defined = FALSE;
2597 if (!is_token_defined)
2598 is_token_defined = &token_defined;
2599 *is_token_defined = FALSE;
2601 parts = tmp = g_strsplit (name, ",", 6);
2602 if (!tmp || !*tmp) {
2607 dllname = g_strstrip (*tmp);
2612 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2613 goto cleanup_and_fail;
2615 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2616 *is_version_defined = TRUE;
2618 if (strlen (version) == 0) {
2619 goto cleanup_and_fail;
2625 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2627 if (strlen (culture) == 0) {
2628 goto cleanup_and_fail;
2634 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2635 *is_token_defined = TRUE;
2637 if (strlen (token) == 0) {
2638 goto cleanup_and_fail;
2644 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2646 if (strlen (key) == 0) {
2647 goto cleanup_and_fail;
2653 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2654 retargetable = value;
2655 retargetable_uq = unquote (retargetable);
2656 if (retargetable_uq != NULL)
2657 retargetable = retargetable_uq;
2659 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2660 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2661 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2662 g_free (retargetable_uq);
2663 goto cleanup_and_fail;
2666 g_free (retargetable_uq);
2671 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2673 procarch_uq = unquote (procarch);
2674 if (procarch_uq != NULL)
2675 procarch = procarch_uq;
2677 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2678 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2679 else if (!g_ascii_strcasecmp (procarch, "X86"))
2680 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2681 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2682 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2683 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2684 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2686 g_free (procarch_uq);
2687 goto cleanup_and_fail;
2690 g_free (procarch_uq);
2699 /* if retargetable flag is set, then we must have a fully qualified name */
2700 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2701 goto cleanup_and_fail;
2704 dllname_uq = unquote (dllname);
2705 version_uq = unquote (version);
2706 culture_uq = unquote (culture);
2707 token_uq = unquote (token);
2708 key_uq = unquote (key);
2710 res = build_assembly_name (
2711 dllname_uq == NULL ? dllname : dllname_uq,
2712 version_uq == NULL ? version : version_uq,
2713 culture_uq == NULL ? culture : culture_uq,
2714 token_uq == NULL ? token : token_uq,
2715 key_uq == NULL ? key : key_uq,
2716 flags, arch, aname, save_public_key);
2718 g_free (dllname_uq);
2719 g_free (version_uq);
2720 g_free (culture_uq);
2733 unquote (const char *str)
2741 slen = strlen (str);
2745 if (*str != '\'' && *str != '\"')
2748 end = str + slen - 1;
2752 return g_strndup (str + 1, slen - 2);
2756 * mono_assembly_name_parse:
2757 * \param name name to parse
2758 * \param aname the destination assembly name
2760 * Parses an assembly qualified type name and assigns the name,
2761 * version, culture and token to the provided assembly name object.
2763 * \returns TRUE if the name could be parsed.
2766 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2768 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2772 * mono_assembly_name_new:
2773 * \param name name to parse
2775 * Allocate a new \c MonoAssemblyName and fill its values from the
2778 * \returns a newly allocated structure or NULL if there was any failure.
2781 mono_assembly_name_new (const char *name)
2783 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2784 if (mono_assembly_name_parse (name, aname))
2791 * mono_assembly_name_get_name:
2794 mono_assembly_name_get_name (MonoAssemblyName *aname)
2800 * mono_assembly_name_get_culture:
2803 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2805 return aname->culture;
2809 * mono_assembly_name_get_pubkeytoken:
2812 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2814 if (aname->public_key_token [0])
2815 return aname->public_key_token;
2820 * mono_assembly_name_get_version:
2823 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2826 *minor = aname->minor;
2828 *build = aname->build;
2830 *revision = aname->revision;
2831 return aname->major;
2834 static MonoAssembly*
2835 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2837 gchar *fullpath = NULL;
2839 const char* direntry;
2840 MonoAssemblyName gac_aname;
2841 gint major=-1, minor=0, build=0, revision=0;
2842 gboolean exact_version;
2844 dirhandle = g_dir_open (basepath, 0, NULL);
2848 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2850 while ((direntry = g_dir_read_name (dirhandle))) {
2851 gboolean match = TRUE;
2853 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2856 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2859 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2860 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2864 if (exact_version) {
2865 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2866 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2868 else if (gac_aname.major < major)
2870 else if (gac_aname.major == major) {
2871 if (gac_aname.minor < minor)
2873 else if (gac_aname.minor == minor) {
2874 if (gac_aname.build < build)
2876 else if (gac_aname.build == build && gac_aname.revision <= revision)
2883 major = gac_aname.major;
2884 minor = gac_aname.minor;
2885 build = gac_aname.build;
2886 revision = gac_aname.revision;
2888 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2891 mono_assembly_name_free (&gac_aname);
2894 g_dir_close (dirhandle);
2896 if (fullpath == NULL)
2899 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2906 * mono_assembly_load_with_partial_name:
2907 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2908 * \param status return status code
2910 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2911 * so it might contain a qualified type name, version, culture and token.
2913 * This will load the assembly from the file whose name is derived from the assembly name
2914 * by appending the \c .dll extension.
2916 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2917 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2918 * if that fails from the GAC.
2920 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2923 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2927 MonoAssemblyName *aname, base_name;
2928 MonoAssemblyName mapped_aname;
2929 gchar *fullname, *gacpath;
2932 memset (&base_name, 0, sizeof (MonoAssemblyName));
2935 if (!mono_assembly_name_parse (name, aname))
2939 * If no specific version has been requested, make sure we load the
2940 * correct version for system assemblies.
2942 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2943 aname = mono_assembly_remap_version (aname, &mapped_aname);
2945 res = mono_assembly_loaded (aname);
2947 mono_assembly_name_free (aname);
2951 res = invoke_assembly_preload_hook (aname, assemblies_path);
2953 res->in_gac = FALSE;
2954 mono_assembly_name_free (aname);
2958 fullname = g_strdup_printf ("%s.dll", aname->name);
2960 if (extra_gac_paths) {
2961 paths = extra_gac_paths;
2962 while (!res && *paths) {
2963 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2964 res = probe_for_partial_name (gacpath, fullname, aname, status);
2973 mono_assembly_name_free (aname);
2977 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2978 res = probe_for_partial_name (gacpath, fullname, aname, status);
2982 mono_assembly_name_free (aname);
2987 MonoDomain *domain = mono_domain_get ();
2989 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
2990 if (!is_ok (&error)) {
2991 mono_error_cleanup (&error);
2992 if (*status == MONO_IMAGE_OK)
2993 *status = MONO_IMAGE_IMAGE_INVALID;
3001 mono_assembly_is_in_gac (const gchar *filename)
3003 const gchar *rootdir;
3007 if (filename == NULL)
3010 for (paths = extra_gac_paths; paths && *paths; paths++) {
3011 if (strstr (*paths, filename) != *paths)
3014 gp = (gchar *) (filename + strlen (*paths));
3015 if (*gp != G_DIR_SEPARATOR)
3018 if (strncmp (gp, "lib", 3))
3021 if (*gp != G_DIR_SEPARATOR)
3024 if (strncmp (gp, "mono", 4))
3027 if (*gp != G_DIR_SEPARATOR)
3030 if (strncmp (gp, "gac", 3))
3033 if (*gp != G_DIR_SEPARATOR)
3039 rootdir = mono_assembly_getrootdir ();
3040 if (strstr (filename, rootdir) != filename)
3043 gp = (gchar *) (filename + strlen (rootdir));
3044 if (*gp != G_DIR_SEPARATOR)
3047 if (strncmp (gp, "mono", 4))
3050 if (*gp != G_DIR_SEPARATOR)
3053 if (strncmp (gp, "gac", 3))
3056 if (*gp != G_DIR_SEPARATOR)
3062 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3065 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
3069 if (strstr (aname->name, ".dll")) {
3070 len = strlen (aname->name) - 4;
3071 name = (gchar *)g_malloc (len + 1);
3072 memcpy (name, aname->name, len);
3075 name = g_strdup (aname->name);
3078 culture = g_utf8_strdown (aname->culture, -1);
3080 culture = g_strdup ("");
3082 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
3083 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
3087 filename = g_strconcat (pname, ".dll", NULL);
3088 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
3094 if (extra_gac_paths) {
3095 paths = extra_gac_paths;
3096 while (!image && *paths) {
3097 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
3098 "lib", "mono", "gac", subpath, NULL);
3099 image = mono_image_open (fullpath, NULL);
3110 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3111 "mono", "gac", subpath, NULL);
3112 image = mono_image_open (fullpath, NULL);
3119 static MonoAssemblyName*
3120 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3122 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3123 dest_name->major = info->new_version.major;
3124 dest_name->minor = info->new_version.minor;
3125 dest_name->build = info->new_version.build;
3126 dest_name->revision = info->new_version.revision;
3131 /* LOCKING: assembly_binding lock must be held */
3132 static MonoAssemblyBindingInfo*
3133 search_binding_loaded (MonoAssemblyName *aname)
3137 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3138 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3139 if (assembly_binding_maps_name (info, aname))
3146 static inline gboolean
3147 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3149 if (left->major != right->major || left->minor != right->minor ||
3150 left->build != right->build || left->revision != right->revision)
3156 static inline gboolean
3157 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3159 if (left->has_old_version_bottom != right->has_old_version_bottom)
3162 if (left->has_old_version_top != right->has_old_version_top)
3165 if (left->has_new_version != right->has_new_version)
3168 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3171 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3174 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3180 /* LOCKING: assumes all the necessary locks are held */
3182 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3184 MonoAssemblyBindingInfo *info_copy;
3186 MonoAssemblyBindingInfo *info_tmp;
3187 MonoDomain *domain = (MonoDomain*)user_data;
3192 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)) {
3193 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3194 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3198 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3199 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3200 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3204 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3205 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3207 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3209 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3211 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3215 get_version_number (int major, int minor)
3217 return major * 256 + minor;
3220 static inline gboolean
3221 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3223 int aname_version_number = get_version_number (aname->major, aname->minor);
3224 if (!info->has_old_version_bottom)
3227 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3230 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3233 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3234 info->major = aname->major;
3235 info->minor = aname->minor;
3240 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3241 static MonoAssemblyBindingInfo*
3242 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3244 MonoAssemblyBindingInfo *info;
3247 if (!domain->assembly_bindings)
3251 for (list = domain->assembly_bindings; list; list = list->next) {
3252 info = (MonoAssemblyBindingInfo *)list->data;
3253 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3259 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3260 info->has_new_version && assembly_binding_maps_name (info, aname))
3261 info->is_valid = TRUE;
3263 info->is_valid = FALSE;
3270 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3272 if (domain->assembly_bindings_parsed)
3274 mono_domain_lock (domain);
3275 if (!domain->assembly_bindings_parsed) {
3277 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3279 if (!domain_config_file_path)
3280 domain_config_file_path = domain_config_file_name;
3282 mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3283 domain->assembly_bindings_parsed = TRUE;
3284 if (domain_config_file_name != domain_config_file_path)
3285 g_free (domain_config_file_path);
3288 mono_domain_unlock (domain);
3291 static MonoAssemblyName*
3292 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3295 MonoAssemblyBindingInfo *info, *info2;
3299 if (aname->public_key_token [0] == 0)
3302 domain = mono_domain_get ();
3304 mono_assembly_binding_lock ();
3305 info = search_binding_loaded (aname);
3306 mono_assembly_binding_unlock ();
3309 mono_domain_lock (domain);
3310 info = get_per_domain_assembly_binding_info (domain, aname);
3311 mono_domain_unlock (domain);
3315 if (!check_policy_versions (info, aname))
3318 mono_assembly_bind_version (info, aname, dest_name);
3322 if (domain && domain->setup && domain->setup->configuration_file) {
3323 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3324 /* expect this to succeed because mono_domain_set_options_from_config () did
3325 * the same thing when the domain was created. */
3326 mono_error_assert_ok (&error);
3327 mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3328 g_free (domain_config_file_name);
3330 mono_domain_lock (domain);
3331 info2 = get_per_domain_assembly_binding_info (domain, aname);
3334 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3335 info->name = g_strdup (info2->name);
3336 info->culture = g_strdup (info2->culture);
3337 info->domain_id = domain->domain_id;
3340 mono_domain_unlock (domain);
3345 info = g_new0 (MonoAssemblyBindingInfo, 1);
3346 info->major = aname->major;
3347 info->minor = aname->minor;
3350 if (!info->is_valid) {
3351 ppimage = mono_assembly_load_publisher_policy (aname);
3353 get_publisher_policy_info (ppimage, aname, info);
3354 mono_image_close (ppimage);
3358 /* Define default error value if needed */
3359 if (!info->is_valid) {
3360 info->name = g_strdup (aname->name);
3361 info->culture = g_strdup (aname->culture);
3362 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3365 mono_assembly_binding_lock ();
3366 info2 = search_binding_loaded (aname);
3368 /* This binding was added by another thread
3370 mono_assembly_binding_info_free (info);
3375 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3377 mono_assembly_binding_unlock ();
3379 if (!info->is_valid || !check_policy_versions (info, aname))
3382 mono_assembly_bind_version (info, aname, dest_name);
3387 * mono_assembly_load_from_gac
3389 * \param aname The assembly name object
3391 static MonoAssembly*
3392 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3394 MonoAssembly *result = NULL;
3395 gchar *name, *version, *culture, *fullpath, *subpath;
3400 if (aname->public_key_token [0] == 0) {
3404 if (strstr (aname->name, ".dll")) {
3405 len = strlen (filename) - 4;
3406 name = (gchar *)g_malloc (len + 1);
3407 memcpy (name, aname->name, len);
3410 name = g_strdup (aname->name);
3413 if (aname->culture) {
3414 culture = g_utf8_strdown (aname->culture, -1);
3416 culture = g_strdup ("");
3419 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3420 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3421 aname->minor, aname->build, aname->revision,
3425 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3430 if (extra_gac_paths) {
3431 paths = extra_gac_paths;
3432 while (!result && *paths) {
3433 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3434 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3441 result->in_gac = TRUE;
3446 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3447 "mono", "gac", subpath, NULL);
3448 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3452 result->in_gac = TRUE;
3460 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3463 MonoAssemblyName *aname;
3466 /* g_print ("corlib already loaded\n"); */
3470 // A nonstandard preload hook may provide a special mscorlib assembly
3471 aname = mono_assembly_name_new ("mscorlib.dll");
3472 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3473 mono_assembly_name_free (aname);
3476 goto return_corlib_and_facades;
3478 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3479 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3480 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3482 goto return_corlib_and_facades;
3485 /* Normal case: Load corlib from mono/<version> */
3486 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3487 if (assemblies_path) { // Custom assemblies path
3488 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3490 g_free (corlib_file);
3491 goto return_corlib_and_facades;
3494 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3495 g_free (corlib_file);
3497 return_corlib_and_facades:
3498 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3499 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3504 static MonoAssembly*
3505 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3507 MonoError refasm_error;
3508 error_init (&refasm_error);
3509 if (candidate && !refonly) {
3510 /* .NET Framework seems to not check for ReferenceAssemblyAttribute on dynamic assemblies */
3511 if (!image_is_dynamic (candidate->image) &&
3512 mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error))
3515 mono_error_cleanup (&refasm_error);
3520 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3522 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3523 MonoAssemblyName *candidate_name = &candidate->aname;
3525 g_assert (wanted_name != NULL);
3526 g_assert (candidate_name != NULL);
3528 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3529 char * s = mono_stringify_assembly_name (wanted_name);
3530 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3532 s = mono_stringify_assembly_name (candidate_name);
3533 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3538 /* Wanted name has no token, not strongly named: always matches. */
3539 if (0 == wanted_name->public_key_token [0]) {
3540 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3544 /* Candidate name has no token, not strongly named: never matches */
3545 if (0 == candidate_name->public_key_token [0]) {
3546 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3550 return exact_sn_match (wanted_name, candidate_name) ||
3551 framework_assembly_sn_match (wanted_name, candidate_name);
3555 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3557 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3559 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3560 result ? "match, returning TRUE" : "don't match, returning FALSE");
3566 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3568 #ifndef DISABLE_DESKTOP_LOADER
3569 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3571 if (!vmap->framework_facade_assembly) {
3572 /* 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. */
3573 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3574 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");
3577 /* For facades, the name and public key token should
3578 * match, but the version doesn't matter. */
3579 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3580 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");
3589 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3590 const char *basedir,
3591 MonoImageOpenStatus *status,
3594 MonoAssembly *result;
3595 char *fullpath, *filename;
3596 MonoAssemblyName maped_aname;
3597 MonoAssemblyName maped_name_pp;
3602 aname = mono_assembly_remap_version (aname, &maped_aname);
3604 /* Reflection only assemblies don't get assembly binding */
3606 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3608 result = mono_assembly_loaded_full (aname, refonly);
3612 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3614 result->in_gac = FALSE;
3618 /* Currently we retrieve the loaded corlib for reflection
3619 * only requests, like a common reflection only assembly
3621 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3622 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3625 MonoAssemblyCandidatePredicate predicate = NULL;
3626 void* predicate_ud = NULL;
3627 #if !defined(DISABLE_DESKTOP_LOADER)
3628 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
3629 predicate = &mono_assembly_candidate_predicate_sn_same_name;
3630 predicate_ud = aname;
3634 len = strlen (aname->name);
3635 for (ext_index = 0; ext_index < 2; ext_index ++) {
3636 ext = ext_index == 0 ? ".dll" : ".exe";
3637 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3638 filename = g_strdup (aname->name);
3639 /* Don't try appending .dll/.exe if it already has one of those extensions */
3642 filename = g_strconcat (aname->name, ext, NULL);
3645 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3652 fullpath = g_build_filename (basedir, filename, NULL);
3653 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, predicate_ud, status);
3656 result->in_gac = FALSE;
3662 result = load_in_path (filename, default_path, status, refonly, predicate, predicate_ud);
3664 result->in_gac = FALSE;
3674 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3676 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3679 /* Try a postload search hook */
3680 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3681 result = prevent_reference_assembly_from_running (result, refonly);
3687 * mono_assembly_load_full:
3688 * \param aname A MonoAssemblyName with the assembly name to load.
3689 * \param basedir A directory to look up the assembly at.
3690 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3691 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3693 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3694 * attempts to load the assembly from that directory before probing the standard locations.
3696 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3697 * assembly binding takes place.
3699 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3700 * value pointed by \p status is updated with an error code.
3703 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3705 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3709 * mono_assembly_load:
3710 * \param aname A MonoAssemblyName with the assembly name to load.
3711 * \param basedir A directory to look up the assembly at.
3712 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3714 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3715 * attempts to load the assembly from that directory before probing the standard locations.
3717 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3718 * value pointed by \p status is updated with an error code.
3721 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3723 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3727 * mono_assembly_loaded_full:
3728 * \param aname an assembly to look for.
3729 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3731 * This is used to determine if the specified assembly has been loaded
3732 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3733 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3736 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3739 MonoAssemblyName maped_aname;
3741 aname = mono_assembly_remap_version (aname, &maped_aname);
3743 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3749 * mono_assembly_loaded:
3750 * \param aname an assembly to look for.
3752 * This is used to determine if the specified assembly has been loaded
3754 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3755 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3758 mono_assembly_loaded (MonoAssemblyName *aname)
3760 return mono_assembly_loaded_full (aname, FALSE);
3764 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3766 if (assembly == NULL || assembly == REFERENCE_MISSING)
3769 if (assembly_is_dynamic (assembly)) {
3771 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3772 for (i = 0; i < dynimg->image.module_count; ++i)
3773 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3774 mono_dynamic_image_release_gc_roots (dynimg);
3779 * Returns whether mono_assembly_close_finish() must be called as
3780 * well. See comment for mono_image_close_except_pools() for why we
3781 * unload in two steps.
3784 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3787 g_return_val_if_fail (assembly != NULL, FALSE);
3789 if (assembly == REFERENCE_MISSING)
3792 /* Might be 0 already */
3793 if (InterlockedDecrement (&assembly->ref_count) > 0)
3796 MONO_PROFILER_RAISE (assembly_unloading, (assembly));
3798 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3800 mono_debug_close_image (assembly->image);
3802 mono_assemblies_lock ();
3803 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3804 mono_assemblies_unlock ();
3806 assembly->image->assembly = NULL;
3808 if (!mono_image_close_except_pools (assembly->image))
3809 assembly->image = NULL;
3811 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3812 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3813 mono_assembly_name_free (fname);
3816 g_slist_free (assembly->friend_assembly_names);
3817 g_free (assembly->basedir);
3819 MONO_PROFILER_RAISE (assembly_unloaded, (assembly));
3825 mono_assembly_close_finish (MonoAssembly *assembly)
3827 g_assert (assembly && assembly != REFERENCE_MISSING);
3829 if (assembly->image)
3830 mono_image_close_finish (assembly->image);
3832 if (assembly_is_dynamic (assembly)) {
3833 g_free ((char*)assembly->aname.culture);
3840 * mono_assembly_close:
3841 * \param assembly the assembly to release.
3843 * This method releases a reference to the \p assembly. The assembly is
3844 * only released when all the outstanding references to it are released.
3847 mono_assembly_close (MonoAssembly *assembly)
3849 if (mono_assembly_close_except_image_pools (assembly))
3850 mono_assembly_close_finish (assembly);
3854 * mono_assembly_load_module:
3857 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3860 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3861 mono_error_assert_ok (&error);
3866 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3868 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3873 * mono_assembly_foreach:
3874 * \param func function to invoke for each assembly loaded
3875 * \param user_data data passed to the callback
3877 * Invokes the provided \p func callback for each assembly loaded into
3878 * the runtime. The first parameter passed to the callback is the
3879 * \c MonoAssembly*, and the second parameter is the \p user_data.
3881 * This is done for all assemblies loaded in the runtime, not just
3882 * those loaded in the current application domain.
3885 mono_assembly_foreach (GFunc func, gpointer user_data)
3890 * We make a copy of the list to avoid calling the callback inside the
3891 * lock, which could lead to deadlocks.
3893 mono_assemblies_lock ();
3894 copy = g_list_copy (loaded_assemblies);
3895 mono_assemblies_unlock ();
3897 g_list_foreach (loaded_assemblies, func, user_data);
3903 * mono_assemblies_cleanup:
3905 * Free all resources used by this module.
3908 mono_assemblies_cleanup (void)
3912 mono_os_mutex_destroy (&assemblies_mutex);
3913 mono_os_mutex_destroy (&assembly_binding_mutex);
3915 for (l = loaded_assembly_bindings; l; l = l->next) {
3916 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3918 mono_assembly_binding_info_free (info);
3921 g_slist_free (loaded_assembly_bindings);
3923 free_assembly_load_hooks ();
3924 free_assembly_search_hooks ();
3925 free_assembly_preload_hooks ();
3928 /*LOCKING takes the assembly_binding lock*/
3930 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3934 mono_assembly_binding_lock ();
3935 iter = &loaded_assembly_bindings;
3938 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3940 if (info->domain_id == domain_id) {
3942 mono_assembly_binding_info_free (info);
3949 mono_assembly_binding_unlock ();
3953 * Holds the assembly of the application, for
3954 * System.Diagnostics.Process::MainModule
3956 static MonoAssembly *main_assembly=NULL;
3959 * mono_assembly_set_main:
3962 mono_assembly_set_main (MonoAssembly *assembly)
3964 main_assembly = assembly;
3968 * mono_assembly_get_main:
3970 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3973 mono_assembly_get_main (void)
3975 return (main_assembly);
3979 * mono_assembly_get_image:
3980 * \param assembly The assembly to retrieve the image from
3982 * \returns the \c MonoImage associated with this assembly.
3985 mono_assembly_get_image (MonoAssembly *assembly)
3987 return assembly->image;
3991 * mono_assembly_get_name:
3992 * \param assembly The assembly to retrieve the name from
3994 * The returned name's lifetime is the same as \p assembly's.
3996 * \returns the \c MonoAssemblyName associated with this assembly.
3999 mono_assembly_get_name (MonoAssembly *assembly)
4001 return &assembly->aname;
4005 * mono_register_bundled_assemblies:
4008 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4010 bundles = assemblies;
4013 #define MONO_DECLSEC_FORMAT_10 0x3C
4014 #define MONO_DECLSEC_FORMAT_20 0x2E
4015 #define MONO_DECLSEC_FIELD 0x53
4016 #define MONO_DECLSEC_PROPERTY 0x54
4018 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4019 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4020 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4021 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4022 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4025 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4029 case MONO_DECLSEC_PROPERTY:
4031 case MONO_DECLSEC_FIELD:
4033 *abort_decoding = TRUE;
4038 if (*p++ != MONO_TYPE_BOOLEAN) {
4039 *abort_decoding = TRUE;
4043 /* property name length */
4044 len = mono_metadata_decode_value (p, &p);
4046 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4057 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4059 int i, j, num, len, params_len;
4061 if (*p == MONO_DECLSEC_FORMAT_10) {
4062 gsize read, written;
4063 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4065 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4071 if (*p++ != MONO_DECLSEC_FORMAT_20)
4074 /* number of encoded permission attributes */
4075 num = mono_metadata_decode_value (p, &p);
4076 for (i = 0; i < num; ++i) {
4077 gboolean is_valid = FALSE;
4078 gboolean abort_decoding = FALSE;
4080 /* attribute name length */
4081 len = mono_metadata_decode_value (p, &p);
4083 /* We don't really need to fully decode the type. Comparing the name is enough */
4084 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4088 /*size of the params table*/
4089 params_len = mono_metadata_decode_value (p, &p);
4091 const char *params_end = p + params_len;
4093 /* number of parameters */
4094 len = mono_metadata_decode_value (p, &p);
4096 for (j = 0; j < len; ++j) {
4097 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4113 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4116 guint32 cols [MONO_DECL_SECURITY_SIZE];
4120 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4121 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4123 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4125 for (i = 0; i < t->rows; ++i) {
4126 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4127 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4129 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4132 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4133 len = mono_metadata_decode_blob_size (blob, &blob);
4137 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4138 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4143 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);