3 * Routines for loading assemblies.
6 * Miguel de Icaza (miguel@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "assembly-internals.h"
22 #include "image-internals.h"
23 #include "object-internals.h"
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/custom-attrs-internals.h>
27 #include <mono/metadata/metadata-internals.h>
28 #include <mono/metadata/profiler-private.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/domain-internals.h>
31 #include <mono/metadata/reflection-internals.h>
32 #include <mono/metadata/mono-endian.h>
33 #include <mono/metadata/mono-debug.h>
34 #include <mono/utils/mono-uri.h>
35 #include <mono/metadata/mono-config.h>
36 #include <mono/metadata/mono-config-dirs.h>
37 #include <mono/utils/mono-digest.h>
38 #include <mono/utils/mono-logger-internals.h>
39 #include <mono/utils/mono-path.h>
40 #include <mono/metadata/reflection.h>
41 #include <mono/metadata/coree.h>
42 #include <mono/metadata/cil-coff.h>
43 #include <mono/utils/mono-io-portability.h>
44 #include <mono/utils/atomic.h>
45 #include <mono/utils/mono-os-mutex.h>
48 #include <sys/types.h>
54 #include <mach-o/dyld.h>
57 /* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
59 const char* assembly_name
;
60 guint8 version_set_index
;
61 const char* new_assembly_name
;
62 gboolean only_lower_versions
;
63 gboolean framework_facade_assembly
;
66 /* the default search path is empty, the first slot is replaced with the computed value */
74 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
75 static char **assemblies_path
= NULL
;
77 /* Contains the list of directories that point to auxiliary GACs */
78 static char **extra_gac_paths
= NULL
;
80 #ifndef DISABLE_DESKTOP_LOADER
82 #define FACADE_ASSEMBLY(str) {str, 0, NULL, FALSE, TRUE}
84 static GHashTable
* assembly_remapping_table
;
85 /* The list of system assemblies what will be remapped to the running
87 * This list is stored in @assembly_remapping_table during initialization.
88 * Keep it sorted just to make maintenance easier.
90 * The integer number is an index in the MonoRuntimeInfo structure, whose
91 * values can be found in domain.c - supported_runtimes. Look there
92 * to understand what remapping will be made.
94 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
97 static const AssemblyVersionMap framework_assemblies
[] = {
99 {"Commons.Xml.Relaxng", 0},
106 {"Microsoft.Build.Engine", 2, NULL
, TRUE
},
107 {"Microsoft.Build.Framework", 2, NULL
, TRUE
},
108 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
109 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
110 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
111 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
112 {"Microsoft.VisualBasic", 1},
113 {"Microsoft.VisualC", 1},
114 FACADE_ASSEMBLY ("Microsoft.Win32.Primitives"),
115 FACADE_ASSEMBLY ("Microsoft.Win32.Registry"),
116 FACADE_ASSEMBLY ("Microsoft.Win32.Registry.AccessControl"),
118 {"Mono.CompilerServices.SymbolWriter", 0},
120 {"Mono.Data.SybaseClient", 0},
121 {"Mono.Data.Tds", 0},
122 {"Mono.Data.TdsClient", 0},
123 {"Mono.GetOptions", 0},
126 {"Mono.Security", 0},
127 {"Mono.Security.Win32", 0},
129 {"Novell.Directory.Ldap", 0},
132 FACADE_ASSEMBLY ("System.AppContext"),
133 FACADE_ASSEMBLY ("System.Collections"),
134 FACADE_ASSEMBLY ("System.Collections.Concurrent"),
135 FACADE_ASSEMBLY ("System.Collections.NonGeneric"),
136 FACADE_ASSEMBLY ("System.Collections.Specialized"),
137 FACADE_ASSEMBLY ("System.ComponentModel"),
138 FACADE_ASSEMBLY ("System.ComponentModel.Annotations"),
139 {"System.ComponentModel.Composition", 2},
140 {"System.ComponentModel.DataAnnotations", 2},
141 FACADE_ASSEMBLY ("System.ComponentModel.EventBasedAsync"),
142 FACADE_ASSEMBLY ("System.ComponentModel.Primitives"),
143 FACADE_ASSEMBLY ("System.ComponentModel.TypeConverter"),
144 {"System.Configuration", 0},
145 {"System.Configuration.Install", 0},
146 FACADE_ASSEMBLY ("System.Console"),
149 FACADE_ASSEMBLY ("System.Data.Common"),
150 {"System.Data.Linq", 2},
151 {"System.Data.OracleClient", 0},
152 {"System.Data.Services", 2},
153 {"System.Data.Services.Client", 2},
154 FACADE_ASSEMBLY ("System.Data.SqlClient"),
155 {"System.Data.SqlXml", 0},
156 {"System.Design", 0},
157 FACADE_ASSEMBLY ("System.Diagnostics.Contracts"),
158 FACADE_ASSEMBLY ("System.Diagnostics.Debug"),
159 FACADE_ASSEMBLY ("System.Diagnostics.FileVersionInfo"),
160 FACADE_ASSEMBLY ("System.Diagnostics.Process"),
161 FACADE_ASSEMBLY ("System.Diagnostics.StackTrace"),
162 FACADE_ASSEMBLY ("System.Diagnostics.TextWriterTraceListener"),
163 FACADE_ASSEMBLY ("System.Diagnostics.Tools"),
164 FACADE_ASSEMBLY ("System.Diagnostics.TraceEvent"),
165 FACADE_ASSEMBLY ("System.Diagnostics.TraceSource"),
166 FACADE_ASSEMBLY ("System.Diagnostics.Tracing"),
167 {"System.DirectoryServices", 0},
168 {"System.Drawing", 0},
169 {"System.Drawing.Design", 0},
170 FACADE_ASSEMBLY ("System.Drawing.Primitives"),
171 FACADE_ASSEMBLY ("System.Dynamic.Runtime"),
172 {"System.EnterpriseServices", 0},
173 FACADE_ASSEMBLY ("System.Globalization"),
174 FACADE_ASSEMBLY ("System.Globalization.Calendars"),
175 FACADE_ASSEMBLY ("System.Globalization.Extensions"),
176 {"System.IdentityModel", 3},
177 {"System.IdentityModel.Selectors", 3},
178 FACADE_ASSEMBLY ("System.IO"),
179 {"System.IO.Compression", 2},
180 FACADE_ASSEMBLY ("System.IO.Compression.ZipFile"),
181 FACADE_ASSEMBLY ("System.IO.FileSystem"),
182 FACADE_ASSEMBLY ("System.IO.FileSystem.AccessControl"),
183 FACADE_ASSEMBLY ("System.IO.FileSystem.DriveInfo"),
184 FACADE_ASSEMBLY ("System.IO.FileSystem.Primitives"),
185 FACADE_ASSEMBLY ("System.IO.FileSystem.Watcher"),
186 FACADE_ASSEMBLY ("System.IO.IsolatedStorage"),
187 FACADE_ASSEMBLY ("System.IO.MemoryMappedFiles"),
188 FACADE_ASSEMBLY ("System.IO.Packaging"),
189 FACADE_ASSEMBLY ("System.IO.Pipes"),
190 FACADE_ASSEMBLY ("System.IO.UnmanagedMemoryStream"),
191 FACADE_ASSEMBLY ("System.Linq"),
192 FACADE_ASSEMBLY ("System.Linq.Expressions"),
193 FACADE_ASSEMBLY ("System.Linq.Parallel"),
194 FACADE_ASSEMBLY ("System.Linq.Queryable"),
195 {"System.Management", 0},
196 {"System.Messaging", 0},
198 FACADE_ASSEMBLY ("System.Net.AuthenticationManager"),
199 FACADE_ASSEMBLY ("System.Net.Cache"),
200 {"System.Net.Http", 4},
201 {"System.Net.Http.Rtc", 0},
202 FACADE_ASSEMBLY ("System.Net.HttpListener"),
203 FACADE_ASSEMBLY ("System.Net.Mail"),
204 FACADE_ASSEMBLY ("System.Net.NameResolution"),
205 FACADE_ASSEMBLY ("System.Net.NetworkInformation"),
206 FACADE_ASSEMBLY ("System.Net.Ping"),
207 FACADE_ASSEMBLY ("System.Net.Primitives"),
208 FACADE_ASSEMBLY ("System.Net.Requests"),
209 FACADE_ASSEMBLY ("System.Net.Security"),
210 FACADE_ASSEMBLY ("System.Net.ServicePoint"),
211 FACADE_ASSEMBLY ("System.Net.Sockets"),
212 FACADE_ASSEMBLY ("System.Net.Utilities"),
213 FACADE_ASSEMBLY ("System.Net.WebHeaderCollection"),
214 FACADE_ASSEMBLY ("System.Net.WebSockets"),
215 FACADE_ASSEMBLY ("System.Net.WebSockets.Client"),
216 {"System.Numerics", 3},
217 {"System.Numerics.Vectors", 3},
218 FACADE_ASSEMBLY ("System.ObjectModel"),
219 FACADE_ASSEMBLY ("System.Reflection"),
220 FACADE_ASSEMBLY ("System.Reflection.DispatchProxy"),
221 FACADE_ASSEMBLY ("System.Reflection.Emit"),
222 FACADE_ASSEMBLY ("System.Reflection.Emit.ILGeneration"),
223 FACADE_ASSEMBLY ("System.Reflection.Emit.Lightweight"),
224 FACADE_ASSEMBLY ("System.Reflection.Extensions"),
225 FACADE_ASSEMBLY ("System.Reflection.Primitives"),
226 FACADE_ASSEMBLY ("System.Reflection.TypeExtensions"),
227 FACADE_ASSEMBLY ("System.Resources.ReaderWriter"),
228 FACADE_ASSEMBLY ("System.Resources.ResourceManager"),
229 FACADE_ASSEMBLY ("System.Runtime"),
230 FACADE_ASSEMBLY ("System.Runtime.CompilerServices.VisualC"),
231 FACADE_ASSEMBLY ("System.Runtime.Extensions"),
232 FACADE_ASSEMBLY ("System.Runtime.Handles"),
233 FACADE_ASSEMBLY ("System.Runtime.InteropServices"),
234 FACADE_ASSEMBLY ("System.Runtime.InteropServices.RuntimeInformation"),
235 FACADE_ASSEMBLY ("System.Runtime.InteropServices.WindowsRuntime"),
236 FACADE_ASSEMBLY ("System.Runtime.Loader"),
237 FACADE_ASSEMBLY ("System.Runtime.Numerics"),
238 {"System.Runtime.Remoting", 0},
239 {"System.Runtime.Serialization", 3},
240 FACADE_ASSEMBLY ("System.Runtime.Serialization.Formatters"),
241 {"System.Runtime.Serialization.Formatters.Soap", 0},
242 FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"),
243 FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"),
244 FACADE_ASSEMBLY ("System.Runtime.Serialization.Xml"),
245 {"System.Security", 0},
246 FACADE_ASSEMBLY ("System.Security.AccessControl"),
247 FACADE_ASSEMBLY ("System.Security.Claims"),
248 FACADE_ASSEMBLY ("System.Security.Cryptography.Algorithms"),
249 FACADE_ASSEMBLY ("System.Security.Cryptography.Cng"),
250 FACADE_ASSEMBLY ("System.Security.Cryptography.Csp"),
251 FACADE_ASSEMBLY ("System.Security.Cryptography.DeriveBytes"),
252 FACADE_ASSEMBLY ("System.Security.Cryptography.Encoding"),
253 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption"),
254 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Aes"),
255 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDiffieHellman"),
256 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDsa"),
257 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing"),
258 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Hashing.Algorithms"),
259 FACADE_ASSEMBLY ("System.Security.Cryptography.OpenSsl"),
260 FACADE_ASSEMBLY ("System.Security.Cryptography.Pkcs"),
261 FACADE_ASSEMBLY ("System.Security.Cryptography.Primitives"),
262 FACADE_ASSEMBLY ("System.Security.Cryptography.ProtectedData"),
263 FACADE_ASSEMBLY ("System.Security.Cryptography.RSA"),
264 FACADE_ASSEMBLY ("System.Security.Cryptography.RandomNumberGenerator"),
265 FACADE_ASSEMBLY ("System.Security.Cryptography.X509Certificates"),
266 FACADE_ASSEMBLY ("System.Security.Principal"),
267 FACADE_ASSEMBLY ("System.Security.Principal.Windows"),
268 FACADE_ASSEMBLY ("System.Security.SecureString"),
269 {"System.ServiceModel", 3},
270 FACADE_ASSEMBLY ("System.ServiceModel.Duplex"),
271 FACADE_ASSEMBLY ("System.ServiceModel.Http"),
272 FACADE_ASSEMBLY ("System.ServiceModel.NetTcp"),
273 FACADE_ASSEMBLY ("System.ServiceModel.Primitives"),
274 FACADE_ASSEMBLY ("System.ServiceModel.Security"),
275 {"System.ServiceModel.Web", 2},
276 {"System.ServiceProcess", 0},
277 FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"),
278 FACADE_ASSEMBLY ("System.Text.Encoding"),
279 FACADE_ASSEMBLY ("System.Text.Encoding.CodePages"),
280 FACADE_ASSEMBLY ("System.Text.Encoding.Extensions"),
281 FACADE_ASSEMBLY ("System.Text.RegularExpressions"),
282 FACADE_ASSEMBLY ("System.Threading"),
283 FACADE_ASSEMBLY ("System.Threading.AccessControl"),
284 FACADE_ASSEMBLY ("System.Threading.Overlapped"),
285 FACADE_ASSEMBLY ("System.Threading.Tasks"),
286 FACADE_ASSEMBLY ("System.Threading.Tasks.Parallel"),
287 FACADE_ASSEMBLY ("System.Threading.Thread"),
288 FACADE_ASSEMBLY ("System.Threading.ThreadPool"),
289 FACADE_ASSEMBLY ("System.Threading.Timer"),
290 {"System.Transactions", 0},
291 FACADE_ASSEMBLY ("System.ValueTuple"),
293 {"System.Web.Abstractions", 2},
294 {"System.Web.DynamicData", 2},
295 {"System.Web.Extensions", 2},
296 {"System.Web.Mobile", 0},
297 {"System.Web.Routing", 2},
298 {"System.Web.Services", 0},
299 {"System.Windows", 0},
300 {"System.Windows.Forms", 0},
302 {"System.Xml.Linq", 2},
303 FACADE_ASSEMBLY ("System.Xml.ReaderWriter"),
304 {"System.Xml.Serialization", 0},
305 FACADE_ASSEMBLY ("System.Xml.XDocument"),
306 FACADE_ASSEMBLY ("System.Xml.XPath"),
307 FACADE_ASSEMBLY ("System.Xml.XPath.XmlDocument"),
308 FACADE_ASSEMBLY ("System.Xml.XPath.XDocument"),
309 FACADE_ASSEMBLY ("System.Xml.XmlDocument"),
310 FACADE_ASSEMBLY ("System.Xml.XmlSerializer"),
311 FACADE_ASSEMBLY ("System.Xml.Xsl.Primitives"),
314 FACADE_ASSEMBLY ("netstandard"),
319 * keeps track of loaded assemblies
321 static GList
*loaded_assemblies
= NULL
;
322 static MonoAssembly
*corlib
;
324 static char* unquote (const char *str
);
326 /* This protects loaded_assemblies and image->references */
327 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
328 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
329 static mono_mutex_t assemblies_mutex
;
331 /* If defined, points to the bundled assembly information */
332 static const MonoBundledAssembly
**bundles
;
334 static mono_mutex_t assembly_binding_mutex
;
336 /* Loaded assembly binding info */
337 static GSList
*loaded_assembly_bindings
= NULL
;
339 /* Class lazy loading functions */
340 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible
, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
342 mono_assembly_invoke_search_hook_internal (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, gboolean refonly
, gboolean postload
);
344 mono_assembly_load_full_internal (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, const char *basedir
, MonoAssemblyContextKind asmctx
, MonoImageOpenStatus
*status
);
346 mono_assembly_load_full_gac_base_default (MonoAssemblyName
*aname
, const char *basedir
, MonoAssemblyContextKind asmctx
, MonoImageOpenStatus
*status
);
348 mono_assembly_load_full_nodomain (MonoAssemblyName
*aname
, MonoAssemblyContextKind asmctx
, MonoImageOpenStatus
*status
);
350 chain_redirections_loadfrom (MonoImage
*image
, MonoImageOpenStatus
*status
);
352 mono_problematic_image_reprobe (MonoImage
*image
, MonoImageOpenStatus
*status
);
355 mono_assembly_is_in_gac (const gchar
*filanem
);
356 static MonoAssemblyName
*
357 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
);
360 prevent_reference_assembly_from_running (MonoAssembly
* candidate
, gboolean refonly
);
362 /* Assembly name matching */
364 exact_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
);
366 framework_assembly_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
);
369 mono_asmctx_get_name (const MonoAssemblyContext
*asmctx
);
372 assembly_loadfrom_asmctx_from_path (const char *filename
, MonoAssembly
*requesting_assembly
, gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
);
375 encode_public_tok (const guchar
*token
, gint32 len
)
377 const static gchar allowed
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
381 res
= (gchar
*)g_malloc (len
* 2 + 1);
382 for (i
= 0; i
< len
; i
++) {
383 res
[i
* 2] = allowed
[token
[i
] >> 4];
384 res
[i
* 2 + 1] = allowed
[token
[i
] & 0xF];
391 * mono_public_tokens_are_equal:
392 * \param pubt1 first public key token
393 * \param pubt2 second public key token
395 * Compare two public key tokens and return TRUE is they are equal and FALSE
399 mono_public_tokens_are_equal (const unsigned char *pubt1
, const unsigned char *pubt2
)
401 return memcmp (pubt1
, pubt2
, 16) == 0;
405 * mono_set_assemblies_path:
406 * \param path list of paths that contain directories where Mono will look for assemblies
408 * Use this method to override the standard assembly lookup system and
409 * override any assemblies coming from the GAC. This is the method
410 * that supports the \c MONO_PATH variable.
412 * Notice that \c MONO_PATH and this method are really a very bad idea as
413 * it prevents the GAC from working and it prevents the standard
414 * resolution mechanisms from working. Nonetheless, for some debugging
415 * situations and bootstrapping setups, this is useful to have.
418 mono_set_assemblies_path (const char* path
)
420 char **splitted
, **dest
;
422 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
424 g_strfreev (assemblies_path
);
425 assemblies_path
= dest
= splitted
;
427 char *tmp
= *splitted
;
429 *dest
++ = mono_path_canonicalize (tmp
);
435 if (g_hasenv ("MONO_DEBUG"))
438 splitted
= assemblies_path
;
440 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
441 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted
);
448 check_path_env (void)
450 if (assemblies_path
!= NULL
)
453 char* path
= g_getenv ("MONO_PATH");
457 mono_set_assemblies_path(path
);
462 check_extra_gac_path_env (void)
465 char **splitted
, **dest
;
467 path
= g_getenv ("MONO_GAC_PREFIX");
471 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
475 g_strfreev (extra_gac_paths
);
476 extra_gac_paths
= dest
= splitted
;
484 if (!g_hasenv ("MONO_DEBUG"))
488 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
489 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted
);
496 assembly_binding_maps_name (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
498 if (!info
|| !info
->name
)
501 if (strcmp (info
->name
, aname
->name
))
504 if (info
->major
!= aname
->major
|| info
->minor
!= aname
->minor
)
507 if ((info
->culture
!= NULL
&& info
->culture
[0]) != (aname
->culture
!= NULL
&& aname
->culture
[0]))
510 if (info
->culture
&& aname
->culture
&& strcmp (info
->culture
, aname
->culture
))
513 if (!mono_public_tokens_are_equal (info
->public_key_token
, aname
->public_key_token
))
520 mono_assembly_binding_info_free (MonoAssemblyBindingInfo
*info
)
526 g_free (info
->culture
);
530 get_publisher_policy_info (MonoImage
*image
, MonoAssemblyName
*aname
, MonoAssemblyBindingInfo
*binding_info
)
533 guint32 cols
[MONO_MANIFEST_SIZE
];
534 const gchar
*filename
;
535 gchar
*subpath
, *fullpath
;
537 t
= &image
->tables
[MONO_TABLE_MANIFESTRESOURCE
];
538 /* MS Impl. accepts policy assemblies with more than
539 * one manifest resource, and only takes the first one */
541 binding_info
->is_valid
= FALSE
;
545 mono_metadata_decode_row (t
, 0, cols
, MONO_MANIFEST_SIZE
);
546 if ((cols
[MONO_MANIFEST_IMPLEMENTATION
] & MONO_IMPLEMENTATION_MASK
) != MONO_IMPLEMENTATION_FILE
) {
547 binding_info
->is_valid
= FALSE
;
551 filename
= mono_metadata_string_heap (image
, cols
[MONO_MANIFEST_NAME
]);
552 g_assert (filename
!= NULL
);
554 subpath
= g_path_get_dirname (image
->name
);
555 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, subpath
, filename
, NULL
);
556 mono_config_parse_publisher_policy (fullpath
, binding_info
);
560 /* Define the optional elements/attributes before checking */
561 if (!binding_info
->culture
)
562 binding_info
->culture
= g_strdup ("");
564 /* Check that the most important elements/attributes exist */
565 if (!binding_info
->name
|| !binding_info
->public_key_token
[0] || !binding_info
->has_old_version_bottom
||
566 !binding_info
->has_new_version
|| !assembly_binding_maps_name (binding_info
, aname
)) {
567 mono_assembly_binding_info_free (binding_info
);
568 binding_info
->is_valid
= FALSE
;
572 binding_info
->is_valid
= TRUE
;
576 compare_versions (AssemblyVersionSet
*v
, MonoAssemblyName
*aname
)
578 if (v
->major
> aname
->major
)
580 else if (v
->major
< aname
->major
)
583 if (v
->minor
> aname
->minor
)
585 else if (v
->minor
< aname
->minor
)
588 if (v
->build
> aname
->build
)
590 else if (v
->build
< aname
->build
)
593 if (v
->revision
> aname
->revision
)
595 else if (v
->revision
< aname
->revision
)
602 check_policy_versions (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*name
)
607 /* If has_old_version_top doesn't exist, we don't have an interval */
608 if (!info
->has_old_version_top
) {
609 if (compare_versions (&info
->old_version_bottom
, name
) == 0)
615 /* Check that the version defined by name is valid for the interval */
616 if (compare_versions (&info
->old_version_top
, name
) < 0)
619 /* We should be greater or equal than the small version */
620 if (compare_versions (&info
->old_version_bottom
, name
) > 0)
627 * mono_assembly_names_equal:
628 * \param l first assembly
629 * \param r second assembly.
631 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
633 * This compares the names, the cultures, the release version and their
636 * \returns TRUE if both assembly names are equal.
639 mono_assembly_names_equal (MonoAssemblyName
*l
, MonoAssemblyName
*r
)
641 return mono_assembly_names_equal_flags (l
, r
, MONO_ANAME_EQ_NONE
);
645 * mono_assembly_names_equal_flags:
646 * \param l first assembly name
647 * \param r second assembly name
648 * \param flags flags that affect what is compared.
650 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
652 * This compares the simple names and cultures and optionally the versions and
653 * public key tokens, depending on the \c flags.
655 * \returns TRUE if both assembly names are equal.
658 mono_assembly_names_equal_flags (MonoAssemblyName
*l
, MonoAssemblyName
*r
, MonoAssemblyNameEqFlags flags
)
660 if (!l
->name
|| !r
->name
)
663 if ((flags
& MONO_ANAME_EQ_IGNORE_CASE
) != 0 && g_strcasecmp (l
->name
, r
->name
))
666 if ((flags
& MONO_ANAME_EQ_IGNORE_CASE
) == 0 && strcmp (l
->name
, r
->name
))
669 if (l
->culture
&& r
->culture
&& strcmp (l
->culture
, r
->culture
))
672 if ((l
->major
!= r
->major
|| l
->minor
!= r
->minor
||
673 l
->build
!= r
->build
|| l
->revision
!= r
->revision
) &&
674 (flags
& MONO_ANAME_EQ_IGNORE_VERSION
) == 0)
675 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)))
678 if (!l
->public_key_token
[0] || !r
->public_key_token
[0] || (flags
& MONO_ANAME_EQ_IGNORE_PUBKEY
) != 0)
681 if (!mono_public_tokens_are_equal (l
->public_key_token
, r
->public_key_token
))
688 * assembly_names_compare_versions:
689 * \param l left assembly name
690 * \param r right assembly name
691 * \param maxcomps how many version components to compare, or -1 to compare all.
693 * \returns a negative if \p l is a lower version than \p r; a positive value
694 * if \p r is a lower version than \p l, or zero if \p l and \p r are equal
695 * versions (comparing upto \p maxcomps components).
697 * Components are \c major, \c minor, \c revision, and \c build. \p maxcomps 1 means just compare
698 * majors. 2 means majors then minors. etc.
701 assembly_names_compare_versions (MonoAssemblyName
*l
, MonoAssemblyName
*r
, int maxcomps
)
704 if (maxcomps
< 0) maxcomps
= 4;
705 #define CMP(field) do { \
706 if (l-> field < r-> field && i < maxcomps) return -1; \
707 if (l-> field > r-> field && i < maxcomps) return 1; \
720 static MonoAssembly
*
721 load_in_path (const char *basename
, const char** search_path
, MonoImageOpenStatus
*status
, MonoAssemblyContextKind asmctx
, MonoAssemblyCandidatePredicate predicate
, gpointer user_data
)
725 MonoAssembly
*result
;
727 for (i
= 0; search_path
[i
]; ++i
) {
728 fullpath
= g_build_filename (search_path
[i
], basename
, NULL
);
729 result
= mono_assembly_open_predicate (fullpath
, asmctx
, predicate
, user_data
, NULL
, status
);
738 * mono_assembly_setrootdir:
739 * \param root_dir The pathname of the root directory where we will locate assemblies
741 * This routine sets the internal default root directory for looking up
744 * This is used by Windows installations to compute dynamically the
745 * place where the Mono assemblies are located.
749 mono_assembly_setrootdir (const char *root_dir
)
752 * Override the MONO_ASSEMBLIES directory configured at compile time.
754 /* Leak if called more than once */
755 default_path
[0] = g_strdup (root_dir
);
759 * mono_assembly_getrootdir:
761 * Obtains the root directory used for looking up assemblies.
763 * Returns: a string with the directory, this string should not be freed.
765 G_CONST_RETURN gchar
*
766 mono_assembly_getrootdir (void)
768 return default_path
[0];
772 * mono_native_getrootdir:
774 * Obtains the root directory used for looking up native libs (.so, .dylib).
776 * Returns: a string with the directory, this string should be freed by
780 mono_native_getrootdir (void)
782 gchar
* fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL
);
788 * \param assembly_dir the base directory for assemblies
789 * \param config_dir the base directory for configuration files
791 * This routine is used internally and by developers embedding
792 * the runtime into their own applications.
794 * There are a number of cases to consider: Mono as a system-installed
795 * package that is available on the location preconfigured or Mono in
796 * a relocated location.
798 * If you are using a system-installed Mono, you can pass NULL
799 * to both parameters. If you are not, you should compute both
800 * directory values and call this routine.
802 * The values for a given PREFIX are:
804 * assembly_dir: PREFIX/lib
805 * config_dir: PREFIX/etc
807 * Notice that embedders that use Mono in a relocated way must
808 * compute the location at runtime, as they will be in control
809 * of where Mono is installed.
812 mono_set_dirs (const char *assembly_dir
, const char *config_dir
)
814 if (assembly_dir
== NULL
)
815 assembly_dir
= mono_config_get_assemblies_dir ();
816 if (config_dir
== NULL
)
817 config_dir
= mono_config_get_cfg_dir ();
818 mono_assembly_setrootdir (assembly_dir
);
819 mono_set_config_dir (config_dir
);
825 compute_base (char *path
)
827 char *p
= strrchr (path
, '/');
831 /* Not a well known Mono executable, we are embedded, cant guess the base */
832 if (strcmp (p
, "/mono") && strcmp (p
, "/mono-boehm") && strcmp (p
, "/mono-sgen") && strcmp (p
, "/pedump") && strcmp (p
, "/monodis"))
836 p
= strrchr (path
, '/');
840 if (strcmp (p
, "/bin") != 0)
849 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
852 static G_GNUC_UNUSED
void
856 char *config
, *lib
, *mono
;
861 * Only /usr prefix is treated specially
863 bindir
= mono_config_get_bin_dir ();
865 if (strncmp (exe
, bindir
, strlen (bindir
)) == 0 || (base
= compute_base (exe
)) == NULL
){
870 config
= g_build_filename (base
, "etc", NULL
);
871 lib
= g_build_filename (base
, "lib", NULL
);
872 mono
= g_build_filename (lib
, "mono/4.5", NULL
); // FIXME: stop hardcoding 4.5 here
873 if (stat (mono
, &buf
) == -1)
876 mono_set_dirs (lib
, config
);
884 #endif /* HOST_WIN32 */
889 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
890 * this auto-detects the prefix where Mono was installed.
893 mono_set_rootdir (void)
895 #if defined(HOST_WIN32) || (defined(HOST_DARWIN) && !defined(TARGET_ARM))
896 gchar
*bindir
, *installdir
, *root
, *name
, *resolvedname
, *config
;
899 name
= mono_get_module_file_name ((HMODULE
) &__ImageBase
);
903 * _NSGetExecutablePath may return -1 to indicate buf is not large
904 * enough, but we ignore that case to avoid having to do extra dynamic
905 * allocation for the path and hope that 4096 is enough - this is
906 * ok in the Linux/Solaris case below at least...
910 guint buf_size
= sizeof (buf
);
913 if (_NSGetExecutablePath (buf
, &buf_size
) == 0)
914 name
= g_strdup (buf
);
923 resolvedname
= mono_path_resolve_symlinks (name
);
925 bindir
= g_path_get_dirname (resolvedname
);
926 installdir
= g_path_get_dirname (bindir
);
927 root
= g_build_path (G_DIR_SEPARATOR_S
, installdir
, "lib", NULL
);
929 config
= g_build_filename (root
, "..", "etc", NULL
);
931 mono_set_dirs (root
, config
);
933 if (g_file_test (root
, G_FILE_TEST_EXISTS
) && g_file_test (config
, G_FILE_TEST_EXISTS
))
934 mono_set_dirs (root
, config
);
944 g_free (resolvedname
);
945 #elif defined(DISABLE_MONO_AUTODETECTION)
953 s
= readlink ("/proc/self/exe", buf
, sizeof (buf
)-1);
961 /* Solaris 10 style */
962 str
= g_strdup_printf ("/proc/%d/path/a.out", getpid ());
963 s
= readlink (str
, buf
, sizeof (buf
)-1);
975 * mono_assemblies_init:
977 * Initialize global variables used by this module.
980 mono_assemblies_init (void)
983 * Initialize our internal paths if we have not been initialized yet.
984 * This happens when embedders use Mono.
986 if (mono_assembly_getrootdir () == NULL
)
990 check_extra_gac_path_env ();
992 mono_os_mutex_init_recursive (&assemblies_mutex
);
993 mono_os_mutex_init (&assembly_binding_mutex
);
995 #ifndef DISABLE_DESKTOP_LOADER
996 assembly_remapping_table
= g_hash_table_new (g_str_hash
, g_str_equal
);
999 for (i
= 0; i
< G_N_ELEMENTS (framework_assemblies
) - 1; ++i
)
1000 g_hash_table_insert (assembly_remapping_table
, (void*)framework_assemblies
[i
].assembly_name
, (void*)&framework_assemblies
[i
]);
1003 mono_install_assembly_asmctx_from_path_hook (assembly_loadfrom_asmctx_from_path
, NULL
);
1008 mono_assembly_binding_lock (void)
1010 mono_locks_os_acquire (&assembly_binding_mutex
, AssemblyBindingLock
);
1014 mono_assembly_binding_unlock (void)
1016 mono_locks_os_release (&assembly_binding_mutex
, AssemblyBindingLock
);
1020 mono_assembly_fill_assembly_name_full (MonoImage
*image
, MonoAssemblyName
*aname
, gboolean copyBlobs
)
1022 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLY
];
1023 guint32 cols
[MONO_ASSEMBLY_SIZE
];
1024 gint32 machine
, flags
;
1029 mono_metadata_decode_row (t
, 0, cols
, MONO_ASSEMBLY_SIZE
);
1031 aname
->hash_len
= 0;
1032 aname
->hash_value
= NULL
;
1033 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_NAME
]);
1035 aname
->name
= g_strdup (aname
->name
);
1036 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_CULTURE
]);
1038 aname
->culture
= g_strdup (aname
->culture
);
1039 aname
->flags
= cols
[MONO_ASSEMBLY_FLAGS
];
1040 aname
->major
= cols
[MONO_ASSEMBLY_MAJOR_VERSION
];
1041 aname
->minor
= cols
[MONO_ASSEMBLY_MINOR_VERSION
];
1042 aname
->build
= cols
[MONO_ASSEMBLY_BUILD_NUMBER
];
1043 aname
->revision
= cols
[MONO_ASSEMBLY_REV_NUMBER
];
1044 aname
->hash_alg
= cols
[MONO_ASSEMBLY_HASH_ALG
];
1045 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
1046 guchar
* token
= (guchar
*)g_malloc (8);
1051 pkey
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
1052 len
= mono_metadata_decode_blob_size (pkey
, &pkey
);
1053 aname
->public_key
= (guchar
*)pkey
;
1055 mono_digest_get_public_token (token
, aname
->public_key
, len
);
1056 encoded
= encode_public_tok (token
, 8);
1057 g_strlcpy ((char*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1063 aname
->public_key
= NULL
;
1064 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1067 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
1068 aname
->public_key
= (guchar
*)mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
1070 const gchar
*pkey_end
;
1071 int len
= mono_metadata_decode_blob_size ((const gchar
*) aname
->public_key
, &pkey_end
);
1072 pkey_end
+= len
; /* move to end */
1073 size_t size
= pkey_end
- (const gchar
*)aname
->public_key
;
1074 guchar
*tmp
= g_new (guchar
, size
);
1075 memcpy (tmp
, aname
->public_key
, size
);
1076 aname
->public_key
= tmp
;
1081 aname
->public_key
= 0;
1083 machine
= ((MonoCLIImageInfo
*)(image
->image_info
))->cli_header
.coff
.coff_machine
;
1084 flags
= ((MonoCLIImageInfo
*)(image
->image_info
))->cli_cli_header
.ch_flags
;
1086 case COFF_MACHINE_I386
:
1087 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1088 if (flags
& (CLI_FLAGS_32BITREQUIRED
|CLI_FLAGS_PREFERRED32BIT
))
1089 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_X86
;
1090 else if ((flags
& 0x70) == 0x70)
1091 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_NONE
;
1093 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_MSIL
;
1095 case COFF_MACHINE_IA64
:
1096 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_IA64
;
1098 case COFF_MACHINE_AMD64
:
1099 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_AMD64
;
1101 case COFF_MACHINE_ARM
:
1102 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_ARM
;
1112 * mono_assembly_fill_assembly_name:
1113 * \param image Image
1115 * \returns TRUE if successful
1118 mono_assembly_fill_assembly_name (MonoImage
*image
, MonoAssemblyName
*aname
)
1120 return mono_assembly_fill_assembly_name_full (image
, aname
, FALSE
);
1124 * mono_stringify_assembly_name:
1125 * \param aname the assembly name.
1127 * Convert \p aname into its string format. The returned string is dynamically
1128 * allocated and should be freed by the caller.
1130 * \returns a newly allocated string with a string representation of
1131 * the assembly name.
1134 mono_stringify_assembly_name (MonoAssemblyName
*aname
)
1136 const char *quote
= (aname
->name
&& g_ascii_isspace (aname
->name
[0])) ? "\"" : "";
1138 return g_strdup_printf (
1139 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1140 quote
, aname
->name
, quote
,
1141 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1142 aname
->culture
&& *aname
->culture
? aname
->culture
: "neutral",
1143 aname
->public_key_token
[0] ? (char *)aname
->public_key_token
: "null",
1144 (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
1148 assemblyref_public_tok (MonoImage
*image
, guint32 key_index
, guint32 flags
)
1150 const gchar
*public_tok
;
1153 public_tok
= mono_metadata_blob_heap (image
, key_index
);
1154 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
1156 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
1158 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
1159 return encode_public_tok (token
, 8);
1162 return encode_public_tok ((guchar
*)public_tok
, len
);
1166 assemblyref_public_tok_checked (MonoImage
*image
, guint32 key_index
, guint32 flags
, MonoError
*error
)
1168 const gchar
*public_tok
;
1171 public_tok
= mono_metadata_blob_heap_checked (image
, key_index
, error
);
1172 return_val_if_nok (error
, NULL
);
1173 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
1175 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
1177 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
1178 return encode_public_tok (token
, 8);
1180 return encode_public_tok ((guchar
*)public_tok
, len
);
1184 * mono_assembly_addref:
1185 * \param assembly the assembly to reference
1187 * This routine increments the reference count on a MonoAssembly.
1188 * The reference count is reduced every time the method mono_assembly_close() is
1192 mono_assembly_addref (MonoAssembly
*assembly
)
1194 mono_atomic_inc_i32 (&assembly
->ref_count
);
1198 * CAUTION: This table must be kept in sync with
1199 * ivkm/reflect/Fusion.cs
1202 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1203 #define WINFX_KEY "31bf3856ad364e35"
1204 #define ECMA_KEY "b77a5c561934e089"
1205 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1206 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1214 static KeyRemapEntry key_remap_table
[] = {
1215 { "CustomMarshalers", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1216 { "Microsoft.CSharp", WINFX_KEY
, MSFINAL_KEY
},
1217 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1218 { "System", SILVERLIGHT_KEY
, ECMA_KEY
},
1219 { "System", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1220 { "System.ComponentModel.Composition", WINFX_KEY
, ECMA_KEY
},
1221 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY
},
1222 { "System.Core", SILVERLIGHT_KEY
, ECMA_KEY
},
1223 { "System.Core", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1224 { "System.Data", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1225 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1226 { "System.Drawing", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1227 { "System.Messaging", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1228 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1229 { "System.Net", SILVERLIGHT_KEY
, MSFINAL_KEY
},
1230 { "System.Numerics", WINFX_KEY
, ECMA_KEY
},
1231 { "System.Runtime.Serialization", SILVERLIGHT_KEY
, ECMA_KEY
},
1232 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1233 { "System.ServiceModel", WINFX_KEY
, ECMA_KEY
},
1234 { "System.ServiceModel", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1235 { "System.ServiceModel.Web", SILVERLIGHT_KEY
, WINFX_KEY
},
1236 { "System.Web.Services", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1237 { "System.Windows", SILVERLIGHT_KEY
, MSFINAL_KEY
},
1238 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1239 { "System.Xml", SILVERLIGHT_KEY
, ECMA_KEY
},
1240 { "System.Xml", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1241 { "System.Xml.Linq", WINFX_KEY
, ECMA_KEY
},
1242 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1243 { "System.Xml.Serialization", WINFX_KEY
, ECMA_KEY
}
1247 remap_keys (MonoAssemblyName
*aname
)
1250 for (i
= 0; i
< G_N_ELEMENTS (key_remap_table
); i
++) {
1251 const KeyRemapEntry
*entry
= &key_remap_table
[i
];
1253 if (strcmp (aname
->name
, entry
->name
) ||
1254 !mono_public_tokens_are_equal (aname
->public_key_token
, (const unsigned char*) entry
->from
))
1257 memcpy (aname
->public_key_token
, entry
->to
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1259 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1260 "Remapped public key token of retargetable assembly %s from %s to %s",
1261 aname
->name
, entry
->from
, entry
->to
);
1266 static MonoAssemblyName
*
1267 mono_assembly_remap_version (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_aname
)
1269 const MonoRuntimeInfo
*current_runtime
;
1271 if (aname
->name
== NULL
) return aname
;
1273 current_runtime
= mono_get_runtime_info ();
1275 if (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) {
1276 const AssemblyVersionSet
* vset
;
1278 /* Remap to current runtime */
1279 vset
= ¤t_runtime
->version_sets
[0];
1281 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
1282 dest_aname
->major
= vset
->major
;
1283 dest_aname
->minor
= vset
->minor
;
1284 dest_aname
->build
= vset
->build
;
1285 dest_aname
->revision
= vset
->revision
;
1286 dest_aname
->flags
&= ~ASSEMBLYREF_RETARGETABLE_FLAG
;
1288 /* Remap assembly name */
1289 if (!strcmp (aname
->name
, "System.Net"))
1290 dest_aname
->name
= g_strdup ("System");
1292 remap_keys (dest_aname
);
1294 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1295 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1297 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1299 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1305 #ifndef DISABLE_DESKTOP_LOADER
1306 const AssemblyVersionMap
*vmap
= (AssemblyVersionMap
*)g_hash_table_lookup (assembly_remapping_table
, aname
->name
);
1308 const AssemblyVersionSet
* vset
;
1309 int index
= vmap
->version_set_index
;
1310 g_assert (index
< G_N_ELEMENTS (current_runtime
->version_sets
));
1311 vset
= ¤t_runtime
->version_sets
[index
];
1313 if (vmap
->framework_facade_assembly
) {
1314 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Assembly %s is a framework Facade asseembly",
1319 if (aname
->major
== vset
->major
&& aname
->minor
== vset
->minor
&&
1320 aname
->build
== vset
->build
&& aname
->revision
== vset
->revision
) {
1321 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1323 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
);
1327 if (vmap
->only_lower_versions
&& compare_versions ((AssemblyVersionSet
*)vset
, aname
) < 0) {
1328 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
,
1329 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1331 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1332 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1337 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0)
1338 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
1339 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1341 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1342 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1345 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
1346 dest_aname
->major
= vset
->major
;
1347 dest_aname
->minor
= vset
->minor
;
1348 dest_aname
->build
= vset
->build
;
1349 dest_aname
->revision
= vset
->revision
;
1350 if (vmap
->new_assembly_name
!= NULL
) {
1351 dest_aname
->name
= vmap
->new_assembly_name
;
1352 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
1353 "The assembly name %s was remapped to %s",
1365 * mono_assembly_get_assemblyref:
1366 * \param image pointer to the \c MonoImage to extract the information from.
1367 * \param index index to the assembly reference in the image.
1368 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1370 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1373 mono_assembly_get_assemblyref (MonoImage
*image
, int index
, MonoAssemblyName
*aname
)
1376 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
1379 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1381 mono_metadata_decode_row (t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
);
1383 hash
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
]);
1384 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
1385 aname
->hash_value
= hash
;
1386 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_NAME
]);
1387 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_CULTURE
]);
1388 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
1389 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
1390 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
1391 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
1392 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
1394 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
1395 gchar
*token
= assemblyref_public_tok (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
);
1396 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1399 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1403 static MonoAssembly
*
1404 load_reference_by_aname_refonly_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*assm
, MonoImageOpenStatus
*status
)
1406 MonoAssembly
*reference
= NULL
;
1407 g_assert (assm
!= NULL
);
1408 *status
= MONO_IMAGE_OK
;
1410 /* We use the loaded corlib */
1411 if (!strcmp (aname
->name
, "mscorlib"))
1412 reference
= mono_assembly_load_full_internal (aname
, assm
, assm
->basedir
, MONO_ASMCTX_DEFAULT
, status
);
1414 reference
= mono_assembly_loaded_full (aname
, TRUE
);
1416 /* Try a postload search hook */
1417 reference
= mono_assembly_invoke_search_hook_internal (aname
, assm
, TRUE
, TRUE
);
1421 * Here we must advice that the error was due to
1422 * a non loaded reference using the ReflectionOnly api
1425 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1430 static MonoAssembly
*
1431 load_reference_by_aname_default_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*assm
, MonoImageOpenStatus
*status
)
1433 MonoAssembly
*reference
= NULL
;
1434 *status
= MONO_IMAGE_OK
;
1436 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1437 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1438 * accordingly, it would fail on the MS runtime before).
1439 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1440 * example bug-349190.2.cs and who knows how much more code in the wild.
1442 reference
= mono_assembly_load_full_internal (aname
, assm
, NULL
, MONO_ASMCTX_DEFAULT
, status
);
1443 if (!reference
&& assm
)
1444 reference
= mono_assembly_load_full_internal (aname
, assm
, assm
->basedir
, MONO_ASMCTX_DEFAULT
, status
);
1449 static MonoAssembly
*
1450 load_reference_by_aname_loadfrom_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, MonoImageOpenStatus
*status
)
1452 MonoAssembly
*reference
= NULL
;
1453 /* Just like default search, but look in the requesting assembly basedir right away */
1454 reference
= mono_assembly_load_full_internal (aname
, requesting
, requesting
->basedir
, MONO_ASMCTX_LOADFROM
, status
);
1459 static MonoAssembly
*
1460 load_reference_by_aname_individual_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, MonoImageOpenStatus
*status
)
1462 /* For an individual assembly, all references must already be loaded or
1463 * else we fire the assembly resolve event - similar to refonly - but
1464 * subject to remaping and binding.
1467 MonoAssembly
*reference
= NULL
;
1468 *status
= MONO_IMAGE_OK
;
1469 MonoAssemblyName maped_aname
;
1470 MonoAssemblyName maped_name_pp
;
1472 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
1473 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
1475 reference
= mono_assembly_loaded_full (aname
, FALSE
);
1476 /* Still try to load from application base directory, MONO_PATH or the
1477 * GAC. This is consistent with what .NET Framework (4.7) actually
1478 * does, rather than what the documentation implies: If `LoadFile` is
1479 * used to load an assembly into "no context"/individual assembly
1480 * context, the runtime will still load assemblies from the GAC or the
1481 * application base directory (e.g. `System.Runtime` will be loaded if
1482 * it wasn't already).
1483 * Moreover, those referenced assemblies are loaded in the default context.
1486 reference
= mono_assembly_load_full_internal (aname
, requesting
, NULL
, MONO_ASMCTX_DEFAULT
, status
);
1488 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1493 * mono_assembly_get_assemblyref:
1494 * \param image pointer to the \c MonoImage to extract the information from.
1495 * \param index index to the assembly reference in the image.
1496 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1497 * \param error set on error
1499 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1501 * \returns TRUE on success, otherwise sets \p error and returns FALSE
1504 mono_assembly_get_assemblyref_checked (MonoImage
*image
, int index
, MonoAssemblyName
*aname
, MonoError
*error
)
1507 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
1510 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1512 if (!mono_metadata_decode_row_checked (image
, t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
, error
))
1515 hash
= mono_metadata_blob_heap_checked (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
], error
);
1516 return_val_if_nok (error
, FALSE
);
1517 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
1518 aname
->hash_value
= hash
;
1519 aname
->name
= mono_metadata_string_heap_checked (image
, cols
[MONO_ASSEMBLYREF_NAME
], error
);
1520 return_val_if_nok (error
, FALSE
);
1521 aname
->culture
= mono_metadata_string_heap_checked (image
, cols
[MONO_ASSEMBLYREF_CULTURE
], error
);
1522 return_val_if_nok (error
, FALSE
);
1523 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
1524 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
1525 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
1526 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
1527 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
1528 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
1529 gchar
*token
= assemblyref_public_tok_checked (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
, error
);
1530 return_val_if_nok (error
, FALSE
);
1531 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1534 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1540 * mono_assembly_load_reference:
1543 mono_assembly_load_reference (MonoImage
*image
, int index
)
1545 MonoAssembly
*reference
;
1546 MonoAssemblyName aname
;
1547 MonoImageOpenStatus status
;
1550 * image->references is shared between threads, so we need to access
1551 * it inside a critical section.
1553 mono_assemblies_lock ();
1554 if (!image
->references
) {
1555 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1557 image
->references
= g_new0 (MonoAssembly
*, t
->rows
+ 1);
1558 image
->nreferences
= t
->rows
;
1560 reference
= image
->references
[index
];
1561 mono_assemblies_unlock ();
1565 mono_assembly_get_assemblyref (image
, index
, &aname
);
1567 if (image
->assembly
) {
1568 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
1569 char *aname_str
= mono_stringify_assembly_name (&aname
);
1570 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Loading reference %d of %s asmctx %s, looking for %s",
1571 index
, image
->name
, mono_asmctx_get_name (&image
->assembly
->context
),
1575 switch (mono_asmctx_get_kind (&image
->assembly
->context
)) {
1576 case MONO_ASMCTX_DEFAULT
:
1577 reference
= load_reference_by_aname_default_asmctx (&aname
, image
->assembly
, &status
);
1579 case MONO_ASMCTX_REFONLY
:
1580 reference
= load_reference_by_aname_refonly_asmctx (&aname
, image
->assembly
, &status
);
1582 case MONO_ASMCTX_LOADFROM
:
1583 reference
= load_reference_by_aname_loadfrom_asmctx (&aname
, image
->assembly
, &status
);
1585 case MONO_ASMCTX_INDIVIDUAL
:
1586 reference
= load_reference_by_aname_individual_asmctx (&aname
, image
->assembly
, &status
);
1589 g_error ("Unexpected assembly load context kind %d for image %s.", mono_asmctx_get_kind (&image
->assembly
->context
), image
->name
);
1593 /* FIXME: can we establish that image->assembly is never NULL and this code is dead? */
1594 reference
= load_reference_by_aname_default_asmctx (&aname
, image
->assembly
, &status
);
1597 if (reference
== NULL
){
1600 if (status
== MONO_IMAGE_ERROR_ERRNO
&& errno
== ENOENT
) {
1601 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
: "" );
1602 } else if (status
== MONO_IMAGE_ERROR_ERRNO
) {
1603 extra_msg
= g_strdup_printf ("System error: %s\n", strerror (errno
));
1604 } else if (status
== MONO_IMAGE_MISSING_ASSEMBLYREF
) {
1605 extra_msg
= g_strdup ("Cannot find an assembly referenced from this one.\n");
1606 } else if (status
== MONO_IMAGE_IMAGE_INVALID
) {
1607 extra_msg
= g_strdup ("The file exists but is not a valid assembly.\n");
1609 extra_msg
= g_strdup ("");
1612 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
, "The following assembly referenced from %s could not be loaded:\n"
1613 " Assembly: %s (assemblyref_index=%d)\n"
1614 " Version: %d.%d.%d.%d\n"
1615 " Public Key: %s\n%s",
1616 image
->name
, aname
.name
, index
,
1617 aname
.major
, aname
.minor
, aname
.build
, aname
.revision
,
1618 strlen ((char*)aname
.public_key_token
) == 0 ? "(none)" : (char*)aname
.public_key_token
, extra_msg
);
1623 mono_assemblies_lock ();
1624 if (reference
== NULL
) {
1625 /* Flag as not found */
1626 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1629 if (!image
->references
[index
]) {
1630 if (reference
!= REFERENCE_MISSING
){
1631 mono_assembly_addref (reference
);
1632 if (image
->assembly
)
1633 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1634 image
->assembly
->aname
.name
, image
->assembly
, reference
->aname
.name
, reference
, reference
->ref_count
);
1636 if (image
->assembly
)
1637 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Failed to load assembly %s[%p].",
1638 image
->assembly
->aname
.name
, image
->assembly
);
1641 image
->references
[index
] = reference
;
1643 mono_assemblies_unlock ();
1645 if (image
->references
[index
] != reference
) {
1646 /* Somebody loaded it before us */
1647 mono_assembly_close (reference
);
1652 * mono_assembly_load_references:
1655 * \deprecated There is no reason to use this method anymore, it does nothing
1657 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1660 mono_assembly_load_references (MonoImage
*image
, MonoImageOpenStatus
*status
)
1662 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1663 *status
= MONO_IMAGE_OK
;
1666 typedef struct AssemblyLoadHook AssemblyLoadHook
;
1667 struct AssemblyLoadHook
{
1668 AssemblyLoadHook
*next
;
1669 MonoAssemblyLoadFunc func
;
1673 static AssemblyLoadHook
*assembly_load_hook
= NULL
;
1676 * mono_assembly_invoke_load_hook:
1679 mono_assembly_invoke_load_hook (MonoAssembly
*ass
)
1681 AssemblyLoadHook
*hook
;
1683 for (hook
= assembly_load_hook
; hook
; hook
= hook
->next
) {
1684 hook
->func (ass
, hook
->user_data
);
1689 * mono_install_assembly_load_hook:
1692 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func
, gpointer user_data
)
1694 AssemblyLoadHook
*hook
;
1696 g_return_if_fail (func
!= NULL
);
1698 hook
= g_new0 (AssemblyLoadHook
, 1);
1700 hook
->user_data
= user_data
;
1701 hook
->next
= assembly_load_hook
;
1702 assembly_load_hook
= hook
;
1706 free_assembly_load_hooks (void)
1708 AssemblyLoadHook
*hook
, *next
;
1710 for (hook
= assembly_load_hook
; hook
; hook
= next
) {
1716 typedef struct AssemblySearchHook AssemblySearchHook
;
1717 struct AssemblySearchHook
{
1718 AssemblySearchHook
*next
;
1719 MonoAssemblySearchFunc func
;
1725 static AssemblySearchHook
*assembly_search_hook
= NULL
;
1727 static MonoAssembly
*
1728 mono_assembly_invoke_search_hook_internal (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, gboolean refonly
, gboolean postload
)
1730 AssemblySearchHook
*hook
;
1732 for (hook
= assembly_search_hook
; hook
; hook
= hook
->next
) {
1733 if ((hook
->refonly
== refonly
) && (hook
->postload
== postload
)) {
1736 * A little explanation is in order here.
1738 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1739 * The embedding API exposes a search hook that doesn't take such argument.
1741 * The original fix would call the default search hook before all the registered ones and pass
1742 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1743 * rely on. Which is the ordering between user hooks and the default runtime hook.
1745 * Registering the hook after mono_jit_init would let your hook run before the default one and
1746 * when using it to handle non standard app layouts this could save your app from a massive amount
1747 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1748 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1750 * So what's the fix? We register the default hook using regular means and special case it when iterating
1751 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1754 if (hook
->func
== (void*)mono_domain_assembly_postload_search
)
1755 ass
= mono_domain_assembly_postload_search (aname
, requesting
, refonly
);
1757 ass
= hook
->func (aname
, hook
->user_data
);
1767 * mono_assembly_invoke_search_hook:
1770 mono_assembly_invoke_search_hook (MonoAssemblyName
*aname
)
1772 return mono_assembly_invoke_search_hook_internal (aname
, NULL
, FALSE
, FALSE
);
1776 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func
, gpointer user_data
, gboolean refonly
, gboolean postload
)
1778 AssemblySearchHook
*hook
;
1780 g_return_if_fail (func
!= NULL
);
1782 hook
= g_new0 (AssemblySearchHook
, 1);
1784 hook
->user_data
= user_data
;
1785 hook
->refonly
= refonly
;
1786 hook
->postload
= postload
;
1787 hook
->next
= assembly_search_hook
;
1788 assembly_search_hook
= hook
;
1792 * mono_install_assembly_search_hook:
1795 mono_install_assembly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1797 mono_install_assembly_search_hook_internal (func
, user_data
, FALSE
, FALSE
);
1801 free_assembly_search_hooks (void)
1803 AssemblySearchHook
*hook
, *next
;
1805 for (hook
= assembly_search_hook
; hook
; hook
= next
) {
1812 * mono_install_assembly_refonly_search_hook:
1815 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1817 mono_install_assembly_search_hook_internal (func
, user_data
, TRUE
, FALSE
);
1821 * mono_install_assembly_postload_search_hook:
1824 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1826 mono_install_assembly_search_hook_internal (func
, user_data
, FALSE
, TRUE
);
1830 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1832 mono_install_assembly_search_hook_internal (func
, user_data
, TRUE
, TRUE
);
1835 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook
;
1836 struct AssemblyPreLoadHook
{
1837 AssemblyPreLoadHook
*next
;
1838 MonoAssemblyPreLoadFunc func
;
1842 static AssemblyPreLoadHook
*assembly_preload_hook
= NULL
;
1843 static AssemblyPreLoadHook
*assembly_refonly_preload_hook
= NULL
;
1845 static MonoAssembly
*
1846 invoke_assembly_preload_hook (MonoAssemblyName
*aname
, gchar
**assemblies_path
)
1848 AssemblyPreLoadHook
*hook
;
1849 MonoAssembly
*assembly
;
1851 for (hook
= assembly_preload_hook
; hook
; hook
= hook
->next
) {
1852 assembly
= hook
->func (aname
, assemblies_path
, hook
->user_data
);
1853 if (assembly
!= NULL
)
1860 static MonoAssembly
*
1861 invoke_assembly_refonly_preload_hook (MonoAssemblyName
*aname
, gchar
**assemblies_path
)
1863 AssemblyPreLoadHook
*hook
;
1864 MonoAssembly
*assembly
;
1866 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= hook
->next
) {
1867 assembly
= hook
->func (aname
, assemblies_path
, hook
->user_data
);
1868 if (assembly
!= NULL
)
1876 * mono_install_assembly_preload_hook:
1879 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
1881 AssemblyPreLoadHook
*hook
;
1883 g_return_if_fail (func
!= NULL
);
1885 hook
= g_new0 (AssemblyPreLoadHook
, 1);
1887 hook
->user_data
= user_data
;
1888 hook
->next
= assembly_preload_hook
;
1889 assembly_preload_hook
= hook
;
1893 * mono_install_assembly_refonly_preload_hook:
1896 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
1898 AssemblyPreLoadHook
*hook
;
1900 g_return_if_fail (func
!= NULL
);
1902 hook
= g_new0 (AssemblyPreLoadHook
, 1);
1904 hook
->user_data
= user_data
;
1905 hook
->next
= assembly_refonly_preload_hook
;
1906 assembly_refonly_preload_hook
= hook
;
1910 free_assembly_preload_hooks (void)
1912 AssemblyPreLoadHook
*hook
, *next
;
1914 for (hook
= assembly_preload_hook
; hook
; hook
= next
) {
1919 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= next
) {
1925 typedef struct AssemblyAsmCtxFromPathHook AssemblyAsmCtxFromPathHook
;
1926 struct AssemblyAsmCtxFromPathHook
{
1927 AssemblyAsmCtxFromPathHook
*next
;
1928 MonoAssemblyAsmCtxFromPathFunc func
;
1932 static AssemblyAsmCtxFromPathHook
*assembly_asmctx_from_path_hook
= NULL
;
1935 * mono_install_assembly_asmctx_from_path_hook:
1937 * \param func Hook function
1938 * \param user_data User data
1940 * Installs a hook function \p func that when called with an absolute path name
1941 * returns \c TRUE and writes to \c out_asmctx if an assembly that name would
1942 * be found by that asmctx. The hooks are called in the order from most
1943 * recently added to oldest.
1947 mono_install_assembly_asmctx_from_path_hook (MonoAssemblyAsmCtxFromPathFunc func
, gpointer user_data
)
1949 g_return_if_fail (func
!= NULL
);
1951 AssemblyAsmCtxFromPathHook
*hook
= g_new0 (AssemblyAsmCtxFromPathHook
, 1);
1953 hook
->user_data
= user_data
;
1954 hook
->next
= assembly_asmctx_from_path_hook
;
1955 assembly_asmctx_from_path_hook
= hook
;
1959 * mono_assembly_invoke_asmctx_from_path_hook:
1961 * \param absfname absolute path name
1962 * \param requesting_assembly the \c MonoAssembly that requested the load, may be \c NULL
1963 * \param out_asmctx assembly context kind, written on output
1965 * Invokes hooks to find the assembly context that would have searched for the
1966 * given assembly name. Writes to \p out_asmctx the assembly context kind from
1967 * the first hook to return \c TRUE. \returns \c TRUE if any hook wrote to \p
1968 * out_asmctx, or \c FALSE otherwise.
1971 assembly_invoke_asmctx_from_path_hook (const char *absfname
, MonoAssembly
*requesting_assembly
, MonoAssemblyContextKind
*out_asmctx
)
1973 g_assert (absfname
);
1974 g_assert (out_asmctx
);
1975 AssemblyAsmCtxFromPathHook
*hook
;
1977 for (hook
= assembly_asmctx_from_path_hook
; hook
; hook
= hook
->next
) {
1978 *out_asmctx
= MONO_ASMCTX_INDIVIDUAL
;
1979 if (hook
->func (absfname
, requesting_assembly
, hook
->user_data
, out_asmctx
))
1987 free_assembly_asmctx_from_path_hooks (void)
1989 AssemblyAsmCtxFromPathHook
*hook
, *next
;
1991 for (hook
= assembly_asmctx_from_path_hook
; hook
; hook
= next
) {
1998 absolute_dir (const gchar
*filename
)
2009 if (g_path_is_absolute (filename
)) {
2010 part
= g_path_get_dirname (filename
);
2011 res
= g_strconcat (part
, G_DIR_SEPARATOR_S
, NULL
);
2016 cwd
= g_get_current_dir ();
2017 mixed
= g_build_filename (cwd
, filename
, NULL
);
2018 parts
= g_strsplit (mixed
, G_DIR_SEPARATOR_S
, 0);
2023 for (i
= 0; (part
= parts
[i
]) != NULL
; i
++) {
2024 if (!strcmp (part
, "."))
2027 if (!strcmp (part
, "..")) {
2028 if (list
&& list
->next
) /* Don't remove root */
2029 list
= g_list_delete_link (list
, list
);
2031 list
= g_list_prepend (list
, part
);
2035 result
= g_string_new ("");
2036 list
= g_list_reverse (list
);
2038 /* Ignores last data pointer, which should be the filename */
2039 for (tmp
= list
; tmp
&& tmp
->next
!= NULL
; tmp
= tmp
->next
){
2041 g_string_append_printf (result
, "%s%c", (char *) tmp
->data
,
2046 g_string_free (result
, FALSE
);
2051 return g_strdup (".");
2058 * mono_assembly_open_from_bundle:
2059 * \param filename Filename requested
2060 * \param status return status code
2062 * This routine tries to open the assembly specified by \p filename from the
2063 * defined bundles, if found, returns the MonoImage for it, if not found
2067 mono_assembly_open_from_bundle (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
2071 gchar
*lowercase_filename
;
2072 MonoImage
*image
= NULL
;
2073 gboolean is_satellite
= FALSE
;
2075 * we do a very simple search for bundled assemblies: it's not a general
2076 * purpose assembly loading mechanism.
2082 lowercase_filename
= g_utf8_strdown (filename
, -1);
2083 is_satellite
= g_str_has_suffix (lowercase_filename
, ".resources.dll");
2084 g_free (lowercase_filename
);
2085 name
= g_path_get_basename (filename
);
2086 mono_assemblies_lock ();
2087 for (i
= 0; !image
&& bundles
[i
]; ++i
) {
2088 if (strcmp (bundles
[i
]->name
, is_satellite
? filename
: name
) == 0) {
2089 image
= mono_image_open_from_data_with_name ((char*)bundles
[i
]->data
, bundles
[i
]->size
, FALSE
, status
, refonly
, name
);
2093 mono_assemblies_unlock ();
2095 mono_image_addref (image
);
2096 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite
? filename
: name
);
2105 * mono_assembly_open_full:
2106 * \param filename the file to load
2107 * \param status return status code
2108 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2110 * This loads an assembly from the specified \p filename. The \p filename allows
2111 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2112 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2113 * is treated as a local path.
2115 * First, an attempt is made to load the assembly from the bundled executable (for those
2116 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2117 * assembly has been registered as an embedded assembly). If this is not the case, then
2118 * the assembly is loaded from disk using `api:mono_image_open_full`.
2120 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2121 * the assembly is made.
2123 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
2124 * the \c System.Reflection API.
2126 * \returns NULL on error, with the \p status set to an error code, or a pointer
2130 mono_assembly_open_full (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
2132 return mono_assembly_open_a_lot (filename
, status
, refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
2136 mono_assembly_open_a_lot (const char *filename
, MonoImageOpenStatus
*status
, MonoAssemblyContextKind asmctx
)
2138 return mono_assembly_open_predicate (filename
, asmctx
, NULL
, NULL
, NULL
, status
);
2142 assembly_loadfrom_asmctx_from_path (const char *filename
, MonoAssembly
*requesting_assembly
,
2143 gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
) {
2144 if (requesting_assembly
&& mono_asmctx_get_kind (&requesting_assembly
->context
) == MONO_ASMCTX_LOADFROM
) {
2145 if (mono_path_filename_in_basedir (filename
, requesting_assembly
->basedir
)) {
2146 *out_asmctx
= MONO_ASMCTX_LOADFROM
;
2154 mono_assembly_open_predicate (const char *filename
, MonoAssemblyContextKind asmctx
,
2155 MonoAssemblyCandidatePredicate predicate
,
2157 MonoAssembly
*requesting_assembly
,
2158 MonoImageOpenStatus
*status
)
2162 MonoImageOpenStatus def_status
;
2165 gboolean loaded_from_bundle
;
2167 g_return_val_if_fail (filename
!= NULL
, NULL
);
2170 status
= &def_status
;
2171 *status
= MONO_IMAGE_OK
;
2173 if (strncmp (filename
, "file://", 7) == 0) {
2174 GError
*gerror
= NULL
;
2175 gchar
*uri
= (gchar
*) filename
;
2179 * MS allows file://c:/... and fails on file://localhost/c:/...
2180 * They also throw an IndexOutOfRangeException if "file://"
2183 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
2186 uri
= mono_escape_uri_string (tmpuri
);
2187 fname
= g_filename_from_uri (uri
, NULL
, &gerror
);
2190 if (tmpuri
!= filename
)
2193 if (gerror
!= NULL
) {
2194 g_warning ("%s\n", gerror
->message
);
2195 g_error_free (gerror
);
2196 fname
= g_strdup (filename
);
2199 fname
= g_strdup (filename
);
2202 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2203 "Assembly Loader probing location: '%s'.", fname
);
2206 if (!mono_assembly_is_in_gac (fname
)) {
2208 new_fname
= mono_make_shadow_copy (fname
, error
);
2209 if (!is_ok (error
)) {
2210 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2211 "Assembly Loader shadow copy error: %s.", mono_error_get_message (error
));
2212 mono_error_cleanup (error
);
2213 *status
= MONO_IMAGE_IMAGE_INVALID
;
2218 if (asmctx
!= MONO_ASMCTX_REFONLY
) {
2219 MonoAssemblyContextKind out_asmctx
;
2220 /* If the path belongs to the appdomain base dir or the
2221 * base dir of the requesting assembly, load the
2222 * assembly in the corresponding asmctx.
2224 if (assembly_invoke_asmctx_from_path_hook (fname
, requesting_assembly
, &out_asmctx
))
2225 asmctx
= out_asmctx
;
2228 if (asmctx
!= MONO_ASMCTX_REFONLY
) {
2229 /* GAC assemblies always in default context or refonly context. */
2230 asmctx
= MONO_ASMCTX_DEFAULT
;
2233 if (new_fname
&& new_fname
!= fname
) {
2236 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2237 "Assembly Loader shadow-copied assembly to: '%s'.", fname
);
2242 const gboolean refonly
= asmctx
== MONO_ASMCTX_REFONLY
;
2243 /* for LoadFrom(string), LoadFile(string) and Load(byte[]), allow them
2244 * to load problematic images. Not sure if ReflectionOnlyLoad(string)
2245 * and ReflectionOnlyLoadFrom(string) should also be allowed - let's
2248 const gboolean load_from_context
= asmctx
== MONO_ASMCTX_LOADFROM
|| asmctx
== MONO_ASMCTX_INDIVIDUAL
|| asmctx
== MONO_ASMCTX_REFONLY
;
2250 // If VM built with mkbundle
2251 loaded_from_bundle
= FALSE
;
2252 if (bundles
!= NULL
) {
2253 image
= mono_assembly_open_from_bundle (fname
, status
, refonly
);
2254 loaded_from_bundle
= image
!= NULL
;
2258 image
= mono_image_open_a_lot (fname
, status
, refonly
, load_from_context
);
2261 if (*status
== MONO_IMAGE_OK
)
2262 *status
= MONO_IMAGE_ERROR_ERRNO
;
2267 if (asmctx
== MONO_ASMCTX_LOADFROM
|| asmctx
== MONO_ASMCTX_INDIVIDUAL
) {
2268 MonoAssembly
*redirected_asm
= NULL
;
2269 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2270 if ((redirected_asm
= chain_redirections_loadfrom (image
, &new_status
))) {
2271 mono_image_close (image
);
2272 image
= redirected_asm
->image
;
2273 mono_image_addref (image
); /* so that mono_image_close, below, has something to do */
2274 /* fall thru to if (image->assembly) below */
2275 } else if (new_status
!= MONO_IMAGE_OK
) {
2276 *status
= new_status
;
2277 mono_image_close (image
);
2283 if (image
->assembly
) {
2284 /* We want to return the MonoAssembly that's already loaded,
2285 * but if we're using the strict assembly loader, we also need
2286 * to check that the previously loaded assembly matches the
2287 * predicate. It could be that we previously loaded a
2288 * different version that happens to have the filename that
2289 * we're currently probing. */
2290 if (mono_loader_get_strict_strong_names () &&
2291 predicate
&& !predicate (image
->assembly
, user_data
)) {
2292 mono_image_close (image
);
2296 /* Already loaded by another appdomain */
2297 mono_assembly_invoke_load_hook (image
->assembly
);
2298 mono_image_close (image
);
2300 return image
->assembly
;
2304 ass
= mono_assembly_load_from_predicate (image
, fname
, asmctx
, predicate
, user_data
, status
);
2307 if (!loaded_from_bundle
)
2308 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2309 "Assembly Loader loaded assembly from location: '%s'.", filename
);
2311 mono_config_for_assembly (ass
->image
);
2314 /* Clear the reference added by mono_image_open */
2315 mono_image_close (image
);
2323 free_item (gpointer val
, gpointer user_data
)
2329 * mono_assembly_load_friends:
2330 * \param ass an assembly
2332 * Load the list of friend assemblies that are allowed to access
2333 * the assembly's internal types and members. They are stored as assembly
2334 * names in custom attributes.
2336 * This is an internal method, we need this because when we load mscorlib
2337 * we do not have the internals visible cattr loaded yet,
2338 * so we need to load these after we initialize the runtime.
2340 * LOCKING: Acquires the assemblies lock plus the loader lock.
2343 mono_assembly_load_friends (MonoAssembly
* ass
)
2347 MonoCustomAttrInfo
* attrs
;
2350 if (ass
->friend_assembly_names_inited
)
2353 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2354 mono_error_assert_ok (error
);
2356 mono_assemblies_lock ();
2357 ass
->friend_assembly_names_inited
= TRUE
;
2358 mono_assemblies_unlock ();
2362 mono_assemblies_lock ();
2363 if (ass
->friend_assembly_names_inited
) {
2364 mono_assemblies_unlock ();
2367 mono_assemblies_unlock ();
2371 * We build the list outside the assemblies lock, the worse that can happen
2372 * is that we'll need to free the allocated list.
2374 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2375 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2376 MonoAssemblyName
*aname
;
2378 uint32_t data_length
;
2379 gchar
*data_with_terminator
;
2380 /* Do some sanity checking */
2381 if (!attr
->ctor
|| attr
->ctor
->klass
!= mono_class_try_get_internals_visible_class ())
2383 if (attr
->data_size
< 4)
2385 data
= (const char*)attr
->data
;
2386 /* 0xFF means null string, see custom attr format */
2387 if (data
[0] != 1 || data
[1] != 0 || (data
[2] & 0xFF) == 0xFF)
2389 data_length
= mono_metadata_decode_value (data
+ 2, &data
);
2390 data_with_terminator
= (char *)g_memdup (data
, data_length
+ 1);
2391 data_with_terminator
[data_length
] = 0;
2392 aname
= g_new0 (MonoAssemblyName
, 1);
2393 /*g_print ("friend ass: %s\n", data);*/
2394 if (mono_assembly_name_parse_full (data_with_terminator
, aname
, TRUE
, NULL
, NULL
)) {
2395 list
= g_slist_prepend (list
, aname
);
2399 g_free (data_with_terminator
);
2401 mono_custom_attrs_free (attrs
);
2403 mono_assemblies_lock ();
2404 if (ass
->friend_assembly_names_inited
) {
2405 mono_assemblies_unlock ();
2406 g_slist_foreach (list
, free_item
, NULL
);
2407 g_slist_free (list
);
2410 ass
->friend_assembly_names
= list
;
2412 /* Because of the double checked locking pattern above */
2413 mono_memory_barrier ();
2414 ass
->friend_assembly_names_inited
= TRUE
;
2415 mono_assemblies_unlock ();
2418 struct HasReferenceAssemblyAttributeIterData
{
2423 has_reference_assembly_attribute_iterator (MonoImage
*image
, guint32 typeref_scope_token
, const char *nspace
, const char *name
, guint32 method_token
, gpointer user_data
)
2425 gboolean stop_scanning
= FALSE
;
2426 struct HasReferenceAssemblyAttributeIterData
*iter_data
= (struct HasReferenceAssemblyAttributeIterData
*)user_data
;
2428 if (!strcmp (name
, "ReferenceAssemblyAttribute") && !strcmp (nspace
, "System.Runtime.CompilerServices")) {
2429 /* Note we don't check the assembly name, same as coreCLR. */
2430 iter_data
->has_attr
= TRUE
;
2431 stop_scanning
= TRUE
;
2434 return stop_scanning
;
2438 * mono_assembly_has_reference_assembly_attribute:
2439 * \param assembly a MonoAssembly
2440 * \param error set on error.
2442 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2443 * On error returns FALSE and sets \p error.
2446 mono_assembly_has_reference_assembly_attribute (MonoAssembly
*assembly
, MonoError
*error
)
2448 g_assert (assembly
&& assembly
->image
);
2449 /* .NET Framework appears to ignore the attribute on dynamic
2450 * assemblies, so don't call this function for dynamic assemblies. */
2451 g_assert (!image_is_dynamic (assembly
->image
));
2455 * This might be called during assembly loading, so do everything using the low-level
2459 struct HasReferenceAssemblyAttributeIterData iter_data
= { FALSE
};
2461 mono_assembly_metadata_foreach_custom_attr (assembly
, &has_reference_assembly_attribute_iterator
, &iter_data
);
2463 return iter_data
.has_attr
;
2467 * chain_redirections_loadfrom:
2468 * \param image a MonoImage that we wanted to load using LoadFrom context
2469 * \param status set if there was an error opening the redirected image
2471 * Check if we need to open a different image instead of the given one for some reason.
2472 * Returns NULL and sets status to \c MONO_IMAGE_OK if the given image was good.
2474 * Otherwise returns the assembly that we opened instead or sets status if
2475 * there was a problem opening the redirected image.
2479 chain_redirections_loadfrom (MonoImage
*image
, MonoImageOpenStatus
*out_status
)
2481 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
2482 MonoAssembly
*redirected
= NULL
;
2484 redirected
= mono_assembly_binding_applies_to_image (image
, &status
);
2485 if (redirected
|| status
!= MONO_IMAGE_OK
) {
2486 *out_status
= status
;
2490 redirected
= mono_problematic_image_reprobe (image
, &status
);
2491 if (redirected
|| status
!= MONO_IMAGE_OK
) {
2492 *out_status
= status
;
2496 *out_status
= MONO_IMAGE_OK
;
2501 * mono_assembly_binding_applies_to_image:
2502 * \param image The image whose assembly name we should check
2503 * \param status sets on error;
2505 * Get the \c MonoAssemblyName from the given \p image metadata and apply binding redirects to it.
2506 * If the resulting name is different from the name in the image, load that \c MonoAssembly instead
2508 * \returns the loaded \c MonoAssembly, or NULL if no binding redirection applied.
2512 mono_assembly_binding_applies_to_image (MonoImage
* image
, MonoImageOpenStatus
*status
)
2514 /* This is a "fun" one now.
2515 * For LoadFrom ("/basedir/some.dll") or LoadFile("/basedir/some.dll") or Load(byte[])),
2516 * apparently what we're meant to do is:
2517 * 1. probe the assembly name from some.dll (or the byte array)
2518 * 2. apply binding redirects
2519 * 3. If we get some other different name, drop this image and use
2520 * the binding redirected name to probe.
2521 * 4. Return the new assembly.
2523 MonoAssemblyName probed_aname
, dest_name
;
2524 if (!mono_assembly_fill_assembly_name_full (image
, &probed_aname
, TRUE
)) {
2525 if (*status
== MONO_IMAGE_OK
)
2526 *status
= MONO_IMAGE_IMAGE_INVALID
;
2529 MonoAssembly
*result_ass
= NULL
;
2530 MonoAssemblyName
*result_name
= &probed_aname
;
2531 result_name
= mono_assembly_apply_binding (result_name
, &dest_name
);
2532 if (result_name
!= &probed_aname
&& !mono_assembly_names_equal (result_name
, &probed_aname
)) {
2533 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
2534 char *probed_fullname
= mono_stringify_assembly_name (&probed_aname
);
2535 char *result_fullname
= mono_stringify_assembly_name (result_name
);
2536 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Request to load from %s in (%s) remapped to %s", probed_fullname
, image
->name
, result_fullname
);
2537 g_free (probed_fullname
);
2538 g_free (result_fullname
);
2540 const char *new_basedir
= NULL
; /* FIXME: null? - do a test of this */
2541 MonoAssemblyContextKind new_asmctx
= MONO_ASMCTX_DEFAULT
; /* FIXME: default? or? */
2542 MonoAssembly
*new_requesting
= NULL
; /* this seems okay */
2543 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2545 result_ass
= mono_assembly_load_full_internal (result_name
, new_requesting
, new_basedir
, new_asmctx
, &new_status
);
2547 if (result_ass
&& new_status
== MONO_IMAGE_OK
) {
2548 g_assert (result_ass
->image
->assembly
!= NULL
);
2550 *status
= new_status
;
2553 mono_assembly_name_free (&probed_aname
);
2558 * mono_problematic_image_reprobe:
2559 * \param image A MonoImage
2560 * \param status set on error
2562 * If the given image is problematic for mono (see image.c), then try to load
2563 * by assembly name in the default context (which should succeed with Mono's
2564 * own implementations of those assemblies).
2566 * Returns NULL and sets status to MONO_IMAGE_OK if no redirect is needed.
2568 * Otherwise returns the assembly we were redirected to, or NULL and sets a
2569 * non-ok status on failure.
2571 * IMPORTANT NOTE: Don't call this if \c image was found by probing the search
2572 * path, you will end up in a loop and a stack overflow.
2575 mono_problematic_image_reprobe (MonoImage
*image
, MonoImageOpenStatus
*status
)
2577 if (G_LIKELY (!mono_is_problematic_image (image
))) {
2578 *status
= MONO_IMAGE_OK
;
2581 MonoAssemblyName probed_aname
;
2582 if (!mono_assembly_fill_assembly_name_full (image
, &probed_aname
, TRUE
)) {
2583 *status
= MONO_IMAGE_IMAGE_INVALID
;
2586 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
2587 char *probed_fullname
= mono_stringify_assembly_name (&probed_aname
);
2588 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Requested to load from problematic image %s, probing instead for assembly with name %s", image
->name
, probed_fullname
);
2589 g_free (probed_fullname
);
2591 const char *new_basedir
= NULL
;
2592 MonoAssemblyContextKind new_asmctx
= MONO_ASMCTX_DEFAULT
;
2593 MonoAssembly
*new_requesting
= NULL
;
2594 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2595 // Note: this interacts with mono_image_open_a_lot (). If the path from
2596 // which we tried to load the problematic image is among the probing
2597 // paths, the MonoImage will be in the hash of loaded images and we
2598 // would just get it back again here, except for the code there that
2599 // mitigates the situation. Instead
2600 MonoAssembly
*result_ass
= mono_assembly_load_full_internal (&probed_aname
, new_requesting
, new_basedir
, new_asmctx
, &new_status
);
2602 if (! (result_ass
&& new_status
== MONO_IMAGE_OK
)) {
2603 *status
= new_status
;
2605 mono_assembly_name_free (&probed_aname
);
2609 * mono_assembly_open:
2610 * \param filename Opens the assembly pointed out by this name
2611 * \param status return status code
2613 * This loads an assembly from the specified \p filename. The \p filename allows
2614 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2615 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2616 * is treated as a local path.
2618 * First, an attempt is made to load the assembly from the bundled executable (for those
2619 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2620 * assembly has been registered as an embedded assembly). If this is not the case, then
2621 * the assembly is loaded from disk using `api:mono_image_open_full`.
2623 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2624 * the assembly is made.
2626 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2627 * assembly or NULL on error. Details about the error are stored in the
2628 * \p status variable.
2631 mono_assembly_open (const char *filename
, MonoImageOpenStatus
*status
)
2633 return mono_assembly_open_predicate (filename
, MONO_ASMCTX_DEFAULT
, NULL
, NULL
, NULL
, status
);
2637 * mono_assembly_load_from_full:
2638 * \param image Image to load the assembly from
2639 * \param fname assembly name to associate with the assembly
2640 * \param status returns the status condition
2641 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2643 * If the provided \p image has an assembly reference, it will process the given
2644 * image as an assembly with the given name.
2646 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2648 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2649 * set to \c MONO_IMAGE_OK; or NULL on error.
2651 * If there is an error loading the assembly the \p status will indicate the
2652 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2653 * image did not contain an assembly reference table.
2656 mono_assembly_load_from_full (MonoImage
*image
, const char*fname
,
2657 MonoImageOpenStatus
*status
, gboolean refonly
)
2659 return mono_assembly_load_from_predicate (image
, fname
, refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
, NULL
, NULL
, status
);
2663 mono_assembly_load_from_predicate (MonoImage
*image
, const char *fname
,
2664 MonoAssemblyContextKind asmctx
,
2665 MonoAssemblyCandidatePredicate predicate
,
2667 MonoImageOpenStatus
*status
)
2669 MonoAssembly
*ass
, *ass2
;
2672 if (!image
->tables
[MONO_TABLE_ASSEMBLY
].rows
) {
2673 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2674 *status
= MONO_IMAGE_IMAGE_INVALID
;
2678 #if defined (HOST_WIN32)
2683 tmp_fn
= g_strdup (fname
);
2684 for (i
= strlen (tmp_fn
) - 1; i
>= 0; i
--) {
2685 if (tmp_fn
[i
] == '/')
2689 base_dir
= absolute_dir (tmp_fn
);
2693 base_dir
= absolute_dir (fname
);
2697 * Create assembly struct, and enter it into the assembly cache
2699 ass
= g_new0 (MonoAssembly
, 1);
2700 ass
->basedir
= base_dir
;
2701 ass
->context
.kind
= asmctx
;
2704 MONO_PROFILER_RAISE (assembly_loading
, (ass
));
2706 mono_assembly_fill_assembly_name (image
, &ass
->aname
);
2708 if (mono_defaults
.corlib
&& strcmp (ass
->aname
.name
, "mscorlib") == 0) {
2709 // MS.NET doesn't support loading other mscorlibs
2712 mono_image_addref (mono_defaults
.corlib
);
2713 *status
= MONO_IMAGE_OK
;
2714 return mono_defaults
.corlib
->assembly
;
2717 /* Add a non-temporary reference because of ass->image */
2718 mono_image_addref (image
);
2720 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Image addref %s[%p] (asmctx %s) -> %s[%p]: %d", ass
->aname
.name
, ass
, mono_asmctx_get_name (&ass
->context
), image
->name
, image
, image
->ref_count
);
2723 * The load hooks might take locks so we can't call them while holding the
2726 if (ass
->aname
.name
&& asmctx
!= MONO_ASMCTX_INDIVIDUAL
) {
2727 /* FIXME: I think individual context should probably also look for an existing MonoAssembly here, we just need to pass the asmctx to the search hook so that it does a filename match (I guess?) */
2728 ass2
= mono_assembly_invoke_search_hook_internal (&ass
->aname
, NULL
, asmctx
== MONO_ASMCTX_REFONLY
, FALSE
);
2730 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Image %s[%p] reusing existing assembly %s[%p]", ass
->aname
.name
, ass
, ass2
->aname
.name
, ass2
);
2733 mono_image_close (image
);
2734 *status
= MONO_IMAGE_OK
;
2739 /* We need to check for ReferenceAssmeblyAttribute before we
2740 * mark the assembly as loaded and before we fire the load
2741 * hook. Otherwise mono_domain_fire_assembly_load () in
2742 * appdomain.c will cache a mapping from the assembly name to
2743 * this image and we won't be able to look for a different
2746 if (asmctx
!= MONO_ASMCTX_REFONLY
) {
2747 ERROR_DECL_VALUE (refasm_error
);
2748 if (mono_assembly_has_reference_assembly_attribute (ass
, &refasm_error
)) {
2749 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass
->aname
.name
, image
->name
);
2752 mono_image_close (image
);
2753 *status
= MONO_IMAGE_IMAGE_INVALID
;
2756 mono_error_cleanup (&refasm_error
);
2759 if (predicate
&& !predicate (ass
, user_data
)) {
2760 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate returned FALSE, skipping '%s' (%s)\n", ass
->aname
.name
, image
->name
);
2763 mono_image_close (image
);
2764 *status
= MONO_IMAGE_IMAGE_INVALID
;
2768 mono_assemblies_lock ();
2770 /* If an assembly is loaded into an individual context, always return a
2771 * new MonoAssembly, even if another assembly with the same name has
2772 * already been loaded.
2774 if (image
->assembly
&& asmctx
!= MONO_ASMCTX_INDIVIDUAL
) {
2776 * This means another thread has already loaded the assembly, but not yet
2777 * called the load hooks so the search hook can't find the assembly.
2779 mono_assemblies_unlock ();
2780 ass2
= image
->assembly
;
2783 mono_image_close (image
);
2784 *status
= MONO_IMAGE_OK
;
2788 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Prepared to set up assembly '%s' (%s)", ass
->aname
.name
, image
->name
);
2790 /* If asmctx is INDIVIDUAL, image->assembly might not be NULL, so don't
2792 if (image
->assembly
== NULL
)
2793 image
->assembly
= ass
;
2795 loaded_assemblies
= g_list_prepend (loaded_assemblies
, ass
);
2796 mono_assemblies_unlock ();
2799 if (image
->is_module_handle
)
2800 mono_image_fixup_vtable (image
);
2803 mono_assembly_invoke_load_hook (ass
);
2805 MONO_PROFILER_RAISE (assembly_loaded
, (ass
));
2811 * mono_assembly_load_from:
2812 * \param image Image to load the assembly from
2813 * \param fname assembly name to associate with the assembly
2814 * \param status return status code
2816 * If the provided \p image has an assembly reference, it will process the given
2817 * image as an assembly with the given name.
2819 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2821 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2822 * \p refonly parameter set to FALSE.
2823 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2824 * set to \c MONO_IMAGE_OK; or NULL on error.
2826 * If there is an error loading the assembly the \p status will indicate the
2827 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2828 * image did not contain an assembly reference table.
2832 mono_assembly_load_from (MonoImage
*image
, const char *fname
,
2833 MonoImageOpenStatus
*status
)
2835 return mono_assembly_load_from_full (image
, fname
, status
, FALSE
);
2839 * mono_assembly_name_free:
2840 * \param aname assembly name to free
2842 * Frees the provided assembly name object.
2843 * (it does not frees the object itself, only the name members).
2846 mono_assembly_name_free (MonoAssemblyName
*aname
)
2851 g_free ((void *) aname
->name
);
2852 g_free ((void *) aname
->culture
);
2853 g_free ((void *) aname
->hash_value
);
2854 g_free ((guint8
*) aname
->public_key
);
2858 parse_public_key (const gchar
*key
, gchar
** pubkey
, gboolean
*is_ecma
)
2861 gchar header
[16], val
, *arr
, *endp
;
2862 gint i
, j
, offset
, bitlen
, keylen
, pkeylen
;
2864 //both pubkey and is_ecma are required arguments
2865 g_assert (pubkey
&& is_ecma
);
2867 keylen
= strlen (key
) >> 1;
2871 /* allow the ECMA standard key */
2872 if (strcmp (key
, "00000000000000000400000000000000") == 0) {
2878 val
= g_ascii_xdigit_value (key
[0]) << 4;
2879 val
|= g_ascii_xdigit_value (key
[1]);
2884 val
= g_ascii_xdigit_value (key
[24]);
2885 val
|= g_ascii_xdigit_value (key
[25]);
2897 /* We need the first 16 bytes
2898 * to check whether this key is valid or not */
2899 pkeylen
= strlen (pkey
) >> 1;
2903 for (i
= 0, j
= 0; i
< 16; i
++) {
2904 header
[i
] = g_ascii_xdigit_value (pkey
[j
++]) << 4;
2905 header
[i
] |= g_ascii_xdigit_value (pkey
[j
++]);
2908 if (header
[0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
2909 header
[1] != 0x02 || /* Version (0x02) */
2910 header
[2] != 0x00 || /* Reserved (word) */
2911 header
[3] != 0x00 ||
2912 (guint
)(read32 (header
+ 8)) != 0x31415352) /* DWORD magic = RSA1 */
2915 /* Based on this length, we _should_ be able to know if the length is right */
2916 bitlen
= read32 (header
+ 12) >> 3;
2917 if ((bitlen
+ 16 + 4) != pkeylen
)
2920 arr
= (gchar
*)g_malloc (keylen
+ 4);
2921 /* Encode the size of the blob */
2922 mono_metadata_encode_value (keylen
, &arr
[0], &endp
);
2923 offset
= (gint
)(endp
-arr
);
2925 for (i
= offset
, j
= 0; i
< keylen
+ offset
; i
++) {
2926 arr
[i
] = g_ascii_xdigit_value (key
[j
++]) << 4;
2927 arr
[i
] |= g_ascii_xdigit_value (key
[j
++]);
2936 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
)
2938 gint major
, minor
, build
, revision
;
2941 gchar
*pkeyptr
, *encoded
, tok
[8];
2943 memset (aname
, 0, sizeof (MonoAssemblyName
));
2946 version_parts
= sscanf (version
, "%u.%u.%u.%u", &major
, &minor
, &build
, &revision
);
2947 if (version_parts
< 2 || version_parts
> 4)
2950 /* FIXME: we should set build & revision to -1 (instead of 0)
2951 if these are not set in the version string. That way, later on,
2952 we can still determine if these were specified. */
2953 aname
->major
= major
;
2954 aname
->minor
= minor
;
2955 if (version_parts
>= 3)
2956 aname
->build
= build
;
2959 if (version_parts
== 4)
2960 aname
->revision
= revision
;
2962 aname
->revision
= 0;
2965 aname
->flags
= flags
;
2967 aname
->name
= g_strdup (name
);
2970 if (g_ascii_strcasecmp (culture
, "neutral") == 0)
2971 aname
->culture
= g_strdup ("");
2973 aname
->culture
= g_strdup (culture
);
2976 if (token
&& strncmp (token
, "null", 4) != 0) {
2979 /* the constant includes the ending NULL, hence the -1 */
2980 if (strlen (token
) != (MONO_PUBLIC_KEY_TOKEN_LENGTH
- 1)) {
2981 mono_assembly_name_free (aname
);
2984 lower
= g_ascii_strdown (token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
2985 g_strlcpy ((char*)aname
->public_key_token
, lower
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
2990 gboolean is_ecma
= FALSE
;
2992 if (strcmp (key
, "null") == 0 || !parse_public_key (key
, &pkey
, &is_ecma
)) {
2993 mono_assembly_name_free (aname
);
2998 g_assert (pkey
== NULL
);
2999 aname
->public_key
= NULL
;
3000 g_strlcpy ((gchar
*)aname
->public_key_token
, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3004 len
= mono_metadata_decode_blob_size ((const gchar
*) pkey
, (const gchar
**) &pkeyptr
);
3005 // We also need to generate the key token
3006 mono_digest_get_public_token ((guchar
*) tok
, (guint8
*) pkeyptr
, len
);
3007 encoded
= encode_public_tok ((guchar
*) tok
, 8);
3008 g_strlcpy ((gchar
*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3011 if (save_public_key
)
3012 aname
->public_key
= (guint8
*) pkey
;
3021 parse_assembly_directory_name (const char *name
, const char *dirname
, MonoAssemblyName
*aname
)
3026 parts
= g_strsplit (dirname
, "_", 3);
3027 if (!parts
|| !parts
[0] || !parts
[1] || !parts
[2]) {
3032 res
= build_assembly_name (name
, parts
[0], parts
[1], parts
[2], NULL
, 0, 0, aname
, FALSE
);
3038 split_key_value (const gchar
*pair
, gchar
**key
, guint32
*keylen
, gchar
**value
)
3040 char *eqsign
= strchr (pair
, '=');
3048 *key
= (gchar
*)pair
;
3049 *keylen
= eqsign
- *key
;
3050 while (*keylen
> 0 && g_ascii_isspace ((*key
) [*keylen
- 1]))
3052 *value
= g_strstrip (eqsign
+ 1);
3057 mono_assembly_name_parse_full (const char *name
, MonoAssemblyName
*aname
, gboolean save_public_key
, gboolean
*is_version_defined
, gboolean
*is_token_defined
)
3061 gchar
*version
= NULL
;
3063 gchar
*culture
= NULL
;
3065 gchar
*token
= NULL
;
3069 gchar
*retargetable
= NULL
;
3070 gchar
*retargetable_uq
;
3074 gchar
*value
, *part_name
;
3075 guint32 part_name_len
;
3078 gboolean version_defined
;
3079 gboolean token_defined
;
3081 guint32 arch
= MONO_PROCESSOR_ARCHITECTURE_NONE
;
3083 if (!is_version_defined
)
3084 is_version_defined
= &version_defined
;
3085 *is_version_defined
= FALSE
;
3086 if (!is_token_defined
)
3087 is_token_defined
= &token_defined
;
3088 *is_token_defined
= FALSE
;
3090 parts
= tmp
= g_strsplit (name
, ",", 6);
3091 if (!tmp
|| !*tmp
) {
3096 dllname
= g_strstrip (*tmp
);
3101 if (!split_key_value (g_strstrip (*tmp
), &part_name
, &part_name_len
, &value
))
3102 goto cleanup_and_fail
;
3104 if (part_name_len
== 7 && !g_ascii_strncasecmp (part_name
, "Version", part_name_len
)) {
3105 *is_version_defined
= TRUE
;
3107 if (strlen (version
) == 0) {
3108 goto cleanup_and_fail
;
3114 if (part_name_len
== 7 && !g_ascii_strncasecmp (part_name
, "Culture", part_name_len
)) {
3116 if (strlen (culture
) == 0) {
3117 goto cleanup_and_fail
;
3123 if (part_name_len
== 14 && !g_ascii_strncasecmp (part_name
, "PublicKeyToken", part_name_len
)) {
3124 *is_token_defined
= TRUE
;
3126 if (strlen (token
) == 0) {
3127 goto cleanup_and_fail
;
3133 if (part_name_len
== 9 && !g_ascii_strncasecmp (part_name
, "PublicKey", part_name_len
)) {
3135 if (strlen (key
) == 0) {
3136 goto cleanup_and_fail
;
3142 if (part_name_len
== 12 && !g_ascii_strncasecmp (part_name
, "Retargetable", part_name_len
)) {
3143 retargetable
= value
;
3144 retargetable_uq
= unquote (retargetable
);
3145 if (retargetable_uq
!= NULL
)
3146 retargetable
= retargetable_uq
;
3148 if (!g_ascii_strcasecmp (retargetable
, "yes")) {
3149 flags
|= ASSEMBLYREF_RETARGETABLE_FLAG
;
3150 } else if (g_ascii_strcasecmp (retargetable
, "no")) {
3151 g_free (retargetable_uq
);
3152 goto cleanup_and_fail
;
3155 g_free (retargetable_uq
);
3160 if (part_name_len
== 21 && !g_ascii_strncasecmp (part_name
, "ProcessorArchitecture", part_name_len
)) {
3162 procarch_uq
= unquote (procarch
);
3163 if (procarch_uq
!= NULL
)
3164 procarch
= procarch_uq
;
3166 if (!g_ascii_strcasecmp (procarch
, "MSIL"))
3167 arch
= MONO_PROCESSOR_ARCHITECTURE_MSIL
;
3168 else if (!g_ascii_strcasecmp (procarch
, "X86"))
3169 arch
= MONO_PROCESSOR_ARCHITECTURE_X86
;
3170 else if (!g_ascii_strcasecmp (procarch
, "IA64"))
3171 arch
= MONO_PROCESSOR_ARCHITECTURE_IA64
;
3172 else if (!g_ascii_strcasecmp (procarch
, "AMD64"))
3173 arch
= MONO_PROCESSOR_ARCHITECTURE_AMD64
;
3175 g_free (procarch_uq
);
3176 goto cleanup_and_fail
;
3179 g_free (procarch_uq
);
3188 /* if retargetable flag is set, then we must have a fully qualified name */
3189 if (retargetable
!= NULL
&& (version
== NULL
|| culture
== NULL
|| (key
== NULL
&& token
== NULL
))) {
3190 goto cleanup_and_fail
;
3193 dllname_uq
= unquote (dllname
);
3194 version_uq
= unquote (version
);
3195 culture_uq
= unquote (culture
);
3196 token_uq
= unquote (token
);
3197 key_uq
= unquote (key
);
3199 res
= build_assembly_name (
3200 dllname_uq
== NULL
? dllname
: dllname_uq
,
3201 version_uq
== NULL
? version
: version_uq
,
3202 culture_uq
== NULL
? culture
: culture_uq
,
3203 token_uq
== NULL
? token
: token_uq
,
3204 key_uq
== NULL
? key
: key_uq
,
3205 flags
, arch
, aname
, save_public_key
);
3207 g_free (dllname_uq
);
3208 g_free (version_uq
);
3209 g_free (culture_uq
);
3222 unquote (const char *str
)
3230 slen
= strlen (str
);
3234 if (*str
!= '\'' && *str
!= '\"')
3237 end
= str
+ slen
- 1;
3241 return g_strndup (str
+ 1, slen
- 2);
3245 * mono_assembly_name_parse:
3246 * \param name name to parse
3247 * \param aname the destination assembly name
3249 * Parses an assembly qualified type name and assigns the name,
3250 * version, culture and token to the provided assembly name object.
3252 * \returns TRUE if the name could be parsed.
3255 mono_assembly_name_parse (const char *name
, MonoAssemblyName
*aname
)
3257 return mono_assembly_name_parse_full (name
, aname
, FALSE
, NULL
, NULL
);
3261 * mono_assembly_name_new:
3262 * \param name name to parse
3264 * Allocate a new \c MonoAssemblyName and fill its values from the
3267 * \returns a newly allocated structure or NULL if there was any failure.
3270 mono_assembly_name_new (const char *name
)
3272 MonoAssemblyName
*aname
= g_new0 (MonoAssemblyName
, 1);
3273 if (mono_assembly_name_parse (name
, aname
))
3280 * mono_assembly_name_get_name:
3283 mono_assembly_name_get_name (MonoAssemblyName
*aname
)
3289 * mono_assembly_name_get_culture:
3292 mono_assembly_name_get_culture (MonoAssemblyName
*aname
)
3294 return aname
->culture
;
3298 * mono_assembly_name_get_pubkeytoken:
3301 mono_assembly_name_get_pubkeytoken (MonoAssemblyName
*aname
)
3303 if (aname
->public_key_token
[0])
3304 return aname
->public_key_token
;
3309 * mono_assembly_name_get_version:
3312 mono_assembly_name_get_version (MonoAssemblyName
*aname
, uint16_t *minor
, uint16_t *build
, uint16_t *revision
)
3315 *minor
= aname
->minor
;
3317 *build
= aname
->build
;
3319 *revision
= aname
->revision
;
3320 return aname
->major
;
3323 static MonoAssembly
*
3324 probe_for_partial_name (const char *basepath
, const char *fullname
, MonoAssemblyName
*aname
, MonoImageOpenStatus
*status
)
3326 gchar
*fullpath
= NULL
;
3328 const char* direntry
;
3329 MonoAssemblyName gac_aname
;
3330 gint major
=-1, minor
=0, build
=0, revision
=0;
3331 gboolean exact_version
;
3333 dirhandle
= g_dir_open (basepath
, 0, NULL
);
3337 exact_version
= (aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0;
3339 while ((direntry
= g_dir_read_name (dirhandle
))) {
3340 gboolean match
= TRUE
;
3342 if(!parse_assembly_directory_name (aname
->name
, direntry
, &gac_aname
))
3345 if (aname
->culture
!= NULL
&& strcmp (aname
->culture
, gac_aname
.culture
) != 0)
3348 if (match
&& strlen ((char*)aname
->public_key_token
) > 0 &&
3349 !mono_public_tokens_are_equal (aname
->public_key_token
, gac_aname
.public_key_token
))
3353 if (exact_version
) {
3354 match
= (aname
->major
== gac_aname
.major
&& aname
->minor
== gac_aname
.minor
&&
3355 aname
->build
== gac_aname
.build
&& aname
->revision
== gac_aname
.revision
);
3357 else if (gac_aname
.major
< major
)
3359 else if (gac_aname
.major
== major
) {
3360 if (gac_aname
.minor
< minor
)
3362 else if (gac_aname
.minor
== minor
) {
3363 if (gac_aname
.build
< build
)
3365 else if (gac_aname
.build
== build
&& gac_aname
.revision
<= revision
)
3372 major
= gac_aname
.major
;
3373 minor
= gac_aname
.minor
;
3374 build
= gac_aname
.build
;
3375 revision
= gac_aname
.revision
;
3377 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, basepath
, direntry
, fullname
, NULL
);
3380 mono_assembly_name_free (&gac_aname
);
3383 g_dir_close (dirhandle
);
3385 if (fullpath
== NULL
)
3388 MonoAssembly
*res
= mono_assembly_open_predicate (fullpath
, MONO_ASMCTX_DEFAULT
, NULL
, NULL
, NULL
, status
);
3395 * mono_assembly_load_with_partial_name:
3396 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
3397 * \param status return status code
3399 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
3400 * so it might contain a qualified type name, version, culture and token.
3402 * This will load the assembly from the file whose name is derived from the assembly name
3403 * by appending the \c .dll extension.
3405 * The assembly is loaded from either one of the extra Global Assembly Caches specified
3406 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
3407 * if that fails from the GAC.
3409 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
3412 mono_assembly_load_with_partial_name (const char *name
, MonoImageOpenStatus
*status
)
3416 MonoAssemblyName
*aname
, base_name
;
3417 MonoAssemblyName mapped_aname
;
3418 gchar
*fullname
, *gacpath
;
3421 memset (&base_name
, 0, sizeof (MonoAssemblyName
));
3424 if (!mono_assembly_name_parse (name
, aname
))
3428 * If no specific version has been requested, make sure we load the
3429 * correct version for system assemblies.
3431 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) == 0)
3432 aname
= mono_assembly_remap_version (aname
, &mapped_aname
);
3434 res
= mono_assembly_loaded (aname
);
3436 mono_assembly_name_free (aname
);
3440 res
= invoke_assembly_preload_hook (aname
, assemblies_path
);
3442 res
->in_gac
= FALSE
;
3443 mono_assembly_name_free (aname
);
3447 fullname
= g_strdup_printf ("%s.dll", aname
->name
);
3449 if (extra_gac_paths
) {
3450 paths
= extra_gac_paths
;
3451 while (!res
&& *paths
) {
3452 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", aname
->name
, NULL
);
3453 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
3462 mono_assembly_name_free (aname
);
3466 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), "mono", "gac", aname
->name
, NULL
);
3467 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
3471 mono_assembly_name_free (aname
);
3476 MonoDomain
*domain
= mono_domain_get ();
3478 res
= mono_try_assembly_resolve (domain
, name
, NULL
, FALSE
, error
);
3479 if (!is_ok (error
)) {
3480 mono_error_cleanup (error
);
3481 if (*status
== MONO_IMAGE_OK
)
3482 *status
= MONO_IMAGE_IMAGE_INVALID
;
3490 mono_assembly_is_in_gac (const gchar
*filename
)
3492 const gchar
*rootdir
;
3496 if (filename
== NULL
)
3499 for (paths
= extra_gac_paths
; paths
&& *paths
; paths
++) {
3500 if (strstr (*paths
, filename
) != *paths
)
3503 gp
= (gchar
*) (filename
+ strlen (*paths
));
3504 if (*gp
!= G_DIR_SEPARATOR
)
3507 if (strncmp (gp
, "lib", 3))
3510 if (*gp
!= G_DIR_SEPARATOR
)
3513 if (strncmp (gp
, "mono", 4))
3516 if (*gp
!= G_DIR_SEPARATOR
)
3519 if (strncmp (gp
, "gac", 3))
3522 if (*gp
!= G_DIR_SEPARATOR
)
3528 rootdir
= mono_assembly_getrootdir ();
3529 if (strstr (filename
, rootdir
) != filename
)
3532 gp
= (gchar
*) (filename
+ strlen (rootdir
));
3533 if (*gp
!= G_DIR_SEPARATOR
)
3536 if (strncmp (gp
, "mono", 4))
3539 if (*gp
!= G_DIR_SEPARATOR
)
3542 if (strncmp (gp
, "gac", 3))
3545 if (*gp
!= G_DIR_SEPARATOR
)
3551 mono_assembly_load_publisher_policy (MonoAssemblyName
*aname
)
3554 gchar
*filename
, *pname
, *name
, *culture
, *version
, *fullpath
, *subpath
;
3558 if (strstr (aname
->name
, ".dll")) {
3559 len
= strlen (aname
->name
) - 4;
3560 name
= (gchar
*)g_malloc (len
+ 1);
3561 memcpy (name
, aname
->name
, len
);
3564 name
= g_strdup (aname
->name
);
3567 culture
= g_utf8_strdown (aname
->culture
, -1);
3569 culture
= g_strdup ("");
3571 pname
= g_strdup_printf ("policy.%d.%d.%s", aname
->major
, aname
->minor
, name
);
3572 version
= g_strdup_printf ("0.0.0.0_%s_%s", culture
, aname
->public_key_token
);
3576 filename
= g_strconcat (pname
, ".dll", NULL
);
3577 subpath
= g_build_path (G_DIR_SEPARATOR_S
, pname
, version
, filename
, NULL
);
3583 if (extra_gac_paths
) {
3584 paths
= extra_gac_paths
;
3585 while (!image
&& *paths
) {
3586 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
,
3587 "lib", "mono", "gac", subpath
, NULL
);
3588 image
= mono_image_open (fullpath
, NULL
);
3599 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
3600 "mono", "gac", subpath
, NULL
);
3601 image
= mono_image_open (fullpath
, NULL
);
3608 static MonoAssemblyName
*
3609 mono_assembly_bind_version (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
3611 memcpy (dest_name
, aname
, sizeof (MonoAssemblyName
));
3612 dest_name
->major
= info
->new_version
.major
;
3613 dest_name
->minor
= info
->new_version
.minor
;
3614 dest_name
->build
= info
->new_version
.build
;
3615 dest_name
->revision
= info
->new_version
.revision
;
3620 /* LOCKING: assembly_binding lock must be held */
3621 static MonoAssemblyBindingInfo
*
3622 search_binding_loaded (MonoAssemblyName
*aname
)
3626 for (tmp
= loaded_assembly_bindings
; tmp
; tmp
= tmp
->next
) {
3627 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)tmp
->data
;
3628 if (assembly_binding_maps_name (info
, aname
))
3635 static inline gboolean
3636 info_compare_versions (AssemblyVersionSet
*left
, AssemblyVersionSet
*right
)
3638 if (left
->major
!= right
->major
|| left
->minor
!= right
->minor
||
3639 left
->build
!= right
->build
|| left
->revision
!= right
->revision
)
3645 static inline gboolean
3646 info_versions_equal (MonoAssemblyBindingInfo
*left
, MonoAssemblyBindingInfo
*right
)
3648 if (left
->has_old_version_bottom
!= right
->has_old_version_bottom
)
3651 if (left
->has_old_version_top
!= right
->has_old_version_top
)
3654 if (left
->has_new_version
!= right
->has_new_version
)
3657 if (left
->has_old_version_bottom
&& !info_compare_versions (&left
->old_version_bottom
, &right
->old_version_bottom
))
3660 if (left
->has_old_version_top
&& !info_compare_versions (&left
->old_version_top
, &right
->old_version_top
))
3663 if (left
->has_new_version
&& !info_compare_versions (&left
->new_version
, &right
->new_version
))
3669 /* LOCKING: assumes all the necessary locks are held */
3671 assembly_binding_info_parsed (MonoAssemblyBindingInfo
*info
, void *user_data
)
3673 MonoAssemblyBindingInfo
*info_copy
;
3675 MonoAssemblyBindingInfo
*info_tmp
;
3676 MonoDomain
*domain
= (MonoDomain
*)user_data
;
3681 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
)) {
3682 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3683 info
->name
, info
->new_version
.major
, info
->new_version
.minor
, info
->new_version
.build
, info
->new_version
.revision
);
3687 for (tmp
= domain
->assembly_bindings
; tmp
; tmp
= tmp
->next
) {
3688 info_tmp
= (MonoAssemblyBindingInfo
*)tmp
->data
;
3689 if (strcmp (info
->name
, info_tmp
->name
) == 0 && info_versions_equal (info
, info_tmp
))
3693 info_copy
= (MonoAssemblyBindingInfo
*)mono_mempool_alloc0 (domain
->mp
, sizeof (MonoAssemblyBindingInfo
));
3694 memcpy (info_copy
, info
, sizeof (MonoAssemblyBindingInfo
));
3696 info_copy
->name
= mono_mempool_strdup (domain
->mp
, info
->name
);
3698 info_copy
->culture
= mono_mempool_strdup (domain
->mp
, info
->culture
);
3700 domain
->assembly_bindings
= g_slist_append_mempool (domain
->mp
, domain
->assembly_bindings
, info_copy
);
3704 get_version_number (int major
, int minor
)
3706 return major
* 256 + minor
;
3709 static inline gboolean
3710 info_major_minor_in_range (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
3712 int aname_version_number
= get_version_number (aname
->major
, aname
->minor
);
3713 if (!info
->has_old_version_bottom
)
3716 if (get_version_number (info
->old_version_bottom
.major
, info
->old_version_bottom
.minor
) > aname_version_number
)
3719 if (info
->has_old_version_top
&& get_version_number (info
->old_version_top
.major
, info
->old_version_top
.minor
) < aname_version_number
)
3722 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3723 info
->major
= aname
->major
;
3724 info
->minor
= aname
->minor
;
3729 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3730 static MonoAssemblyBindingInfo
*
3731 get_per_domain_assembly_binding_info (MonoDomain
*domain
, MonoAssemblyName
*aname
)
3733 MonoAssemblyBindingInfo
*info
;
3736 if (!domain
->assembly_bindings
)
3740 for (list
= domain
->assembly_bindings
; list
; list
= list
->next
) {
3741 info
= (MonoAssemblyBindingInfo
*)list
->data
;
3742 if (info
&& !strcmp (aname
->name
, info
->name
) && info_major_minor_in_range (info
, aname
))
3748 if (info
->name
&& info
->public_key_token
[0] && info
->has_old_version_bottom
&&
3749 info
->has_new_version
&& assembly_binding_maps_name (info
, aname
))
3750 info
->is_valid
= TRUE
;
3752 info
->is_valid
= FALSE
;
3759 mono_domain_parse_assembly_bindings (MonoDomain
*domain
, int amajor
, int aminor
, gchar
*domain_config_file_name
)
3761 if (domain
->assembly_bindings_parsed
)
3763 mono_domain_lock (domain
);
3764 if (!domain
->assembly_bindings_parsed
) {
3766 gchar
*domain_config_file_path
= mono_portability_find_file (domain_config_file_name
, TRUE
);
3768 if (!domain_config_file_path
)
3769 domain_config_file_path
= domain_config_file_name
;
3771 mono_config_parse_assembly_bindings (domain_config_file_path
, amajor
, aminor
, domain
, assembly_binding_info_parsed
);
3772 domain
->assembly_bindings_parsed
= TRUE
;
3773 if (domain_config_file_name
!= domain_config_file_path
)
3774 g_free (domain_config_file_path
);
3777 mono_domain_unlock (domain
);
3780 static MonoAssemblyName
*
3781 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
3784 MonoAssemblyBindingInfo
*info
, *info2
;
3788 if (aname
->public_key_token
[0] == 0)
3791 domain
= mono_domain_get ();
3793 mono_assembly_binding_lock ();
3794 info
= search_binding_loaded (aname
);
3795 mono_assembly_binding_unlock ();
3798 mono_domain_lock (domain
);
3799 info
= get_per_domain_assembly_binding_info (domain
, aname
);
3800 mono_domain_unlock (domain
);
3804 if (!check_policy_versions (info
, aname
))
3807 mono_assembly_bind_version (info
, aname
, dest_name
);
3811 if (domain
&& domain
->setup
&& domain
->setup
->configuration_file
) {
3812 gchar
*domain_config_file_name
= mono_string_to_utf8_checked (domain
->setup
->configuration_file
, error
);
3813 /* expect this to succeed because mono_domain_set_options_from_config () did
3814 * the same thing when the domain was created. */
3815 mono_error_assert_ok (error
);
3816 mono_domain_parse_assembly_bindings (domain
, aname
->major
, aname
->minor
, domain_config_file_name
);
3817 g_free (domain_config_file_name
);
3819 mono_domain_lock (domain
);
3820 info2
= get_per_domain_assembly_binding_info (domain
, aname
);
3823 info
= (MonoAssemblyBindingInfo
*)g_memdup (info2
, sizeof (MonoAssemblyBindingInfo
));
3824 info
->name
= g_strdup (info2
->name
);
3825 info
->culture
= g_strdup (info2
->culture
);
3826 info
->domain_id
= domain
->domain_id
;
3829 mono_domain_unlock (domain
);
3834 info
= g_new0 (MonoAssemblyBindingInfo
, 1);
3835 info
->major
= aname
->major
;
3836 info
->minor
= aname
->minor
;
3839 if (!info
->is_valid
) {
3840 ppimage
= mono_assembly_load_publisher_policy (aname
);
3842 get_publisher_policy_info (ppimage
, aname
, info
);
3843 mono_image_close (ppimage
);
3847 /* Define default error value if needed */
3848 if (!info
->is_valid
) {
3849 info
->name
= g_strdup (aname
->name
);
3850 info
->culture
= g_strdup (aname
->culture
);
3851 g_strlcpy ((char *)info
->public_key_token
, (const char *)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3854 mono_assembly_binding_lock ();
3855 info2
= search_binding_loaded (aname
);
3857 /* This binding was added by another thread
3859 mono_assembly_binding_info_free (info
);
3864 loaded_assembly_bindings
= g_slist_prepend (loaded_assembly_bindings
, info
);
3866 mono_assembly_binding_unlock ();
3868 if (!info
->is_valid
|| !check_policy_versions (info
, aname
))
3871 mono_assembly_bind_version (info
, aname
, dest_name
);
3876 * mono_assembly_load_from_gac
3878 * \param aname The assembly name object
3880 static MonoAssembly
*
3881 mono_assembly_load_from_gac (MonoAssemblyName
*aname
, gchar
*filename
, MonoImageOpenStatus
*status
, MonoBoolean refonly
)
3883 MonoAssembly
*result
= NULL
;
3884 gchar
*name
, *version
, *culture
, *fullpath
, *subpath
;
3889 if (aname
->public_key_token
[0] == 0) {
3893 if (strstr (aname
->name
, ".dll")) {
3894 len
= strlen (filename
) - 4;
3895 name
= (gchar
*)g_malloc (len
+ 1);
3896 memcpy (name
, aname
->name
, len
);
3899 name
= g_strdup (aname
->name
);
3902 if (aname
->culture
) {
3903 culture
= g_utf8_strdown (aname
->culture
, -1);
3905 culture
= g_strdup ("");
3908 pubtok
= g_ascii_strdown ((char*)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3909 version
= g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname
->major
,
3910 aname
->minor
, aname
->build
, aname
->revision
,
3914 subpath
= g_build_path (G_DIR_SEPARATOR_S
, name
, version
, filename
, NULL
);
3919 const MonoAssemblyContextKind asmctx
= refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
;
3921 if (extra_gac_paths
) {
3922 paths
= extra_gac_paths
;
3923 while (!result
&& *paths
) {
3924 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", subpath
, NULL
);
3925 result
= mono_assembly_open_predicate (fullpath
, asmctx
, NULL
, NULL
, NULL
, status
);
3932 result
->in_gac
= TRUE
;
3937 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
3938 "mono", "gac", subpath
, NULL
);
3939 result
= mono_assembly_open_predicate (fullpath
, asmctx
, NULL
, NULL
, NULL
, status
);
3943 result
->in_gac
= TRUE
;
3951 mono_assembly_load_corlib (const MonoRuntimeInfo
*runtime
, MonoImageOpenStatus
*status
)
3954 MonoAssemblyName
*aname
;
3957 /* g_print ("corlib already loaded\n"); */
3961 // A nonstandard preload hook may provide a special mscorlib assembly
3962 aname
= mono_assembly_name_new ("mscorlib.dll");
3963 corlib
= invoke_assembly_preload_hook (aname
, assemblies_path
);
3964 mono_assembly_name_free (aname
);
3967 goto return_corlib_and_facades
;
3969 // This unusual directory layout can occur if mono is being built and run out of its own source repo
3970 if (assemblies_path
) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
3971 corlib
= load_in_path ("mscorlib.dll", (const char**)assemblies_path
, status
, MONO_ASMCTX_DEFAULT
, NULL
, NULL
);
3973 goto return_corlib_and_facades
;
3976 /* Normal case: Load corlib from mono/<version> */
3977 corlib_file
= g_build_filename ("mono", runtime
->framework_version
, "mscorlib.dll", NULL
);
3978 if (assemblies_path
) { // Custom assemblies path
3979 corlib
= load_in_path (corlib_file
, (const char**)assemblies_path
, status
, MONO_ASMCTX_DEFAULT
, NULL
, NULL
);
3981 g_free (corlib_file
);
3982 goto return_corlib_and_facades
;
3985 corlib
= load_in_path (corlib_file
, default_path
, status
, MONO_ASMCTX_DEFAULT
, NULL
, NULL
);
3986 g_free (corlib_file
);
3988 return_corlib_and_facades
:
3989 if (corlib
&& !strcmp (runtime
->framework_version
, "4.5")) // FIXME: stop hardcoding 4.5 here
3990 default_path
[1] = g_strdup_printf ("%s/Facades", corlib
->basedir
);
3995 static MonoAssembly
*
3996 prevent_reference_assembly_from_running (MonoAssembly
* candidate
, gboolean refonly
)
3998 ERROR_DECL_VALUE (refasm_error
);
3999 error_init (&refasm_error
);
4000 if (candidate
&& !refonly
) {
4001 /* .NET Framework seems to not check for ReferenceAssemblyAttribute on dynamic assemblies */
4002 if (!image_is_dynamic (candidate
->image
) &&
4003 mono_assembly_has_reference_assembly_attribute (candidate
, &refasm_error
))
4006 mono_error_cleanup (&refasm_error
);
4011 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly
*candidate
, gpointer ud
)
4013 MonoAssemblyName
*wanted_name
= (MonoAssemblyName
*)ud
;
4014 MonoAssemblyName
*candidate_name
= &candidate
->aname
;
4016 g_assert (wanted_name
!= NULL
);
4017 g_assert (candidate_name
!= NULL
);
4019 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
4020 char * s
= mono_stringify_assembly_name (wanted_name
);
4021 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: wanted = %s\n", s
);
4023 s
= mono_stringify_assembly_name (candidate_name
);
4024 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate = %s\n", s
);
4029 /* Wanted name has no token, not strongly named: always matches. */
4030 if (0 == wanted_name
->public_key_token
[0]) {
4031 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: wanted has no token, returning TRUE\n");
4035 /* Candidate name has no token, not strongly named: never matches */
4036 if (0 == candidate_name
->public_key_token
[0]) {
4037 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate has no token, returning FALSE\n");
4041 return exact_sn_match (wanted_name
, candidate_name
) ||
4042 framework_assembly_sn_match (wanted_name
, candidate_name
);
4046 exact_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
)
4048 gboolean result
= mono_assembly_names_equal (wanted_name
, candidate_name
);
4050 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s\n",
4051 result
? "match, returning TRUE" : "don't match, returning FALSE");
4057 framework_assembly_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
)
4059 #ifndef DISABLE_DESKTOP_LOADER
4060 const AssemblyVersionMap
*vmap
= (AssemblyVersionMap
*)g_hash_table_lookup (assembly_remapping_table
, wanted_name
->name
);
4062 if (!vmap
->framework_facade_assembly
) {
4063 /* 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. */
4064 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_PUBKEY
);
4065 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");
4068 /* For facades, the name and public key token should
4069 * match, but the version doesn't matter as long as the
4070 * candidate is not older. */
4071 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_VERSION
);
4072 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s (ignoring version)", result
? "match" : "don't match, returning FALSE");
4074 // compare major of candidate and wanted
4075 int c
= assembly_names_compare_versions (candidate_name
, wanted_name
, 1);
4076 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate major version is %s wanted major version, returning %s\n", c
== 0 ? "the same as" : (c
< 0 ? "lower than" : "greater than"),
4077 (c
>= 0) ? "TRUE" : "FALSE");
4078 return (c
>= 0); // don't accept a candidate that's older than wanted.
4089 mono_assembly_load_full_nosearch (MonoAssemblyName
*aname
,
4090 const char *basedir
,
4091 MonoAssemblyContextKind asmctx
,
4092 MonoImageOpenStatus
*status
)
4095 MonoAssembly
*result
;
4096 MonoAssemblyName maped_aname
;
4097 MonoAssemblyName maped_name_pp
;
4099 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
4101 const gboolean refonly
= asmctx
== MONO_ASMCTX_REFONLY
;
4103 /* Reflection only assemblies don't get assembly binding */
4105 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
4107 result
= mono_assembly_loaded_full (aname
, refonly
);
4111 result
= refonly
? invoke_assembly_refonly_preload_hook (aname
, assemblies_path
) : invoke_assembly_preload_hook (aname
, assemblies_path
);
4113 result
->in_gac
= FALSE
;
4117 return mono_assembly_load_full_gac_base_default (aname
, basedir
, asmctx
, status
);
4120 /* Like mono_assembly_load_full_nosearch, but don't ask the preload look (ie,
4121 * the appdomain) to run. Just looks in the gac, the specified base dir or the
4122 * default_path. Does NOT look in the appdomain application base or in the
4126 mono_assembly_load_full_gac_base_default (MonoAssemblyName
*aname
,
4127 const char *basedir
,
4128 MonoAssemblyContextKind asmctx
,
4129 MonoImageOpenStatus
*status
)
4131 MonoAssembly
*result
;
4132 char *fullpath
, *filename
;
4137 /* Currently we retrieve the loaded corlib for reflection
4138 * only requests, like a common reflection only assembly
4140 if (strcmp (aname
->name
, "mscorlib") == 0 || strcmp (aname
->name
, "mscorlib.dll") == 0) {
4141 return mono_assembly_load_corlib (mono_get_runtime_info (), status
);
4144 MonoAssemblyCandidatePredicate predicate
= NULL
;
4145 void* predicate_ud
= NULL
;
4146 #if !defined(DISABLE_DESKTOP_LOADER)
4147 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
4148 predicate
= &mono_assembly_candidate_predicate_sn_same_name
;
4149 predicate_ud
= aname
;
4153 const gboolean refonly
= asmctx
== MONO_ASMCTX_REFONLY
;
4155 len
= strlen (aname
->name
);
4156 for (ext_index
= 0; ext_index
< 2; ext_index
++) {
4157 ext
= ext_index
== 0 ? ".dll" : ".exe";
4158 if (len
> 4 && (!strcmp (aname
->name
+ len
- 4, ".dll") || !strcmp (aname
->name
+ len
- 4, ".exe"))) {
4159 filename
= g_strdup (aname
->name
);
4160 /* Don't try appending .dll/.exe if it already has one of those extensions */
4163 filename
= g_strconcat (aname
->name
, ext
, NULL
);
4166 result
= mono_assembly_load_from_gac (aname
, filename
, status
, refonly
);
4173 fullpath
= g_build_filename (basedir
, filename
, NULL
);
4174 result
= mono_assembly_open_predicate (fullpath
, asmctx
, predicate
, predicate_ud
, NULL
, status
);
4177 result
->in_gac
= FALSE
;
4183 result
= load_in_path (filename
, default_path
, status
, asmctx
, predicate
, predicate_ud
);
4185 result
->in_gac
= FALSE
;
4195 * Try to load the assembly without looking in the domain:
4196 * tries the MONO_PATH, then the gac, and the default_path.
4199 mono_assembly_load_full_nodomain (MonoAssemblyName
*aname
,
4200 MonoAssemblyContextKind asmctx
,
4201 MonoImageOpenStatus
*status
)
4203 MonoAssembly
*result
= NULL
;
4204 result
= mono_assembly_load_from_assemblies_path (assemblies_path
, aname
, asmctx
);
4206 result
= mono_assembly_load_full_gac_base_default (aname
, NULL
, asmctx
, status
);
4211 mono_assembly_load_full_internal (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, const char *basedir
, MonoAssemblyContextKind asmctx
, MonoImageOpenStatus
*status
)
4213 MonoAssembly
*result
= mono_assembly_load_full_nosearch (aname
, basedir
, asmctx
, status
);
4214 const gboolean refonly
= asmctx
== MONO_ASMCTX_REFONLY
;
4217 /* Try a postload search hook */
4218 result
= mono_assembly_invoke_search_hook_internal (aname
, requesting
, refonly
, TRUE
);
4219 result
= prevent_reference_assembly_from_running (result
, refonly
);
4225 * mono_assembly_load_full:
4226 * \param aname A MonoAssemblyName with the assembly name to load.
4227 * \param basedir A directory to look up the assembly at.
4228 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
4229 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
4231 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
4232 * attempts to load the assembly from that directory before probing the standard locations.
4234 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
4235 * assembly binding takes place.
4237 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
4238 * value pointed by \p status is updated with an error code.
4241 mono_assembly_load_full (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
, gboolean refonly
)
4243 return mono_assembly_load_full_internal (aname
, NULL
, basedir
, refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
, status
);
4247 * mono_assembly_load:
4248 * \param aname A MonoAssemblyName with the assembly name to load.
4249 * \param basedir A directory to look up the assembly at.
4250 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
4252 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
4253 * attempts to load the assembly from that directory before probing the standard locations.
4255 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
4256 * value pointed by \p status is updated with an error code.
4259 mono_assembly_load (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
)
4261 return mono_assembly_load_full_internal (aname
, NULL
, basedir
, MONO_ASMCTX_DEFAULT
, status
);
4265 * mono_assembly_loaded_full:
4266 * \param aname an assembly to look for.
4267 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
4269 * This is used to determine if the specified assembly has been loaded
4270 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
4271 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
4274 mono_assembly_loaded_full (MonoAssemblyName
*aname
, gboolean refonly
)
4277 MonoAssemblyName maped_aname
;
4279 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
4281 res
= mono_assembly_invoke_search_hook_internal (aname
, NULL
, refonly
, FALSE
);
4287 * mono_assembly_loaded:
4288 * \param aname an assembly to look for.
4290 * This is used to determine if the specified assembly has been loaded
4292 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
4293 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
4296 mono_assembly_loaded (MonoAssemblyName
*aname
)
4298 return mono_assembly_loaded_full (aname
, FALSE
);
4302 mono_assembly_release_gc_roots (MonoAssembly
*assembly
)
4304 if (assembly
== NULL
|| assembly
== REFERENCE_MISSING
)
4307 if (assembly_is_dynamic (assembly
)) {
4309 MonoDynamicImage
*dynimg
= (MonoDynamicImage
*)assembly
->image
;
4310 for (i
= 0; i
< dynimg
->image
.module_count
; ++i
)
4311 mono_dynamic_image_release_gc_roots ((MonoDynamicImage
*)dynimg
->image
.modules
[i
]);
4312 mono_dynamic_image_release_gc_roots (dynimg
);
4317 * Returns whether mono_assembly_close_finish() must be called as
4318 * well. See comment for mono_image_close_except_pools() for why we
4319 * unload in two steps.
4322 mono_assembly_close_except_image_pools (MonoAssembly
*assembly
)
4325 g_return_val_if_fail (assembly
!= NULL
, FALSE
);
4327 if (assembly
== REFERENCE_MISSING
)
4330 /* Might be 0 already */
4331 if (mono_atomic_dec_i32 (&assembly
->ref_count
) > 0)
4334 MONO_PROFILER_RAISE (assembly_unloading
, (assembly
));
4336 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Unloading assembly %s [%p].", assembly
->aname
.name
, assembly
);
4338 mono_debug_close_image (assembly
->image
);
4340 mono_assemblies_lock ();
4341 loaded_assemblies
= g_list_remove (loaded_assemblies
, assembly
);
4342 mono_assemblies_unlock ();
4344 assembly
->image
->assembly
= NULL
;
4346 if (!mono_image_close_except_pools (assembly
->image
))
4347 assembly
->image
= NULL
;
4349 for (tmp
= assembly
->friend_assembly_names
; tmp
; tmp
= tmp
->next
) {
4350 MonoAssemblyName
*fname
= (MonoAssemblyName
*)tmp
->data
;
4351 mono_assembly_name_free (fname
);
4354 g_slist_free (assembly
->friend_assembly_names
);
4355 g_free (assembly
->basedir
);
4357 MONO_PROFILER_RAISE (assembly_unloaded
, (assembly
));
4363 mono_assembly_close_finish (MonoAssembly
*assembly
)
4365 g_assert (assembly
&& assembly
!= REFERENCE_MISSING
);
4367 if (assembly
->image
)
4368 mono_image_close_finish (assembly
->image
);
4370 if (assembly_is_dynamic (assembly
)) {
4371 g_free ((char*)assembly
->aname
.culture
);
4378 * mono_assembly_close:
4379 * \param assembly the assembly to release.
4381 * This method releases a reference to the \p assembly. The assembly is
4382 * only released when all the outstanding references to it are released.
4385 mono_assembly_close (MonoAssembly
*assembly
)
4387 if (mono_assembly_close_except_image_pools (assembly
))
4388 mono_assembly_close_finish (assembly
);
4392 * mono_assembly_load_module:
4395 mono_assembly_load_module (MonoAssembly
*assembly
, guint32 idx
)
4398 MonoImage
*result
= mono_assembly_load_module_checked (assembly
, idx
, error
);
4399 mono_error_assert_ok (error
);
4404 mono_assembly_load_module_checked (MonoAssembly
*assembly
, uint32_t idx
, MonoError
*error
)
4406 return mono_image_load_file_for_image_checked (assembly
->image
, idx
, error
);
4411 * mono_assembly_foreach:
4412 * \param func function to invoke for each assembly loaded
4413 * \param user_data data passed to the callback
4415 * Invokes the provided \p func callback for each assembly loaded into
4416 * the runtime. The first parameter passed to the callback is the
4417 * \c MonoAssembly*, and the second parameter is the \p user_data.
4419 * This is done for all assemblies loaded in the runtime, not just
4420 * those loaded in the current application domain.
4423 mono_assembly_foreach (GFunc func
, gpointer user_data
)
4428 * We make a copy of the list to avoid calling the callback inside the
4429 * lock, which could lead to deadlocks.
4431 mono_assemblies_lock ();
4432 copy
= g_list_copy (loaded_assemblies
);
4433 mono_assemblies_unlock ();
4435 g_list_foreach (loaded_assemblies
, func
, user_data
);
4441 * mono_assemblies_cleanup:
4443 * Free all resources used by this module.
4446 mono_assemblies_cleanup (void)
4450 mono_os_mutex_destroy (&assemblies_mutex
);
4451 mono_os_mutex_destroy (&assembly_binding_mutex
);
4453 for (l
= loaded_assembly_bindings
; l
; l
= l
->next
) {
4454 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)l
->data
;
4456 mono_assembly_binding_info_free (info
);
4459 g_slist_free (loaded_assembly_bindings
);
4461 free_assembly_asmctx_from_path_hooks ();
4462 free_assembly_load_hooks ();
4463 free_assembly_search_hooks ();
4464 free_assembly_preload_hooks ();
4467 /*LOCKING takes the assembly_binding lock*/
4469 mono_assembly_cleanup_domain_bindings (guint32 domain_id
)
4473 mono_assembly_binding_lock ();
4474 iter
= &loaded_assembly_bindings
;
4477 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)l
->data
;
4479 if (info
->domain_id
== domain_id
) {
4481 mono_assembly_binding_info_free (info
);
4488 mono_assembly_binding_unlock ();
4492 * Holds the assembly of the application, for
4493 * System.Diagnostics.Process::MainModule
4495 static MonoAssembly
*main_assembly
=NULL
;
4498 * mono_assembly_set_main:
4501 mono_assembly_set_main (MonoAssembly
*assembly
)
4503 main_assembly
= assembly
;
4507 * mono_assembly_get_main:
4509 * Returns: the assembly for the application, the first assembly that is loaded by the VM
4512 mono_assembly_get_main (void)
4514 return (main_assembly
);
4518 * mono_assembly_get_image:
4519 * \param assembly The assembly to retrieve the image from
4521 * \returns the \c MonoImage associated with this assembly.
4524 mono_assembly_get_image (MonoAssembly
*assembly
)
4526 return assembly
->image
;
4530 * mono_assembly_get_name:
4531 * \param assembly The assembly to retrieve the name from
4533 * The returned name's lifetime is the same as \p assembly's.
4535 * \returns the \c MonoAssemblyName associated with this assembly.
4538 mono_assembly_get_name (MonoAssembly
*assembly
)
4540 return &assembly
->aname
;
4544 * mono_register_bundled_assemblies:
4547 mono_register_bundled_assemblies (const MonoBundledAssembly
**assemblies
)
4549 bundles
= assemblies
;
4552 #define MONO_DECLSEC_FORMAT_10 0x3C
4553 #define MONO_DECLSEC_FORMAT_20 0x2E
4554 #define MONO_DECLSEC_FIELD 0x53
4555 #define MONO_DECLSEC_PROPERTY 0x54
4557 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4558 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4559 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4560 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4561 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4564 mono_assembly_try_decode_skip_verification_param (const char *p
, const char **resp
, gboolean
*abort_decoding
)
4568 case MONO_DECLSEC_PROPERTY
:
4570 case MONO_DECLSEC_FIELD
:
4572 *abort_decoding
= TRUE
;
4577 if (*p
++ != MONO_TYPE_BOOLEAN
) {
4578 *abort_decoding
= TRUE
;
4582 /* property name length */
4583 len
= mono_metadata_decode_value (p
, &p
);
4585 if (len
>= SKIP_VISIBILITY_PROPERTY_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_PROPERTY_NAME
, SKIP_VISIBILITY_PROPERTY_SIZE
)) {
4596 mono_assembly_try_decode_skip_verification (const char *p
, const char *endn
)
4598 int i
, j
, num
, len
, params_len
;
4600 if (*p
== MONO_DECLSEC_FORMAT_10
) {
4601 gsize read
, written
;
4602 char *res
= g_convert (p
, endn
- p
, "UTF-8", "UTF-16LE", &read
, &written
, NULL
);
4604 gboolean found
= strstr (res
, SKIP_VISIBILITY_XML_ATTRIBUTE
) != NULL
;
4610 if (*p
++ != MONO_DECLSEC_FORMAT_20
)
4613 /* number of encoded permission attributes */
4614 num
= mono_metadata_decode_value (p
, &p
);
4615 for (i
= 0; i
< num
; ++i
) {
4616 gboolean is_valid
= FALSE
;
4617 gboolean abort_decoding
= FALSE
;
4619 /* attribute name length */
4620 len
= mono_metadata_decode_value (p
, &p
);
4622 /* We don't really need to fully decode the type. Comparing the name is enough */
4623 is_valid
= len
>= SKIP_VISIBILITY_ATTRIBUTE_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_ATTRIBUTE_NAME
, SKIP_VISIBILITY_ATTRIBUTE_SIZE
);
4627 /*size of the params table*/
4628 params_len
= mono_metadata_decode_value (p
, &p
);
4630 const char *params_end
= p
+ params_len
;
4632 /* number of parameters */
4633 len
= mono_metadata_decode_value (p
, &p
);
4635 for (j
= 0; j
< len
; ++j
) {
4636 if (mono_assembly_try_decode_skip_verification_param (p
, &p
, &abort_decoding
))
4652 mono_assembly_has_skip_verification (MonoAssembly
*assembly
)
4655 guint32 cols
[MONO_DECL_SECURITY_SIZE
];
4659 if (MONO_SECMAN_FLAG_INIT (assembly
->skipverification
))
4660 return MONO_SECMAN_FLAG_GET_VALUE (assembly
->skipverification
);
4662 t
= &assembly
->image
->tables
[MONO_TABLE_DECLSECURITY
];
4664 for (i
= 0; i
< t
->rows
; ++i
) {
4665 mono_metadata_decode_row (t
, i
, cols
, MONO_DECL_SECURITY_SIZE
);
4666 if ((cols
[MONO_DECL_SECURITY_PARENT
] & MONO_HAS_DECL_SECURITY_MASK
) != MONO_HAS_DECL_SECURITY_ASSEMBLY
)
4668 if (cols
[MONO_DECL_SECURITY_ACTION
] != SECURITY_ACTION_REQMIN
)
4671 blob
= mono_metadata_blob_heap (assembly
->image
, cols
[MONO_DECL_SECURITY_PERMISSIONSET
]);
4672 len
= mono_metadata_decode_blob_size (blob
, &blob
);
4676 if (mono_assembly_try_decode_skip_verification (blob
, blob
+ len
)) {
4677 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, TRUE
);
4682 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, FALSE
);
4686 MonoAssemblyContextKind
4687 mono_asmctx_get_kind (const MonoAssemblyContext
*ctx
)
4693 mono_asmctx_get_name (const MonoAssemblyContext
*asmctx
)
4695 static const char* names
[] = {
4701 g_assert (asmctx
->kind
>= 0 && asmctx
->kind
<= MONO_ASMCTX_LAST
);
4702 return names
[asmctx
->kind
];