3 * Routines for loading assemblies.
6 * Miguel de Icaza (miguel@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "assembly-internals.h"
22 #include "image-internals.h"
23 #include "object-internals.h"
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/custom-attrs-internals.h>
27 #include <mono/metadata/metadata-internals.h>
28 #include <mono/metadata/profiler-private.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/domain-internals.h>
31 #include <mono/metadata/reflection-internals.h>
32 #include <mono/metadata/mono-endian.h>
33 #include <mono/metadata/mono-debug.h>
34 #include <mono/utils/mono-uri.h>
35 #include <mono/metadata/mono-config.h>
36 #include <mono/metadata/mono-config-dirs.h>
37 #include <mono/utils/mono-digest.h>
38 #include <mono/utils/mono-logger-internals.h>
39 #include <mono/utils/mono-path.h>
40 #include <mono/metadata/reflection.h>
41 #include <mono/metadata/coree.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/utils/mono-io-portability.h>
44 #include <mono/utils/atomic.h>
45 #include <mono/utils/mono-os-mutex.h>
48 #include <sys/types.h>
53 #ifdef PLATFORM_MACOSX
54 #include <mach-o/dyld.h>
57 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
59 const char* assembly_name;
60 guint8 version_set_index;
61 const char* new_assembly_name;
62 gboolean only_lower_versions;
63 gboolean framework_facade_assembly;
66 /* Flag bits for assembly_names_equal_flags (). */
68 /* Default comparison: all fields must match */
70 /* Don't compare public key token */
71 ANAME_EQ_IGNORE_PUBKEY = 0x1,
72 /* Don't compare the versions */
73 ANAME_EQ_IGNORE_VERSION = 0x2,
76 } AssemblyNameEqFlags;
78 /* the default search path is empty, the first slot is replaced with the computed value */
86 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
87 static char **assemblies_path = NULL;
89 /* Contains the list of directories that point to auxiliary GACs */
90 static char **extra_gac_paths = NULL;
92 #ifndef DISABLE_DESKTOP_LOADER
94 #define FACADE_ASSEMBLY(str) {str, 0, NULL, FALSE, TRUE}
96 static GHashTable* assembly_remapping_table;
97 /* The list of system assemblies what will be remapped to the running
99 * This list is stored in @assembly_remapping_table during initialization.
100 * Keep it sorted just to make maintenance easier.
102 * The integer number is an index in the MonoRuntimeInfo structure, whose
103 * values can be found in domain.c - supported_runtimes. Look there
104 * to understand what remapping will be made.
106 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
109 static const AssemblyVersionMap framework_assemblies [] = {
110 {"Accessibility", 0},
111 {"Commons.Xml.Relaxng", 0},
118 {"Microsoft.Build.Engine", 2, NULL, TRUE},
119 {"Microsoft.Build.Framework", 2, NULL, TRUE},
120 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
121 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
122 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
123 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
124 {"Microsoft.VisualBasic", 1},
125 {"Microsoft.VisualC", 1},
126 FACADE_ASSEMBLY ("Microsoft.Win32.Primitives"),
127 FACADE_ASSEMBLY ("Microsoft.Win32.Registry"),
128 FACADE_ASSEMBLY ("Microsoft.Win32.Registry.AccessControl"),
130 {"Mono.CompilerServices.SymbolWriter", 0},
132 {"Mono.Data.SybaseClient", 0},
133 {"Mono.Data.Tds", 0},
134 {"Mono.Data.TdsClient", 0},
135 {"Mono.GetOptions", 0},
138 {"Mono.Security", 0},
139 {"Mono.Security.Win32", 0},
141 {"Novell.Directory.Ldap", 0},
144 FACADE_ASSEMBLY ("System.AppContext"),
145 FACADE_ASSEMBLY ("System.Collections"),
146 FACADE_ASSEMBLY ("System.Collections.Concurrent"),
147 FACADE_ASSEMBLY ("System.Collections.NonGeneric"),
148 FACADE_ASSEMBLY ("System.Collections.Specialized"),
149 FACADE_ASSEMBLY ("System.ComponentModel"),
150 FACADE_ASSEMBLY ("System.ComponentModel.Annotations"),
151 {"System.ComponentModel.Composition", 2},
152 {"System.ComponentModel.DataAnnotations", 2},
153 FACADE_ASSEMBLY ("System.ComponentModel.EventBasedAsync"),
154 FACADE_ASSEMBLY ("System.ComponentModel.Primitives"),
155 FACADE_ASSEMBLY ("System.ComponentModel.TypeConverter"),
156 {"System.Configuration", 0},
157 {"System.Configuration.Install", 0},
158 FACADE_ASSEMBLY ("System.Console"),
161 FACADE_ASSEMBLY ("System.Data.Common"),
162 {"System.Data.Linq", 2},
163 {"System.Data.OracleClient", 0},
164 {"System.Data.Services", 2},
165 {"System.Data.Services.Client", 2},
166 FACADE_ASSEMBLY ("System.Data.SqlClient"),
167 {"System.Data.SqlXml", 0},
168 {"System.Design", 0},
169 FACADE_ASSEMBLY ("System.Diagnostics.Contracts"),
170 FACADE_ASSEMBLY ("System.Diagnostics.Debug"),
171 FACADE_ASSEMBLY ("System.Diagnostics.FileVersionInfo"),
172 FACADE_ASSEMBLY ("System.Diagnostics.Process"),
173 FACADE_ASSEMBLY ("System.Diagnostics.StackTrace"),
174 FACADE_ASSEMBLY ("System.Diagnostics.TextWriterTraceListener"),
175 FACADE_ASSEMBLY ("System.Diagnostics.Tools"),
176 FACADE_ASSEMBLY ("System.Diagnostics.TraceEvent"),
177 FACADE_ASSEMBLY ("System.Diagnostics.TraceSource"),
178 FACADE_ASSEMBLY ("System.Diagnostics.Tracing"),
179 {"System.DirectoryServices", 0},
180 {"System.Drawing", 0},
181 {"System.Drawing.Design", 0},
182 FACADE_ASSEMBLY ("System.Drawing.Primitives"),
183 FACADE_ASSEMBLY ("System.Dynamic.Runtime"),
184 {"System.EnterpriseServices", 0},
185 FACADE_ASSEMBLY ("System.Globalization"),
186 FACADE_ASSEMBLY ("System.Globalization.Calendars"),
187 FACADE_ASSEMBLY ("System.Globalization.Extensions"),
188 {"System.IdentityModel", 3},
189 {"System.IdentityModel.Selectors", 3},
190 FACADE_ASSEMBLY ("System.IO"),
191 {"System.IO.Compression", 2},
192 FACADE_ASSEMBLY ("System.IO.Compression.ZipFile"),
193 FACADE_ASSEMBLY ("System.IO.FileSystem"),
194 FACADE_ASSEMBLY ("System.IO.FileSystem.AccessControl"),
195 FACADE_ASSEMBLY ("System.IO.FileSystem.DriveInfo"),
196 FACADE_ASSEMBLY ("System.IO.FileSystem.Primitives"),
197 FACADE_ASSEMBLY ("System.IO.FileSystem.Watcher"),
198 FACADE_ASSEMBLY ("System.IO.IsolatedStorage"),
199 FACADE_ASSEMBLY ("System.IO.MemoryMappedFiles"),
200 FACADE_ASSEMBLY ("System.IO.Packaging"),
201 FACADE_ASSEMBLY ("System.IO.Pipes"),
202 FACADE_ASSEMBLY ("System.IO.UnmanagedMemoryStream"),
203 FACADE_ASSEMBLY ("System.Linq"),
204 FACADE_ASSEMBLY ("System.Linq.Expressions"),
205 FACADE_ASSEMBLY ("System.Linq.Parallel"),
206 FACADE_ASSEMBLY ("System.Linq.Queryable"),
207 {"System.Management", 0},
208 {"System.Messaging", 0},
210 FACADE_ASSEMBLY ("System.Net.AuthenticationManager"),
211 FACADE_ASSEMBLY ("System.Net.Cache"),
212 {"System.Net.Http", 4},
213 {"System.Net.Http.Rtc", 0},
214 FACADE_ASSEMBLY ("System.Net.HttpListener"),
215 FACADE_ASSEMBLY ("System.Net.Mail"),
216 FACADE_ASSEMBLY ("System.Net.NameResolution"),
217 FACADE_ASSEMBLY ("System.Net.NetworkInformation"),
218 FACADE_ASSEMBLY ("System.Net.Ping"),
219 FACADE_ASSEMBLY ("System.Net.Primitives"),
220 FACADE_ASSEMBLY ("System.Net.Requests"),
221 FACADE_ASSEMBLY ("System.Net.Security"),
222 FACADE_ASSEMBLY ("System.Net.ServicePoint"),
223 FACADE_ASSEMBLY ("System.Net.Sockets"),
224 FACADE_ASSEMBLY ("System.Net.Utilities"),
225 FACADE_ASSEMBLY ("System.Net.WebHeaderCollection"),
226 FACADE_ASSEMBLY ("System.Net.WebSockets"),
227 FACADE_ASSEMBLY ("System.Net.WebSockets.Client"),
228 {"System.Numerics.Vectors", 3},
229 FACADE_ASSEMBLY ("System.ObjectModel"),
230 FACADE_ASSEMBLY ("System.Reflection"),
231 FACADE_ASSEMBLY ("System.Reflection.DispatchProxy"),
232 FACADE_ASSEMBLY ("System.Reflection.Emit"),
233 FACADE_ASSEMBLY ("System.Reflection.Emit.ILGeneration"),
234 FACADE_ASSEMBLY ("System.Reflection.Emit.Lightweight"),
235 FACADE_ASSEMBLY ("System.Reflection.Extensions"),
236 FACADE_ASSEMBLY ("System.Reflection.Primitives"),
237 FACADE_ASSEMBLY ("System.Reflection.TypeExtensions"),
238 FACADE_ASSEMBLY ("System.Resources.ReaderWriter"),
239 FACADE_ASSEMBLY ("System.Resources.ResourceManager"),
240 FACADE_ASSEMBLY ("System.Runtime"),
241 FACADE_ASSEMBLY ("System.Runtime.CompilerServices.VisualC"),
242 FACADE_ASSEMBLY ("System.Runtime.Extensions"),
243 FACADE_ASSEMBLY ("System.Runtime.Handles"),
244 FACADE_ASSEMBLY ("System.Runtime.InteropServices"),
245 FACADE_ASSEMBLY ("System.Runtime.InteropServices.RuntimeInformation"),
246 FACADE_ASSEMBLY ("System.Runtime.InteropServices.WindowsRuntime"),
247 FACADE_ASSEMBLY ("System.Runtime.Loader"),
248 FACADE_ASSEMBLY ("System.Runtime.Numerics"),
249 {"System.Runtime.Remoting", 0},
250 {"System.Runtime.Serialization", 3},
251 FACADE_ASSEMBLY ("System.Runtime.Serialization.Formatters"),
252 {"System.Runtime.Serialization.Formatters.Soap", 0},
253 FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"),
254 FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"),
255 FACADE_ASSEMBLY ("System.Runtime.Serialization.Xml"),
256 {"System.Security", 0},
257 FACADE_ASSEMBLY ("System.Security.AccessControl"),
258 FACADE_ASSEMBLY ("System.Security.Claims"),
259 FACADE_ASSEMBLY ("System.Security.Cryptography.Algorithms"),
260 FACADE_ASSEMBLY ("System.Security.Cryptography.Cng"),
261 FACADE_ASSEMBLY ("System.Security.Cryptography.Csp"),
262 FACADE_ASSEMBLY ("System.Security.Cryptography.DeriveBytes"),
263 FACADE_ASSEMBLY ("System.Security.Cryptography.Encoding"),
264 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption"),
265 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Aes"),
266 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDiffieHellman"),
267 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDsa"),
268 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing"),
269 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing.Algorithms"),
270 FACADE_ASSEMBLY ("System.Security.Cryptography.OpenSsl"),
271 FACADE_ASSEMBLY ("System.Security.Cryptography.Pkcs"),
272 FACADE_ASSEMBLY ("System.Security.Cryptography.Primitives"),
273 FACADE_ASSEMBLY ("System.Security.Cryptography.ProtectedData"),
274 FACADE_ASSEMBLY ("System.Security.Cryptography.RSA"),
275 FACADE_ASSEMBLY ("System.Security.Cryptography.RandomNumberGenerator"),
276 FACADE_ASSEMBLY ("System.Security.Cryptography.X509Certificates"),
277 FACADE_ASSEMBLY ("System.Security.Principal"),
278 FACADE_ASSEMBLY ("System.Security.Principal.Windows"),
279 FACADE_ASSEMBLY ("System.Security.SecureString"),
280 {"System.ServiceModel", 3},
281 FACADE_ASSEMBLY ("System.ServiceModel.Duplex"),
282 FACADE_ASSEMBLY ("System.ServiceModel.Http"),
283 FACADE_ASSEMBLY ("System.ServiceModel.NetTcp"),
284 FACADE_ASSEMBLY ("System.ServiceModel.Primitives"),
285 FACADE_ASSEMBLY ("System.ServiceModel.Security"),
286 {"System.ServiceModel.Web", 2},
287 {"System.ServiceProcess", 0},
288 FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"),
289 FACADE_ASSEMBLY ("System.Text.Encoding"),
290 FACADE_ASSEMBLY ("System.Text.Encoding.CodePages"),
291 FACADE_ASSEMBLY ("System.Text.Encoding.Extensions"),
292 FACADE_ASSEMBLY ("System.Text.RegularExpressions"),
293 FACADE_ASSEMBLY ("System.Threading"),
294 FACADE_ASSEMBLY ("System.Threading.AccessControl"),
295 FACADE_ASSEMBLY ("System.Threading.Overlapped"),
296 FACADE_ASSEMBLY ("System.Threading.Tasks"),
297 FACADE_ASSEMBLY ("System.Threading.Tasks.Parallel"),
298 FACADE_ASSEMBLY ("System.Threading.Thread"),
299 FACADE_ASSEMBLY ("System.Threading.ThreadPool"),
300 FACADE_ASSEMBLY ("System.Threading.Timer"),
301 {"System.Transactions", 0},
302 FACADE_ASSEMBLY ("System.ValueTuple"),
304 {"System.Web.Abstractions", 2},
305 {"System.Web.DynamicData", 2},
306 {"System.Web.Extensions", 2},
307 {"System.Web.Mobile", 0},
308 {"System.Web.Routing", 2},
309 {"System.Web.Services", 0},
310 {"System.Windows", 0},
311 {"System.Windows.Forms", 0},
313 {"System.Xml.Linq", 2},
314 FACADE_ASSEMBLY ("System.Xml.ReaderWriter"),
315 {"System.Xml.Serialization", 0},
316 FACADE_ASSEMBLY ("System.Xml.XDocument"),
317 FACADE_ASSEMBLY ("System.Xml.XPath"),
318 FACADE_ASSEMBLY ("System.Xml.XPath.XmlDocument"),
319 FACADE_ASSEMBLY ("System.Xml.XPath.XDocument"),
320 FACADE_ASSEMBLY ("System.Xml.XmlDocument"),
321 FACADE_ASSEMBLY ("System.Xml.XmlSerializer"),
322 FACADE_ASSEMBLY ("System.Xml.Xsl.Primitives"),
325 FACADE_ASSEMBLY ("netstandard"),
330 * keeps track of loaded assemblies
332 static GList *loaded_assemblies = NULL;
333 static MonoAssembly *corlib;
335 #if defined(__native_client__)
337 /* On Native Client, allow mscorlib to be loaded from memory */
338 /* instead of loaded off disk. If these are not set, default */
339 /* mscorlib loading will take place */
341 /* NOTE: If mscorlib data is passed to mono in this way then */
342 /* it needs to remain allocated during the use of mono. */
344 static void *corlibData = NULL;
345 static size_t corlibSize = 0;
348 mono_set_corlib_data (void *data, size_t size)
356 static char* unquote (const char *str);
358 /* This protects loaded_assemblies and image->references */
359 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
360 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
361 static mono_mutex_t assemblies_mutex;
363 /* If defined, points to the bundled assembly information */
364 const MonoBundledAssembly **bundles;
366 static mono_mutex_t assembly_binding_mutex;
368 /* Loaded assembly binding info */
369 static GSList *loaded_assembly_bindings = NULL;
371 /* Class lazy loading functions */
372 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
374 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
376 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
378 mono_assembly_is_in_gac (const gchar *filanem);
381 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
384 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags);
386 /* Assembly name matching */
388 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
390 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
393 encode_public_tok (const guchar *token, gint32 len)
395 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
399 res = (gchar *)g_malloc (len * 2 + 1);
400 for (i = 0; i < len; i++) {
401 res [i * 2] = allowed [token [i] >> 4];
402 res [i * 2 + 1] = allowed [token [i] & 0xF];
409 * mono_public_tokens_are_equal:
410 * \param pubt1 first public key token
411 * \param pubt2 second public key token
413 * Compare two public key tokens and return TRUE is they are equal and FALSE
417 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
419 return memcmp (pubt1, pubt2, 16) == 0;
423 * mono_set_assemblies_path:
424 * \param path list of paths that contain directories where Mono will look for assemblies
426 * Use this method to override the standard assembly lookup system and
427 * override any assemblies coming from the GAC. This is the method
428 * that supports the \c MONO_PATH variable.
430 * Notice that \c MONO_PATH and this method are really a very bad idea as
431 * it prevents the GAC from working and it prevents the standard
432 * resolution mechanisms from working. Nonetheless, for some debugging
433 * situations and bootstrapping setups, this is useful to have.
436 mono_set_assemblies_path (const char* path)
438 char **splitted, **dest;
440 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
442 g_strfreev (assemblies_path);
443 assemblies_path = dest = splitted;
445 char *tmp = *splitted;
447 *dest++ = mono_path_canonicalize (tmp);
453 if (g_hasenv ("MONO_DEBUG"))
456 splitted = assemblies_path;
458 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
459 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
465 /* Native Client can't get this info from an environment variable so */
466 /* it's passed in to the runtime, or set manually by embedding code. */
467 #ifdef __native_client__
468 char* nacl_mono_path = NULL;
472 check_path_env (void)
474 if (assemblies_path != NULL)
477 char* path = g_getenv ("MONO_PATH");
478 #ifdef __native_client__
480 path = strdup (nacl_mono_path);
485 mono_set_assemblies_path(path);
490 check_extra_gac_path_env (void)
493 char **splitted, **dest;
495 path = g_getenv ("MONO_GAC_PREFIX");
499 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
503 g_strfreev (extra_gac_paths);
504 extra_gac_paths = dest = splitted;
512 if (!g_hasenv ("MONO_DEBUG"))
516 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
517 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
524 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
526 if (!info || !info->name)
529 if (strcmp (info->name, aname->name))
532 if (info->major != aname->major || info->minor != aname->minor)
535 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
538 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
541 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
548 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
554 g_free (info->culture);
558 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
561 guint32 cols [MONO_MANIFEST_SIZE];
562 const gchar *filename;
563 gchar *subpath, *fullpath;
565 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
566 /* MS Impl. accepts policy assemblies with more than
567 * one manifest resource, and only takes the first one */
569 binding_info->is_valid = FALSE;
573 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
574 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
575 binding_info->is_valid = FALSE;
579 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
580 g_assert (filename != NULL);
582 subpath = g_path_get_dirname (image->name);
583 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
584 mono_config_parse_publisher_policy (fullpath, binding_info);
588 /* Define the optional elements/attributes before checking */
589 if (!binding_info->culture)
590 binding_info->culture = g_strdup ("");
592 /* Check that the most important elements/attributes exist */
593 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
594 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
595 mono_assembly_binding_info_free (binding_info);
596 binding_info->is_valid = FALSE;
600 binding_info->is_valid = TRUE;
604 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
606 if (v->major > aname->major)
608 else if (v->major < aname->major)
611 if (v->minor > aname->minor)
613 else if (v->minor < aname->minor)
616 if (v->build > aname->build)
618 else if (v->build < aname->build)
621 if (v->revision > aname->revision)
623 else if (v->revision < aname->revision)
630 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
635 /* If has_old_version_top doesn't exist, we don't have an interval */
636 if (!info->has_old_version_top) {
637 if (compare_versions (&info->old_version_bottom, name) == 0)
643 /* Check that the version defined by name is valid for the interval */
644 if (compare_versions (&info->old_version_top, name) < 0)
647 /* We should be greater or equal than the small version */
648 if (compare_versions (&info->old_version_bottom, name) > 0)
655 * mono_assembly_names_equal:
656 * \param l first assembly
657 * \param r second assembly.
659 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
661 * This compares the names, the cultures, the release version and their
664 * \returns TRUE if both assembly names are equal.
667 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
669 return assembly_names_equal_flags (l, r, ANAME_EQ_NONE);
673 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags)
675 if (!l->name || !r->name)
678 if (strcmp (l->name, r->name))
681 if (l->culture && r->culture && strcmp (l->culture, r->culture))
684 if ((l->major != r->major || l->minor != r->minor ||
685 l->build != r->build || l->revision != r->revision) &&
686 (flags & ANAME_EQ_IGNORE_VERSION) == 0)
687 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)))
690 if (!l->public_key_token [0] || !r->public_key_token [0] || (flags & ANAME_EQ_IGNORE_PUBKEY) != 0)
693 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
699 static MonoAssembly *
700 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
704 MonoAssembly *result;
706 for (i = 0; search_path [i]; ++i) {
707 fullpath = g_build_filename (search_path [i], basename, NULL);
708 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
717 * mono_assembly_setrootdir:
718 * \param root_dir The pathname of the root directory where we will locate assemblies
720 * This routine sets the internal default root directory for looking up
723 * This is used by Windows installations to compute dynamically the
724 * place where the Mono assemblies are located.
728 mono_assembly_setrootdir (const char *root_dir)
731 * Override the MONO_ASSEMBLIES directory configured at compile time.
733 /* Leak if called more than once */
734 default_path [0] = g_strdup (root_dir);
738 * mono_assembly_getrootdir:
740 * Obtains the root directory used for looking up assemblies.
742 * Returns: a string with the directory, this string should not be freed.
744 G_CONST_RETURN gchar *
745 mono_assembly_getrootdir (void)
747 return default_path [0];
751 * mono_native_getrootdir:
753 * Obtains the root directory used for looking up native libs (.so, .dylib).
755 * Returns: a string with the directory, this string should be freed by
759 mono_native_getrootdir (void)
761 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
767 * \param assembly_dir the base directory for assemblies
768 * \param config_dir the base directory for configuration files
770 * This routine is used internally and by developers embedding
771 * the runtime into their own applications.
773 * There are a number of cases to consider: Mono as a system-installed
774 * package that is available on the location preconfigured or Mono in
775 * a relocated location.
777 * If you are using a system-installed Mono, you can pass NULL
778 * to both parameters. If you are not, you should compute both
779 * directory values and call this routine.
781 * The values for a given PREFIX are:
783 * assembly_dir: PREFIX/lib
784 * config_dir: PREFIX/etc
786 * Notice that embedders that use Mono in a relocated way must
787 * compute the location at runtime, as they will be in control
788 * of where Mono is installed.
791 mono_set_dirs (const char *assembly_dir, const char *config_dir)
793 if (assembly_dir == NULL)
794 assembly_dir = mono_config_get_assemblies_dir ();
795 if (config_dir == NULL)
796 config_dir = mono_config_get_cfg_dir ();
797 mono_assembly_setrootdir (assembly_dir);
798 mono_set_config_dir (config_dir);
804 compute_base (char *path)
806 char *p = strrchr (path, '/');
810 /* Not a well known Mono executable, we are embedded, cant guess the base */
811 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
815 p = strrchr (path, '/');
819 if (strcmp (p, "/bin") != 0)
828 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
831 static G_GNUC_UNUSED void
835 char *config, *lib, *mono;
840 * Only /usr prefix is treated specially
842 bindir = mono_config_get_bin_dir ();
844 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
849 config = g_build_filename (base, "etc", NULL);
850 lib = g_build_filename (base, "lib", NULL);
851 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
852 if (stat (mono, &buf) == -1)
855 mono_set_dirs (lib, config);
863 #endif /* HOST_WIN32 */
868 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
869 * this auto-detects the prefix where Mono was installed.
872 mono_set_rootdir (void)
874 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
875 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
878 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
882 * _NSGetExecutablePath may return -1 to indicate buf is not large
883 * enough, but we ignore that case to avoid having to do extra dynamic
884 * allocation for the path and hope that 4096 is enough - this is
885 * ok in the Linux/Solaris case below at least...
889 guint buf_size = sizeof (buf);
892 if (_NSGetExecutablePath (buf, &buf_size) == 0)
893 name = g_strdup (buf);
902 resolvedname = mono_path_resolve_symlinks (name);
904 bindir = g_path_get_dirname (resolvedname);
905 installdir = g_path_get_dirname (bindir);
906 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
908 config = g_build_filename (root, "..", "etc", NULL);
910 mono_set_dirs (root, config);
912 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
913 mono_set_dirs (root, config);
923 g_free (resolvedname);
924 #elif defined(DISABLE_MONO_AUTODETECTION)
932 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
940 /* Solaris 10 style */
941 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
942 s = readlink (str, buf, sizeof (buf)-1);
954 * mono_assemblies_init:
956 * Initialize global variables used by this module.
959 mono_assemblies_init (void)
962 * Initialize our internal paths if we have not been initialized yet.
963 * This happens when embedders use Mono.
965 if (mono_assembly_getrootdir () == NULL)
969 check_extra_gac_path_env ();
971 mono_os_mutex_init_recursive (&assemblies_mutex);
972 mono_os_mutex_init (&assembly_binding_mutex);
974 #ifndef DISABLE_DESKTOP_LOADER
975 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
978 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
979 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
985 mono_assembly_binding_lock (void)
987 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
991 mono_assembly_binding_unlock (void)
993 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
997 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
999 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
1000 guint32 cols [MONO_ASSEMBLY_SIZE];
1001 gint32 machine, flags;
1006 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
1008 aname->hash_len = 0;
1009 aname->hash_value = NULL;
1010 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
1012 aname->name = g_strdup (aname->name);
1013 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
1015 aname->culture = g_strdup (aname->culture);
1016 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
1017 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
1018 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
1019 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
1020 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
1021 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
1022 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
1023 guchar* token = (guchar *)g_malloc (8);
1028 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
1029 len = mono_metadata_decode_blob_size (pkey, &pkey);
1030 aname->public_key = (guchar*)pkey;
1032 mono_digest_get_public_token (token, aname->public_key, len);
1033 encoded = encode_public_tok (token, 8);
1034 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1040 aname->public_key = NULL;
1041 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1044 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
1045 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
1047 const gchar *pkey_end;
1048 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
1049 pkey_end += len; /* move to end */
1050 size_t size = pkey_end - (const gchar*)aname->public_key;
1051 guchar *tmp = g_new (guchar, size);
1052 memcpy (tmp, aname->public_key, size);
1053 aname->public_key = tmp;
1058 aname->public_key = 0;
1060 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
1061 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
1063 case COFF_MACHINE_I386:
1064 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1065 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
1066 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
1067 else if ((flags & 0x70) == 0x70)
1068 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
1070 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
1072 case COFF_MACHINE_IA64:
1073 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
1075 case COFF_MACHINE_AMD64:
1076 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
1078 case COFF_MACHINE_ARM:
1079 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
1089 * mono_assembly_fill_assembly_name:
1090 * \param image Image
1092 * \returns TRUE if successful
1095 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
1097 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
1101 * mono_stringify_assembly_name:
1102 * \param aname the assembly name.
1104 * Convert \p aname into its string format. The returned string is dynamically
1105 * allocated and should be freed by the caller.
1107 * \returns a newly allocated string with a string representation of
1108 * the assembly name.
1111 mono_stringify_assembly_name (MonoAssemblyName *aname)
1113 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
1115 return g_strdup_printf (
1116 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1117 quote, aname->name, quote,
1118 aname->major, aname->minor, aname->build, aname->revision,
1119 aname->culture && *aname->culture? aname->culture: "neutral",
1120 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
1121 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
1125 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
1127 const gchar *public_tok;
1130 public_tok = mono_metadata_blob_heap (image, key_index);
1131 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
1133 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
1135 mono_digest_get_public_token (token, (guchar*)public_tok, len);
1136 return encode_public_tok (token, 8);
1139 return encode_public_tok ((guchar*)public_tok, len);
1143 * mono_assembly_addref:
1144 * \param assembly the assembly to reference
1146 * This routine increments the reference count on a MonoAssembly.
1147 * The reference count is reduced every time the method mono_assembly_close() is
1151 mono_assembly_addref (MonoAssembly *assembly)
1153 InterlockedIncrement (&assembly->ref_count);
1157 * CAUTION: This table must be kept in sync with
1158 * ivkm/reflect/Fusion.cs
1161 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1162 #define WINFX_KEY "31bf3856ad364e35"
1163 #define ECMA_KEY "b77a5c561934e089"
1164 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1165 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1173 static KeyRemapEntry key_remap_table[] = {
1174 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1175 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1176 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1177 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1178 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1179 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1180 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1181 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1182 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1183 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1184 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1185 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1186 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1187 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1188 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1189 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1190 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1191 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1192 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1193 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1194 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1195 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1196 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1197 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1198 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1199 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1200 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1201 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1202 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1206 remap_keys (MonoAssemblyName *aname)
1209 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1210 const KeyRemapEntry *entry = &key_remap_table [i];
1212 if (strcmp (aname->name, entry->name) ||
1213 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1216 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1218 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1219 "Remapped public key token of retargetable assembly %s from %s to %s",
1220 aname->name, entry->from, entry->to);
1225 static MonoAssemblyName *
1226 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1228 const MonoRuntimeInfo *current_runtime;
1230 if (aname->name == NULL) return aname;
1232 current_runtime = mono_get_runtime_info ();
1234 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1235 const AssemblyVersionSet* vset;
1237 /* Remap to current runtime */
1238 vset = ¤t_runtime->version_sets [0];
1240 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1241 dest_aname->major = vset->major;
1242 dest_aname->minor = vset->minor;
1243 dest_aname->build = vset->build;
1244 dest_aname->revision = vset->revision;
1245 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1247 /* Remap assembly name */
1248 if (!strcmp (aname->name, "System.Net"))
1249 dest_aname->name = g_strdup ("System");
1251 remap_keys (dest_aname);
1253 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1254 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1256 aname->major, aname->minor, aname->build, aname->revision,
1258 vset->major, vset->minor, vset->build, vset->revision
1264 #ifndef DISABLE_DESKTOP_LOADER
1265 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1267 const AssemblyVersionSet* vset;
1268 int index = vmap->version_set_index;
1269 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1270 vset = ¤t_runtime->version_sets [index];
1272 if (vmap->framework_facade_assembly) {
1273 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s is a framework Facade asseembly",
1278 if (aname->major == vset->major && aname->minor == vset->minor &&
1279 aname->build == vset->build && aname->revision == vset->revision) {
1280 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1282 aname->major, aname->minor, aname->build, aname->revision);
1286 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1287 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1288 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1290 aname->major, aname->minor, aname->build, aname->revision,
1291 vset->major, vset->minor, vset->build, vset->revision
1296 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1297 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1298 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1300 aname->major, aname->minor, aname->build, aname->revision,
1301 vset->major, vset->minor, vset->build, vset->revision
1304 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1305 dest_aname->major = vset->major;
1306 dest_aname->minor = vset->minor;
1307 dest_aname->build = vset->build;
1308 dest_aname->revision = vset->revision;
1309 if (vmap->new_assembly_name != NULL) {
1310 dest_aname->name = vmap->new_assembly_name;
1311 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1312 "The assembly name %s was remapped to %s",
1324 * mono_assembly_get_assemblyref:
1325 * \param image pointer to the \c MonoImage to extract the information from.
1326 * \param index index to the assembly reference in the image.
1327 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1329 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1332 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1335 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1338 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1340 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1342 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1343 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1344 aname->hash_value = hash;
1345 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1346 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1347 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1348 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1349 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1350 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1351 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1353 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1354 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1355 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1358 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1363 * mono_assembly_load_reference:
1366 mono_assembly_load_reference (MonoImage *image, int index)
1368 MonoAssembly *reference;
1369 MonoAssemblyName aname;
1370 MonoImageOpenStatus status;
1373 * image->references is shared between threads, so we need to access
1374 * it inside a critical section.
1376 mono_assemblies_lock ();
1377 if (!image->references) {
1378 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1380 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1381 image->nreferences = t->rows;
1383 reference = image->references [index];
1384 mono_assemblies_unlock ();
1388 mono_assembly_get_assemblyref (image, index, &aname);
1390 if (image->assembly && image->assembly->ref_only) {
1391 /* We use the loaded corlib */
1392 if (!strcmp (aname.name, "mscorlib"))
1393 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1395 reference = mono_assembly_loaded_full (&aname, TRUE);
1397 /* Try a postload search hook */
1398 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1402 * Here we must advice that the error was due to
1403 * a non loaded reference using the ReflectionOnly api
1406 reference = (MonoAssembly *)REFERENCE_MISSING;
1408 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1409 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1410 * accordingly, it would fail on the MS runtime before).
1411 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1412 * example bug-349190.2.cs and who knows how much more code in the wild.
1414 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1415 if (!reference && image->assembly)
1416 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1419 if (reference == NULL){
1422 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1423 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 : "" );
1424 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1425 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1426 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1427 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1428 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1429 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1431 extra_msg = g_strdup ("");
1434 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1435 " Assembly: %s (assemblyref_index=%d)\n"
1436 " Version: %d.%d.%d.%d\n"
1437 " Public Key: %s\n%s",
1438 image->name, aname.name, index,
1439 aname.major, aname.minor, aname.build, aname.revision,
1440 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1445 mono_assemblies_lock ();
1446 if (reference == NULL) {
1447 /* Flag as not found */
1448 reference = (MonoAssembly *)REFERENCE_MISSING;
1451 if (!image->references [index]) {
1452 if (reference != REFERENCE_MISSING){
1453 mono_assembly_addref (reference);
1454 if (image->assembly)
1455 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1456 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1458 if (image->assembly)
1459 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1460 image->assembly->aname.name, image->assembly);
1463 image->references [index] = reference;
1465 mono_assemblies_unlock ();
1467 if (image->references [index] != reference) {
1468 /* Somebody loaded it before us */
1469 mono_assembly_close (reference);
1474 * mono_assembly_load_references:
1477 * \deprecated There is no reason to use this method anymore, it does nothing
1479 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1482 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1484 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1485 *status = MONO_IMAGE_OK;
1488 typedef struct AssemblyLoadHook AssemblyLoadHook;
1489 struct AssemblyLoadHook {
1490 AssemblyLoadHook *next;
1491 MonoAssemblyLoadFunc func;
1495 AssemblyLoadHook *assembly_load_hook = NULL;
1498 * mono_assembly_invoke_load_hook:
1501 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1503 AssemblyLoadHook *hook;
1505 for (hook = assembly_load_hook; hook; hook = hook->next) {
1506 hook->func (ass, hook->user_data);
1511 * mono_install_assembly_load_hook:
1514 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1516 AssemblyLoadHook *hook;
1518 g_return_if_fail (func != NULL);
1520 hook = g_new0 (AssemblyLoadHook, 1);
1522 hook->user_data = user_data;
1523 hook->next = assembly_load_hook;
1524 assembly_load_hook = hook;
1528 free_assembly_load_hooks (void)
1530 AssemblyLoadHook *hook, *next;
1532 for (hook = assembly_load_hook; hook; hook = next) {
1538 typedef struct AssemblySearchHook AssemblySearchHook;
1539 struct AssemblySearchHook {
1540 AssemblySearchHook *next;
1541 MonoAssemblySearchFunc func;
1547 AssemblySearchHook *assembly_search_hook = NULL;
1549 static MonoAssembly*
1550 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1552 AssemblySearchHook *hook;
1554 for (hook = assembly_search_hook; hook; hook = hook->next) {
1555 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1558 * A little explanation is in order here.
1560 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1561 * The embedding API exposes a search hook that doesn't take such argument.
1563 * The original fix would call the default search hook before all the registered ones and pass
1564 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1565 * rely on. Which is the ordering between user hooks and the default runtime hook.
1567 * Registering the hook after mono_jit_init would let your hook run before the default one and
1568 * when using it to handle non standard app layouts this could save your app from a massive amount
1569 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1570 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1572 * So what's the fix? We register the default hook using regular means and special case it when iterating
1573 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1576 if (hook->func == (void*)mono_domain_assembly_postload_search)
1577 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1579 ass = hook->func (aname, hook->user_data);
1589 * mono_assembly_invoke_search_hook:
1592 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1594 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1598 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1600 AssemblySearchHook *hook;
1602 g_return_if_fail (func != NULL);
1604 hook = g_new0 (AssemblySearchHook, 1);
1606 hook->user_data = user_data;
1607 hook->refonly = refonly;
1608 hook->postload = postload;
1609 hook->next = assembly_search_hook;
1610 assembly_search_hook = hook;
1614 * mono_install_assembly_search_hook:
1617 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1619 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1623 free_assembly_search_hooks (void)
1625 AssemblySearchHook *hook, *next;
1627 for (hook = assembly_search_hook; hook; hook = next) {
1634 * mono_install_assembly_refonly_search_hook:
1637 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1639 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1643 * mono_install_assembly_postload_search_hook:
1646 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1648 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1652 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1654 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1657 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1658 struct AssemblyPreLoadHook {
1659 AssemblyPreLoadHook *next;
1660 MonoAssemblyPreLoadFunc func;
1664 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1665 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1667 static MonoAssembly *
1668 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1670 AssemblyPreLoadHook *hook;
1671 MonoAssembly *assembly;
1673 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1674 assembly = hook->func (aname, assemblies_path, hook->user_data);
1675 if (assembly != NULL)
1682 static MonoAssembly *
1683 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1685 AssemblyPreLoadHook *hook;
1686 MonoAssembly *assembly;
1688 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1689 assembly = hook->func (aname, assemblies_path, hook->user_data);
1690 if (assembly != NULL)
1698 * mono_install_assembly_preload_hook:
1701 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1703 AssemblyPreLoadHook *hook;
1705 g_return_if_fail (func != NULL);
1707 hook = g_new0 (AssemblyPreLoadHook, 1);
1709 hook->user_data = user_data;
1710 hook->next = assembly_preload_hook;
1711 assembly_preload_hook = hook;
1715 * mono_install_assembly_refonly_preload_hook:
1718 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1720 AssemblyPreLoadHook *hook;
1722 g_return_if_fail (func != NULL);
1724 hook = g_new0 (AssemblyPreLoadHook, 1);
1726 hook->user_data = user_data;
1727 hook->next = assembly_refonly_preload_hook;
1728 assembly_refonly_preload_hook = hook;
1732 free_assembly_preload_hooks (void)
1734 AssemblyPreLoadHook *hook, *next;
1736 for (hook = assembly_preload_hook; hook; hook = next) {
1741 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1748 absolute_dir (const gchar *filename)
1759 if (g_path_is_absolute (filename)) {
1760 part = g_path_get_dirname (filename);
1761 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1766 cwd = g_get_current_dir ();
1767 mixed = g_build_filename (cwd, filename, NULL);
1768 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1773 for (i = 0; (part = parts [i]) != NULL; i++) {
1774 if (!strcmp (part, "."))
1777 if (!strcmp (part, "..")) {
1778 if (list && list->next) /* Don't remove root */
1779 list = g_list_delete_link (list, list);
1781 list = g_list_prepend (list, part);
1785 result = g_string_new ("");
1786 list = g_list_reverse (list);
1788 /* Ignores last data pointer, which should be the filename */
1789 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1791 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1796 g_string_free (result, FALSE);
1801 return g_strdup (".");
1808 * mono_assembly_open_from_bundle:
1809 * \param filename Filename requested
1810 * \param status return status code
1812 * This routine tries to open the assembly specified by \p filename from the
1813 * defined bundles, if found, returns the MonoImage for it, if not found
1817 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1821 gchar *lowercase_filename;
1822 MonoImage *image = NULL;
1823 gboolean is_satellite = FALSE;
1825 * we do a very simple search for bundled assemblies: it's not a general
1826 * purpose assembly loading mechanism.
1832 lowercase_filename = g_utf8_strdown (filename, -1);
1833 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1834 g_free (lowercase_filename);
1835 name = g_path_get_basename (filename);
1836 mono_assemblies_lock ();
1837 for (i = 0; !image && bundles [i]; ++i) {
1838 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1839 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1843 mono_assemblies_unlock ();
1845 mono_image_addref (image);
1846 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1855 * mono_assembly_open_full:
1856 * \param filename the file to load
1857 * \param status return status code
1858 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1860 * This loads an assembly from the specified \p filename. The \p filename allows
1861 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1862 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1863 * is treated as a local path.
1865 * First, an attempt is made to load the assembly from the bundled executable (for those
1866 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1867 * assembly has been registered as an embedded assembly). If this is not the case, then
1868 * the assembly is loaded from disk using `api:mono_image_open_full`.
1870 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1871 * the assembly is made.
1873 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1874 * the \c System.Reflection API.
1876 * \returns NULL on error, with the \p status set to an error code, or a pointer
1880 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1882 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1886 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1888 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1892 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1893 gboolean load_from_context,
1894 MonoAssemblyCandidatePredicate predicate,
1896 MonoImageOpenStatus *status)
1900 MonoImageOpenStatus def_status;
1903 gboolean loaded_from_bundle;
1905 g_return_val_if_fail (filename != NULL, NULL);
1908 status = &def_status;
1909 *status = MONO_IMAGE_OK;
1911 if (strncmp (filename, "file://", 7) == 0) {
1912 GError *error = NULL;
1913 gchar *uri = (gchar *) filename;
1917 * MS allows file://c:/... and fails on file://localhost/c:/...
1918 * They also throw an IndexOutOfRangeException if "file://"
1921 uri = g_strdup_printf ("file:///%s", uri + 7);
1924 uri = mono_escape_uri_string (tmpuri);
1925 fname = g_filename_from_uri (uri, NULL, &error);
1928 if (tmpuri != filename)
1931 if (error != NULL) {
1932 g_warning ("%s\n", error->message);
1933 g_error_free (error);
1934 fname = g_strdup (filename);
1937 fname = g_strdup (filename);
1940 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1941 "Assembly Loader probing location: '%s'.", fname);
1944 if (!mono_assembly_is_in_gac (fname)) {
1946 new_fname = mono_make_shadow_copy (fname, &error);
1947 if (!is_ok (&error)) {
1948 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1949 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1950 mono_error_cleanup (&error);
1951 *status = MONO_IMAGE_IMAGE_INVALID;
1956 if (new_fname && new_fname != fname) {
1959 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1960 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1965 // If VM built with mkbundle
1966 loaded_from_bundle = FALSE;
1967 if (bundles != NULL) {
1968 image = mono_assembly_open_from_bundle (fname, status, refonly);
1969 loaded_from_bundle = image != NULL;
1973 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1976 if (*status == MONO_IMAGE_OK)
1977 *status = MONO_IMAGE_ERROR_ERRNO;
1982 if (image->assembly) {
1983 /* Already loaded by another appdomain */
1984 mono_assembly_invoke_load_hook (image->assembly);
1985 mono_image_close (image);
1987 return image->assembly;
1990 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1993 if (!loaded_from_bundle)
1994 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1995 "Assembly Loader loaded assembly from location: '%s'.", filename);
1997 mono_config_for_assembly (ass->image);
2000 /* Clear the reference added by mono_image_open */
2001 mono_image_close (image);
2009 free_item (gpointer val, gpointer user_data)
2015 * mono_assembly_load_friends:
2016 * \param ass an assembly
2018 * Load the list of friend assemblies that are allowed to access
2019 * the assembly's internal types and members. They are stored as assembly
2020 * names in custom attributes.
2022 * This is an internal method, we need this because when we load mscorlib
2023 * we do not have the internals visible cattr loaded yet,
2024 * so we need to load these after we initialize the runtime.
2026 * LOCKING: Acquires the assemblies lock plus the loader lock.
2029 mono_assembly_load_friends (MonoAssembly* ass)
2033 MonoCustomAttrInfo* attrs;
2036 if (ass->friend_assembly_names_inited)
2039 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
2040 mono_error_assert_ok (&error);
2042 mono_assemblies_lock ();
2043 ass->friend_assembly_names_inited = TRUE;
2044 mono_assemblies_unlock ();
2048 mono_assemblies_lock ();
2049 if (ass->friend_assembly_names_inited) {
2050 mono_assemblies_unlock ();
2053 mono_assemblies_unlock ();
2057 * We build the list outside the assemblies lock, the worse that can happen
2058 * is that we'll need to free the allocated list.
2060 for (i = 0; i < attrs->num_attrs; ++i) {
2061 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2062 MonoAssemblyName *aname;
2064 /* Do some sanity checking */
2065 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
2067 if (attr->data_size < 4)
2069 data = (const char*)attr->data;
2070 /* 0xFF means null string, see custom attr format */
2071 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
2073 mono_metadata_decode_value (data + 2, &data);
2074 aname = g_new0 (MonoAssemblyName, 1);
2075 /*g_print ("friend ass: %s\n", data);*/
2076 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
2077 list = g_slist_prepend (list, aname);
2082 mono_custom_attrs_free (attrs);
2084 mono_assemblies_lock ();
2085 if (ass->friend_assembly_names_inited) {
2086 mono_assemblies_unlock ();
2087 g_slist_foreach (list, free_item, NULL);
2088 g_slist_free (list);
2091 ass->friend_assembly_names = list;
2093 /* Because of the double checked locking pattern above */
2094 mono_memory_barrier ();
2095 ass->friend_assembly_names_inited = TRUE;
2096 mono_assemblies_unlock ();
2099 struct HasReferenceAssemblyAttributeIterData {
2104 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
2106 gboolean stop_scanning = FALSE;
2107 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
2109 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
2110 /* Note we don't check the assembly name, same as coreCLR. */
2111 iter_data->has_attr = TRUE;
2112 stop_scanning = TRUE;
2115 return stop_scanning;
2119 * mono_assembly_has_reference_assembly_attribute:
2120 * \param assembly a MonoAssembly
2121 * \param error set on error.
2123 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2124 * On error returns FALSE and sets \p error.
2127 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
2132 * This might be called during assembly loading, so do everything using the low-level
2136 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
2138 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
2140 return iter_data.has_attr;
2144 * mono_assembly_open:
2145 * \param filename Opens the assembly pointed out by this name
2146 * \param status return status code
2148 * This loads an assembly from the specified \p filename. The \p filename allows
2149 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2150 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2151 * is treated as a local path.
2153 * First, an attempt is made to load the assembly from the bundled executable (for those
2154 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2155 * assembly has been registered as an embedded assembly). If this is not the case, then
2156 * the assembly is loaded from disk using `api:mono_image_open_full`.
2158 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2159 * the assembly is made.
2161 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2162 * assembly or NULL on error. Details about the error are stored in the
2163 * \p status variable.
2166 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2168 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2172 * mono_assembly_load_from_full:
2173 * \param image Image to load the assembly from
2174 * \param fname assembly name to associate with the assembly
2175 * \param status returns the status condition
2176 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2178 * If the provided \p image has an assembly reference, it will process the given
2179 * image as an assembly with the given name.
2181 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2183 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2184 * set to \c MONO_IMAGE_OK; or NULL on error.
2186 * If there is an error loading the assembly the \p status will indicate the
2187 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2188 * image did not contain an assembly reference table.
2191 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2192 MonoImageOpenStatus *status, gboolean refonly)
2194 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2198 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2200 MonoAssemblyCandidatePredicate predicate,
2202 MonoImageOpenStatus *status)
2204 MonoAssembly *ass, *ass2;
2207 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2208 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2209 *status = MONO_IMAGE_IMAGE_INVALID;
2213 #if defined (HOST_WIN32)
2218 tmp_fn = g_strdup (fname);
2219 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2220 if (tmp_fn [i] == '/')
2224 base_dir = absolute_dir (tmp_fn);
2228 base_dir = absolute_dir (fname);
2232 * Create assembly struct, and enter it into the assembly cache
2234 ass = g_new0 (MonoAssembly, 1);
2235 ass->basedir = base_dir;
2236 ass->ref_only = refonly;
2239 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2241 mono_assembly_fill_assembly_name (image, &ass->aname);
2243 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2244 // MS.NET doesn't support loading other mscorlibs
2247 mono_image_addref (mono_defaults.corlib);
2248 *status = MONO_IMAGE_OK;
2249 return mono_defaults.corlib->assembly;
2252 /* Add a non-temporary reference because of ass->image */
2253 mono_image_addref (image);
2255 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);
2258 * The load hooks might take locks so we can't call them while holding the
2261 if (ass->aname.name) {
2262 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2266 mono_image_close (image);
2267 *status = MONO_IMAGE_OK;
2272 /* We need to check for ReferenceAssmeblyAttribute before we
2273 * mark the assembly as loaded and before we fire the load
2274 * hook. Otherwise mono_domain_fire_assembly_load () in
2275 * appdomain.c will cache a mapping from the assembly name to
2276 * this image and we won't be able to look for a different
2280 MonoError refasm_error;
2281 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2282 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2285 mono_image_close (image);
2286 *status = MONO_IMAGE_IMAGE_INVALID;
2289 mono_error_cleanup (&refasm_error);
2292 if (predicate && !predicate (ass, user_data)) {
2293 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2296 mono_image_close (image);
2297 *status = MONO_IMAGE_IMAGE_INVALID;
2301 mono_assemblies_lock ();
2303 if (image->assembly) {
2305 * This means another thread has already loaded the assembly, but not yet
2306 * called the load hooks so the search hook can't find the assembly.
2308 mono_assemblies_unlock ();
2309 ass2 = image->assembly;
2312 mono_image_close (image);
2313 *status = MONO_IMAGE_OK;
2317 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2319 image->assembly = ass;
2321 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2322 mono_assemblies_unlock ();
2325 if (image->is_module_handle)
2326 mono_image_fixup_vtable (image);
2329 mono_assembly_invoke_load_hook (ass);
2331 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2337 * mono_assembly_load_from:
2338 * \param image Image to load the assembly from
2339 * \param fname assembly name to associate with the assembly
2340 * \param status return status code
2342 * If the provided \p image has an assembly reference, it will process the given
2343 * image as an assembly with the given name.
2345 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2347 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2348 * \p refonly parameter set to FALSE.
2349 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2350 * set to \c MONO_IMAGE_OK; or NULL on error.
2352 * If there is an error loading the assembly the \p status will indicate the
2353 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2354 * image did not contain an assembly reference table.
2358 mono_assembly_load_from (MonoImage *image, const char *fname,
2359 MonoImageOpenStatus *status)
2361 return mono_assembly_load_from_full (image, fname, status, FALSE);
2365 * mono_assembly_name_free:
2366 * \param aname assembly name to free
2368 * Frees the provided assembly name object.
2369 * (it does not frees the object itself, only the name members).
2372 mono_assembly_name_free (MonoAssemblyName *aname)
2377 g_free ((void *) aname->name);
2378 g_free ((void *) aname->culture);
2379 g_free ((void *) aname->hash_value);
2380 g_free ((guint8*) aname->public_key);
2384 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2387 gchar header [16], val, *arr;
2388 gint i, j, offset, bitlen, keylen, pkeylen;
2390 keylen = strlen (key) >> 1;
2394 /* allow the ECMA standard key */
2395 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2397 *pubkey = g_strdup (key);
2403 val = g_ascii_xdigit_value (key [0]) << 4;
2404 val |= g_ascii_xdigit_value (key [1]);
2409 val = g_ascii_xdigit_value (key [24]);
2410 val |= g_ascii_xdigit_value (key [25]);
2422 /* We need the first 16 bytes
2423 * to check whether this key is valid or not */
2424 pkeylen = strlen (pkey) >> 1;
2428 for (i = 0, j = 0; i < 16; i++) {
2429 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2430 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2433 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2434 header [1] != 0x02 || /* Version (0x02) */
2435 header [2] != 0x00 || /* Reserved (word) */
2436 header [3] != 0x00 ||
2437 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2440 /* Based on this length, we _should_ be able to know if the length is right */
2441 bitlen = read32 (header + 12) >> 3;
2442 if ((bitlen + 16 + 4) != pkeylen)
2445 /* parsing is OK and the public key itself is not requested back */
2449 /* Encode the size of the blob */
2451 if (keylen <= 127) {
2452 arr = (gchar *)g_malloc (keylen + 1);
2453 arr [offset++] = keylen;
2455 arr = (gchar *)g_malloc (keylen + 2);
2456 arr [offset++] = 0x80; /* 10bs */
2457 arr [offset++] = keylen;
2460 for (i = offset, j = 0; i < keylen + offset; i++) {
2461 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2462 arr [i] |= g_ascii_xdigit_value (key [j++]);
2471 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)
2473 gint major, minor, build, revision;
2476 gchar *pkey, *pkeyptr, *encoded, tok [8];
2478 memset (aname, 0, sizeof (MonoAssemblyName));
2481 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2482 if (version_parts < 2 || version_parts > 4)
2485 /* FIXME: we should set build & revision to -1 (instead of 0)
2486 if these are not set in the version string. That way, later on,
2487 we can still determine if these were specified. */
2488 aname->major = major;
2489 aname->minor = minor;
2490 if (version_parts >= 3)
2491 aname->build = build;
2494 if (version_parts == 4)
2495 aname->revision = revision;
2497 aname->revision = 0;
2500 aname->flags = flags;
2502 aname->name = g_strdup (name);
2505 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2506 aname->culture = g_strdup ("");
2508 aname->culture = g_strdup (culture);
2511 if (token && strncmp (token, "null", 4) != 0) {
2514 /* the constant includes the ending NULL, hence the -1 */
2515 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2516 mono_assembly_name_free (aname);
2519 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2520 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2526 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2527 mono_assembly_name_free (aname);
2532 if (save_public_key)
2533 aname->public_key = (guint8*)pkey;
2536 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2540 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2541 // We also need to generate the key token
2542 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2543 encoded = encode_public_tok ((guchar*) tok, 8);
2544 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2547 if (save_public_key)
2548 aname->public_key = (guint8*) pkey;
2557 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2562 parts = g_strsplit (dirname, "_", 3);
2563 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2568 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2574 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2576 char *eqsign = strchr (pair, '=');
2584 *key = (gchar*)pair;
2585 *keylen = eqsign - *key;
2586 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2588 *value = g_strstrip (eqsign + 1);
2593 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2597 gchar *version = NULL;
2599 gchar *culture = NULL;
2601 gchar *token = NULL;
2605 gchar *retargetable = NULL;
2606 gchar *retargetable_uq;
2610 gchar *value, *part_name;
2611 guint32 part_name_len;
2614 gboolean version_defined;
2615 gboolean token_defined;
2617 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2619 if (!is_version_defined)
2620 is_version_defined = &version_defined;
2621 *is_version_defined = FALSE;
2622 if (!is_token_defined)
2623 is_token_defined = &token_defined;
2624 *is_token_defined = FALSE;
2626 parts = tmp = g_strsplit (name, ",", 6);
2627 if (!tmp || !*tmp) {
2632 dllname = g_strstrip (*tmp);
2637 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2638 goto cleanup_and_fail;
2640 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2641 *is_version_defined = TRUE;
2643 if (strlen (version) == 0) {
2644 goto cleanup_and_fail;
2650 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2652 if (strlen (culture) == 0) {
2653 goto cleanup_and_fail;
2659 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2660 *is_token_defined = TRUE;
2662 if (strlen (token) == 0) {
2663 goto cleanup_and_fail;
2669 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2671 if (strlen (key) == 0) {
2672 goto cleanup_and_fail;
2678 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2679 retargetable = value;
2680 retargetable_uq = unquote (retargetable);
2681 if (retargetable_uq != NULL)
2682 retargetable = retargetable_uq;
2684 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2685 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2686 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2687 g_free (retargetable_uq);
2688 goto cleanup_and_fail;
2691 g_free (retargetable_uq);
2696 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2698 procarch_uq = unquote (procarch);
2699 if (procarch_uq != NULL)
2700 procarch = procarch_uq;
2702 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2703 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2704 else if (!g_ascii_strcasecmp (procarch, "X86"))
2705 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2706 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2707 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2708 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2709 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2711 g_free (procarch_uq);
2712 goto cleanup_and_fail;
2715 g_free (procarch_uq);
2724 /* if retargetable flag is set, then we must have a fully qualified name */
2725 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2726 goto cleanup_and_fail;
2729 dllname_uq = unquote (dllname);
2730 version_uq = unquote (version);
2731 culture_uq = unquote (culture);
2732 token_uq = unquote (token);
2733 key_uq = unquote (key);
2735 res = build_assembly_name (
2736 dllname_uq == NULL ? dllname : dllname_uq,
2737 version_uq == NULL ? version : version_uq,
2738 culture_uq == NULL ? culture : culture_uq,
2739 token_uq == NULL ? token : token_uq,
2740 key_uq == NULL ? key : key_uq,
2741 flags, arch, aname, save_public_key);
2743 g_free (dllname_uq);
2744 g_free (version_uq);
2745 g_free (culture_uq);
2758 unquote (const char *str)
2766 slen = strlen (str);
2770 if (*str != '\'' && *str != '\"')
2773 end = str + slen - 1;
2777 return g_strndup (str + 1, slen - 2);
2781 * mono_assembly_name_parse:
2782 * \param name name to parse
2783 * \param aname the destination assembly name
2785 * Parses an assembly qualified type name and assigns the name,
2786 * version, culture and token to the provided assembly name object.
2788 * \returns TRUE if the name could be parsed.
2791 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2793 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2797 * mono_assembly_name_new:
2798 * \param name name to parse
2800 * Allocate a new \c MonoAssemblyName and fill its values from the
2803 * \returns a newly allocated structure or NULL if there was any failure.
2806 mono_assembly_name_new (const char *name)
2808 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2809 if (mono_assembly_name_parse (name, aname))
2816 * mono_assembly_name_get_name:
2819 mono_assembly_name_get_name (MonoAssemblyName *aname)
2825 * mono_assembly_name_get_culture:
2828 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2830 return aname->culture;
2834 * mono_assembly_name_get_pubkeytoken:
2837 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2839 if (aname->public_key_token [0])
2840 return aname->public_key_token;
2845 * mono_assembly_name_get_version:
2848 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2851 *minor = aname->minor;
2853 *build = aname->build;
2855 *revision = aname->revision;
2856 return aname->major;
2859 static MonoAssembly*
2860 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2862 gchar *fullpath = NULL;
2864 const char* direntry;
2865 MonoAssemblyName gac_aname;
2866 gint major=-1, minor=0, build=0, revision=0;
2867 gboolean exact_version;
2869 dirhandle = g_dir_open (basepath, 0, NULL);
2873 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2875 while ((direntry = g_dir_read_name (dirhandle))) {
2876 gboolean match = TRUE;
2878 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2881 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2884 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2885 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2889 if (exact_version) {
2890 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2891 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2893 else if (gac_aname.major < major)
2895 else if (gac_aname.major == major) {
2896 if (gac_aname.minor < minor)
2898 else if (gac_aname.minor == minor) {
2899 if (gac_aname.build < build)
2901 else if (gac_aname.build == build && gac_aname.revision <= revision)
2908 major = gac_aname.major;
2909 minor = gac_aname.minor;
2910 build = gac_aname.build;
2911 revision = gac_aname.revision;
2913 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2916 mono_assembly_name_free (&gac_aname);
2919 g_dir_close (dirhandle);
2921 if (fullpath == NULL)
2924 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2931 * mono_assembly_load_with_partial_name:
2932 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2933 * \param status return status code
2935 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2936 * so it might contain a qualified type name, version, culture and token.
2938 * This will load the assembly from the file whose name is derived from the assembly name
2939 * by appending the \c .dll extension.
2941 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2942 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2943 * if that fails from the GAC.
2945 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2948 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2952 MonoAssemblyName *aname, base_name;
2953 MonoAssemblyName mapped_aname;
2954 gchar *fullname, *gacpath;
2957 memset (&base_name, 0, sizeof (MonoAssemblyName));
2960 if (!mono_assembly_name_parse (name, aname))
2964 * If no specific version has been requested, make sure we load the
2965 * correct version for system assemblies.
2967 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2968 aname = mono_assembly_remap_version (aname, &mapped_aname);
2970 res = mono_assembly_loaded (aname);
2972 mono_assembly_name_free (aname);
2976 res = invoke_assembly_preload_hook (aname, assemblies_path);
2978 res->in_gac = FALSE;
2979 mono_assembly_name_free (aname);
2983 fullname = g_strdup_printf ("%s.dll", aname->name);
2985 if (extra_gac_paths) {
2986 paths = extra_gac_paths;
2987 while (!res && *paths) {
2988 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2989 res = probe_for_partial_name (gacpath, fullname, aname, status);
2998 mono_assembly_name_free (aname);
3002 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
3003 res = probe_for_partial_name (gacpath, fullname, aname, status);
3007 mono_assembly_name_free (aname);
3012 MonoDomain *domain = mono_domain_get ();
3014 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
3015 if (!is_ok (&error)) {
3016 mono_error_cleanup (&error);
3017 if (*status == MONO_IMAGE_OK)
3018 *status = MONO_IMAGE_IMAGE_INVALID;
3026 mono_assembly_is_in_gac (const gchar *filename)
3028 const gchar *rootdir;
3032 if (filename == NULL)
3035 for (paths = extra_gac_paths; paths && *paths; paths++) {
3036 if (strstr (*paths, filename) != *paths)
3039 gp = (gchar *) (filename + strlen (*paths));
3040 if (*gp != G_DIR_SEPARATOR)
3043 if (strncmp (gp, "lib", 3))
3046 if (*gp != G_DIR_SEPARATOR)
3049 if (strncmp (gp, "mono", 4))
3052 if (*gp != G_DIR_SEPARATOR)
3055 if (strncmp (gp, "gac", 3))
3058 if (*gp != G_DIR_SEPARATOR)
3064 rootdir = mono_assembly_getrootdir ();
3065 if (strstr (filename, rootdir) != filename)
3068 gp = (gchar *) (filename + strlen (rootdir));
3069 if (*gp != G_DIR_SEPARATOR)
3072 if (strncmp (gp, "mono", 4))
3075 if (*gp != G_DIR_SEPARATOR)
3078 if (strncmp (gp, "gac", 3))
3081 if (*gp != G_DIR_SEPARATOR)
3087 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3090 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
3094 if (strstr (aname->name, ".dll")) {
3095 len = strlen (aname->name) - 4;
3096 name = (gchar *)g_malloc (len + 1);
3097 memcpy (name, aname->name, len);
3100 name = g_strdup (aname->name);
3103 culture = g_utf8_strdown (aname->culture, -1);
3105 culture = g_strdup ("");
3107 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
3108 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
3112 filename = g_strconcat (pname, ".dll", NULL);
3113 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
3119 if (extra_gac_paths) {
3120 paths = extra_gac_paths;
3121 while (!image && *paths) {
3122 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
3123 "lib", "mono", "gac", subpath, NULL);
3124 image = mono_image_open (fullpath, NULL);
3135 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3136 "mono", "gac", subpath, NULL);
3137 image = mono_image_open (fullpath, NULL);
3144 static MonoAssemblyName*
3145 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3147 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3148 dest_name->major = info->new_version.major;
3149 dest_name->minor = info->new_version.minor;
3150 dest_name->build = info->new_version.build;
3151 dest_name->revision = info->new_version.revision;
3156 /* LOCKING: assembly_binding lock must be held */
3157 static MonoAssemblyBindingInfo*
3158 search_binding_loaded (MonoAssemblyName *aname)
3162 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3163 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3164 if (assembly_binding_maps_name (info, aname))
3171 static inline gboolean
3172 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3174 if (left->major != right->major || left->minor != right->minor ||
3175 left->build != right->build || left->revision != right->revision)
3181 static inline gboolean
3182 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3184 if (left->has_old_version_bottom != right->has_old_version_bottom)
3187 if (left->has_old_version_top != right->has_old_version_top)
3190 if (left->has_new_version != right->has_new_version)
3193 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3196 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3199 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3205 /* LOCKING: assumes all the necessary locks are held */
3207 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3209 MonoAssemblyBindingInfo *info_copy;
3211 MonoAssemblyBindingInfo *info_tmp;
3212 MonoDomain *domain = (MonoDomain*)user_data;
3217 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)) {
3218 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3219 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3223 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3224 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3225 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3229 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3230 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3232 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3234 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3236 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3240 get_version_number (int major, int minor)
3242 return major * 256 + minor;
3245 static inline gboolean
3246 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3248 int aname_version_number = get_version_number (aname->major, aname->minor);
3249 if (!info->has_old_version_bottom)
3252 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3255 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3258 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3259 info->major = aname->major;
3260 info->minor = aname->minor;
3265 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3266 static MonoAssemblyBindingInfo*
3267 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3269 MonoAssemblyBindingInfo *info;
3272 if (!domain->assembly_bindings)
3276 for (list = domain->assembly_bindings; list; list = list->next) {
3277 info = (MonoAssemblyBindingInfo *)list->data;
3278 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3284 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3285 info->has_new_version && assembly_binding_maps_name (info, aname))
3286 info->is_valid = TRUE;
3288 info->is_valid = FALSE;
3295 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3297 if (domain->assembly_bindings_parsed)
3299 mono_domain_lock (domain);
3300 if (!domain->assembly_bindings_parsed) {
3302 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3304 if (!domain_config_file_path)
3305 domain_config_file_path = domain_config_file_name;
3307 mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3308 domain->assembly_bindings_parsed = TRUE;
3309 if (domain_config_file_name != domain_config_file_path)
3310 g_free (domain_config_file_path);
3313 mono_domain_unlock (domain);
3316 static MonoAssemblyName*
3317 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3320 MonoAssemblyBindingInfo *info, *info2;
3324 if (aname->public_key_token [0] == 0)
3327 domain = mono_domain_get ();
3329 mono_assembly_binding_lock ();
3330 info = search_binding_loaded (aname);
3331 mono_assembly_binding_unlock ();
3334 mono_domain_lock (domain);
3335 info = get_per_domain_assembly_binding_info (domain, aname);
3336 mono_domain_unlock (domain);
3340 if (!check_policy_versions (info, aname))
3343 mono_assembly_bind_version (info, aname, dest_name);
3347 if (domain && domain->setup && domain->setup->configuration_file) {
3348 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3349 /* expect this to succeed because mono_domain_set_options_from_config () did
3350 * the same thing when the domain was created. */
3351 mono_error_assert_ok (&error);
3352 mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3353 g_free (domain_config_file_name);
3355 mono_domain_lock (domain);
3356 info2 = get_per_domain_assembly_binding_info (domain, aname);
3359 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3360 info->name = g_strdup (info2->name);
3361 info->culture = g_strdup (info2->culture);
3362 info->domain_id = domain->domain_id;
3365 mono_domain_unlock (domain);
3370 info = g_new0 (MonoAssemblyBindingInfo, 1);
3371 info->major = aname->major;
3372 info->minor = aname->minor;
3375 if (!info->is_valid) {
3376 ppimage = mono_assembly_load_publisher_policy (aname);
3378 get_publisher_policy_info (ppimage, aname, info);
3379 mono_image_close (ppimage);
3383 /* Define default error value if needed */
3384 if (!info->is_valid) {
3385 info->name = g_strdup (aname->name);
3386 info->culture = g_strdup (aname->culture);
3387 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3390 mono_assembly_binding_lock ();
3391 info2 = search_binding_loaded (aname);
3393 /* This binding was added by another thread
3395 mono_assembly_binding_info_free (info);
3400 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3402 mono_assembly_binding_unlock ();
3404 if (!info->is_valid || !check_policy_versions (info, aname))
3407 mono_assembly_bind_version (info, aname, dest_name);
3412 * mono_assembly_load_from_gac
3414 * \param aname The assembly name object
3416 static MonoAssembly*
3417 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3419 MonoAssembly *result = NULL;
3420 gchar *name, *version, *culture, *fullpath, *subpath;
3425 if (aname->public_key_token [0] == 0) {
3429 if (strstr (aname->name, ".dll")) {
3430 len = strlen (filename) - 4;
3431 name = (gchar *)g_malloc (len + 1);
3432 memcpy (name, aname->name, len);
3435 name = g_strdup (aname->name);
3438 if (aname->culture) {
3439 culture = g_utf8_strdown (aname->culture, -1);
3441 culture = g_strdup ("");
3444 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3445 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3446 aname->minor, aname->build, aname->revision,
3450 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3455 if (extra_gac_paths) {
3456 paths = extra_gac_paths;
3457 while (!result && *paths) {
3458 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3459 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3466 result->in_gac = TRUE;
3471 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3472 "mono", "gac", subpath, NULL);
3473 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3477 result->in_gac = TRUE;
3485 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3488 MonoAssemblyName *aname;
3491 /* g_print ("corlib already loaded\n"); */
3495 // In native client, Corlib is embedded in the executable as static variable corlibData
3496 #if defined(__native_client__)
3497 if (corlibData != NULL && corlibSize != 0) {
3499 /* First "FALSE" instructs mono not to make a copy. */
3500 /* Second "FALSE" says this is not just a ref. */
3501 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3502 if (image == NULL || status != 0)
3503 g_print("mono_image_open_from_data_full failed: %d\n", status);
3504 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3505 if (corlib == NULL || status != 0)
3506 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3512 // A nonstandard preload hook may provide a special mscorlib assembly
3513 aname = mono_assembly_name_new ("mscorlib.dll");
3514 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3515 mono_assembly_name_free (aname);
3518 goto return_corlib_and_facades;
3520 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3521 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3522 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3524 goto return_corlib_and_facades;
3527 /* Normal case: Load corlib from mono/<version> */
3528 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3529 if (assemblies_path) { // Custom assemblies path
3530 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3532 g_free (corlib_file);
3533 goto return_corlib_and_facades;
3536 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3537 g_free (corlib_file);
3539 return_corlib_and_facades:
3540 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3541 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3546 static MonoAssembly*
3547 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3549 MonoError refasm_error;
3550 error_init (&refasm_error);
3551 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3554 mono_error_cleanup (&refasm_error);
3559 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3561 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3562 MonoAssemblyName *candidate_name = &candidate->aname;
3564 g_assert (wanted_name != NULL);
3565 g_assert (candidate_name != NULL);
3567 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3568 char * s = mono_stringify_assembly_name (wanted_name);
3569 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3571 s = mono_stringify_assembly_name (candidate_name);
3572 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3577 /* Wanted name has no token, not strongly named: always matches. */
3578 if (0 == wanted_name->public_key_token [0]) {
3579 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3583 /* Candidate name has no token, not strongly named: never matches */
3584 if (0 == candidate_name->public_key_token [0]) {
3585 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3589 return exact_sn_match (wanted_name, candidate_name) ||
3590 framework_assembly_sn_match (wanted_name, candidate_name);
3594 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3596 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3598 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3599 result ? "match, returning TRUE" : "don't match, returning FALSE");
3605 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3607 #ifndef DISABLE_DESKTOP_LOADER
3608 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3610 if (!vmap->framework_facade_assembly) {
3611 /* 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. */
3612 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3613 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");
3616 /* For facades, the name and public key token should
3617 * match, but the version doesn't matter. */
3618 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3619 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");
3628 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3629 const char *basedir,
3630 MonoImageOpenStatus *status,
3633 MonoAssembly *result;
3634 char *fullpath, *filename;
3635 MonoAssemblyName maped_aname;
3636 MonoAssemblyName maped_name_pp;
3641 aname = mono_assembly_remap_version (aname, &maped_aname);
3643 /* Reflection only assemblies don't get assembly binding */
3645 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3647 result = mono_assembly_loaded_full (aname, refonly);
3651 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3653 result->in_gac = FALSE;
3657 /* Currently we retrieve the loaded corlib for reflection
3658 * only requests, like a common reflection only assembly
3660 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3661 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3664 MonoAssemblyCandidatePredicate predicate = NULL;
3665 void* predicate_ud = NULL;
3666 #if !defined(DISABLE_DESKTOP_LOADER)
3667 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
3668 predicate = &mono_assembly_candidate_predicate_sn_same_name;
3669 predicate_ud = aname;
3673 len = strlen (aname->name);
3674 for (ext_index = 0; ext_index < 2; ext_index ++) {
3675 ext = ext_index == 0 ? ".dll" : ".exe";
3676 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3677 filename = g_strdup (aname->name);
3678 /* Don't try appending .dll/.exe if it already has one of those extensions */
3681 filename = g_strconcat (aname->name, ext, NULL);
3684 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3691 fullpath = g_build_filename (basedir, filename, NULL);
3692 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, predicate_ud, status);
3695 result->in_gac = FALSE;
3701 result = load_in_path (filename, default_path, status, refonly, predicate, predicate_ud);
3703 result->in_gac = FALSE;
3713 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3715 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3718 /* Try a postload search hook */
3719 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3720 result = prevent_reference_assembly_from_running (result, refonly);
3726 * mono_assembly_load_full:
3727 * \param aname A MonoAssemblyName with the assembly name to load.
3728 * \param basedir A directory to look up the assembly at.
3729 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3730 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3732 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3733 * attempts to load the assembly from that directory before probing the standard locations.
3735 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3736 * assembly binding takes place.
3738 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3739 * value pointed by \p status is updated with an error code.
3742 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3744 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3748 * mono_assembly_load:
3749 * \param aname A MonoAssemblyName with the assembly name to load.
3750 * \param basedir A directory to look up the assembly at.
3751 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3753 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3754 * attempts to load the assembly from that directory before probing the standard locations.
3756 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3757 * value pointed by \p status is updated with an error code.
3760 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3762 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3766 * mono_assembly_loaded_full:
3767 * \param aname an assembly to look for.
3768 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3770 * This is used to determine if the specified assembly has been loaded
3771 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3772 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3775 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3778 MonoAssemblyName maped_aname;
3780 aname = mono_assembly_remap_version (aname, &maped_aname);
3782 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3788 * mono_assembly_loaded:
3789 * \param aname an assembly to look for.
3791 * This is used to determine if the specified assembly has been loaded
3793 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3794 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3797 mono_assembly_loaded (MonoAssemblyName *aname)
3799 return mono_assembly_loaded_full (aname, FALSE);
3803 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3805 if (assembly == NULL || assembly == REFERENCE_MISSING)
3808 if (assembly_is_dynamic (assembly)) {
3810 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3811 for (i = 0; i < dynimg->image.module_count; ++i)
3812 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3813 mono_dynamic_image_release_gc_roots (dynimg);
3818 * Returns whether mono_assembly_close_finish() must be called as
3819 * well. See comment for mono_image_close_except_pools() for why we
3820 * unload in two steps.
3823 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3826 g_return_val_if_fail (assembly != NULL, FALSE);
3828 if (assembly == REFERENCE_MISSING)
3831 /* Might be 0 already */
3832 if (InterlockedDecrement (&assembly->ref_count) > 0)
3835 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3837 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3839 mono_debug_close_image (assembly->image);
3841 mono_assemblies_lock ();
3842 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3843 mono_assemblies_unlock ();
3845 assembly->image->assembly = NULL;
3847 if (!mono_image_close_except_pools (assembly->image))
3848 assembly->image = NULL;
3850 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3851 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3852 mono_assembly_name_free (fname);
3855 g_slist_free (assembly->friend_assembly_names);
3856 g_free (assembly->basedir);
3858 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3864 mono_assembly_close_finish (MonoAssembly *assembly)
3866 g_assert (assembly && assembly != REFERENCE_MISSING);
3868 if (assembly->image)
3869 mono_image_close_finish (assembly->image);
3871 if (assembly_is_dynamic (assembly)) {
3872 g_free ((char*)assembly->aname.culture);
3879 * mono_assembly_close:
3880 * \param assembly the assembly to release.
3882 * This method releases a reference to the \p assembly. The assembly is
3883 * only released when all the outstanding references to it are released.
3886 mono_assembly_close (MonoAssembly *assembly)
3888 if (mono_assembly_close_except_image_pools (assembly))
3889 mono_assembly_close_finish (assembly);
3893 * mono_assembly_load_module:
3896 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3899 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3900 mono_error_assert_ok (&error);
3905 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3907 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3912 * mono_assembly_foreach:
3913 * \param func function to invoke for each assembly loaded
3914 * \param user_data data passed to the callback
3916 * Invokes the provided \p func callback for each assembly loaded into
3917 * the runtime. The first parameter passed to the callback is the
3918 * \c MonoAssembly*, and the second parameter is the \p user_data.
3920 * This is done for all assemblies loaded in the runtime, not just
3921 * those loaded in the current application domain.
3924 mono_assembly_foreach (GFunc func, gpointer user_data)
3929 * We make a copy of the list to avoid calling the callback inside the
3930 * lock, which could lead to deadlocks.
3932 mono_assemblies_lock ();
3933 copy = g_list_copy (loaded_assemblies);
3934 mono_assemblies_unlock ();
3936 g_list_foreach (loaded_assemblies, func, user_data);
3942 * mono_assemblies_cleanup:
3944 * Free all resources used by this module.
3947 mono_assemblies_cleanup (void)
3951 mono_os_mutex_destroy (&assemblies_mutex);
3952 mono_os_mutex_destroy (&assembly_binding_mutex);
3954 for (l = loaded_assembly_bindings; l; l = l->next) {
3955 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3957 mono_assembly_binding_info_free (info);
3960 g_slist_free (loaded_assembly_bindings);
3962 free_assembly_load_hooks ();
3963 free_assembly_search_hooks ();
3964 free_assembly_preload_hooks ();
3967 /*LOCKING takes the assembly_binding lock*/
3969 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3973 mono_assembly_binding_lock ();
3974 iter = &loaded_assembly_bindings;
3977 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3979 if (info->domain_id == domain_id) {
3981 mono_assembly_binding_info_free (info);
3988 mono_assembly_binding_unlock ();
3992 * Holds the assembly of the application, for
3993 * System.Diagnostics.Process::MainModule
3995 static MonoAssembly *main_assembly=NULL;
3998 * mono_assembly_set_main:
4001 mono_assembly_set_main (MonoAssembly *assembly)
4003 main_assembly = assembly;
4007 * mono_assembly_get_main:
4009 * Returns: the assembly for the application, the first assembly that is loaded by the VM
4012 mono_assembly_get_main (void)
4014 return (main_assembly);
4018 * mono_assembly_get_image:
4019 * \param assembly The assembly to retrieve the image from
4021 * \returns the \c MonoImage associated with this assembly.
4024 mono_assembly_get_image (MonoAssembly *assembly)
4026 return assembly->image;
4030 * mono_assembly_get_name:
4031 * \param assembly The assembly to retrieve the name from
4033 * The returned name's lifetime is the same as \p assembly's.
4035 * \returns the \c MonoAssemblyName associated with this assembly.
4038 mono_assembly_get_name (MonoAssembly *assembly)
4040 return &assembly->aname;
4044 * mono_register_bundled_assemblies:
4047 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4049 bundles = assemblies;
4052 #define MONO_DECLSEC_FORMAT_10 0x3C
4053 #define MONO_DECLSEC_FORMAT_20 0x2E
4054 #define MONO_DECLSEC_FIELD 0x53
4055 #define MONO_DECLSEC_PROPERTY 0x54
4057 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4058 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4059 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4060 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4061 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4064 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4068 case MONO_DECLSEC_PROPERTY:
4070 case MONO_DECLSEC_FIELD:
4072 *abort_decoding = TRUE;
4077 if (*p++ != MONO_TYPE_BOOLEAN) {
4078 *abort_decoding = TRUE;
4082 /* property name length */
4083 len = mono_metadata_decode_value (p, &p);
4085 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4096 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4098 int i, j, num, len, params_len;
4100 if (*p == MONO_DECLSEC_FORMAT_10) {
4101 gsize read, written;
4102 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4104 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4110 if (*p++ != MONO_DECLSEC_FORMAT_20)
4113 /* number of encoded permission attributes */
4114 num = mono_metadata_decode_value (p, &p);
4115 for (i = 0; i < num; ++i) {
4116 gboolean is_valid = FALSE;
4117 gboolean abort_decoding = FALSE;
4119 /* attribute name length */
4120 len = mono_metadata_decode_value (p, &p);
4122 /* We don't really need to fully decode the type. Comparing the name is enough */
4123 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4127 /*size of the params table*/
4128 params_len = mono_metadata_decode_value (p, &p);
4130 const char *params_end = p + params_len;
4132 /* number of parameters */
4133 len = mono_metadata_decode_value (p, &p);
4135 for (j = 0; j < len; ++j) {
4136 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4152 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4155 guint32 cols [MONO_DECL_SECURITY_SIZE];
4159 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4160 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4162 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4164 for (i = 0; i < t->rows; ++i) {
4165 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4166 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4168 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4171 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4172 len = mono_metadata_decode_blob_size (blob, &blob);
4176 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4177 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4182 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);