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_ASSEMBLY_REMAPPING
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 {"System.Runtime.InteropServices.RuntimeInformation", 2},
243 FACADE_ASSEMBLY ("System.Runtime.InteropServices.WindowsRuntime"),
244 FACADE_ASSEMBLY ("System.Runtime.Numerics"),
245 {"System.Runtime.Remoting", 0},
246 {"System.Runtime.Serialization", 3},
247 {"System.Runtime.Serialization.Formatters", 3},
248 {"System.Runtime.Serialization.Formatters.Soap", 0},
249 FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"),
250 FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"),
251 FACADE_ASSEMBLY ("System.Runtime.Serialization.Xml"),
252 {"System.Security", 0},
253 FACADE_ASSEMBLY ("System.Security.AccessControl"),
254 FACADE_ASSEMBLY ("System.Security.Claims"),
255 FACADE_ASSEMBLY ("System.Security.Cryptography.Algorithms"),
256 FACADE_ASSEMBLY ("System.Security.Cryptography.Cng"),
257 FACADE_ASSEMBLY ("System.Security.Cryptography.Csp"),
258 FACADE_ASSEMBLY ("System.Security.Cryptography.DeriveBytes"),
259 FACADE_ASSEMBLY ("System.Security.Cryptography.Encoding"),
260 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption"),
261 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Aes"),
262 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDiffieHellman"),
263 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDsa"),
264 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing"),
265 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing.Algorithms"),
266 FACADE_ASSEMBLY ("System.Security.Cryptography.OpenSsl"),
267 FACADE_ASSEMBLY ("System.Security.Cryptography.Pkcs"),
268 FACADE_ASSEMBLY ("System.Security.Cryptography.Primitives"),
269 FACADE_ASSEMBLY ("System.Security.Cryptography.ProtectedData"),
270 FACADE_ASSEMBLY ("System.Security.Cryptography.RSA"),
271 FACADE_ASSEMBLY ("System.Security.Cryptography.RandomNumberGenerator"),
272 FACADE_ASSEMBLY ("System.Security.Cryptography.X509Certificates"),
273 FACADE_ASSEMBLY ("System.Security.Principal"),
274 FACADE_ASSEMBLY ("System.Security.Principal.Windows"),
275 FACADE_ASSEMBLY ("System.Security.SecureString"),
276 {"System.ServiceModel", 3},
277 {"System.ServiceModel.Duplex", 3},
278 {"System.ServiceModel.Http", 3},
279 {"System.ServiceModel.NetTcp", 3},
280 {"System.ServiceModel.Primitives", 3},
281 {"System.ServiceModel.Security", 3},
282 {"System.ServiceModel.Web", 2},
283 {"System.ServiceProcess", 0},
284 FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"),
285 FACADE_ASSEMBLY ("System.Text.Encoding"),
286 FACADE_ASSEMBLY ("System.Text.Encoding.CodePages"),
287 FACADE_ASSEMBLY ("System.Text.Encoding.Extensions"),
288 FACADE_ASSEMBLY ("System.Text.RegularExpressions"),
289 FACADE_ASSEMBLY ("System.Threading"),
290 FACADE_ASSEMBLY ("System.Threading.AccessControl"),
291 FACADE_ASSEMBLY ("System.Threading.Overlapped"),
292 FACADE_ASSEMBLY ("System.Threading.Tasks"),
293 FACADE_ASSEMBLY ("System.Threading.Tasks.Parallel"),
294 FACADE_ASSEMBLY ("System.Threading.Thread"),
295 FACADE_ASSEMBLY ("System.Threading.ThreadPool"),
296 FACADE_ASSEMBLY ("System.Threading.Timer"),
297 {"System.Transactions", 0},
298 FACADE_ASSEMBLY ("System.ValueTuple"),
300 {"System.Web.Abstractions", 2},
301 {"System.Web.DynamicData", 2},
302 {"System.Web.Extensions", 2},
303 {"System.Web.Mobile", 0},
304 {"System.Web.Routing", 2},
305 {"System.Web.Services", 0},
306 {"System.Windows", 0},
307 {"System.Windows.Forms", 0},
309 {"System.Xml.Linq", 2},
310 FACADE_ASSEMBLY ("System.Xml.ReaderWriter"),
311 {"System.Xml.Serialization", 0},
312 FACADE_ASSEMBLY ("System.Xml.XDocument"),
313 FACADE_ASSEMBLY ("System.Xml.XPath"),
314 {"System.Xml.XPath.XmlDocument", 3},
315 FACADE_ASSEMBLY ("System.Xml.XPath.XDocument"),
316 FACADE_ASSEMBLY ("System.Xml.XmlDocument"),
317 FACADE_ASSEMBLY ("System.Xml.XmlSerializer"),
318 FACADE_ASSEMBLY ("System.Xml.Xsl.Primitives"),
321 FACADE_ASSEMBLY ("netstandard"),
326 * keeps track of loaded assemblies
328 static GList *loaded_assemblies = NULL;
329 static MonoAssembly *corlib;
331 #if defined(__native_client__)
333 /* On Native Client, allow mscorlib to be loaded from memory */
334 /* instead of loaded off disk. If these are not set, default */
335 /* mscorlib loading will take place */
337 /* NOTE: If mscorlib data is passed to mono in this way then */
338 /* it needs to remain allocated during the use of mono. */
340 static void *corlibData = NULL;
341 static size_t corlibSize = 0;
344 mono_set_corlib_data (void *data, size_t size)
352 static char* unquote (const char *str);
354 /* This protects loaded_assemblies and image->references */
355 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
356 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
357 static mono_mutex_t assemblies_mutex;
359 /* If defined, points to the bundled assembly information */
360 const MonoBundledAssembly **bundles;
362 static mono_mutex_t assembly_binding_mutex;
364 /* Loaded assembly binding info */
365 static GSList *loaded_assembly_bindings = NULL;
367 /* Class lazy loading functions */
368 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
370 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
372 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
374 mono_assembly_is_in_gac (const gchar *filanem);
377 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
380 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags);
382 /* Assembly name matching */
384 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
386 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name);
389 encode_public_tok (const guchar *token, gint32 len)
391 const static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
395 res = (gchar *)g_malloc (len * 2 + 1);
396 for (i = 0; i < len; i++) {
397 res [i * 2] = allowed [token [i] >> 4];
398 res [i * 2 + 1] = allowed [token [i] & 0xF];
405 * mono_public_tokens_are_equal:
406 * \param pubt1 first public key token
407 * \param pubt2 second public key token
409 * Compare two public key tokens and return TRUE is they are equal and FALSE
413 mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
415 return memcmp (pubt1, pubt2, 16) == 0;
419 * mono_set_assemblies_path:
420 * \param path list of paths that contain directories where Mono will look for assemblies
422 * Use this method to override the standard assembly lookup system and
423 * override any assemblies coming from the GAC. This is the method
424 * that supports the \c MONO_PATH variable.
426 * Notice that \c MONO_PATH and this method are really a very bad idea as
427 * it prevents the GAC from working and it prevents the standard
428 * resolution mechanisms from working. Nonetheless, for some debugging
429 * situations and bootstrapping setups, this is useful to have.
432 mono_set_assemblies_path (const char* path)
434 char **splitted, **dest;
436 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
438 g_strfreev (assemblies_path);
439 assemblies_path = dest = splitted;
441 char *tmp = *splitted;
443 *dest++ = mono_path_canonicalize (tmp);
449 if (g_hasenv ("MONO_DEBUG"))
452 splitted = assemblies_path;
454 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
455 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted);
461 /* Native Client can't get this info from an environment variable so */
462 /* it's passed in to the runtime, or set manually by embedding code. */
463 #ifdef __native_client__
464 char* nacl_mono_path = NULL;
468 check_path_env (void)
470 if (assemblies_path != NULL)
473 char* path = g_getenv ("MONO_PATH");
474 #ifdef __native_client__
476 path = strdup (nacl_mono_path);
481 mono_set_assemblies_path(path);
486 check_extra_gac_path_env (void)
489 char **splitted, **dest;
491 path = g_getenv ("MONO_GAC_PREFIX");
495 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
499 g_strfreev (extra_gac_paths);
500 extra_gac_paths = dest = splitted;
508 if (!g_hasenv ("MONO_DEBUG"))
512 if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR))
513 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted);
520 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
522 if (!info || !info->name)
525 if (strcmp (info->name, aname->name))
528 if (info->major != aname->major || info->minor != aname->minor)
531 if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0]))
534 if (info->culture && aname->culture && strcmp (info->culture, aname->culture))
537 if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
544 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
550 g_free (info->culture);
554 get_publisher_policy_info (MonoImage *image, MonoAssemblyName *aname, MonoAssemblyBindingInfo *binding_info)
557 guint32 cols [MONO_MANIFEST_SIZE];
558 const gchar *filename;
559 gchar *subpath, *fullpath;
561 t = &image->tables [MONO_TABLE_MANIFESTRESOURCE];
562 /* MS Impl. accepts policy assemblies with more than
563 * one manifest resource, and only takes the first one */
565 binding_info->is_valid = FALSE;
569 mono_metadata_decode_row (t, 0, cols, MONO_MANIFEST_SIZE);
570 if ((cols [MONO_MANIFEST_IMPLEMENTATION] & MONO_IMPLEMENTATION_MASK) != MONO_IMPLEMENTATION_FILE) {
571 binding_info->is_valid = FALSE;
575 filename = mono_metadata_string_heap (image, cols [MONO_MANIFEST_NAME]);
576 g_assert (filename != NULL);
578 subpath = g_path_get_dirname (image->name);
579 fullpath = g_build_path (G_DIR_SEPARATOR_S, subpath, filename, NULL);
580 mono_config_parse_publisher_policy (fullpath, binding_info);
584 /* Define the optional elements/attributes before checking */
585 if (!binding_info->culture)
586 binding_info->culture = g_strdup ("");
588 /* Check that the most important elements/attributes exist */
589 if (!binding_info->name || !binding_info->public_key_token [0] || !binding_info->has_old_version_bottom ||
590 !binding_info->has_new_version || !assembly_binding_maps_name (binding_info, aname)) {
591 mono_assembly_binding_info_free (binding_info);
592 binding_info->is_valid = FALSE;
596 binding_info->is_valid = TRUE;
600 compare_versions (AssemblyVersionSet *v, MonoAssemblyName *aname)
602 if (v->major > aname->major)
604 else if (v->major < aname->major)
607 if (v->minor > aname->minor)
609 else if (v->minor < aname->minor)
612 if (v->build > aname->build)
614 else if (v->build < aname->build)
617 if (v->revision > aname->revision)
619 else if (v->revision < aname->revision)
626 check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
631 /* If has_old_version_top doesn't exist, we don't have an interval */
632 if (!info->has_old_version_top) {
633 if (compare_versions (&info->old_version_bottom, name) == 0)
639 /* Check that the version defined by name is valid for the interval */
640 if (compare_versions (&info->old_version_top, name) < 0)
643 /* We should be greater or equal than the small version */
644 if (compare_versions (&info->old_version_bottom, name) > 0)
651 * mono_assembly_names_equal:
652 * \param l first assembly
653 * \param r second assembly.
655 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
657 * This compares the names, the cultures, the release version and their
660 * \returns TRUE if both assembly names are equal.
663 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
665 return assembly_names_equal_flags (l, r, ANAME_EQ_NONE);
669 assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, AssemblyNameEqFlags flags)
671 if (!l->name || !r->name)
674 if (strcmp (l->name, r->name))
677 if (l->culture && r->culture && strcmp (l->culture, r->culture))
680 if ((l->major != r->major || l->minor != r->minor ||
681 l->build != r->build || l->revision != r->revision) &&
682 (flags & ANAME_EQ_IGNORE_VERSION) == 0)
683 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)))
686 if (!l->public_key_token [0] || !r->public_key_token [0] || (flags & ANAME_EQ_IGNORE_PUBKEY) != 0)
689 if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
695 static MonoAssembly *
696 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
700 MonoAssembly *result;
702 for (i = 0; search_path [i]; ++i) {
703 fullpath = g_build_filename (search_path [i], basename, NULL);
704 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
713 * mono_assembly_setrootdir:
714 * \param root_dir The pathname of the root directory where we will locate assemblies
716 * This routine sets the internal default root directory for looking up
719 * This is used by Windows installations to compute dynamically the
720 * place where the Mono assemblies are located.
724 mono_assembly_setrootdir (const char *root_dir)
727 * Override the MONO_ASSEMBLIES directory configured at compile time.
729 /* Leak if called more than once */
730 default_path [0] = g_strdup (root_dir);
734 * mono_assembly_getrootdir:
736 * Obtains the root directory used for looking up assemblies.
738 * Returns: a string with the directory, this string should not be freed.
740 G_CONST_RETURN gchar *
741 mono_assembly_getrootdir (void)
743 return default_path [0];
747 * mono_native_getrootdir:
749 * Obtains the root directory used for looking up native libs (.so, .dylib).
751 * Returns: a string with the directory, this string should be freed by
755 mono_native_getrootdir (void)
757 gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
763 * \param assembly_dir the base directory for assemblies
764 * \param config_dir the base directory for configuration files
766 * This routine is used internally and by developers embedding
767 * the runtime into their own applications.
769 * There are a number of cases to consider: Mono as a system-installed
770 * package that is available on the location preconfigured or Mono in
771 * a relocated location.
773 * If you are using a system-installed Mono, you can pass NULL
774 * to both parameters. If you are not, you should compute both
775 * directory values and call this routine.
777 * The values for a given PREFIX are:
779 * assembly_dir: PREFIX/lib
780 * config_dir: PREFIX/etc
782 * Notice that embedders that use Mono in a relocated way must
783 * compute the location at runtime, as they will be in control
784 * of where Mono is installed.
787 mono_set_dirs (const char *assembly_dir, const char *config_dir)
789 if (assembly_dir == NULL)
790 assembly_dir = mono_config_get_assemblies_dir ();
791 if (config_dir == NULL)
792 config_dir = mono_config_get_cfg_dir ();
793 mono_assembly_setrootdir (assembly_dir);
794 mono_set_config_dir (config_dir);
800 compute_base (char *path)
802 char *p = strrchr (path, '/');
806 /* Not a well known Mono executable, we are embedded, cant guess the base */
807 if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
811 p = strrchr (path, '/');
815 if (strcmp (p, "/bin") != 0)
824 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
827 static G_GNUC_UNUSED void
831 char *config, *lib, *mono;
836 * Only /usr prefix is treated specially
838 bindir = mono_config_get_bin_dir ();
840 if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
845 config = g_build_filename (base, "etc", NULL);
846 lib = g_build_filename (base, "lib", NULL);
847 mono = g_build_filename (lib, "mono/4.5", NULL); // FIXME: stop hardcoding 4.5 here
848 if (stat (mono, &buf) == -1)
851 mono_set_dirs (lib, config);
859 #endif /* HOST_WIN32 */
864 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
865 * this auto-detects the prefix where Mono was installed.
868 mono_set_rootdir (void)
870 #if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM))
871 gchar *bindir, *installdir, *root, *name, *resolvedname, *config;
874 name = mono_get_module_file_name ((HMODULE) &__ImageBase);
878 * _NSGetExecutablePath may return -1 to indicate buf is not large
879 * enough, but we ignore that case to avoid having to do extra dynamic
880 * allocation for the path and hope that 4096 is enough - this is
881 * ok in the Linux/Solaris case below at least...
885 guint buf_size = sizeof (buf);
888 if (_NSGetExecutablePath (buf, &buf_size) == 0)
889 name = g_strdup (buf);
898 resolvedname = mono_path_resolve_symlinks (name);
900 bindir = g_path_get_dirname (resolvedname);
901 installdir = g_path_get_dirname (bindir);
902 root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL);
904 config = g_build_filename (root, "..", "etc", NULL);
906 mono_set_dirs (root, config);
908 if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS))
909 mono_set_dirs (root, config);
919 g_free (resolvedname);
920 #elif defined(DISABLE_MONO_AUTODETECTION)
928 s = readlink ("/proc/self/exe", buf, sizeof (buf)-1);
936 /* Solaris 10 style */
937 str = g_strdup_printf ("/proc/%d/path/a.out", getpid ());
938 s = readlink (str, buf, sizeof (buf)-1);
950 * mono_assemblies_init:
952 * Initialize global variables used by this module.
955 mono_assemblies_init (void)
958 * Initialize our internal paths if we have not been initialized yet.
959 * This happens when embedders use Mono.
961 if (mono_assembly_getrootdir () == NULL)
965 check_extra_gac_path_env ();
967 mono_os_mutex_init_recursive (&assemblies_mutex);
968 mono_os_mutex_init (&assembly_binding_mutex);
970 #ifndef DISABLE_ASSEMBLY_REMAPPING
971 assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
974 for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
975 g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
981 mono_assembly_binding_lock (void)
983 mono_locks_os_acquire (&assembly_binding_mutex, AssemblyBindingLock);
987 mono_assembly_binding_unlock (void)
989 mono_locks_os_release (&assembly_binding_mutex, AssemblyBindingLock);
993 mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
995 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
996 guint32 cols [MONO_ASSEMBLY_SIZE];
997 gint32 machine, flags;
1002 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
1004 aname->hash_len = 0;
1005 aname->hash_value = NULL;
1006 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
1008 aname->name = g_strdup (aname->name);
1009 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
1011 aname->culture = g_strdup (aname->culture);
1012 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
1013 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
1014 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
1015 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
1016 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
1017 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
1018 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
1019 guchar* token = (guchar *)g_malloc (8);
1024 pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
1025 len = mono_metadata_decode_blob_size (pkey, &pkey);
1026 aname->public_key = (guchar*)pkey;
1028 mono_digest_get_public_token (token, aname->public_key, len);
1029 encoded = encode_public_tok (token, 8);
1030 g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1036 aname->public_key = NULL;
1037 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1040 if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
1041 aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
1043 const gchar *pkey_end;
1044 int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
1045 pkey_end += len; /* move to end */
1046 size_t size = pkey_end - (const gchar*)aname->public_key;
1047 guchar *tmp = g_new (guchar, size);
1048 memcpy (tmp, aname->public_key, size);
1049 aname->public_key = tmp;
1054 aname->public_key = 0;
1056 machine = ((MonoCLIImageInfo*)(image->image_info))->cli_header.coff.coff_machine;
1057 flags = ((MonoCLIImageInfo*)(image->image_info))->cli_cli_header.ch_flags;
1059 case COFF_MACHINE_I386:
1060 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1061 if (flags & (CLI_FLAGS_32BITREQUIRED|CLI_FLAGS_PREFERRED32BIT))
1062 aname->arch = MONO_PROCESSOR_ARCHITECTURE_X86;
1063 else if ((flags & 0x70) == 0x70)
1064 aname->arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
1066 aname->arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
1068 case COFF_MACHINE_IA64:
1069 aname->arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
1071 case COFF_MACHINE_AMD64:
1072 aname->arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
1074 case COFF_MACHINE_ARM:
1075 aname->arch = MONO_PROCESSOR_ARCHITECTURE_ARM;
1085 * mono_assembly_fill_assembly_name:
1086 * \param image Image
1088 * \returns TRUE if successful
1091 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
1093 return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
1097 * mono_stringify_assembly_name:
1098 * \param aname the assembly name.
1100 * Convert \p aname into its string format. The returned string is dynamically
1101 * allocated and should be freed by the caller.
1103 * \returns a newly allocated string with a string representation of
1104 * the assembly name.
1107 mono_stringify_assembly_name (MonoAssemblyName *aname)
1109 const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : "";
1111 return g_strdup_printf (
1112 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1113 quote, aname->name, quote,
1114 aname->major, aname->minor, aname->build, aname->revision,
1115 aname->culture && *aname->culture? aname->culture: "neutral",
1116 aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
1117 (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
1121 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
1123 const gchar *public_tok;
1126 public_tok = mono_metadata_blob_heap (image, key_index);
1127 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
1129 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
1131 mono_digest_get_public_token (token, (guchar*)public_tok, len);
1132 return encode_public_tok (token, 8);
1135 return encode_public_tok ((guchar*)public_tok, len);
1139 * mono_assembly_addref:
1140 * \param assembly the assembly to reference
1142 * This routine increments the reference count on a MonoAssembly.
1143 * The reference count is reduced every time the method mono_assembly_close() is
1147 mono_assembly_addref (MonoAssembly *assembly)
1149 InterlockedIncrement (&assembly->ref_count);
1153 * CAUTION: This table must be kept in sync with
1154 * ivkm/reflect/Fusion.cs
1157 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1158 #define WINFX_KEY "31bf3856ad364e35"
1159 #define ECMA_KEY "b77a5c561934e089"
1160 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1161 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1169 static KeyRemapEntry key_remap_table[] = {
1170 { "CustomMarshalers", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1171 { "Microsoft.CSharp", WINFX_KEY, MSFINAL_KEY },
1172 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1173 { "System", SILVERLIGHT_KEY, ECMA_KEY },
1174 { "System", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1175 { "System.ComponentModel.Composition", WINFX_KEY, ECMA_KEY },
1176 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY },
1177 { "System.Core", SILVERLIGHT_KEY, ECMA_KEY },
1178 { "System.Core", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1179 { "System.Data", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1180 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1181 { "System.Drawing", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1182 { "System.Messaging", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1183 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1184 { "System.Net", SILVERLIGHT_KEY, MSFINAL_KEY },
1185 { "System.Numerics", WINFX_KEY, ECMA_KEY },
1186 { "System.Runtime.Serialization", SILVERLIGHT_KEY, ECMA_KEY },
1187 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1188 { "System.ServiceModel", WINFX_KEY, ECMA_KEY },
1189 { "System.ServiceModel", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1190 { "System.ServiceModel.Web", SILVERLIGHT_KEY, WINFX_KEY },
1191 { "System.Web.Services", COMPACTFRAMEWORK_KEY, MSFINAL_KEY },
1192 { "System.Windows", SILVERLIGHT_KEY, MSFINAL_KEY },
1193 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1194 { "System.Xml", SILVERLIGHT_KEY, ECMA_KEY },
1195 { "System.Xml", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1196 { "System.Xml.Linq", WINFX_KEY, ECMA_KEY },
1197 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY, ECMA_KEY },
1198 { "System.Xml.Serialization", WINFX_KEY, ECMA_KEY }
1202 remap_keys (MonoAssemblyName *aname)
1205 for (i = 0; i < G_N_ELEMENTS (key_remap_table); i++) {
1206 const KeyRemapEntry *entry = &key_remap_table [i];
1208 if (strcmp (aname->name, entry->name) ||
1209 !mono_public_tokens_are_equal (aname->public_key_token, (const unsigned char*) entry->from))
1212 memcpy (aname->public_key_token, entry->to, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1214 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1215 "Remapped public key token of retargetable assembly %s from %s to %s",
1216 aname->name, entry->from, entry->to);
1221 static MonoAssemblyName *
1222 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
1224 const MonoRuntimeInfo *current_runtime;
1226 if (aname->name == NULL) return aname;
1228 current_runtime = mono_get_runtime_info ();
1230 if (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) {
1231 const AssemblyVersionSet* vset;
1233 /* Remap to current runtime */
1234 vset = ¤t_runtime->version_sets [0];
1236 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1237 dest_aname->major = vset->major;
1238 dest_aname->minor = vset->minor;
1239 dest_aname->build = vset->build;
1240 dest_aname->revision = vset->revision;
1241 dest_aname->flags &= ~ASSEMBLYREF_RETARGETABLE_FLAG;
1243 /* Remap assembly name */
1244 if (!strcmp (aname->name, "System.Net"))
1245 dest_aname->name = g_strdup ("System");
1247 remap_keys (dest_aname);
1249 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1250 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1252 aname->major, aname->minor, aname->build, aname->revision,
1254 vset->major, vset->minor, vset->build, vset->revision
1260 #ifndef DISABLE_ASSEMBLY_REMAPPING
1261 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
1263 const AssemblyVersionSet* vset;
1264 int index = vmap->version_set_index;
1265 g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
1266 vset = ¤t_runtime->version_sets [index];
1268 if (vmap->framework_facade_assembly) {
1269 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s is a framework Facade asseembly",
1274 if (aname->major == vset->major && aname->minor == vset->minor &&
1275 aname->build == vset->build && aname->revision == vset->revision) {
1276 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1278 aname->major, aname->minor, aname->build, aname->revision);
1282 if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
1283 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
1284 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1286 aname->major, aname->minor, aname->build, aname->revision,
1287 vset->major, vset->minor, vset->build, vset->revision
1292 if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
1293 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1294 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1296 aname->major, aname->minor, aname->build, aname->revision,
1297 vset->major, vset->minor, vset->build, vset->revision
1300 memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
1301 dest_aname->major = vset->major;
1302 dest_aname->minor = vset->minor;
1303 dest_aname->build = vset->build;
1304 dest_aname->revision = vset->revision;
1305 if (vmap->new_assembly_name != NULL) {
1306 dest_aname->name = vmap->new_assembly_name;
1307 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
1308 "The assembly name %s was remapped to %s",
1320 * mono_assembly_get_assemblyref:
1321 * \param image pointer to the \c MonoImage to extract the information from.
1322 * \param index index to the assembly reference in the image.
1323 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1325 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1328 mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *aname)
1331 guint32 cols [MONO_ASSEMBLYREF_SIZE];
1334 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1336 mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
1338 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
1339 aname->hash_len = mono_metadata_decode_blob_size (hash, &hash);
1340 aname->hash_value = hash;
1341 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
1342 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
1343 aname->flags = cols [MONO_ASSEMBLYREF_FLAGS];
1344 aname->major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
1345 aname->minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
1346 aname->build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
1347 aname->revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
1349 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
1350 gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
1351 g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1354 memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
1359 * mono_assembly_load_reference:
1362 mono_assembly_load_reference (MonoImage *image, int index)
1364 MonoAssembly *reference;
1365 MonoAssemblyName aname;
1366 MonoImageOpenStatus status;
1369 * image->references is shared between threads, so we need to access
1370 * it inside a critical section.
1372 mono_assemblies_lock ();
1373 if (!image->references) {
1374 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
1376 image->references = g_new0 (MonoAssembly *, t->rows + 1);
1377 image->nreferences = t->rows;
1379 reference = image->references [index];
1380 mono_assemblies_unlock ();
1384 mono_assembly_get_assemblyref (image, index, &aname);
1386 if (image->assembly && image->assembly->ref_only) {
1387 /* We use the loaded corlib */
1388 if (!strcmp (aname.name, "mscorlib"))
1389 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1391 reference = mono_assembly_loaded_full (&aname, TRUE);
1393 /* Try a postload search hook */
1394 reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
1398 * Here we must advice that the error was due to
1399 * a non loaded reference using the ReflectionOnly api
1402 reference = (MonoAssembly *)REFERENCE_MISSING;
1404 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1405 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1406 * accordingly, it would fail on the MS runtime before).
1407 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1408 * example bug-349190.2.cs and who knows how much more code in the wild.
1410 reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
1411 if (!reference && image->assembly)
1412 reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
1415 if (reference == NULL){
1418 if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) {
1419 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 : "" );
1420 } else if (status == MONO_IMAGE_ERROR_ERRNO) {
1421 extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
1422 } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
1423 extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
1424 } else if (status == MONO_IMAGE_IMAGE_INVALID) {
1425 extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
1427 extra_msg = g_strdup ("");
1430 mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n"
1431 " Assembly: %s (assemblyref_index=%d)\n"
1432 " Version: %d.%d.%d.%d\n"
1433 " Public Key: %s\n%s",
1434 image->name, aname.name, index,
1435 aname.major, aname.minor, aname.build, aname.revision,
1436 strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
1441 mono_assemblies_lock ();
1442 if (reference == NULL) {
1443 /* Flag as not found */
1444 reference = (MonoAssembly *)REFERENCE_MISSING;
1447 if (!image->references [index]) {
1448 if (reference != REFERENCE_MISSING){
1449 mono_assembly_addref (reference);
1450 if (image->assembly)
1451 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1452 image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
1454 if (image->assembly)
1455 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
1456 image->assembly->aname.name, image->assembly);
1459 image->references [index] = reference;
1461 mono_assemblies_unlock ();
1463 if (image->references [index] != reference) {
1464 /* Somebody loaded it before us */
1465 mono_assembly_close (reference);
1470 * mono_assembly_load_references:
1473 * \deprecated There is no reason to use this method anymore, it does nothing
1475 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1478 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
1480 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1481 *status = MONO_IMAGE_OK;
1484 typedef struct AssemblyLoadHook AssemblyLoadHook;
1485 struct AssemblyLoadHook {
1486 AssemblyLoadHook *next;
1487 MonoAssemblyLoadFunc func;
1491 AssemblyLoadHook *assembly_load_hook = NULL;
1494 * mono_assembly_invoke_load_hook:
1497 mono_assembly_invoke_load_hook (MonoAssembly *ass)
1499 AssemblyLoadHook *hook;
1501 for (hook = assembly_load_hook; hook; hook = hook->next) {
1502 hook->func (ass, hook->user_data);
1507 * mono_install_assembly_load_hook:
1510 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
1512 AssemblyLoadHook *hook;
1514 g_return_if_fail (func != NULL);
1516 hook = g_new0 (AssemblyLoadHook, 1);
1518 hook->user_data = user_data;
1519 hook->next = assembly_load_hook;
1520 assembly_load_hook = hook;
1524 free_assembly_load_hooks (void)
1526 AssemblyLoadHook *hook, *next;
1528 for (hook = assembly_load_hook; hook; hook = next) {
1534 typedef struct AssemblySearchHook AssemblySearchHook;
1535 struct AssemblySearchHook {
1536 AssemblySearchHook *next;
1537 MonoAssemblySearchFunc func;
1543 AssemblySearchHook *assembly_search_hook = NULL;
1545 static MonoAssembly*
1546 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
1548 AssemblySearchHook *hook;
1550 for (hook = assembly_search_hook; hook; hook = hook->next) {
1551 if ((hook->refonly == refonly) && (hook->postload == postload)) {
1554 * A little explanation is in order here.
1556 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1557 * The embedding API exposes a search hook that doesn't take such argument.
1559 * The original fix would call the default search hook before all the registered ones and pass
1560 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1561 * rely on. Which is the ordering between user hooks and the default runtime hook.
1563 * Registering the hook after mono_jit_init would let your hook run before the default one and
1564 * when using it to handle non standard app layouts this could save your app from a massive amount
1565 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1566 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1568 * So what's the fix? We register the default hook using regular means and special case it when iterating
1569 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1572 if (hook->func == (void*)mono_domain_assembly_postload_search)
1573 ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
1575 ass = hook->func (aname, hook->user_data);
1585 * mono_assembly_invoke_search_hook:
1588 mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
1590 return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
1594 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func, gpointer user_data, gboolean refonly, gboolean postload)
1596 AssemblySearchHook *hook;
1598 g_return_if_fail (func != NULL);
1600 hook = g_new0 (AssemblySearchHook, 1);
1602 hook->user_data = user_data;
1603 hook->refonly = refonly;
1604 hook->postload = postload;
1605 hook->next = assembly_search_hook;
1606 assembly_search_hook = hook;
1610 * mono_install_assembly_search_hook:
1613 mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1615 mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
1619 free_assembly_search_hooks (void)
1621 AssemblySearchHook *hook, *next;
1623 for (hook = assembly_search_hook; hook; hook = next) {
1630 * mono_install_assembly_refonly_search_hook:
1633 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1635 mono_install_assembly_search_hook_internal (func, user_data, TRUE, FALSE);
1639 * mono_install_assembly_postload_search_hook:
1642 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1644 mono_install_assembly_search_hook_internal (func, user_data, FALSE, TRUE);
1648 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
1650 mono_install_assembly_search_hook_internal (func, user_data, TRUE, TRUE);
1653 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
1654 struct AssemblyPreLoadHook {
1655 AssemblyPreLoadHook *next;
1656 MonoAssemblyPreLoadFunc func;
1660 static AssemblyPreLoadHook *assembly_preload_hook = NULL;
1661 static AssemblyPreLoadHook *assembly_refonly_preload_hook = NULL;
1663 static MonoAssembly *
1664 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1666 AssemblyPreLoadHook *hook;
1667 MonoAssembly *assembly;
1669 for (hook = assembly_preload_hook; hook; hook = hook->next) {
1670 assembly = hook->func (aname, assemblies_path, hook->user_data);
1671 if (assembly != NULL)
1678 static MonoAssembly *
1679 invoke_assembly_refonly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
1681 AssemblyPreLoadHook *hook;
1682 MonoAssembly *assembly;
1684 for (hook = assembly_refonly_preload_hook; hook; hook = hook->next) {
1685 assembly = hook->func (aname, assemblies_path, hook->user_data);
1686 if (assembly != NULL)
1694 * mono_install_assembly_preload_hook:
1697 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1699 AssemblyPreLoadHook *hook;
1701 g_return_if_fail (func != NULL);
1703 hook = g_new0 (AssemblyPreLoadHook, 1);
1705 hook->user_data = user_data;
1706 hook->next = assembly_preload_hook;
1707 assembly_preload_hook = hook;
1711 * mono_install_assembly_refonly_preload_hook:
1714 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
1716 AssemblyPreLoadHook *hook;
1718 g_return_if_fail (func != NULL);
1720 hook = g_new0 (AssemblyPreLoadHook, 1);
1722 hook->user_data = user_data;
1723 hook->next = assembly_refonly_preload_hook;
1724 assembly_refonly_preload_hook = hook;
1728 free_assembly_preload_hooks (void)
1730 AssemblyPreLoadHook *hook, *next;
1732 for (hook = assembly_preload_hook; hook; hook = next) {
1737 for (hook = assembly_refonly_preload_hook; hook; hook = next) {
1744 absolute_dir (const gchar *filename)
1755 if (g_path_is_absolute (filename)) {
1756 part = g_path_get_dirname (filename);
1757 res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL);
1762 cwd = g_get_current_dir ();
1763 mixed = g_build_filename (cwd, filename, NULL);
1764 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
1769 for (i = 0; (part = parts [i]) != NULL; i++) {
1770 if (!strcmp (part, "."))
1773 if (!strcmp (part, "..")) {
1774 if (list && list->next) /* Don't remove root */
1775 list = g_list_delete_link (list, list);
1777 list = g_list_prepend (list, part);
1781 result = g_string_new ("");
1782 list = g_list_reverse (list);
1784 /* Ignores last data pointer, which should be the filename */
1785 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
1787 g_string_append_printf (result, "%s%c", (char *) tmp->data,
1792 g_string_free (result, FALSE);
1797 return g_strdup (".");
1804 * mono_assembly_open_from_bundle:
1805 * \param filename Filename requested
1806 * \param status return status code
1808 * This routine tries to open the assembly specified by \p filename from the
1809 * defined bundles, if found, returns the MonoImage for it, if not found
1813 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1817 gchar *lowercase_filename;
1818 MonoImage *image = NULL;
1819 gboolean is_satellite = FALSE;
1821 * we do a very simple search for bundled assemblies: it's not a general
1822 * purpose assembly loading mechanism.
1828 lowercase_filename = g_utf8_strdown (filename, -1);
1829 is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
1830 g_free (lowercase_filename);
1831 name = g_path_get_basename (filename);
1832 mono_assemblies_lock ();
1833 for (i = 0; !image && bundles [i]; ++i) {
1834 if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
1835 image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
1839 mono_assemblies_unlock ();
1841 mono_image_addref (image);
1842 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
1851 * mono_assembly_open_full:
1852 * \param filename the file to load
1853 * \param status return status code
1854 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
1856 * This loads an assembly from the specified \p filename. The \p filename allows
1857 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
1858 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
1859 * is treated as a local path.
1861 * First, an attempt is made to load the assembly from the bundled executable (for those
1862 * deployments that have been done with the \c mkbundle tool or for scenarios where the
1863 * assembly has been registered as an embedded assembly). If this is not the case, then
1864 * the assembly is loaded from disk using `api:mono_image_open_full`.
1866 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
1867 * the assembly is made.
1869 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
1870 * the \c System.Reflection API.
1872 * \returns NULL on error, with the \p status set to an error code, or a pointer
1876 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
1878 return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
1882 mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1884 return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
1888 mono_assembly_open_predicate (const char *filename, gboolean refonly,
1889 gboolean load_from_context,
1890 MonoAssemblyCandidatePredicate predicate,
1892 MonoImageOpenStatus *status)
1896 MonoImageOpenStatus def_status;
1899 gboolean loaded_from_bundle;
1901 g_return_val_if_fail (filename != NULL, NULL);
1904 status = &def_status;
1905 *status = MONO_IMAGE_OK;
1907 if (strncmp (filename, "file://", 7) == 0) {
1908 GError *error = NULL;
1909 gchar *uri = (gchar *) filename;
1913 * MS allows file://c:/... and fails on file://localhost/c:/...
1914 * They also throw an IndexOutOfRangeException if "file://"
1917 uri = g_strdup_printf ("file:///%s", uri + 7);
1920 uri = mono_escape_uri_string (tmpuri);
1921 fname = g_filename_from_uri (uri, NULL, &error);
1924 if (tmpuri != filename)
1927 if (error != NULL) {
1928 g_warning ("%s\n", error->message);
1929 g_error_free (error);
1930 fname = g_strdup (filename);
1933 fname = g_strdup (filename);
1936 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1937 "Assembly Loader probing location: '%s'.", fname);
1940 if (!mono_assembly_is_in_gac (fname)) {
1942 new_fname = mono_make_shadow_copy (fname, &error);
1943 if (!is_ok (&error)) {
1944 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1945 "Assembly Loader shadow copy error: %s.", mono_error_get_message (&error));
1946 mono_error_cleanup (&error);
1947 *status = MONO_IMAGE_IMAGE_INVALID;
1952 if (new_fname && new_fname != fname) {
1955 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1956 "Assembly Loader shadow-copied assembly to: '%s'.", fname);
1961 // If VM built with mkbundle
1962 loaded_from_bundle = FALSE;
1963 if (bundles != NULL) {
1964 image = mono_assembly_open_from_bundle (fname, status, refonly);
1965 loaded_from_bundle = image != NULL;
1969 image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
1972 if (*status == MONO_IMAGE_OK)
1973 *status = MONO_IMAGE_ERROR_ERRNO;
1978 if (image->assembly) {
1979 /* Already loaded by another appdomain */
1980 mono_assembly_invoke_load_hook (image->assembly);
1981 mono_image_close (image);
1983 return image->assembly;
1986 ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
1989 if (!loaded_from_bundle)
1990 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
1991 "Assembly Loader loaded assembly from location: '%s'.", filename);
1993 mono_config_for_assembly (ass->image);
1996 /* Clear the reference added by mono_image_open */
1997 mono_image_close (image);
2005 free_item (gpointer val, gpointer user_data)
2011 * mono_assembly_load_friends:
2012 * \param ass an assembly
2014 * Load the list of friend assemblies that are allowed to access
2015 * the assembly's internal types and members. They are stored as assembly
2016 * names in custom attributes.
2018 * This is an internal method, we need this because when we load mscorlib
2019 * we do not have the internals visible cattr loaded yet,
2020 * so we need to load these after we initialize the runtime.
2022 * LOCKING: Acquires the assemblies lock plus the loader lock.
2025 mono_assembly_load_friends (MonoAssembly* ass)
2029 MonoCustomAttrInfo* attrs;
2032 if (ass->friend_assembly_names_inited)
2035 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
2036 mono_error_assert_ok (&error);
2038 mono_assemblies_lock ();
2039 ass->friend_assembly_names_inited = TRUE;
2040 mono_assemblies_unlock ();
2044 mono_assemblies_lock ();
2045 if (ass->friend_assembly_names_inited) {
2046 mono_assemblies_unlock ();
2049 mono_assemblies_unlock ();
2053 * We build the list outside the assemblies lock, the worse that can happen
2054 * is that we'll need to free the allocated list.
2056 for (i = 0; i < attrs->num_attrs; ++i) {
2057 MonoCustomAttrEntry *attr = &attrs->attrs [i];
2058 MonoAssemblyName *aname;
2060 /* Do some sanity checking */
2061 if (!attr->ctor || attr->ctor->klass != mono_class_try_get_internals_visible_class ())
2063 if (attr->data_size < 4)
2065 data = (const char*)attr->data;
2066 /* 0xFF means null string, see custom attr format */
2067 if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
2069 mono_metadata_decode_value (data + 2, &data);
2070 aname = g_new0 (MonoAssemblyName, 1);
2071 /*g_print ("friend ass: %s\n", data);*/
2072 if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
2073 list = g_slist_prepend (list, aname);
2078 mono_custom_attrs_free (attrs);
2080 mono_assemblies_lock ();
2081 if (ass->friend_assembly_names_inited) {
2082 mono_assemblies_unlock ();
2083 g_slist_foreach (list, free_item, NULL);
2084 g_slist_free (list);
2087 ass->friend_assembly_names = list;
2089 /* Because of the double checked locking pattern above */
2090 mono_memory_barrier ();
2091 ass->friend_assembly_names_inited = TRUE;
2092 mono_assemblies_unlock ();
2095 struct HasReferenceAssemblyAttributeIterData {
2100 has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
2102 gboolean stop_scanning = FALSE;
2103 struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
2105 if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
2106 /* Note we don't check the assembly name, same as coreCLR. */
2107 iter_data->has_attr = TRUE;
2108 stop_scanning = TRUE;
2111 return stop_scanning;
2115 * mono_assembly_has_reference_assembly_attribute:
2116 * \param assembly a MonoAssembly
2117 * \param error set on error.
2119 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2120 * On error returns FALSE and sets \p error.
2123 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
2128 * This might be called during assembly loading, so do everything using the low-level
2132 struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
2134 mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
2136 return iter_data.has_attr;
2140 * mono_assembly_open:
2141 * \param filename Opens the assembly pointed out by this name
2142 * \param status return status code
2144 * This loads an assembly from the specified \p filename. The \p filename allows
2145 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2146 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2147 * is treated as a local path.
2149 * First, an attempt is made to load the assembly from the bundled executable (for those
2150 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2151 * assembly has been registered as an embedded assembly). If this is not the case, then
2152 * the assembly is loaded from disk using `api:mono_image_open_full`.
2154 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2155 * the assembly is made.
2157 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2158 * assembly or NULL on error. Details about the error are stored in the
2159 * \p status variable.
2162 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
2164 return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
2168 * mono_assembly_load_from_full:
2169 * \param image Image to load the assembly from
2170 * \param fname assembly name to associate with the assembly
2171 * \param status returns the status condition
2172 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2174 * If the provided \p image has an assembly reference, it will process the given
2175 * image as an assembly with the given name.
2177 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2179 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2180 * set to \c MONO_IMAGE_OK; or NULL on error.
2182 * If there is an error loading the assembly the \p status will indicate the
2183 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2184 * image did not contain an assembly reference table.
2187 mono_assembly_load_from_full (MonoImage *image, const char*fname,
2188 MonoImageOpenStatus *status, gboolean refonly)
2190 return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
2194 mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
2196 MonoAssemblyCandidatePredicate predicate,
2198 MonoImageOpenStatus *status)
2200 MonoAssembly *ass, *ass2;
2203 if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
2204 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2205 *status = MONO_IMAGE_IMAGE_INVALID;
2209 #if defined (HOST_WIN32)
2214 tmp_fn = g_strdup (fname);
2215 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
2216 if (tmp_fn [i] == '/')
2220 base_dir = absolute_dir (tmp_fn);
2224 base_dir = absolute_dir (fname);
2228 * Create assembly struct, and enter it into the assembly cache
2230 ass = g_new0 (MonoAssembly, 1);
2231 ass->basedir = base_dir;
2232 ass->ref_only = refonly;
2235 mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
2237 mono_assembly_fill_assembly_name (image, &ass->aname);
2239 if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
2240 // MS.NET doesn't support loading other mscorlibs
2243 mono_image_addref (mono_defaults.corlib);
2244 *status = MONO_IMAGE_OK;
2245 return mono_defaults.corlib->assembly;
2248 /* Add a non-temporary reference because of ass->image */
2249 mono_image_addref (image);
2251 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);
2254 * The load hooks might take locks so we can't call them while holding the
2257 if (ass->aname.name) {
2258 ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
2262 mono_image_close (image);
2263 *status = MONO_IMAGE_OK;
2268 /* We need to check for ReferenceAssmeblyAttribute before we
2269 * mark the assembly as loaded and before we fire the load
2270 * hook. Otherwise mono_domain_fire_assembly_load () in
2271 * appdomain.c will cache a mapping from the assembly name to
2272 * this image and we won't be able to look for a different
2276 MonoError refasm_error;
2277 if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
2278 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
2281 mono_image_close (image);
2282 *status = MONO_IMAGE_IMAGE_INVALID;
2285 mono_error_cleanup (&refasm_error);
2288 if (predicate && !predicate (ass, user_data)) {
2289 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
2292 mono_image_close (image);
2293 *status = MONO_IMAGE_IMAGE_INVALID;
2297 mono_assemblies_lock ();
2299 if (image->assembly) {
2301 * This means another thread has already loaded the assembly, but not yet
2302 * called the load hooks so the search hook can't find the assembly.
2304 mono_assemblies_unlock ();
2305 ass2 = image->assembly;
2308 mono_image_close (image);
2309 *status = MONO_IMAGE_OK;
2313 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
2315 image->assembly = ass;
2317 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
2318 mono_assemblies_unlock ();
2321 if (image->is_module_handle)
2322 mono_image_fixup_vtable (image);
2325 mono_assembly_invoke_load_hook (ass);
2327 mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
2333 * mono_assembly_load_from:
2334 * \param image Image to load the assembly from
2335 * \param fname assembly name to associate with the assembly
2336 * \param status return status code
2338 * If the provided \p image has an assembly reference, it will process the given
2339 * image as an assembly with the given name.
2341 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2343 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2344 * \p refonly parameter set to FALSE.
2345 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2346 * set to \c MONO_IMAGE_OK; or NULL on error.
2348 * If there is an error loading the assembly the \p status will indicate the
2349 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2350 * image did not contain an assembly reference table.
2354 mono_assembly_load_from (MonoImage *image, const char *fname,
2355 MonoImageOpenStatus *status)
2357 return mono_assembly_load_from_full (image, fname, status, FALSE);
2361 * mono_assembly_name_free:
2362 * \param aname assembly name to free
2364 * Frees the provided assembly name object.
2365 * (it does not frees the object itself, only the name members).
2368 mono_assembly_name_free (MonoAssemblyName *aname)
2373 g_free ((void *) aname->name);
2374 g_free ((void *) aname->culture);
2375 g_free ((void *) aname->hash_value);
2376 g_free ((guint8*) aname->public_key);
2380 parse_public_key (const gchar *key, gchar** pubkey, gboolean *is_ecma)
2383 gchar header [16], val, *arr;
2384 gint i, j, offset, bitlen, keylen, pkeylen;
2386 keylen = strlen (key) >> 1;
2390 /* allow the ECMA standard key */
2391 if (strcmp (key, "00000000000000000400000000000000") == 0) {
2393 *pubkey = g_strdup (key);
2399 val = g_ascii_xdigit_value (key [0]) << 4;
2400 val |= g_ascii_xdigit_value (key [1]);
2405 val = g_ascii_xdigit_value (key [24]);
2406 val |= g_ascii_xdigit_value (key [25]);
2418 /* We need the first 16 bytes
2419 * to check whether this key is valid or not */
2420 pkeylen = strlen (pkey) >> 1;
2424 for (i = 0, j = 0; i < 16; i++) {
2425 header [i] = g_ascii_xdigit_value (pkey [j++]) << 4;
2426 header [i] |= g_ascii_xdigit_value (pkey [j++]);
2429 if (header [0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2430 header [1] != 0x02 || /* Version (0x02) */
2431 header [2] != 0x00 || /* Reserved (word) */
2432 header [3] != 0x00 ||
2433 (guint)(read32 (header + 8)) != 0x31415352) /* DWORD magic = RSA1 */
2436 /* Based on this length, we _should_ be able to know if the length is right */
2437 bitlen = read32 (header + 12) >> 3;
2438 if ((bitlen + 16 + 4) != pkeylen)
2441 /* parsing is OK and the public key itself is not requested back */
2445 /* Encode the size of the blob */
2447 if (keylen <= 127) {
2448 arr = (gchar *)g_malloc (keylen + 1);
2449 arr [offset++] = keylen;
2451 arr = (gchar *)g_malloc (keylen + 2);
2452 arr [offset++] = 0x80; /* 10bs */
2453 arr [offset++] = keylen;
2456 for (i = offset, j = 0; i < keylen + offset; i++) {
2457 arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
2458 arr [i] |= g_ascii_xdigit_value (key [j++]);
2467 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)
2469 gint major, minor, build, revision;
2472 gchar *pkey, *pkeyptr, *encoded, tok [8];
2474 memset (aname, 0, sizeof (MonoAssemblyName));
2477 version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
2478 if (version_parts < 2 || version_parts > 4)
2481 /* FIXME: we should set build & revision to -1 (instead of 0)
2482 if these are not set in the version string. That way, later on,
2483 we can still determine if these were specified. */
2484 aname->major = major;
2485 aname->minor = minor;
2486 if (version_parts >= 3)
2487 aname->build = build;
2490 if (version_parts == 4)
2491 aname->revision = revision;
2493 aname->revision = 0;
2496 aname->flags = flags;
2498 aname->name = g_strdup (name);
2501 if (g_ascii_strcasecmp (culture, "neutral") == 0)
2502 aname->culture = g_strdup ("");
2504 aname->culture = g_strdup (culture);
2507 if (token && strncmp (token, "null", 4) != 0) {
2510 /* the constant includes the ending NULL, hence the -1 */
2511 if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
2512 mono_assembly_name_free (aname);
2515 lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2516 g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2522 if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey, &is_ecma)) {
2523 mono_assembly_name_free (aname);
2528 if (save_public_key)
2529 aname->public_key = (guint8*)pkey;
2532 g_strlcpy ((gchar*)aname->public_key_token, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH);
2536 len = mono_metadata_decode_blob_size ((const gchar *) pkey, (const gchar **) &pkeyptr);
2537 // We also need to generate the key token
2538 mono_digest_get_public_token ((guchar*) tok, (guint8*) pkeyptr, len);
2539 encoded = encode_public_tok ((guchar*) tok, 8);
2540 g_strlcpy ((gchar*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
2543 if (save_public_key)
2544 aname->public_key = (guint8*) pkey;
2553 parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
2558 parts = g_strsplit (dirname, "_", 3);
2559 if (!parts || !parts[0] || !parts[1] || !parts[2]) {
2564 res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, 0, aname, FALSE);
2570 split_key_value (const gchar *pair, gchar **key, guint32 *keylen, gchar **value)
2572 char *eqsign = strchr (pair, '=');
2580 *key = (gchar*)pair;
2581 *keylen = eqsign - *key;
2582 while (*keylen > 0 && g_ascii_isspace ((*key) [*keylen - 1]))
2584 *value = g_strstrip (eqsign + 1);
2589 mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
2593 gchar *version = NULL;
2595 gchar *culture = NULL;
2597 gchar *token = NULL;
2601 gchar *retargetable = NULL;
2602 gchar *retargetable_uq;
2606 gchar *value, *part_name;
2607 guint32 part_name_len;
2610 gboolean version_defined;
2611 gboolean token_defined;
2613 guint32 arch = MONO_PROCESSOR_ARCHITECTURE_NONE;
2615 if (!is_version_defined)
2616 is_version_defined = &version_defined;
2617 *is_version_defined = FALSE;
2618 if (!is_token_defined)
2619 is_token_defined = &token_defined;
2620 *is_token_defined = FALSE;
2622 parts = tmp = g_strsplit (name, ",", 6);
2623 if (!tmp || !*tmp) {
2628 dllname = g_strstrip (*tmp);
2633 if (!split_key_value (g_strstrip (*tmp), &part_name, &part_name_len, &value))
2634 goto cleanup_and_fail;
2636 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Version", part_name_len)) {
2637 *is_version_defined = TRUE;
2639 if (strlen (version) == 0) {
2640 goto cleanup_and_fail;
2646 if (part_name_len == 7 && !g_ascii_strncasecmp (part_name, "Culture", part_name_len)) {
2648 if (strlen (culture) == 0) {
2649 goto cleanup_and_fail;
2655 if (part_name_len == 14 && !g_ascii_strncasecmp (part_name, "PublicKeyToken", part_name_len)) {
2656 *is_token_defined = TRUE;
2658 if (strlen (token) == 0) {
2659 goto cleanup_and_fail;
2665 if (part_name_len == 9 && !g_ascii_strncasecmp (part_name, "PublicKey", part_name_len)) {
2667 if (strlen (key) == 0) {
2668 goto cleanup_and_fail;
2674 if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
2675 retargetable = value;
2676 retargetable_uq = unquote (retargetable);
2677 if (retargetable_uq != NULL)
2678 retargetable = retargetable_uq;
2680 if (!g_ascii_strcasecmp (retargetable, "yes")) {
2681 flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
2682 } else if (g_ascii_strcasecmp (retargetable, "no")) {
2683 g_free (retargetable_uq);
2684 goto cleanup_and_fail;
2687 g_free (retargetable_uq);
2692 if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
2694 procarch_uq = unquote (procarch);
2695 if (procarch_uq != NULL)
2696 procarch = procarch_uq;
2698 if (!g_ascii_strcasecmp (procarch, "MSIL"))
2699 arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
2700 else if (!g_ascii_strcasecmp (procarch, "X86"))
2701 arch = MONO_PROCESSOR_ARCHITECTURE_X86;
2702 else if (!g_ascii_strcasecmp (procarch, "IA64"))
2703 arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
2704 else if (!g_ascii_strcasecmp (procarch, "AMD64"))
2705 arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
2707 g_free (procarch_uq);
2708 goto cleanup_and_fail;
2711 g_free (procarch_uq);
2720 /* if retargetable flag is set, then we must have a fully qualified name */
2721 if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
2722 goto cleanup_and_fail;
2725 dllname_uq = unquote (dllname);
2726 version_uq = unquote (version);
2727 culture_uq = unquote (culture);
2728 token_uq = unquote (token);
2729 key_uq = unquote (key);
2731 res = build_assembly_name (
2732 dllname_uq == NULL ? dllname : dllname_uq,
2733 version_uq == NULL ? version : version_uq,
2734 culture_uq == NULL ? culture : culture_uq,
2735 token_uq == NULL ? token : token_uq,
2736 key_uq == NULL ? key : key_uq,
2737 flags, arch, aname, save_public_key);
2739 g_free (dllname_uq);
2740 g_free (version_uq);
2741 g_free (culture_uq);
2754 unquote (const char *str)
2762 slen = strlen (str);
2766 if (*str != '\'' && *str != '\"')
2769 end = str + slen - 1;
2773 return g_strndup (str + 1, slen - 2);
2777 * mono_assembly_name_parse:
2778 * \param name name to parse
2779 * \param aname the destination assembly name
2781 * Parses an assembly qualified type name and assigns the name,
2782 * version, culture and token to the provided assembly name object.
2784 * \returns TRUE if the name could be parsed.
2787 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
2789 return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
2793 * mono_assembly_name_new:
2794 * \param name name to parse
2796 * Allocate a new \c MonoAssemblyName and fill its values from the
2799 * \returns a newly allocated structure or NULL if there was any failure.
2802 mono_assembly_name_new (const char *name)
2804 MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1);
2805 if (mono_assembly_name_parse (name, aname))
2812 * mono_assembly_name_get_name:
2815 mono_assembly_name_get_name (MonoAssemblyName *aname)
2821 * mono_assembly_name_get_culture:
2824 mono_assembly_name_get_culture (MonoAssemblyName *aname)
2826 return aname->culture;
2830 * mono_assembly_name_get_pubkeytoken:
2833 mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname)
2835 if (aname->public_key_token [0])
2836 return aname->public_key_token;
2841 * mono_assembly_name_get_version:
2844 mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision)
2847 *minor = aname->minor;
2849 *build = aname->build;
2851 *revision = aname->revision;
2852 return aname->major;
2855 static MonoAssembly*
2856 probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
2858 gchar *fullpath = NULL;
2860 const char* direntry;
2861 MonoAssemblyName gac_aname;
2862 gint major=-1, minor=0, build=0, revision=0;
2863 gboolean exact_version;
2865 dirhandle = g_dir_open (basepath, 0, NULL);
2869 exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
2871 while ((direntry = g_dir_read_name (dirhandle))) {
2872 gboolean match = TRUE;
2874 if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
2877 if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
2880 if (match && strlen ((char*)aname->public_key_token) > 0 &&
2881 !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
2885 if (exact_version) {
2886 match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
2887 aname->build == gac_aname.build && aname->revision == gac_aname.revision);
2889 else if (gac_aname.major < major)
2891 else if (gac_aname.major == major) {
2892 if (gac_aname.minor < minor)
2894 else if (gac_aname.minor == minor) {
2895 if (gac_aname.build < build)
2897 else if (gac_aname.build == build && gac_aname.revision <= revision)
2904 major = gac_aname.major;
2905 minor = gac_aname.minor;
2906 build = gac_aname.build;
2907 revision = gac_aname.revision;
2909 fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
2912 mono_assembly_name_free (&gac_aname);
2915 g_dir_close (dirhandle);
2917 if (fullpath == NULL)
2920 MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
2927 * mono_assembly_load_with_partial_name:
2928 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
2929 * \param status return status code
2931 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
2932 * so it might contain a qualified type name, version, culture and token.
2934 * This will load the assembly from the file whose name is derived from the assembly name
2935 * by appending the \c .dll extension.
2937 * The assembly is loaded from either one of the extra Global Assembly Caches specified
2938 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
2939 * if that fails from the GAC.
2941 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
2944 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
2948 MonoAssemblyName *aname, base_name;
2949 MonoAssemblyName mapped_aname;
2950 gchar *fullname, *gacpath;
2953 memset (&base_name, 0, sizeof (MonoAssemblyName));
2956 if (!mono_assembly_name_parse (name, aname))
2960 * If no specific version has been requested, make sure we load the
2961 * correct version for system assemblies.
2963 if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
2964 aname = mono_assembly_remap_version (aname, &mapped_aname);
2966 res = mono_assembly_loaded (aname);
2968 mono_assembly_name_free (aname);
2972 res = invoke_assembly_preload_hook (aname, assemblies_path);
2974 res->in_gac = FALSE;
2975 mono_assembly_name_free (aname);
2979 fullname = g_strdup_printf ("%s.dll", aname->name);
2981 if (extra_gac_paths) {
2982 paths = extra_gac_paths;
2983 while (!res && *paths) {
2984 gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
2985 res = probe_for_partial_name (gacpath, fullname, aname, status);
2994 mono_assembly_name_free (aname);
2998 gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
2999 res = probe_for_partial_name (gacpath, fullname, aname, status);
3003 mono_assembly_name_free (aname);
3008 MonoDomain *domain = mono_domain_get ();
3010 res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
3011 if (!is_ok (&error)) {
3012 mono_error_cleanup (&error);
3013 if (*status == MONO_IMAGE_OK)
3014 *status = MONO_IMAGE_IMAGE_INVALID;
3022 mono_assembly_is_in_gac (const gchar *filename)
3024 const gchar *rootdir;
3028 if (filename == NULL)
3031 for (paths = extra_gac_paths; paths && *paths; paths++) {
3032 if (strstr (*paths, filename) != *paths)
3035 gp = (gchar *) (filename + strlen (*paths));
3036 if (*gp != G_DIR_SEPARATOR)
3039 if (strncmp (gp, "lib", 3))
3042 if (*gp != G_DIR_SEPARATOR)
3045 if (strncmp (gp, "mono", 4))
3048 if (*gp != G_DIR_SEPARATOR)
3051 if (strncmp (gp, "gac", 3))
3054 if (*gp != G_DIR_SEPARATOR)
3060 rootdir = mono_assembly_getrootdir ();
3061 if (strstr (filename, rootdir) != filename)
3064 gp = (gchar *) (filename + strlen (rootdir));
3065 if (*gp != G_DIR_SEPARATOR)
3068 if (strncmp (gp, "mono", 4))
3071 if (*gp != G_DIR_SEPARATOR)
3074 if (strncmp (gp, "gac", 3))
3077 if (*gp != G_DIR_SEPARATOR)
3083 mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
3086 gchar *filename, *pname, *name, *culture, *version, *fullpath, *subpath;
3090 if (strstr (aname->name, ".dll")) {
3091 len = strlen (aname->name) - 4;
3092 name = (gchar *)g_malloc (len + 1);
3093 memcpy (name, aname->name, len);
3096 name = g_strdup (aname->name);
3099 culture = g_utf8_strdown (aname->culture, -1);
3101 culture = g_strdup ("");
3103 pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name);
3104 version = g_strdup_printf ("0.0.0.0_%s_%s", culture, aname->public_key_token);
3108 filename = g_strconcat (pname, ".dll", NULL);
3109 subpath = g_build_path (G_DIR_SEPARATOR_S, pname, version, filename, NULL);
3115 if (extra_gac_paths) {
3116 paths = extra_gac_paths;
3117 while (!image && *paths) {
3118 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths,
3119 "lib", "mono", "gac", subpath, NULL);
3120 image = mono_image_open (fullpath, NULL);
3131 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3132 "mono", "gac", subpath, NULL);
3133 image = mono_image_open (fullpath, NULL);
3140 static MonoAssemblyName*
3141 mono_assembly_bind_version (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3143 memcpy (dest_name, aname, sizeof (MonoAssemblyName));
3144 dest_name->major = info->new_version.major;
3145 dest_name->minor = info->new_version.minor;
3146 dest_name->build = info->new_version.build;
3147 dest_name->revision = info->new_version.revision;
3152 /* LOCKING: assembly_binding lock must be held */
3153 static MonoAssemblyBindingInfo*
3154 search_binding_loaded (MonoAssemblyName *aname)
3158 for (tmp = loaded_assembly_bindings; tmp; tmp = tmp->next) {
3159 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)tmp->data;
3160 if (assembly_binding_maps_name (info, aname))
3167 static inline gboolean
3168 info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
3170 if (left->major != right->major || left->minor != right->minor ||
3171 left->build != right->build || left->revision != right->revision)
3177 static inline gboolean
3178 info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
3180 if (left->has_old_version_bottom != right->has_old_version_bottom)
3183 if (left->has_old_version_top != right->has_old_version_top)
3186 if (left->has_new_version != right->has_new_version)
3189 if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
3192 if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
3195 if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
3201 /* LOCKING: assumes all the necessary locks are held */
3203 assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
3205 MonoAssemblyBindingInfo *info_copy;
3207 MonoAssemblyBindingInfo *info_tmp;
3208 MonoDomain *domain = (MonoDomain*)user_data;
3213 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)) {
3214 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3215 info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
3219 for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
3220 info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
3221 if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
3225 info_copy = (MonoAssemblyBindingInfo *)mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
3226 memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
3228 info_copy->name = mono_mempool_strdup (domain->mp, info->name);
3230 info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
3232 domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
3236 get_version_number (int major, int minor)
3238 return major * 256 + minor;
3241 static inline gboolean
3242 info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
3244 int aname_version_number = get_version_number (aname->major, aname->minor);
3245 if (!info->has_old_version_bottom)
3248 if (get_version_number (info->old_version_bottom.major, info->old_version_bottom.minor) > aname_version_number)
3251 if (info->has_old_version_top && get_version_number (info->old_version_top.major, info->old_version_top.minor) < aname_version_number)
3254 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3255 info->major = aname->major;
3256 info->minor = aname->minor;
3261 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3262 static MonoAssemblyBindingInfo*
3263 get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
3265 MonoAssemblyBindingInfo *info;
3268 if (!domain->assembly_bindings)
3272 for (list = domain->assembly_bindings; list; list = list->next) {
3273 info = (MonoAssemblyBindingInfo *)list->data;
3274 if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
3280 if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
3281 info->has_new_version && assembly_binding_maps_name (info, aname))
3282 info->is_valid = TRUE;
3284 info->is_valid = FALSE;
3291 mono_domain_parse_assembly_bindings (MonoDomain *domain, int amajor, int aminor, gchar *domain_config_file_name)
3293 if (domain->assembly_bindings_parsed)
3295 mono_domain_lock (domain);
3296 if (!domain->assembly_bindings_parsed) {
3298 gchar *domain_config_file_path = mono_portability_find_file (domain_config_file_name, TRUE);
3300 if (!domain_config_file_path)
3301 domain_config_file_path = domain_config_file_name;
3303 mono_config_parse_assembly_bindings (domain_config_file_path, amajor, aminor, domain, assembly_binding_info_parsed);
3304 domain->assembly_bindings_parsed = TRUE;
3305 if (domain_config_file_name != domain_config_file_path)
3306 g_free (domain_config_file_path);
3309 mono_domain_unlock (domain);
3312 static MonoAssemblyName*
3313 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
3316 MonoAssemblyBindingInfo *info, *info2;
3320 if (aname->public_key_token [0] == 0)
3323 domain = mono_domain_get ();
3325 mono_assembly_binding_lock ();
3326 info = search_binding_loaded (aname);
3327 mono_assembly_binding_unlock ();
3330 mono_domain_lock (domain);
3331 info = get_per_domain_assembly_binding_info (domain, aname);
3332 mono_domain_unlock (domain);
3336 if (!check_policy_versions (info, aname))
3339 mono_assembly_bind_version (info, aname, dest_name);
3343 if (domain && domain->setup && domain->setup->configuration_file) {
3344 gchar *domain_config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
3345 /* expect this to succeed because mono_domain_set_options_from_config () did
3346 * the same thing when the domain was created. */
3347 mono_error_assert_ok (&error);
3348 mono_domain_parse_assembly_bindings (domain, aname->major, aname->minor, domain_config_file_name);
3349 g_free (domain_config_file_name);
3351 mono_domain_lock (domain);
3352 info2 = get_per_domain_assembly_binding_info (domain, aname);
3355 info = (MonoAssemblyBindingInfo *)g_memdup (info2, sizeof (MonoAssemblyBindingInfo));
3356 info->name = g_strdup (info2->name);
3357 info->culture = g_strdup (info2->culture);
3358 info->domain_id = domain->domain_id;
3361 mono_domain_unlock (domain);
3366 info = g_new0 (MonoAssemblyBindingInfo, 1);
3367 info->major = aname->major;
3368 info->minor = aname->minor;
3371 if (!info->is_valid) {
3372 ppimage = mono_assembly_load_publisher_policy (aname);
3374 get_publisher_policy_info (ppimage, aname, info);
3375 mono_image_close (ppimage);
3379 /* Define default error value if needed */
3380 if (!info->is_valid) {
3381 info->name = g_strdup (aname->name);
3382 info->culture = g_strdup (aname->culture);
3383 g_strlcpy ((char *)info->public_key_token, (const char *)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3386 mono_assembly_binding_lock ();
3387 info2 = search_binding_loaded (aname);
3389 /* This binding was added by another thread
3391 mono_assembly_binding_info_free (info);
3396 loaded_assembly_bindings = g_slist_prepend (loaded_assembly_bindings, info);
3398 mono_assembly_binding_unlock ();
3400 if (!info->is_valid || !check_policy_versions (info, aname))
3403 mono_assembly_bind_version (info, aname, dest_name);
3408 * mono_assembly_load_from_gac
3410 * \param aname The assembly name object
3412 static MonoAssembly*
3413 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status, MonoBoolean refonly)
3415 MonoAssembly *result = NULL;
3416 gchar *name, *version, *culture, *fullpath, *subpath;
3421 if (aname->public_key_token [0] == 0) {
3425 if (strstr (aname->name, ".dll")) {
3426 len = strlen (filename) - 4;
3427 name = (gchar *)g_malloc (len + 1);
3428 memcpy (name, aname->name, len);
3431 name = g_strdup (aname->name);
3434 if (aname->culture) {
3435 culture = g_utf8_strdown (aname->culture, -1);
3437 culture = g_strdup ("");
3440 pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
3441 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
3442 aname->minor, aname->build, aname->revision,
3446 subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
3451 if (extra_gac_paths) {
3452 paths = extra_gac_paths;
3453 while (!result && *paths) {
3454 fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
3455 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3462 result->in_gac = TRUE;
3467 fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
3468 "mono", "gac", subpath, NULL);
3469 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
3473 result->in_gac = TRUE;
3481 mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status)
3484 MonoAssemblyName *aname;
3487 /* g_print ("corlib already loaded\n"); */
3491 // In native client, Corlib is embedded in the executable as static variable corlibData
3492 #if defined(__native_client__)
3493 if (corlibData != NULL && corlibSize != 0) {
3495 /* First "FALSE" instructs mono not to make a copy. */
3496 /* Second "FALSE" says this is not just a ref. */
3497 MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE);
3498 if (image == NULL || status != 0)
3499 g_print("mono_image_open_from_data_full failed: %d\n", status);
3500 corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE);
3501 if (corlib == NULL || status != 0)
3502 g_print ("mono_assembly_load_from_full failed: %d\n", status);
3508 // A nonstandard preload hook may provide a special mscorlib assembly
3509 aname = mono_assembly_name_new ("mscorlib.dll");
3510 corlib = invoke_assembly_preload_hook (aname, assemblies_path);
3511 mono_assembly_name_free (aname);
3514 goto return_corlib_and_facades;
3516 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3517 if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3518 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
3520 goto return_corlib_and_facades;
3523 /* Normal case: Load corlib from mono/<version> */
3524 corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
3525 if (assemblies_path) { // Custom assemblies path
3526 corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
3528 g_free (corlib_file);
3529 goto return_corlib_and_facades;
3532 corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
3533 g_free (corlib_file);
3535 return_corlib_and_facades:
3536 if (corlib && !strcmp (runtime->framework_version, "4.5")) // FIXME: stop hardcoding 4.5 here
3537 default_path [1] = g_strdup_printf ("%s/Facades", corlib->basedir);
3542 static MonoAssembly*
3543 prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
3545 MonoError refasm_error;
3546 error_init (&refasm_error);
3547 if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
3550 mono_error_cleanup (&refasm_error);
3555 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
3557 MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
3558 MonoAssemblyName *candidate_name = &candidate->aname;
3560 g_assert (wanted_name != NULL);
3561 g_assert (candidate_name != NULL);
3563 if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
3564 char * s = mono_stringify_assembly_name (wanted_name);
3565 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
3567 s = mono_stringify_assembly_name (candidate_name);
3568 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
3573 /* Wanted name has no token, not strongly named: always matches. */
3574 if (0 == wanted_name->public_key_token [0]) {
3575 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
3579 /* Candidate name has no token, not strongly named: never matches */
3580 if (0 == candidate_name->public_key_token [0]) {
3581 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
3585 return exact_sn_match (wanted_name, candidate_name) ||
3586 framework_assembly_sn_match (wanted_name, candidate_name);
3590 exact_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3592 gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
3594 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
3595 result ? "match, returning TRUE" : "don't match, returning FALSE");
3601 framework_assembly_sn_match (MonoAssemblyName *wanted_name, MonoAssemblyName *candidate_name)
3603 #ifndef DISABLE_ASSEMBLY_REMAPPING
3604 const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, wanted_name->name);
3606 if (!vmap->framework_facade_assembly) {
3607 /* 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. */
3608 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_PUBKEY);
3609 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");
3612 /* For facades, the name and public key token should
3613 * match, but the version doesn't matter. */
3614 gboolean result = assembly_names_equal_flags (wanted_name, candidate_name, ANAME_EQ_IGNORE_VERSION);
3615 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");
3624 mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
3625 const char *basedir,
3626 MonoImageOpenStatus *status,
3629 MonoAssembly *result;
3630 char *fullpath, *filename;
3631 MonoAssemblyName maped_aname;
3632 MonoAssemblyName maped_name_pp;
3637 aname = mono_assembly_remap_version (aname, &maped_aname);
3639 /* Reflection only assemblies don't get assembly binding */
3641 aname = mono_assembly_apply_binding (aname, &maped_name_pp);
3643 result = mono_assembly_loaded_full (aname, refonly);
3647 result = refonly ? invoke_assembly_refonly_preload_hook (aname, assemblies_path) : invoke_assembly_preload_hook (aname, assemblies_path);
3649 result->in_gac = FALSE;
3653 /* Currently we retrieve the loaded corlib for reflection
3654 * only requests, like a common reflection only assembly
3656 if (strcmp (aname->name, "mscorlib") == 0 || strcmp (aname->name, "mscorlib.dll") == 0) {
3657 return mono_assembly_load_corlib (mono_get_runtime_info (), status);
3660 len = strlen (aname->name);
3661 for (ext_index = 0; ext_index < 2; ext_index ++) {
3662 ext = ext_index == 0 ? ".dll" : ".exe";
3663 if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
3664 filename = g_strdup (aname->name);
3665 /* Don't try appending .dll/.exe if it already has one of those extensions */
3668 filename = g_strconcat (aname->name, ext, NULL);
3671 result = mono_assembly_load_from_gac (aname, filename, status, refonly);
3678 fullpath = g_build_filename (basedir, filename, NULL);
3679 result = mono_assembly_open_predicate (fullpath, refonly, FALSE, &mono_assembly_candidate_predicate_sn_same_name, aname, status);
3682 result->in_gac = FALSE;
3688 result = load_in_path (filename, default_path, status, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
3690 result->in_gac = FALSE;
3700 mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3702 MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
3705 /* Try a postload search hook */
3706 result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
3707 result = prevent_reference_assembly_from_running (result, refonly);
3713 * mono_assembly_load_full:
3714 * \param aname A MonoAssemblyName with the assembly name to load.
3715 * \param basedir A directory to look up the assembly at.
3716 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3717 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3719 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3720 * attempts to load the assembly from that directory before probing the standard locations.
3722 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
3723 * assembly binding takes place.
3725 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3726 * value pointed by \p status is updated with an error code.
3729 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
3731 return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
3735 * mono_assembly_load:
3736 * \param aname A MonoAssemblyName with the assembly name to load.
3737 * \param basedir A directory to look up the assembly at.
3738 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
3740 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
3741 * attempts to load the assembly from that directory before probing the standard locations.
3743 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
3744 * value pointed by \p status is updated with an error code.
3747 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
3749 return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
3753 * mono_assembly_loaded_full:
3754 * \param aname an assembly to look for.
3755 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3757 * This is used to determine if the specified assembly has been loaded
3758 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3759 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3762 mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
3765 MonoAssemblyName maped_aname;
3767 aname = mono_assembly_remap_version (aname, &maped_aname);
3769 res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
3775 * mono_assembly_loaded:
3776 * \param aname an assembly to look for.
3778 * This is used to determine if the specified assembly has been loaded
3780 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
3781 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
3784 mono_assembly_loaded (MonoAssemblyName *aname)
3786 return mono_assembly_loaded_full (aname, FALSE);
3790 mono_assembly_release_gc_roots (MonoAssembly *assembly)
3792 if (assembly == NULL || assembly == REFERENCE_MISSING)
3795 if (assembly_is_dynamic (assembly)) {
3797 MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
3798 for (i = 0; i < dynimg->image.module_count; ++i)
3799 mono_dynamic_image_release_gc_roots ((MonoDynamicImage *)dynimg->image.modules [i]);
3800 mono_dynamic_image_release_gc_roots (dynimg);
3805 * Returns whether mono_assembly_close_finish() must be called as
3806 * well. See comment for mono_image_close_except_pools() for why we
3807 * unload in two steps.
3810 mono_assembly_close_except_image_pools (MonoAssembly *assembly)
3813 g_return_val_if_fail (assembly != NULL, FALSE);
3815 if (assembly == REFERENCE_MISSING)
3818 /* Might be 0 already */
3819 if (InterlockedDecrement (&assembly->ref_count) > 0)
3822 mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
3824 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
3826 mono_debug_close_image (assembly->image);
3828 mono_assemblies_lock ();
3829 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
3830 mono_assemblies_unlock ();
3832 assembly->image->assembly = NULL;
3834 if (!mono_image_close_except_pools (assembly->image))
3835 assembly->image = NULL;
3837 for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) {
3838 MonoAssemblyName *fname = (MonoAssemblyName *)tmp->data;
3839 mono_assembly_name_free (fname);
3842 g_slist_free (assembly->friend_assembly_names);
3843 g_free (assembly->basedir);
3845 mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
3851 mono_assembly_close_finish (MonoAssembly *assembly)
3853 g_assert (assembly && assembly != REFERENCE_MISSING);
3855 if (assembly->image)
3856 mono_image_close_finish (assembly->image);
3858 if (assembly_is_dynamic (assembly)) {
3859 g_free ((char*)assembly->aname.culture);
3866 * mono_assembly_close:
3867 * \param assembly the assembly to release.
3869 * This method releases a reference to the \p assembly. The assembly is
3870 * only released when all the outstanding references to it are released.
3873 mono_assembly_close (MonoAssembly *assembly)
3875 if (mono_assembly_close_except_image_pools (assembly))
3876 mono_assembly_close_finish (assembly);
3880 * mono_assembly_load_module:
3883 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
3886 MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
3887 mono_error_assert_ok (&error);
3892 mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
3894 return mono_image_load_file_for_image_checked (assembly->image, idx, error);
3899 * mono_assembly_foreach:
3900 * \param func function to invoke for each assembly loaded
3901 * \param user_data data passed to the callback
3903 * Invokes the provided \p func callback for each assembly loaded into
3904 * the runtime. The first parameter passed to the callback is the
3905 * \c MonoAssembly*, and the second parameter is the \p user_data.
3907 * This is done for all assemblies loaded in the runtime, not just
3908 * those loaded in the current application domain.
3911 mono_assembly_foreach (GFunc func, gpointer user_data)
3916 * We make a copy of the list to avoid calling the callback inside the
3917 * lock, which could lead to deadlocks.
3919 mono_assemblies_lock ();
3920 copy = g_list_copy (loaded_assemblies);
3921 mono_assemblies_unlock ();
3923 g_list_foreach (loaded_assemblies, func, user_data);
3929 * mono_assemblies_cleanup:
3931 * Free all resources used by this module.
3934 mono_assemblies_cleanup (void)
3938 mono_os_mutex_destroy (&assemblies_mutex);
3939 mono_os_mutex_destroy (&assembly_binding_mutex);
3941 for (l = loaded_assembly_bindings; l; l = l->next) {
3942 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3944 mono_assembly_binding_info_free (info);
3947 g_slist_free (loaded_assembly_bindings);
3949 free_assembly_load_hooks ();
3950 free_assembly_search_hooks ();
3951 free_assembly_preload_hooks ();
3954 /*LOCKING takes the assembly_binding lock*/
3956 mono_assembly_cleanup_domain_bindings (guint32 domain_id)
3960 mono_assembly_binding_lock ();
3961 iter = &loaded_assembly_bindings;
3964 MonoAssemblyBindingInfo *info = (MonoAssemblyBindingInfo *)l->data;
3966 if (info->domain_id == domain_id) {
3968 mono_assembly_binding_info_free (info);
3975 mono_assembly_binding_unlock ();
3979 * Holds the assembly of the application, for
3980 * System.Diagnostics.Process::MainModule
3982 static MonoAssembly *main_assembly=NULL;
3985 * mono_assembly_set_main:
3988 mono_assembly_set_main (MonoAssembly *assembly)
3990 main_assembly = assembly;
3994 * mono_assembly_get_main:
3996 * Returns: the assembly for the application, the first assembly that is loaded by the VM
3999 mono_assembly_get_main (void)
4001 return (main_assembly);
4005 * mono_assembly_get_image:
4006 * \param assembly The assembly to retrieve the image from
4008 * \returns the \c MonoImage associated with this assembly.
4011 mono_assembly_get_image (MonoAssembly *assembly)
4013 return assembly->image;
4017 * mono_assembly_get_name:
4018 * \param assembly The assembly to retrieve the name from
4020 * The returned name's lifetime is the same as \p assembly's.
4022 * \returns the \c MonoAssemblyName associated with this assembly.
4025 mono_assembly_get_name (MonoAssembly *assembly)
4027 return &assembly->aname;
4031 * mono_register_bundled_assemblies:
4034 mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
4036 bundles = assemblies;
4039 #define MONO_DECLSEC_FORMAT_10 0x3C
4040 #define MONO_DECLSEC_FORMAT_20 0x2E
4041 #define MONO_DECLSEC_FIELD 0x53
4042 #define MONO_DECLSEC_PROPERTY 0x54
4044 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4045 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4046 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4047 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4048 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4051 mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding)
4055 case MONO_DECLSEC_PROPERTY:
4057 case MONO_DECLSEC_FIELD:
4059 *abort_decoding = TRUE;
4064 if (*p++ != MONO_TYPE_BOOLEAN) {
4065 *abort_decoding = TRUE;
4069 /* property name length */
4070 len = mono_metadata_decode_value (p, &p);
4072 if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) {
4083 mono_assembly_try_decode_skip_verification (const char *p, const char *endn)
4085 int i, j, num, len, params_len;
4087 if (*p == MONO_DECLSEC_FORMAT_10) {
4088 gsize read, written;
4089 char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL);
4091 gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL;
4097 if (*p++ != MONO_DECLSEC_FORMAT_20)
4100 /* number of encoded permission attributes */
4101 num = mono_metadata_decode_value (p, &p);
4102 for (i = 0; i < num; ++i) {
4103 gboolean is_valid = FALSE;
4104 gboolean abort_decoding = FALSE;
4106 /* attribute name length */
4107 len = mono_metadata_decode_value (p, &p);
4109 /* We don't really need to fully decode the type. Comparing the name is enough */
4110 is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE);
4114 /*size of the params table*/
4115 params_len = mono_metadata_decode_value (p, &p);
4117 const char *params_end = p + params_len;
4119 /* number of parameters */
4120 len = mono_metadata_decode_value (p, &p);
4122 for (j = 0; j < len; ++j) {
4123 if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding))
4139 mono_assembly_has_skip_verification (MonoAssembly *assembly)
4142 guint32 cols [MONO_DECL_SECURITY_SIZE];
4146 if (MONO_SECMAN_FLAG_INIT (assembly->skipverification))
4147 return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification);
4149 t = &assembly->image->tables [MONO_TABLE_DECLSECURITY];
4151 for (i = 0; i < t->rows; ++i) {
4152 mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE);
4153 if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY)
4155 if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN)
4158 blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]);
4159 len = mono_metadata_decode_blob_size (blob, &blob);
4163 if (mono_assembly_try_decode_skip_verification (blob, blob + len)) {
4164 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE);
4169 MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE);