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},
127 {"Mono.CompilerServices.SymbolWriter", 0},
129 {"Mono.Data.SybaseClient", 0},
130 {"Mono.Data.Tds", 0},
131 {"Mono.Data.TdsClient", 0},
132 {"Mono.GetOptions", 0},
135 {"Mono.Security", 0},
136 {"Mono.Security.Win32", 0},
138 {"Novell.Directory.Ldap", 0},
141 FACADE_ASSEMBLY ("System.AppContext"),
142 FACADE_ASSEMBLY ("System.Collections"),
143 FACADE_ASSEMBLY ("System.Collections.Concurrent"),
144 FACADE_ASSEMBLY ("System.Collections.NonGeneric"),
145 FACADE_ASSEMBLY ("System.Collections.Specialized"),
146 FACADE_ASSEMBLY ("System.ComponentModel"),
147 FACADE_ASSEMBLY ("System.ComponentModel.Annotations"),
148 {"System.ComponentModel.Composition", 2},
149 {"System.ComponentModel.DataAnnotations", 2},
150 FACADE_ASSEMBLY ("System.ComponentModel.EventBasedAsync"),
151 FACADE_ASSEMBLY ("System.ComponentModel.Primitives"),
152 FACADE_ASSEMBLY ("System.ComponentModel.TypeConverter"),
153 {"System.Configuration", 0},
154 {"System.Configuration.Install", 0},
155 FACADE_ASSEMBLY ("System.Console"),
158 FACADE_ASSEMBLY ("System.Data.Common"),
159 {"System.Data.Linq", 2},
160 {"System.Data.OracleClient", 0},
161 {"System.Data.Services", 2},
162 {"System.Data.Services.Client", 2},
163 FACADE_ASSEMBLY ("System.Data.SqlClient"),
164 {"System.Data.SqlXml", 0},
165 {"System.Design", 0},
166 FACADE_ASSEMBLY ("System.Diagnostics.Contracts"),
167 FACADE_ASSEMBLY ("System.Diagnostics.Debug"),
168 FACADE_ASSEMBLY ("System.Diagnostics.FileVersionInfo"),
169 FACADE_ASSEMBLY ("System.Diagnostics.Process"),
170 FACADE_ASSEMBLY ("System.Diagnostics.StackTrace"),
171 FACADE_ASSEMBLY ("System.Diagnostics.TextWriterTraceListener"),
172 FACADE_ASSEMBLY ("System.Diagnostics.Tools"),
173 FACADE_ASSEMBLY ("System.Diagnostics.TraceEvent"),
174 FACADE_ASSEMBLY ("System.Diagnostics.TraceSource"),
175 FACADE_ASSEMBLY ("System.Diagnostics.Tracing"),
176 {"System.DirectoryServices", 0},
177 {"System.Drawing", 0},
178 {"System.Drawing.Design", 0},
179 FACADE_ASSEMBLY ("System.Drawing.Primitives"),
180 FACADE_ASSEMBLY ("System.Dynamic.Runtime"),
181 {"System.EnterpriseServices", 0},
182 FACADE_ASSEMBLY ("System.Globalization"),
183 FACADE_ASSEMBLY ("System.Globalization.Calendars"),
184 FACADE_ASSEMBLY ("System.Globalization.Extensions"),
185 {"System.IdentityModel", 3},
186 {"System.IdentityModel.Selectors", 3},
187 FACADE_ASSEMBLY ("System.IO"),
188 {"System.IO.Compression", 2},
189 FACADE_ASSEMBLY ("System.IO.Compression.ZipFile"),
190 FACADE_ASSEMBLY ("System.IO.FileSystem"),
191 FACADE_ASSEMBLY ("System.IO.FileSystem.AccessControl"),
192 FACADE_ASSEMBLY ("System.IO.FileSystem.DriveInfo"),
193 FACADE_ASSEMBLY ("System.IO.FileSystem.Primitives"),
194 FACADE_ASSEMBLY ("System.IO.FileSystem.Watcher"),
195 FACADE_ASSEMBLY ("System.IO.IsolatedStorage"),
196 FACADE_ASSEMBLY ("System.IO.MemoryMappedFiles"),
197 FACADE_ASSEMBLY ("System.IO.Packaging"),
198 FACADE_ASSEMBLY ("System.IO.Pipes"),
199 FACADE_ASSEMBLY ("System.IO.UnmanagedMemoryStream"),
200 FACADE_ASSEMBLY ("System.Linq"),
201 FACADE_ASSEMBLY ("System.Linq.Expressions"),
202 FACADE_ASSEMBLY ("System.Linq.Parallel"),
203 FACADE_ASSEMBLY ("System.Linq.Queryable"),
204 {"System.Management", 0},
205 {"System.Messaging", 0},
207 FACADE_ASSEMBLY ("System.Net.AuthenticationManager"),
208 FACADE_ASSEMBLY ("System.Net.Cache"),
209 {"System.Net.Http", 4},
210 {"System.Net.Http.Rtc", 0},
211 FACADE_ASSEMBLY ("System.Net.HttpListener"),
212 {"System.Net.NetworkInformation", 0},
213 FACADE_ASSEMBLY ("System.Net.Mail"),
214 FACADE_ASSEMBLY ("System.Net.NameResolution"),
215 FACADE_ASSEMBLY ("System.Net.NetworkInformation"),
216 FACADE_ASSEMBLY ("System.Net.Ping"),
217 FACADE_ASSEMBLY ("System.Net.Primitives"),
218 FACADE_ASSEMBLY ("System.Net.Requests"),
219 FACADE_ASSEMBLY ("System.Net.Security"),
220 FACADE_ASSEMBLY ("System.Net.ServicePoint"),
221 FACADE_ASSEMBLY ("System.Net.Sockets"),
222 FACADE_ASSEMBLY ("System.Net.Utilities"),
223 FACADE_ASSEMBLY ("System.Net.WebHeaderCollection"),
224 FACADE_ASSEMBLY ("System.Net.WebSockets"),
225 FACADE_ASSEMBLY ("System.Net.WebSockets.Client"),
226 {"System.Numerics.Vectors", 3},
227 FACADE_ASSEMBLY ("System.ObjectModel"),
228 FACADE_ASSEMBLY ("System.Reflection"),
229 FACADE_ASSEMBLY ("System.Reflection.Emit"),
230 FACADE_ASSEMBLY ("System.Reflection.Emit.ILGeneration"),
231 FACADE_ASSEMBLY ("System.Reflection.Emit.Lightweight"),
232 FACADE_ASSEMBLY ("System.Reflection.Extensions"),
233 FACADE_ASSEMBLY ("System.Reflection.Primitives"),
234 FACADE_ASSEMBLY ("System.Reflection.TypeExtensions"),
235 FACADE_ASSEMBLY ("System.Resources.ReaderWriter"),
236 FACADE_ASSEMBLY ("System.Resources.ResourceManager"),
237 FACADE_ASSEMBLY ("System.Runtime"),
238 FACADE_ASSEMBLY ("System.Runtime.CompilerServices.VisualC"),
239 FACADE_ASSEMBLY ("System.Runtime.Extensions"),
240 FACADE_ASSEMBLY ("System.Runtime.Handles"),
241 FACADE_ASSEMBLY ("System.Runtime.InteropServices"),
242 FACADE_ASSEMBLY ("System.Runtime.InteropServices.RuntimeInformation"),
243 FACADE_ASSEMBLY ("System.Runtime.InteropServices.WindowsRuntime"),
244 FACADE_ASSEMBLY ("System.Runtime.Loader"),
245 FACADE_ASSEMBLY ("System.Runtime.Numerics"),
246 {"System.Runtime.Remoting", 0},
247 {"System.Runtime.Serialization", 3},
248 {"System.Runtime.Serialization.Formatters", 3},
249 {"System.Runtime.Serialization.Formatters.Soap", 0},
250 FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"),
251 FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"),
252 FACADE_ASSEMBLY ("System.Runtime.Serialization.Xml"),
253 {"System.Security", 0},
254 FACADE_ASSEMBLY ("System.Security.AccessControl"),
255 FACADE_ASSEMBLY ("System.Security.Claims"),
256 FACADE_ASSEMBLY ("System.Security.Cryptography.Algorithms"),
257 FACADE_ASSEMBLY ("System.Security.Cryptography.Cng"),
258 FACADE_ASSEMBLY ("System.Security.Cryptography.Csp"),
259 FACADE_ASSEMBLY ("System.Security.Cryptography.DeriveBytes"),
260 FACADE_ASSEMBLY ("System.Security.Cryptography.Encoding"),
261 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption"),
262 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Aes"),
263 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDiffieHellman"),
264 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDsa"),
265 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing"),
266 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing.Algorithms"),
267 FACADE_ASSEMBLY ("System.Security.Cryptography.OpenSsl"),
268 FACADE_ASSEMBLY ("System.Security.Cryptography.Pkcs"),
269 FACADE_ASSEMBLY ("System.Security.Cryptography.Primitives"),
270 FACADE_ASSEMBLY ("System.Security.Cryptography.ProtectedData"),
271 FACADE_ASSEMBLY ("System.Security.Cryptography.RSA"),
272 FACADE_ASSEMBLY ("System.Security.Cryptography.RandomNumberGenerator"),
273 FACADE_ASSEMBLY ("System.Security.Cryptography.X509Certificates"),
274 FACADE_ASSEMBLY ("System.Security.Principal"),
275 FACADE_ASSEMBLY ("System.Security.Principal.Windows"),
276 FACADE_ASSEMBLY ("System.Security.SecureString"),
277 {"System.ServiceModel", 3},
278 {"System.ServiceModel.Duplex", 3},
279 {"System.ServiceModel.Http", 3},
280 {"System.ServiceModel.NetTcp", 3},
281 {"System.ServiceModel.Primitives", 3},
282 {"System.ServiceModel.Security", 3},
283 {"System.ServiceModel.Web", 2},
284 {"System.ServiceProcess", 0},
285 FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"),
286 FACADE_ASSEMBLY ("System.Text.Encoding"),
287 FACADE_ASSEMBLY ("System.Text.Encoding.CodePages"),
288 FACADE_ASSEMBLY ("System.Text.Encoding.Extensions"),
289 FACADE_ASSEMBLY ("System.Text.RegularExpressions"),
290 FACADE_ASSEMBLY ("System.Threading"),
291 FACADE_ASSEMBLY ("System.Threading.AccessControl"),
292 FACADE_ASSEMBLY ("System.Threading.Overlapped"),
293 FACADE_ASSEMBLY ("System.Threading.Tasks"),
294 FACADE_ASSEMBLY ("System.Threading.Tasks.Parallel"),
295 FACADE_ASSEMBLY ("System.Threading.Thread"),
296 FACADE_ASSEMBLY ("System.Threading.ThreadPool"),
297 FACADE_ASSEMBLY ("System.Threading.Timer"),
298 {"System.Transactions", 0},
299 FACADE_ASSEMBLY ("System.ValueTuple"),
301 {"System.Web.Abstractions", 2},
302 {"System.Web.DynamicData", 2},
303 {"System.Web.Extensions", 2},
304 {"System.Web.Mobile", 0},
305 {"System.Web.Routing", 2},
306 {"System.Web.Services", 0},
307 {"System.Windows", 0},
308 {"System.Windows.Forms", 0},
310 {"System.Xml.Linq", 2},
311 FACADE_ASSEMBLY ("System.Xml.ReaderWriter"),
312 {"System.Xml.Serialization", 0},
313 FACADE_ASSEMBLY ("System.Xml.XDocument"),
314 FACADE_ASSEMBLY ("System.Xml.XPath"),
315 FACADE_ASSEMBLY ("System.Xml.XPath.XmlDocument"),
316 FACADE_ASSEMBLY ("System.Xml.XPath.XDocument"),
317 FACADE_ASSEMBLY ("System.Xml.XmlDocument"),
318 FACADE_ASSEMBLY ("System.Xml.XmlSerializer"),
319 FACADE_ASSEMBLY ("System.Xml.Xsl.Primitives"),
322 FACADE_ASSEMBLY ("netstandard"),
327 * keeps track of loaded assemblies
329 static GList *loaded_assemblies = NULL;
330 static MonoAssembly *corlib;
332 #if defined(__native_client__)
334 /* On Native Client, allow mscorlib to be loaded from memory */
335 /* instead of loaded off disk. If these are not set, default */
336 /* mscorlib loading will take place */
338 /* NOTE: If mscorlib data is passed to mono in this way then */
339 /* it needs to remain allocated during the use of mono. */
341 static void *corlibData = NULL;
342 static size_t corlibSize = 0;
345 mono_set_corlib_data (void *data, size_t size)
353 static char* unquote (const char *str);
355 /* This protects loaded_assemblies and image->references */
356 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
357 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
358 static mono_mutex_t assemblies_mutex;
360 /* If defined, points to the bundled assembly information */
361 const MonoBundledAssembly **bundles;
363 static mono_mutex_t assembly_binding_mutex;
365 /* Loaded assembly binding info */
366 static GSList *loaded_assembly_bindings = NULL;
368 /* Class lazy loading functions */
369 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
371 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
373 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
375 mono_assembly_is_in_gac (const gchar *filanem);
378 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
381 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags);
383 /* Assembly name matching */
385 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
387 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
390 encode_public_tok (const guchar *token, gint32 len)
392 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
396 res = (gchar *)g_malloc (len * 2 + 1);
397 for (i = 0; i < len; i++) {
398 res [i * 2] = allowed [token [i] >> 4];
399 res [i * 2 + 1] = allowed [token [i] & 0xF];
406 * mono_public_tokens_are_equal:
407 * \param pubt1 first public key token
408 * \param pubt2 second public key token
410 * Compare two public key tokens and return TRUE is they are equal and FALSE
414 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
416 return memcmp (pubt1, pubt2, 16) == 0;
420 * mono_set_assemblies_path:
421 * \param path list of paths that contain directories where Mono will look for assemblies
423 * Use this method to override the standard assembly lookup system and
424 * override any assemblies coming from the GAC. This is the method
425 * that supports the \c MONO_PATH variable.
427 * Notice that \c MONO_PATH and this method are really a very bad idea as
428 * it prevents the GAC from working and it prevents the standard
429 * resolution mechanisms from working. Nonetheless, for some debugging
430 * situations and bootstrapping setups, this is useful to have.
433 mono_set_assemblies_path (const char* path)
435 char **splitted, **dest;
437 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
439 g_strfreev (assemblies_path);
440 assemblies_path = dest = splitted;
442 char *tmp = *splitted;
444 *dest++ = mono_path_canonicalize (tmp);
450 if (g_hasenv ("MONO_DEBUG"))
453 splitted = assemblies_path;
455 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
456 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
462 /* Native Client can't get this info from an environment variable so */
463 /* it's passed in to the runtime, or set manually by embedding code. */
464 #ifdef __native_client__
465 char* nacl_mono_path = NULL;
469 check_path_env (void)
471 if (assemblies_path != NULL)
474 char* path = g_getenv ("MONO_PATH");
475 #ifdef __native_client__
477 path = strdup (nacl_mono_path);
482 mono_set_assemblies_path(path);
487 check_extra_gac_path_env (void)
490 char **splitted, **dest;
492 path = g_getenv ("MONO_GAC_PREFIX");
496 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
500 g_strfreev (extra_gac_paths);
501 extra_gac_paths = dest = splitted;
509 if (!g_hasenv ("MONO_DEBUG"))
513 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
514 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
521 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
523 if (!info || !info->name)
526 if (strcmp (info->name, aname->name))
529 if (info->major != aname->major || info->minor != aname->minor)
532 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
535 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
538 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
545 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
551 g_free (info->culture);
555 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
558 guint32 cols [MONO_MANIFEST_SIZE];
559 const gchar *filename;
560 gchar *subpath, *fullpath;
562 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
563 /* MS Impl. accepts policy assemblies with more than
564 * one manifest resource, and only takes the first one */
566 binding_info->is_valid = FALSE;
570 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
571 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
572 binding_info->is_valid = FALSE;
576 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
577 g_assert (filename != NULL);
579 subpath = g_path_get_dirname (image->name);
580 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
581 mono_config_parse_publisher_policy (fullpath, binding_info);
585 /* Define the optional elements/attributes before checking */
586 if (!binding_info->culture)
587 binding_info->culture = g_strdup ("");
589 /* Check that the most important elements/attributes exist */
590 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
591 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
592 mono_assembly_binding_info_free (binding_info);
593 binding_info->is_valid = FALSE;
597 binding_info->is_valid = TRUE;
601 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
603 if (v->major > aname->major)
605 else if (v->major < aname->major)
608 if (v->minor > aname->minor)
610 else if (v->minor < aname->minor)
613 if (v->build > aname->build)
615 else if (v->build < aname->build)
618 if (v->revision > aname->revision)
620 else if (v->revision < aname->revision)
627 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
632 /* If has_old_version_top doesn't exist, we don't have an interval */
633 if (!info->has_old_version_top) {
634 if (compare_versions (&info->old_version_bottom, name) == 0)
640 /* Check that the version defined by name is valid for the interval */
641 if (compare_versions (&info->old_version_top, name) < 0)
644 /* We should be greater or equal than the small version */
645 if (compare_versions (&info->old_version_bottom, name) > 0)
652 * mono_assembly_names_equal:
653 * \param l first assembly
654 * \param r second assembly.
656 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
658 * This compares the names, the cultures, the release version and their
661 * \returns TRUE if both assembly names are equal.
664 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
666 return assembly_names_equal_flags (l, r, ANAME_EQ_NONE);
670 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags)
672 if (!l->name || !r->name)
675 if (strcmp (l->name, r->name))
678 if (l->culture && r->culture && strcmp (l->culture, r->culture))
681 if ((l->major != r->major || l->minor != r->minor ||
682 l->build != r->build || l->revision != r->revision) &&
683 (flags & ANAME_EQ_IGNORE_VERSION) == 0)
684 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)))
687 if (!l->public_key_token [0] || !r->public_key_token [0] || (flags & ANAME_EQ_IGNORE_PUBKEY) != 0)
690 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
696 static MonoAssembly *
697 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
701 MonoAssembly *result;
703 for (i = 0; search_path [i]; ++i) {
704 fullpath = g_build_filename (search_path [i], basename, NULL);
705 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
714 * mono_assembly_setrootdir:
715 * \param root_dir The pathname of the root directory where we will locate assemblies
717 * This routine sets the internal default root directory for looking up
720 * This is used by Windows installations to compute dynamically the
721 * place where the Mono assemblies are located.
725 mono_assembly_setrootdir (const char *root_dir)
728 * Override the MONO_ASSEMBLIES directory configured at compile time.
730 /* Leak if called more than once */
731 default_path [0] = g_strdup (root_dir);
735 * mono_assembly_getrootdir:
737 * Obtains the root directory used for looking up assemblies.
739 * Returns: a string with the directory, this string should not be freed.
741 G_CONST_RETURN gchar *
742 mono_assembly_getrootdir (void)
744 return default_path [0];
748 * mono_native_getrootdir:
750 * Obtains the root directory used for looking up native libs (.so, .dylib).
752 * Returns: a string with the directory, this string should be freed by
756 mono_native_getrootdir (void)
758 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
764 * \param assembly_dir the base directory for assemblies
765 * \param config_dir the base directory for configuration files
767 * This routine is used internally and by developers embedding
768 * the runtime into their own applications.
770 * There are a number of cases to consider: Mono as a system-installed
771 * package that is available on the location preconfigured or Mono in
772 * a relocated location.
774 * If you are using a system-installed Mono, you can pass NULL
775 * to both parameters. If you are not, you should compute both
776 * directory values and call this routine.
778 * The values for a given PREFIX are:
780 * assembly_dir: PREFIX/lib
781 * config_dir: PREFIX/etc
783 * Notice that embedders that use Mono in a relocated way must
784 * compute the location at runtime, as they will be in control
785 * of where Mono is installed.
788 mono_set_dirs (const char *assembly_dir, const char *config_dir)
790 if (assembly_dir == NULL)
791 assembly_dir = mono_config_get_assemblies_dir ();
792 if (config_dir == NULL)
793 config_dir = mono_config_get_cfg_dir ();
794 mono_assembly_setrootdir (assembly_dir);
795 mono_set_config_dir (config_dir);
801 compute_base (char *path)
803 char *p = strrchr (path, '/');
807 /* Not a well known Mono executable, we are embedded, cant guess the base */
808 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
812 p = strrchr (path, '/');
816 if (strcmp (p, "/bin") != 0)
825 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
828 static G_GNUC_UNUSED void
832 char *config, *lib, *mono;
837 * Only /usr prefix is treated specially
839 bindir = mono_config_get_bin_dir ();
841 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
846 config = g_build_filename (base, "etc", NULL);
847 lib = g_build_filename (base, "lib", NULL);
848 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
849 if (stat (mono, &buf) == -1)
852 mono_set_dirs (lib, config);
860 #endif /* HOST_WIN32 */
865 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
866 * this auto-detects the prefix where Mono was installed.
869 mono_set_rootdir (void)
871 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
872 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
875 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
879 * _NSGetExecutablePath may return -1 to indicate buf is not large
880 * enough, but we ignore that case to avoid having to do extra dynamic
881 * allocation for the path and hope that 4096 is enough - this is
882 * ok in the Linux/Solaris case below at least...
886 guint buf_size = sizeof (buf);
889 if (_NSGetExecutablePath (buf, &buf_size) == 0)
890 name = g_strdup (buf);
899 resolvedname = mono_path_resolve_symlinks (name);
901 bindir = g_path_get_dirname (resolvedname);
902 installdir = g_path_get_dirname (bindir);
903 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
905 config = g_build_filename (root, "..", "etc", NULL);
907 mono_set_dirs (root, config);
909 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
910 mono_set_dirs (root, config);
920 g_free (resolvedname);
921 #elif defined(DISABLE_MONO_AUTODETECTION)
929 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
937 /* Solaris 10 style */
938 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
939 s = readlink (str, buf, sizeof (buf)-1);
951 * mono_assemblies_init:
953 * Initialize global variables used by this module.
956 mono_assemblies_init (void)
959 * Initialize our internal paths if we have not been initialized yet.
960 * This happens when embedders use Mono.
962 if (mono_assembly_getrootdir () == NULL)
966 check_extra_gac_path_env ();
968 mono_os_mutex_init_recursive (&assemblies_mutex);
969 mono_os_mutex_init (&assembly_binding_mutex);
971 #ifndef DISABLE_DESKTOP_LOADER
972 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
975 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
976 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
982 mono_assembly_binding_lock (void)
984 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
988 mono_assembly_binding_unlock (void)
990 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
994 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
996 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
997 guint32 cols [MONO_ASSEMBLY_SIZE];
998 gint32 machine, flags;
1003 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
1005 aname->hash_len = 0;
1006 aname->hash_value = NULL;
1007 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
1009 aname->name = g_strdup (aname->name);
1010 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
1012 aname->culture = g_strdup (aname->culture);
1013 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
1014 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
1015 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
1016 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
1017 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
1018 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
1019 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
1020 guchar* token = (guchar *)g_malloc (8);
1025 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
1026 len = mono_metadata_decode_blob_size (pkey, &pkey);
1027 aname->public_key = (guchar*)pkey;
1029 mono_digest_get_public_token (token, aname->public_key, len);
1030 encoded = encode_public_tok (token, 8);
1031 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1037 aname->public_key = NULL;
1038 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1041 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
1042 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
1044 const gchar *pkey_end;
1045 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
1046 pkey_end += len; /* move to end */
1047 size_t size = pkey_end - (const gchar*)aname->public_key;
1048 guchar *tmp = g_new (guchar, size);
1049 memcpy (tmp, aname->public_key, size);
1050 aname->public_key = tmp;
1055 aname->public_key = 0;
1057 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
1058 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
1060 case COFF_MACHINE_I386:
1061 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1062 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
1063 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
1064 else if ((flags & 0x70) == 0x70)
1065 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
1067 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
1069 case COFF_MACHINE_IA64:
1070 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
1072 case COFF_MACHINE_AMD64:
1073 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
1075 case COFF_MACHINE_ARM:
1076 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
1086 * mono_assembly_fill_assembly_name:
1087 * \param image Image
1089 * \returns TRUE if successful
1092 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
1094 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
1098 * mono_stringify_assembly_name:
1099 * \param aname the assembly name.
1101 * Convert \p aname into its string format. The returned string is dynamically
1102 * allocated and should be freed by the caller.
1104 * \returns a newly allocated string with a string representation of
1105 * the assembly name.
1108 mono_stringify_assembly_name (MonoAssemblyName *aname)
1110 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
1112 return g_strdup_printf (
1113 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1114 quote, aname->name, quote,
1115 aname->major, aname->minor, aname->build, aname->revision,
1116 aname->culture && *aname->culture? aname->culture: "neutral",
1117 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
1118 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
1122 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
1124 const gchar *public_tok;
1127 public_tok = mono_metadata_blob_heap (image, key_index);
1128 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
1130 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
1132 mono_digest_get_public_token (token, (guchar*)public_tok, len);
1133 return encode_public_tok (token, 8);
1136 return encode_public_tok ((guchar*)public_tok, len);
1140 * mono_assembly_addref:
1141 * \param assembly the assembly to reference
1143 * This routine increments the reference count on a MonoAssembly.
1144 * The reference count is reduced every time the method mono_assembly_close() is
1148 mono_assembly_addref (MonoAssembly *assembly)
1150 InterlockedIncrement (&assembly->ref_count);
1154 * CAUTION: This table must be kept in sync with
1155 * ivkm/reflect/Fusion.cs
1158 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1159 #define WINFX_KEY "31bf3856ad364e35"
1160 #define ECMA_KEY "b77a5c561934e089"
1161 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1162 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1170 static KeyRemapEntry key_remap_table[] = {
1171 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1172 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1173 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1174 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1175 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1176 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1177 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1178 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1179 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1180 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1181 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1182 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1183 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1184 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1185 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1186 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1187 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1188 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1189 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1190 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1191 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1192 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1193 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1194 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1195 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1196 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1197 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1198 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1199 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1203 remap_keys (MonoAssemblyName *aname)
1206 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1207 const KeyRemapEntry *entry = &key_remap_table [i];
1209 if (strcmp (aname->name, entry->name) ||
1210 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1213 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1215 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1216 "Remapped public key token of retargetable assembly %s from %s to %s",
1217 aname->name, entry->from, entry->to);
1222 static MonoAssemblyName *
1223 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1225 const MonoRuntimeInfo *current_runtime;
1227 if (aname->name == NULL) return aname;
1229 current_runtime = mono_get_runtime_info ();
1231 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1232 const AssemblyVersionSet* vset;
1234 /* Remap to current runtime */
1235 vset = ¤t_runtime->version_sets [0];
1237 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1238 dest_aname->major = vset->major;
1239 dest_aname->minor = vset->minor;
1240 dest_aname->build = vset->build;
1241 dest_aname->revision = vset->revision;
1242 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1244 /* Remap assembly name */
1245 if (!strcmp (aname->name, "System.Net"))
1246 dest_aname->name = g_strdup ("System");
1248 remap_keys (dest_aname);
1250 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1251 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1253 aname->major, aname->minor, aname->build, aname->revision,
1255 vset->major, vset->minor, vset->build, vset->revision
1261 #ifndef DISABLE_DESKTOP_LOADER
1262 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1264 const AssemblyVersionSet* vset;
1265 int index = vmap->version_set_index;
1266 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1267 vset = ¤t_runtime->version_sets [index];
1269 if (vmap->framework_facade_assembly) {
1270 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s is a framework Facade asseembly",
1275 if (aname->major == vset->major && aname->minor == vset->minor &&
1276 aname->build == vset->build && aname->revision == vset->revision) {
1277 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1279 aname->major, aname->minor, aname->build, aname->revision);
1283 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1284 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1285 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1287 aname->major, aname->minor, aname->build, aname->revision,
1288 vset->major, vset->minor, vset->build, vset->revision
1293 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1294 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1295 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1297 aname->major, aname->minor, aname->build, aname->revision,
1298 vset->major, vset->minor, vset->build, vset->revision
1301 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1302 dest_aname->major = vset->major;
1303 dest_aname->minor = vset->minor;
1304 dest_aname->build = vset->build;
1305 dest_aname->revision = vset->revision;
1306 if (vmap->new_assembly_name != NULL) {
1307 dest_aname->name = vmap->new_assembly_name;
1308 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1309 "The assembly name %s was remapped to %s",
1321 * mono_assembly_get_assemblyref:
1322 * \param image pointer to the \c MonoImage to extract the information from.
1323 * \param index index to the assembly reference in the image.
1324 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1326 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1329 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1332 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1335 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1337 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1339 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1340 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1341 aname->hash_value = hash;
1342 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1343 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1344 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1345 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1346 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1347 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1348 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1350 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1351 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1352 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1355 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1360 * mono_assembly_load_reference:
1363 mono_assembly_load_reference (MonoImage *image, int index)
1365 MonoAssembly *reference;
1366 MonoAssemblyName aname;
1367 MonoImageOpenStatus status;
1370 * image->references is shared between threads, so we need to access
1371 * it inside a critical section.
1373 mono_assemblies_lock ();
1374 if (!image->references) {
1375 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1377 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1378 image->nreferences = t->rows;
1380 reference = image->references [index];
1381 mono_assemblies_unlock ();
1385 mono_assembly_get_assemblyref (image, index, &aname);
1387 if (image->assembly && image->assembly->ref_only) {
1388 /* We use the loaded corlib */
1389 if (!strcmp (aname.name, "mscorlib"))
1390 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1392 reference = mono_assembly_loaded_full (&aname, TRUE);
1394 /* Try a postload search hook */
1395 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1399 * Here we must advice that the error was due to
1400 * a non loaded reference using the ReflectionOnly api
1403 reference = (MonoAssembly *)REFERENCE_MISSING;
1405 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1406 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1407 * accordingly, it would fail on the MS runtime before).
1408 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1409 * example bug-349190.2.cs and who knows how much more code in the wild.
1411 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1412 if (!reference && image->assembly)
1413 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1416 if (reference == NULL){
1419 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1420 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 : "" );
1421 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1422 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1423 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1424 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1425 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1426 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1428 extra_msg = g_strdup ("");
1431 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1432 " Assembly: %s (assemblyref_index=%d)\n"
1433 " Version: %d.%d.%d.%d\n"
1434 " Public Key: %s\n%s",
1435 image->name, aname.name, index,
1436 aname.major, aname.minor, aname.build, aname.revision,
1437 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1442 mono_assemblies_lock ();
1443 if (reference == NULL) {
1444 /* Flag as not found */
1445 reference = (MonoAssembly *)REFERENCE_MISSING;
1448 if (!image->references [index]) {
1449 if (reference != REFERENCE_MISSING){
1450 mono_assembly_addref (reference);
1451 if (image->assembly)
1452 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1453 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1455 if (image->assembly)
1456 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1457 image->assembly->aname.name, image->assembly);
1460 image->references [index] = reference;
1462 mono_assemblies_unlock ();
1464 if (image->references [index] != reference) {
1465 /* Somebody loaded it before us */
1466 mono_assembly_close (reference);
1471 * mono_assembly_load_references:
1474 * \deprecated There is no reason to use this method anymore, it does nothing
1476 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1479 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1481 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1482 *status = MONO_IMAGE_OK;
1485 typedef struct AssemblyLoadHook AssemblyLoadHook;
1486 struct AssemblyLoadHook {
1487 AssemblyLoadHook *next;
1488 MonoAssemblyLoadFunc func;
1492 AssemblyLoadHook *assembly_load_hook = NULL;
1495 * mono_assembly_invoke_load_hook:
1498 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1500 AssemblyLoadHook *hook;
1502 for (hook = assembly_load_hook; hook; hook = hook->next) {
1503 hook->func (ass, hook->user_data);
1508 * mono_install_assembly_load_hook:
1511 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1513 AssemblyLoadHook *hook;
1515 g_return_if_fail (func != NULL);
1517 hook = g_new0 (AssemblyLoadHook, 1);
1519 hook->user_data = user_data;
1520 hook->next = assembly_load_hook;
1521 assembly_load_hook = hook;
1525 free_assembly_load_hooks (void)
1527 AssemblyLoadHook *hook, *next;
1529 for (hook = assembly_load_hook; hook; hook = next) {
1535 typedef struct AssemblySearchHook AssemblySearchHook;
1536 struct AssemblySearchHook {
1537 AssemblySearchHook *next;
1538 MonoAssemblySearchFunc func;
1544 AssemblySearchHook *assembly_search_hook = NULL;
1546 static MonoAssembly*
1547 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1549 AssemblySearchHook *hook;
1551 for (hook = assembly_search_hook; hook; hook = hook->next) {
1552 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1555 * A little explanation is in order here.
1557 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1558 * The embedding API exposes a search hook that doesn't take such argument.
1560 * The original fix would call the default search hook before all the registered ones and pass
1561 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1562 * rely on. Which is the ordering between user hooks and the default runtime hook.
1564 * Registering the hook after mono_jit_init would let your hook run before the default one and
1565 * when using it to handle non standard app layouts this could save your app from a massive amount
1566 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1567 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1569 * So what's the fix? We register the default hook using regular means and special case it when iterating
1570 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1573 if (hook->func == (void*)mono_domain_assembly_postload_search)
1574 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1576 ass = hook->func (aname, hook->user_data);
1586 * mono_assembly_invoke_search_hook:
1589 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1591 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1595 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1597 AssemblySearchHook *hook;
1599 g_return_if_fail (func != NULL);
1601 hook = g_new0 (AssemblySearchHook, 1);
1603 hook->user_data = user_data;
1604 hook->refonly = refonly;
1605 hook->postload = postload;
1606 hook->next = assembly_search_hook;
1607 assembly_search_hook = hook;
1611 * mono_install_assembly_search_hook:
1614 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1616 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1620 free_assembly_search_hooks (void)
1622 AssemblySearchHook *hook, *next;
1624 for (hook = assembly_search_hook; hook; hook = next) {
1631 * mono_install_assembly_refonly_search_hook:
1634 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1636 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1640 * mono_install_assembly_postload_search_hook:
1643 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1645 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1649 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1651 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1654 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1655 struct AssemblyPreLoadHook {
1656 AssemblyPreLoadHook *next;
1657 MonoAssemblyPreLoadFunc func;
1661 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1662 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1664 static MonoAssembly *
1665 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1667 AssemblyPreLoadHook *hook;
1668 MonoAssembly *assembly;
1670 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1671 assembly = hook->func (aname, assemblies_path, hook->user_data);
1672 if (assembly != NULL)
1679 static MonoAssembly *
1680 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1682 AssemblyPreLoadHook *hook;
1683 MonoAssembly *assembly;
1685 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1686 assembly = hook->func (aname, assemblies_path, hook->user_data);
1687 if (assembly != NULL)
1695 * mono_install_assembly_preload_hook:
1698 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1700 AssemblyPreLoadHook *hook;
1702 g_return_if_fail (func != NULL);
1704 hook = g_new0 (AssemblyPreLoadHook, 1);
1706 hook->user_data = user_data;
1707 hook->next = assembly_preload_hook;
1708 assembly_preload_hook = hook;
1712 * mono_install_assembly_refonly_preload_hook:
1715 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1717 AssemblyPreLoadHook *hook;
1719 g_return_if_fail (func != NULL);
1721 hook = g_new0 (AssemblyPreLoadHook, 1);
1723 hook->user_data = user_data;
1724 hook->next = assembly_refonly_preload_hook;
1725 assembly_refonly_preload_hook = hook;
1729 free_assembly_preload_hooks (void)
1731 AssemblyPreLoadHook *hook, *next;
1733 for (hook = assembly_preload_hook; hook; hook = next) {
1738 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1745 absolute_dir (const gchar *filename)
1756 if (g_path_is_absolute (filename)) {
1757 part = g_path_get_dirname (filename);
1758 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1763 cwd = g_get_current_dir ();
1764 mixed = g_build_filename (cwd, filename, NULL);
1765 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1770 for (i = 0; (part = parts [i]) != NULL; i++) {
1771 if (!strcmp (part, "."))
1774 if (!strcmp (part, "..")) {
1775 if (list && list->next) /* Don't remove root */
1776 list = g_list_delete_link (list, list);
1778 list = g_list_prepend (list, part);
1782 result = g_string_new ("");
1783 list = g_list_reverse (list);
1785 /* Ignores last data pointer, which should be the filename */
1786 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1788 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1793 g_string_free (result, FALSE);
1798 return g_strdup (".");
1805 * mono_assembly_open_from_bundle:
1806 * \param filename Filename requested
1807 * \param status return status code
1809 * This routine tries to open the assembly specified by \p filename from the
1810 * defined bundles, if found, returns the MonoImage for it, if not found
1814 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1818 gchar *lowercase_filename;
1819 MonoImage *image = NULL;
1820 gboolean is_satellite = FALSE;
1822 * we do a very simple search for bundled assemblies: it's not a general
1823 * purpose assembly loading mechanism.
1829 lowercase_filename = g_utf8_strdown (filename, -1);
1830 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1831 g_free (lowercase_filename);
1832 name = g_path_get_basename (filename);
1833 mono_assemblies_lock ();
1834 for (i = 0; !image && bundles [i]; ++i) {
1835 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1836 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1840 mono_assemblies_unlock ();
1842 mono_image_addref (image);
1843 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1852 * mono_assembly_open_full:
1853 * \param filename the file to load
1854 * \param status return status code
1855 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1857 * This loads an assembly from the specified \p filename. The \p filename allows
1858 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1859 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1860 * is treated as a local path.
1862 * First, an attempt is made to load the assembly from the bundled executable (for those
1863 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1864 * assembly has been registered as an embedded assembly). If this is not the case, then
1865 * the assembly is loaded from disk using `api:mono_image_open_full`.
1867 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1868 * the assembly is made.
1870 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1871 * the \c System.Reflection API.
1873 * \returns NULL on error, with the \p status set to an error code, or a pointer
1877 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1879 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1883 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1885 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1889 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1890 gboolean load_from_context,
1891 MonoAssemblyCandidatePredicate predicate,
1893 MonoImageOpenStatus *status)
1897 MonoImageOpenStatus def_status;
1900 gboolean loaded_from_bundle;
1902 g_return_val_if_fail (filename != NULL, NULL);
1905 status = &def_status;
1906 *status = MONO_IMAGE_OK;
1908 if (strncmp (filename, "file://", 7) == 0) {
1909 GError *error = NULL;
1910 gchar *uri = (gchar *) filename;
1914 * MS allows file://c:/... and fails on file://localhost/c:/...
1915 * They also throw an IndexOutOfRangeException if "file://"
1918 uri = g_strdup_printf ("file:///%s", uri + 7);
1921 uri = mono_escape_uri_string (tmpuri);
1922 fname = g_filename_from_uri (uri, NULL, &error);
1925 if (tmpuri != filename)
1928 if (error != NULL) {
1929 g_warning ("%s\n", error->message);
1930 g_error_free (error);
1931 fname = g_strdup (filename);
1934 fname = g_strdup (filename);
1937 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1938 "Assembly Loader probing location: '%s'.", fname);
1941 if (!mono_assembly_is_in_gac (fname)) {
1943 new_fname = mono_make_shadow_copy (fname, &error);
1944 if (!is_ok (&error)) {
1945 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1946 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1947 mono_error_cleanup (&error);
1948 *status = MONO_IMAGE_IMAGE_INVALID;
1953 if (new_fname && new_fname != fname) {
1956 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1957 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1962 // If VM built with mkbundle
1963 loaded_from_bundle = FALSE;
1964 if (bundles != NULL) {
1965 image = mono_assembly_open_from_bundle (fname, status, refonly);
1966 loaded_from_bundle = image != NULL;
1970 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1973 if (*status == MONO_IMAGE_OK)
1974 *status = MONO_IMAGE_ERROR_ERRNO;
1979 if (image->assembly) {
1980 /* Already loaded by another appdomain */
1981 mono_assembly_invoke_load_hook (image->assembly);
1982 mono_image_close (image);
1984 return image->assembly;
1987 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1990 if (!loaded_from_bundle)
1991 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1992 "Assembly Loader loaded assembly from location: '%s'.", filename);
1994 mono_config_for_assembly (ass->image);
1997 /* Clear the reference added by mono_image_open */
1998 mono_image_close (image);
2006 free_item (gpointer val, gpointer user_data)
2012 * mono_assembly_load_friends:
2013 * \param ass an assembly
2015 * Load the list of friend assemblies that are allowed to access
2016 * the assembly's internal types and members. They are stored as assembly
2017 * names in custom attributes.
2019 * This is an internal method, we need this because when we load mscorlib
2020 * we do not have the internals visible cattr loaded yet,
2021 * so we need to load these after we initialize the runtime.
2023 * LOCKING: Acquires the assemblies lock plus the loader lock.
2026 mono_assembly_load_friends (MonoAssembly* ass)
2030 MonoCustomAttrInfo* attrs;
2033 if (ass->friend_assembly_names_inited)
2036 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
2037 mono_error_assert_ok (&error);
2039 mono_assemblies_lock ();
2040 ass->friend_assembly_names_inited = TRUE;
2041 mono_assemblies_unlock ();
2045 mono_assemblies_lock ();
2046 if (ass->friend_assembly_names_inited) {
2047 mono_assemblies_unlock ();
2050 mono_assemblies_unlock ();
2054 * We build the list outside the assemblies lock, the worse that can happen
2055 * is that we'll need to free the allocated list.
2057 for (i = 0; i < attrs->num_attrs; ++i) {
2058 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2059 MonoAssemblyName *aname;
2061 /* Do some sanity checking */
2062 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
2064 if (attr->data_size < 4)
2066 data = (const char*)attr->data;
2067 /* 0xFF means null string, see custom attr format */
2068 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
2070 mono_metadata_decode_value (data + 2, &data);
2071 aname = g_new0 (MonoAssemblyName, 1);
2072 /*g_print ("friend ass: %s\n", data);*/
2073 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
2074 list = g_slist_prepend (list, aname);
2079 mono_custom_attrs_free (attrs);
2081 mono_assemblies_lock ();
2082 if (ass->friend_assembly_names_inited) {
2083 mono_assemblies_unlock ();
2084 g_slist_foreach (list, free_item, NULL);
2085 g_slist_free (list);
2088 ass->friend_assembly_names = list;
2090 /* Because of the double checked locking pattern above */
2091 mono_memory_barrier ();
2092 ass->friend_assembly_names_inited = TRUE;
2093 mono_assemblies_unlock ();
2096 struct HasReferenceAssemblyAttributeIterData {
2101 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
2103 gboolean stop_scanning = FALSE;
2104 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
2106 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
2107 /* Note we don't check the assembly name, same as coreCLR. */
2108 iter_data->has_attr = TRUE;
2109 stop_scanning = TRUE;
2112 return stop_scanning;
2116 * mono_assembly_has_reference_assembly_attribute:
2117 * \param assembly a MonoAssembly
2118 * \param error set on error.
2120 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2121 * On error returns FALSE and sets \p error.
2124 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
2129 * This might be called during assembly loading, so do everything using the low-level
2133 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
2135 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
2137 return iter_data.has_attr;
2141 * mono_assembly_open:
2142 * \param filename Opens the assembly pointed out by this name
2143 * \param status return status code
2145 * This loads an assembly from the specified \p filename. The \p filename allows
2146 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2147 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2148 * is treated as a local path.
2150 * First, an attempt is made to load the assembly from the bundled executable (for those
2151 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2152 * assembly has been registered as an embedded assembly). If this is not the case, then
2153 * the assembly is loaded from disk using `api:mono_image_open_full`.
2155 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2156 * the assembly is made.
2158 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2159 * assembly or NULL on error. Details about the error are stored in the
2160 * \p status variable.
2163 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2165 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2169 * mono_assembly_load_from_full:
2170 * \param image Image to load the assembly from
2171 * \param fname assembly name to associate with the assembly
2172 * \param status returns the status condition
2173 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2175 * If the provided \p image has an assembly reference, it will process the given
2176 * image as an assembly with the given name.
2178 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2180 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2181 * set to \c MONO_IMAGE_OK; or NULL on error.
2183 * If there is an error loading the assembly the \p status will indicate the
2184 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2185 * image did not contain an assembly reference table.
2188 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2189 MonoImageOpenStatus *status, gboolean refonly)
2191 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2195 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2197 MonoAssemblyCandidatePredicate predicate,
2199 MonoImageOpenStatus *status)
2201 MonoAssembly *ass, *ass2;
2204 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2205 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2206 *status = MONO_IMAGE_IMAGE_INVALID;
2210 #if defined (HOST_WIN32)
2215 tmp_fn = g_strdup (fname);
2216 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2217 if (tmp_fn [i] == '/')
2221 base_dir = absolute_dir (tmp_fn);
2225 base_dir = absolute_dir (fname);
2229 * Create assembly struct, and enter it into the assembly cache
2231 ass = g_new0 (MonoAssembly, 1);
2232 ass->basedir = base_dir;
2233 ass->ref_only = refonly;
2236 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2238 mono_assembly_fill_assembly_name (image, &ass->aname);
2240 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2241 // MS.NET doesn't support loading other mscorlibs
2244 mono_image_addref (mono_defaults.corlib);
2245 *status = MONO_IMAGE_OK;
2246 return mono_defaults.corlib->assembly;
2249 /* Add a non-temporary reference because of ass->image */
2250 mono_image_addref (image);
2252 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);
2255 * The load hooks might take locks so we can't call them while holding the
2258 if (ass->aname.name) {
2259 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2263 mono_image_close (image);
2264 *status = MONO_IMAGE_OK;
2269 /* We need to check for ReferenceAssmeblyAttribute before we
2270 * mark the assembly as loaded and before we fire the load
2271 * hook. Otherwise mono_domain_fire_assembly_load () in
2272 * appdomain.c will cache a mapping from the assembly name to
2273 * this image and we won't be able to look for a different
2277 MonoError refasm_error;
2278 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2279 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2282 mono_image_close (image);
2283 *status = MONO_IMAGE_IMAGE_INVALID;
2286 mono_error_cleanup (&refasm_error);
2289 if (predicate && !predicate (ass, user_data)) {
2290 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2293 mono_image_close (image);
2294 *status = MONO_IMAGE_IMAGE_INVALID;
2298 mono_assemblies_lock ();
2300 if (image->assembly) {
2302 * This means another thread has already loaded the assembly, but not yet
2303 * called the load hooks so the search hook can't find the assembly.
2305 mono_assemblies_unlock ();
2306 ass2 = image->assembly;
2309 mono_image_close (image);
2310 *status = MONO_IMAGE_OK;
2314 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2316 image->assembly = ass;
2318 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2319 mono_assemblies_unlock ();
2322 if (image->is_module_handle)
2323 mono_image_fixup_vtable (image);
2326 mono_assembly_invoke_load_hook (ass);
2328 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2334 * mono_assembly_load_from:
2335 * \param image Image to load the assembly from
2336 * \param fname assembly name to associate with the assembly
2337 * \param status return status code
2339 * If the provided \p image has an assembly reference, it will process the given
2340 * image as an assembly with the given name.
2342 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2344 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2345 * \p refonly parameter set to FALSE.
2346 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2347 * set to \c MONO_IMAGE_OK; or NULL on error.
2349 * If there is an error loading the assembly the \p status will indicate the
2350 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2351 * image did not contain an assembly reference table.
2355 mono_assembly_load_from (MonoImage *image, const char *fname,
2356 MonoImageOpenStatus *status)
2358 return mono_assembly_load_from_full (image, fname, status, FALSE);
2362 * mono_assembly_name_free:
2363 * \param aname assembly name to free
2365 * Frees the provided assembly name object.
2366 * (it does not frees the object itself, only the name members).
2369 mono_assembly_name_free (MonoAssemblyName *aname)
2374 g_free ((void *) aname->name);
2375 g_free ((void *) aname->culture);
2376 g_free ((void *) aname->hash_value);
2377 g_free ((guint8*) aname->public_key);
2381 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2384 gchar header [16], val, *arr;
2385 gint i, j, offset, bitlen, keylen, pkeylen;
2387 keylen = strlen (key) >> 1;
2391 /* allow the ECMA standard key */
2392 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2394 *pubkey = g_strdup (key);
2400 val = g_ascii_xdigit_value (key [0]) << 4;
2401 val |= g_ascii_xdigit_value (key [1]);
2406 val = g_ascii_xdigit_value (key [24]);
2407 val |= g_ascii_xdigit_value (key [25]);
2419 /* We need the first 16 bytes
2420 * to check whether this key is valid or not */
2421 pkeylen = strlen (pkey) >> 1;
2425 for (i = 0, j = 0; i < 16; i++) {
2426 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2427 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2430 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2431 header [1] != 0x02 || /* Version (0x02) */
2432 header [2] != 0x00 || /* Reserved (word) */
2433 header [3] != 0x00 ||
2434 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2437 /* Based on this length, we _should_ be able to know if the length is right */
2438 bitlen = read32 (header + 12) >> 3;
2439 if ((bitlen + 16 + 4) != pkeylen)
2442 /* parsing is OK and the public key itself is not requested back */
2446 /* Encode the size of the blob */
2448 if (keylen <= 127) {
2449 arr = (gchar *)g_malloc (keylen + 1);
2450 arr [offset++] = keylen;
2452 arr = (gchar *)g_malloc (keylen + 2);
2453 arr [offset++] = 0x80; /* 10bs */
2454 arr [offset++] = keylen;
2457 for (i = offset, j = 0; i < keylen + offset; i++) {
2458 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2459 arr [i] |= g_ascii_xdigit_value (key [j++]);
2468 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)
2470 gint major, minor, build, revision;
2473 gchar *pkey, *pkeyptr, *encoded, tok [8];
2475 memset (aname, 0, sizeof (MonoAssemblyName));
2478 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2479 if (version_parts < 2 || version_parts > 4)
2482 /* FIXME: we should set build & revision to -1 (instead of 0)
2483 if these are not set in the version string. That way, later on,
2484 we can still determine if these were specified. */
2485 aname->major = major;
2486 aname->minor = minor;
2487 if (version_parts >= 3)
2488 aname->build = build;
2491 if (version_parts == 4)
2492 aname->revision = revision;
2494 aname->revision = 0;
2497 aname->flags = flags;
2499 aname->name = g_strdup (name);
2502 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2503 aname->culture = g_strdup ("");
2505 aname->culture = g_strdup (culture);
2508 if (token && strncmp (token, "null", 4) != 0) {
2511 /* the constant includes the ending NULL, hence the -1 */
2512 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2513 mono_assembly_name_free (aname);
2516 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2517 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2523 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2524 mono_assembly_name_free (aname);
2529 if (save_public_key)
2530 aname->public_key = (guint8*)pkey;
2533 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2537 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2538 // We also need to generate the key token
2539 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2540 encoded = encode_public_tok ((guchar*) tok, 8);
2541 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2544 if (save_public_key)
2545 aname->public_key = (guint8*) pkey;
2554 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2559 parts = g_strsplit (dirname, "_", 3);
2560 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2565 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2571 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2573 char *eqsign = strchr (pair, '=');
2581 *key = (gchar*)pair;
2582 *keylen = eqsign - *key;
2583 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2585 *value = g_strstrip (eqsign + 1);
2590 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2594 gchar *version = NULL;
2596 gchar *culture = NULL;
2598 gchar *token = NULL;
2602 gchar *retargetable = NULL;
2603 gchar *retargetable_uq;
2607 gchar *value, *part_name;
2608 guint32 part_name_len;
2611 gboolean version_defined;
2612 gboolean token_defined;
2614 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2616 if (!is_version_defined)
2617 is_version_defined = &version_defined;
2618 *is_version_defined = FALSE;
2619 if (!is_token_defined)
2620 is_token_defined = &token_defined;
2621 *is_token_defined = FALSE;
2623 parts = tmp = g_strsplit (name, ",", 6);
2624 if (!tmp || !*tmp) {
2629 dllname = g_strstrip (*tmp);
2634 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2635 goto cleanup_and_fail;
2637 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2638 *is_version_defined = TRUE;
2640 if (strlen (version) == 0) {
2641 goto cleanup_and_fail;
2647 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2649 if (strlen (culture) == 0) {
2650 goto cleanup_and_fail;
2656 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2657 *is_token_defined = TRUE;
2659 if (strlen (token) == 0) {
2660 goto cleanup_and_fail;
2666 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2668 if (strlen (key) == 0) {
2669 goto cleanup_and_fail;
2675 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2676 retargetable = value;
2677 retargetable_uq = unquote (retargetable);
2678 if (retargetable_uq != NULL)
2679 retargetable = retargetable_uq;
2681 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2682 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2683 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2684 g_free (retargetable_uq);
2685 goto cleanup_and_fail;
2688 g_free (retargetable_uq);
2693 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2695 procarch_uq = unquote (procarch);
2696 if (procarch_uq != NULL)
2697 procarch = procarch_uq;
2699 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2700 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2701 else if (!g_ascii_strcasecmp (procarch, "X86"))
2702 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2703 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2704 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2705 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2706 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2708 g_free (procarch_uq);
2709 goto cleanup_and_fail;
2712 g_free (procarch_uq);
2721 /* if retargetable flag is set, then we must have a fully qualified name */
2722 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2723 goto cleanup_and_fail;
2726 dllname_uq = unquote (dllname);
2727 version_uq = unquote (version);
2728 culture_uq = unquote (culture);
2729 token_uq = unquote (token);
2730 key_uq = unquote (key);
2732 res = build_assembly_name (
2733 dllname_uq == NULL ? dllname : dllname_uq,
2734 version_uq == NULL ? version : version_uq,
2735 culture_uq == NULL ? culture : culture_uq,
2736 token_uq == NULL ? token : token_uq,
2737 key_uq == NULL ? key : key_uq,
2738 flags, arch, aname, save_public_key);
2740 g_free (dllname_uq);
2741 g_free (version_uq);
2742 g_free (culture_uq);
2755 unquote (const char *str)
2763 slen = strlen (str);
2767 if (*str != '\'' && *str != '\"')
2770 end = str + slen - 1;
2774 return g_strndup (str + 1, slen - 2);
2778 * mono_assembly_name_parse:
2779 * \param name name to parse
2780 * \param aname the destination assembly name
2782 * Parses an assembly qualified type name and assigns the name,
2783 * version, culture and token to the provided assembly name object.
2785 * \returns TRUE if the name could be parsed.
2788 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2790 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2794 * mono_assembly_name_new:
2795 * \param name name to parse
2797 * Allocate a new \c MonoAssemblyName and fill its values from the
2800 * \returns a newly allocated structure or NULL if there was any failure.
2803 mono_assembly_name_new (const char *name)
2805 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2806 if (mono_assembly_name_parse (name, aname))
2813 * mono_assembly_name_get_name:
2816 mono_assembly_name_get_name (MonoAssemblyName *aname)
2822 * mono_assembly_name_get_culture:
2825 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2827 return aname->culture;
2831 * mono_assembly_name_get_pubkeytoken:
2834 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2836 if (aname->public_key_token [0])
2837 return aname->public_key_token;
2842 * mono_assembly_name_get_version:
2845 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2848 *minor = aname->minor;
2850 *build = aname->build;
2852 *revision = aname->revision;
2853 return aname->major;
2856 static MonoAssembly*
2857 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2859 gchar *fullpath = NULL;
2861 const char* direntry;
2862 MonoAssemblyName gac_aname;
2863 gint major=-1, minor=0, build=0, revision=0;
2864 gboolean exact_version;
2866 dirhandle = g_dir_open (basepath, 0, NULL);
2870 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2872 while ((direntry = g_dir_read_name (dirhandle))) {
2873 gboolean match = TRUE;
2875 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2878 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2881 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2882 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2886 if (exact_version) {
2887 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2888 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2890 else if (gac_aname.major < major)
2892 else if (gac_aname.major == major) {
2893 if (gac_aname.minor < minor)
2895 else if (gac_aname.minor == minor) {
2896 if (gac_aname.build < build)
2898 else if (gac_aname.build == build && gac_aname.revision <= revision)
2905 major = gac_aname.major;
2906 minor = gac_aname.minor;
2907 build = gac_aname.build;
2908 revision = gac_aname.revision;
2910 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2913 mono_assembly_name_free (&gac_aname);
2916 g_dir_close (dirhandle);
2918 if (fullpath == NULL)
2921 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2928 * mono_assembly_load_with_partial_name:
2929 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2930 * \param status return status code
2932 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2933 * so it might contain a qualified type name, version, culture and token.
2935 * This will load the assembly from the file whose name is derived from the assembly name
2936 * by appending the \c .dll extension.
2938 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2939 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2940 * if that fails from the GAC.
2942 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2945 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2949 MonoAssemblyName *aname, base_name;
2950 MonoAssemblyName mapped_aname;
2951 gchar *fullname, *gacpath;
2954 memset (&base_name, 0, sizeof (MonoAssemblyName));
2957 if (!mono_assembly_name_parse (name, aname))
2961 * If no specific version has been requested, make sure we load the
2962 * correct version for system assemblies.
2964 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2965 aname = mono_assembly_remap_version (aname, &mapped_aname);
2967 res = mono_assembly_loaded (aname);
2969 mono_assembly_name_free (aname);
2973 res = invoke_assembly_preload_hook (aname, assemblies_path);
2975 res->in_gac = FALSE;
2976 mono_assembly_name_free (aname);
2980 fullname = g_strdup_printf ("%s.dll", aname->name);
2982 if (extra_gac_paths) {
2983 paths = extra_gac_paths;
2984 while (!res && *paths) {
2985 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2986 res = probe_for_partial_name (gacpath, fullname, aname, status);
2995 mono_assembly_name_free (aname);
2999 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
3000 res = probe_for_partial_name (gacpath, fullname, aname, status);
3004 mono_assembly_name_free (aname);
3009 MonoDomain *domain = mono_domain_get ();
3011 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
3012 if (!is_ok (&error)) {
3013 mono_error_cleanup (&error);
3014 if (*status == MONO_IMAGE_OK)
3015 *status = MONO_IMAGE_IMAGE_INVALID;
3023 mono_assembly_is_in_gac (const gchar *filename)
3025 const gchar *rootdir;
3029 if (filename == NULL)
3032 for (paths = extra_gac_paths; paths && *paths; paths++) {
3033 if (strstr (*paths, filename) != *paths)
3036 gp = (gchar *) (filename + strlen (*paths));
3037 if (*gp != G_DIR_SEPARATOR)
3040 if (strncmp (gp, "lib", 3))
3043 if (*gp != G_DIR_SEPARATOR)
3046 if (strncmp (gp, "mono", 4))
3049 if (*gp != G_DIR_SEPARATOR)
3052 if (strncmp (gp, "gac", 3))
3055 if (*gp != G_DIR_SEPARATOR)
3061 rootdir = mono_assembly_getrootdir ();
3062 if (strstr (filename, rootdir) != filename)
3065 gp = (gchar *) (filename + strlen (rootdir));
3066 if (*gp != G_DIR_SEPARATOR)
3069 if (strncmp (gp, "mono", 4))
3072 if (*gp != G_DIR_SEPARATOR)
3075 if (strncmp (gp, "gac", 3))
3078 if (*gp != G_DIR_SEPARATOR)
3084 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3087 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
3091 if (strstr (aname->name, ".dll")) {
3092 len = strlen (aname->name) - 4;
3093 name = (gchar *)g_malloc (len + 1);
3094 memcpy (name, aname->name, len);
3097 name = g_strdup (aname->name);
3100 culture = g_utf8_strdown (aname->culture, -1);
3102 culture = g_strdup ("");
3104 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
3105 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
3109 filename = g_strconcat (pname, ".dll", NULL);
3110 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
3116 if (extra_gac_paths) {
3117 paths = extra_gac_paths;
3118 while (!image && *paths) {
3119 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
3120 "lib", "mono", "gac", subpath, NULL);
3121 image = mono_image_open (fullpath, NULL);
3132 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3133 "mono", "gac", subpath, NULL);
3134 image = mono_image_open (fullpath, NULL);
3141 static MonoAssemblyName*
3142 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3144 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3145 dest_name->major = info->new_version.major;
3146 dest_name->minor = info->new_version.minor;
3147 dest_name->build = info->new_version.build;
3148 dest_name->revision = info->new_version.revision;
3153 /* LOCKING: assembly_binding lock must be held */
3154 static MonoAssemblyBindingInfo*
3155 search_binding_loaded (MonoAssemblyName *aname)
3159 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3160 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3161 if (assembly_binding_maps_name (info, aname))
3168 static inline gboolean
3169 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3171 if (left->major != right->major || left->minor != right->minor ||
3172 left->build != right->build || left->revision != right->revision)
3178 static inline gboolean
3179 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3181 if (left->has_old_version_bottom != right->has_old_version_bottom)
3184 if (left->has_old_version_top != right->has_old_version_top)
3187 if (left->has_new_version != right->has_new_version)
3190 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3193 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3196 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3202 /* LOCKING: assumes all the necessary locks are held */
3204 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3206 MonoAssemblyBindingInfo *info_copy;
3208 MonoAssemblyBindingInfo *info_tmp;
3209 MonoDomain *domain = (MonoDomain*)user_data;
3214 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)) {
3215 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3216 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3220 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3221 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3222 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3226 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3227 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3229 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3231 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3233 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3237 get_version_number (int major, int minor)
3239 return major * 256 + minor;
3242 static inline gboolean
3243 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3245 int aname_version_number = get_version_number (aname->major, aname->minor);
3246 if (!info->has_old_version_bottom)
3249 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3252 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3255 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3256 info->major = aname->major;
3257 info->minor = aname->minor;
3262 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3263 static MonoAssemblyBindingInfo*
3264 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3266 MonoAssemblyBindingInfo *info;
3269 if (!domain->assembly_bindings)
3273 for (list = domain->assembly_bindings; list; list = list->next) {
3274 info = (MonoAssemblyBindingInfo *)list->data;
3275 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3281 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3282 info->has_new_version && assembly_binding_maps_name (info, aname))
3283 info->is_valid = TRUE;
3285 info->is_valid = FALSE;
3292 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3294 if (domain->assembly_bindings_parsed)
3296 mono_domain_lock (domain);
3297 if (!domain->assembly_bindings_parsed) {
3299 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3301 if (!domain_config_file_path)
3302 domain_config_file_path = domain_config_file_name;
3304 mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3305 domain->assembly_bindings_parsed = TRUE;
3306 if (domain_config_file_name != domain_config_file_path)
3307 g_free (domain_config_file_path);
3310 mono_domain_unlock (domain);
3313 static MonoAssemblyName*
3314 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3317 MonoAssemblyBindingInfo *info, *info2;
3321 if (aname->public_key_token [0] == 0)
3324 domain = mono_domain_get ();
3326 mono_assembly_binding_lock ();
3327 info = search_binding_loaded (aname);
3328 mono_assembly_binding_unlock ();
3331 mono_domain_lock (domain);
3332 info = get_per_domain_assembly_binding_info (domain, aname);
3333 mono_domain_unlock (domain);
3337 if (!check_policy_versions (info, aname))
3340 mono_assembly_bind_version (info, aname, dest_name);
3344 if (domain && domain->setup && domain->setup->configuration_file) {
3345 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3346 /* expect this to succeed because mono_domain_set_options_from_config () did
3347 * the same thing when the domain was created. */
3348 mono_error_assert_ok (&error);
3349 mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3350 g_free (domain_config_file_name);
3352 mono_domain_lock (domain);
3353 info2 = get_per_domain_assembly_binding_info (domain, aname);
3356 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3357 info->name = g_strdup (info2->name);
3358 info->culture = g_strdup (info2->culture);
3359 info->domain_id = domain->domain_id;
3362 mono_domain_unlock (domain);
3367 info = g_new0 (MonoAssemblyBindingInfo, 1);
3368 info->major = aname->major;
3369 info->minor = aname->minor;
3372 if (!info->is_valid) {
3373 ppimage = mono_assembly_load_publisher_policy (aname);
3375 get_publisher_policy_info (ppimage, aname, info);
3376 mono_image_close (ppimage);
3380 /* Define default error value if needed */
3381 if (!info->is_valid) {
3382 info->name = g_strdup (aname->name);
3383 info->culture = g_strdup (aname->culture);
3384 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3387 mono_assembly_binding_lock ();
3388 info2 = search_binding_loaded (aname);
3390 /* This binding was added by another thread
3392 mono_assembly_binding_info_free (info);
3397 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3399 mono_assembly_binding_unlock ();
3401 if (!info->is_valid || !check_policy_versions (info, aname))
3404 mono_assembly_bind_version (info, aname, dest_name);
3409 * mono_assembly_load_from_gac
3411 * \param aname The assembly name object
3413 static MonoAssembly*
3414 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3416 MonoAssembly *result = NULL;
3417 gchar *name, *version, *culture, *fullpath, *subpath;
3422 if (aname->public_key_token [0] == 0) {
3426 if (strstr (aname->name, ".dll")) {
3427 len = strlen (filename) - 4;
3428 name = (gchar *)g_malloc (len + 1);
3429 memcpy (name, aname->name, len);
3432 name = g_strdup (aname->name);
3435 if (aname->culture) {
3436 culture = g_utf8_strdown (aname->culture, -1);
3438 culture = g_strdup ("");
3441 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3442 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3443 aname->minor, aname->build, aname->revision,
3447 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3452 if (extra_gac_paths) {
3453 paths = extra_gac_paths;
3454 while (!result && *paths) {
3455 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3456 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3463 result->in_gac = TRUE;
3468 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3469 "mono", "gac", subpath, NULL);
3470 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3474 result->in_gac = TRUE;
3482 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3485 MonoAssemblyName *aname;
3488 /* g_print ("corlib already loaded\n"); */
3492 // In native client, Corlib is embedded in the executable as static variable corlibData
3493 #if defined(__native_client__)
3494 if (corlibData != NULL && corlibSize != 0) {
3496 /* First "FALSE" instructs mono not to make a copy. */
3497 /* Second "FALSE" says this is not just a ref. */
3498 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3499 if (image == NULL || status != 0)
3500 g_print("mono_image_open_from_data_full failed: %d\n", status);
3501 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3502 if (corlib == NULL || status != 0)
3503 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3509 // A nonstandard preload hook may provide a special mscorlib assembly
3510 aname = mono_assembly_name_new ("mscorlib.dll");
3511 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3512 mono_assembly_name_free (aname);
3515 goto return_corlib_and_facades;
3517 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3518 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3519 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3521 goto return_corlib_and_facades;
3524 /* Normal case: Load corlib from mono/<version> */
3525 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3526 if (assemblies_path) { // Custom assemblies path
3527 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3529 g_free (corlib_file);
3530 goto return_corlib_and_facades;
3533 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3534 g_free (corlib_file);
3536 return_corlib_and_facades:
3537 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3538 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3543 static MonoAssembly*
3544 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3546 MonoError refasm_error;
3547 error_init (&refasm_error);
3548 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3551 mono_error_cleanup (&refasm_error);
3556 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3558 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3559 MonoAssemblyName *candidate_name = &candidate->aname;
3561 g_assert (wanted_name != NULL);
3562 g_assert (candidate_name != NULL);
3564 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3565 char * s = mono_stringify_assembly_name (wanted_name);
3566 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3568 s = mono_stringify_assembly_name (candidate_name);
3569 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3574 /* Wanted name has no token, not strongly named: always matches. */
3575 if (0 == wanted_name->public_key_token [0]) {
3576 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3580 /* Candidate name has no token, not strongly named: never matches */
3581 if (0 == candidate_name->public_key_token [0]) {
3582 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3586 return exact_sn_match (wanted_name, candidate_name) ||
3587 framework_assembly_sn_match (wanted_name, candidate_name);
3591 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3593 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3595 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3596 result ? "match, returning TRUE" : "don't match, returning FALSE");
3602 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3604 #ifndef DISABLE_DESKTOP_LOADER
3605 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3607 if (!vmap->framework_facade_assembly) {
3608 /* 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. */
3609 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3610 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");
3613 /* For facades, the name and public key token should
3614 * match, but the version doesn't matter. */
3615 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3616 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");
3625 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3626 const char *basedir,
3627 MonoImageOpenStatus *status,
3630 MonoAssembly *result;
3631 char *fullpath, *filename;
3632 MonoAssemblyName maped_aname;
3633 MonoAssemblyName maped_name_pp;
3638 aname = mono_assembly_remap_version (aname, &maped_aname);
3640 /* Reflection only assemblies don't get assembly binding */
3642 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3644 result = mono_assembly_loaded_full (aname, refonly);
3648 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3650 result->in_gac = FALSE;
3654 /* Currently we retrieve the loaded corlib for reflection
3655 * only requests, like a common reflection only assembly
3657 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3658 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3661 MonoAssemblyCandidatePredicate predicate = NULL;
3662 void* predicate_ud = NULL;
3663 #if !defined(DISABLE_DESKTOP_LOADER)
3664 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
3665 predicate = &mono_assembly_candidate_predicate_sn_same_name;
3666 predicate_ud = aname;
3670 len = strlen (aname->name);
3671 for (ext_index = 0; ext_index < 2; ext_index ++) {
3672 ext = ext_index == 0 ? ".dll" : ".exe";
3673 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3674 filename = g_strdup (aname->name);
3675 /* Don't try appending .dll/.exe if it already has one of those extensions */
3678 filename = g_strconcat (aname->name, ext, NULL);
3681 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3688 fullpath = g_build_filename (basedir, filename, NULL);
3689 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, predicate_ud, status);
3692 result->in_gac = FALSE;
3698 result = load_in_path (filename, default_path, status, refonly, predicate, predicate_ud);
3700 result->in_gac = FALSE;
3710 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3712 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3715 /* Try a postload search hook */
3716 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3717 result = prevent_reference_assembly_from_running (result, refonly);
3723 * mono_assembly_load_full:
3724 * \param aname A MonoAssemblyName with the assembly name to load.
3725 * \param basedir A directory to look up the assembly at.
3726 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3727 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3729 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3730 * attempts to load the assembly from that directory before probing the standard locations.
3732 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3733 * assembly binding takes place.
3735 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3736 * value pointed by \p status is updated with an error code.
3739 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3741 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3745 * mono_assembly_load:
3746 * \param aname A MonoAssemblyName with the assembly name to load.
3747 * \param basedir A directory to look up the assembly at.
3748 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3750 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3751 * attempts to load the assembly from that directory before probing the standard locations.
3753 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3754 * value pointed by \p status is updated with an error code.
3757 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3759 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3763 * mono_assembly_loaded_full:
3764 * \param aname an assembly to look for.
3765 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3767 * This is used to determine if the specified assembly has been loaded
3768 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3769 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3772 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3775 MonoAssemblyName maped_aname;
3777 aname = mono_assembly_remap_version (aname, &maped_aname);
3779 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3785 * mono_assembly_loaded:
3786 * \param aname an assembly to look for.
3788 * This is used to determine if the specified assembly has been loaded
3790 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3791 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3794 mono_assembly_loaded (MonoAssemblyName *aname)
3796 return mono_assembly_loaded_full (aname, FALSE);
3800 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3802 if (assembly == NULL || assembly == REFERENCE_MISSING)
3805 if (assembly_is_dynamic (assembly)) {
3807 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3808 for (i = 0; i < dynimg->image.module_count; ++i)
3809 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3810 mono_dynamic_image_release_gc_roots (dynimg);
3815 * Returns whether mono_assembly_close_finish() must be called as
3816 * well. See comment for mono_image_close_except_pools() for why we
3817 * unload in two steps.
3820 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3823 g_return_val_if_fail (assembly != NULL, FALSE);
3825 if (assembly == REFERENCE_MISSING)
3828 /* Might be 0 already */
3829 if (InterlockedDecrement (&assembly->ref_count) > 0)
3832 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3834 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3836 mono_debug_close_image (assembly->image);
3838 mono_assemblies_lock ();
3839 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3840 mono_assemblies_unlock ();
3842 assembly->image->assembly = NULL;
3844 if (!mono_image_close_except_pools (assembly->image))
3845 assembly->image = NULL;
3847 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3848 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3849 mono_assembly_name_free (fname);
3852 g_slist_free (assembly->friend_assembly_names);
3853 g_free (assembly->basedir);
3855 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3861 mono_assembly_close_finish (MonoAssembly *assembly)
3863 g_assert (assembly && assembly != REFERENCE_MISSING);
3865 if (assembly->image)
3866 mono_image_close_finish (assembly->image);
3868 if (assembly_is_dynamic (assembly)) {
3869 g_free ((char*)assembly->aname.culture);
3876 * mono_assembly_close:
3877 * \param assembly the assembly to release.
3879 * This method releases a reference to the \p assembly. The assembly is
3880 * only released when all the outstanding references to it are released.
3883 mono_assembly_close (MonoAssembly *assembly)
3885 if (mono_assembly_close_except_image_pools (assembly))
3886 mono_assembly_close_finish (assembly);
3890 * mono_assembly_load_module:
3893 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3896 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3897 mono_error_assert_ok (&error);
3902 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3904 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3909 * mono_assembly_foreach:
3910 * \param func function to invoke for each assembly loaded
3911 * \param user_data data passed to the callback
3913 * Invokes the provided \p func callback for each assembly loaded into
3914 * the runtime. The first parameter passed to the callback is the
3915 * \c MonoAssembly*, and the second parameter is the \p user_data.
3917 * This is done for all assemblies loaded in the runtime, not just
3918 * those loaded in the current application domain.
3921 mono_assembly_foreach (GFunc func, gpointer user_data)
3926 * We make a copy of the list to avoid calling the callback inside the
3927 * lock, which could lead to deadlocks.
3929 mono_assemblies_lock ();
3930 copy = g_list_copy (loaded_assemblies);
3931 mono_assemblies_unlock ();
3933 g_list_foreach (loaded_assemblies, func, user_data);
3939 * mono_assemblies_cleanup:
3941 * Free all resources used by this module.
3944 mono_assemblies_cleanup (void)
3948 mono_os_mutex_destroy (&assemblies_mutex);
3949 mono_os_mutex_destroy (&assembly_binding_mutex);
3951 for (l = loaded_assembly_bindings; l; l = l->next) {
3952 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3954 mono_assembly_binding_info_free (info);
3957 g_slist_free (loaded_assembly_bindings);
3959 free_assembly_load_hooks ();
3960 free_assembly_search_hooks ();
3961 free_assembly_preload_hooks ();
3964 /*LOCKING takes the assembly_binding lock*/
3966 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3970 mono_assembly_binding_lock ();
3971 iter = &loaded_assembly_bindings;
3974 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3976 if (info->domain_id == domain_id) {
3978 mono_assembly_binding_info_free (info);
3985 mono_assembly_binding_unlock ();
3989 * Holds the assembly of the application, for
3990 * System.Diagnostics.Process::MainModule
3992 static MonoAssembly *main_assembly=NULL;
3995 * mono_assembly_set_main:
3998 mono_assembly_set_main (MonoAssembly *assembly)
4000 main_assembly = assembly;
4004 * mono_assembly_get_main:
4006 * Returns: the assembly for the application, the first assembly that is loaded by the VM
4009 mono_assembly_get_main (void)
4011 return (main_assembly);
4015 * mono_assembly_get_image:
4016 * \param assembly The assembly to retrieve the image from
4018 * \returns the \c MonoImage associated with this assembly.
4021 mono_assembly_get_image (MonoAssembly *assembly)
4023 return assembly->image;
4027 * mono_assembly_get_name:
4028 * \param assembly The assembly to retrieve the name from
4030 * The returned name's lifetime is the same as \p assembly's.
4032 * \returns the \c MonoAssemblyName associated with this assembly.
4035 mono_assembly_get_name (MonoAssembly *assembly)
4037 return &assembly->aname;
4041 * mono_register_bundled_assemblies:
4044 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4046 bundles = assemblies;
4049 #define MONO_DECLSEC_FORMAT_10 0x3C
4050 #define MONO_DECLSEC_FORMAT_20 0x2E
4051 #define MONO_DECLSEC_FIELD 0x53
4052 #define MONO_DECLSEC_PROPERTY 0x54
4054 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4055 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4056 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4057 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4058 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4061 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4065 case MONO_DECLSEC_PROPERTY:
4067 case MONO_DECLSEC_FIELD:
4069 *abort_decoding = TRUE;
4074 if (*p++ != MONO_TYPE_BOOLEAN) {
4075 *abort_decoding = TRUE;
4079 /* property name length */
4080 len = mono_metadata_decode_value (p, &p);
4082 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4093 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4095 int i, j, num, len, params_len;
4097 if (*p == MONO_DECLSEC_FORMAT_10) {
4098 gsize read, written;
4099 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4101 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4107 if (*p++ != MONO_DECLSEC_FORMAT_20)
4110 /* number of encoded permission attributes */
4111 num = mono_metadata_decode_value (p, &p);
4112 for (i = 0; i < num; ++i) {
4113 gboolean is_valid = FALSE;
4114 gboolean abort_decoding = FALSE;
4116 /* attribute name length */
4117 len = mono_metadata_decode_value (p, &p);
4119 /* We don't really need to fully decode the type. Comparing the name is enough */
4120 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4124 /*size of the params table*/
4125 params_len = mono_metadata_decode_value (p, &p);
4127 const char *params_end = p + params_len;
4129 /* number of parameters */
4130 len = mono_metadata_decode_value (p, &p);
4132 for (j = 0; j < len; ++j) {
4133 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4149 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4152 guint32 cols [MONO_DECL_SECURITY_SIZE];
4156 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4157 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4159 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4161 for (i = 0; i < t->rows; ++i) {
4162 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4163 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4165 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4168 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4169 len = mono_metadata_decode_blob_size (blob, &blob);
4173 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4174 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4179 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);