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},
100 {"CustomMarshalers", 0},
107 {"Microsoft.Build.Engine", 2, NULL
, TRUE
},
108 {"Microsoft.Build.Framework", 2, NULL
, TRUE
},
109 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
110 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
111 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
112 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
113 {"Microsoft.CSharp", 0},
114 {"Microsoft.VisualBasic", 1},
115 {"Microsoft.VisualC", 1},
116 FACADE_ASSEMBLY ("Microsoft.Win32.Primitives"),
117 FACADE_ASSEMBLY ("Microsoft.Win32.Registry"),
118 FACADE_ASSEMBLY ("Microsoft.Win32.Registry.AccessControl"),
120 {"Mono.CompilerServices.SymbolWriter", 0},
122 {"Mono.Data.SybaseClient", 0},
123 {"Mono.Data.Tds", 0},
124 {"Mono.Data.TdsClient", 0},
125 {"Mono.GetOptions", 0},
128 {"Mono.Security", 0},
129 {"Mono.Security.Win32", 0},
131 {"Novell.Directory.Ldap", 0},
134 FACADE_ASSEMBLY ("System.AppContext"),
135 FACADE_ASSEMBLY ("System.Buffers"),
136 FACADE_ASSEMBLY ("System.Collections"),
137 FACADE_ASSEMBLY ("System.Collections.Concurrent"),
138 FACADE_ASSEMBLY ("System.Collections.NonGeneric"),
139 FACADE_ASSEMBLY ("System.Collections.Specialized"),
140 FACADE_ASSEMBLY ("System.ComponentModel"),
141 FACADE_ASSEMBLY ("System.ComponentModel.Annotations"),
142 {"System.ComponentModel.Composition", 2},
143 {"System.ComponentModel.DataAnnotations", 2},
144 FACADE_ASSEMBLY ("System.ComponentModel.EventBasedAsync"),
145 FACADE_ASSEMBLY ("System.ComponentModel.Primitives"),
146 FACADE_ASSEMBLY ("System.ComponentModel.TypeConverter"),
147 {"System.Configuration", 0},
148 {"System.Configuration.Install", 0},
149 FACADE_ASSEMBLY ("System.Console"),
152 FACADE_ASSEMBLY ("System.Data.Common"),
153 {"System.Data.DataSetExtensions", 0},
154 {"System.Data.Entity", 0},
155 {"System.Data.Linq", 2},
156 {"System.Data.OracleClient", 0},
157 {"System.Data.Services", 2},
158 {"System.Data.Services.Client", 2},
159 FACADE_ASSEMBLY ("System.Data.SqlClient"),
160 {"System.Data.SqlXml", 0},
161 {"System.Deployment", 0},
162 {"System.Design", 0},
163 FACADE_ASSEMBLY ("System.Diagnostics.Contracts"),
164 FACADE_ASSEMBLY ("System.Diagnostics.Debug"),
165 FACADE_ASSEMBLY ("System.Diagnostics.FileVersionInfo"),
166 FACADE_ASSEMBLY ("System.Diagnostics.Process"),
167 FACADE_ASSEMBLY ("System.Diagnostics.StackTrace"),
168 FACADE_ASSEMBLY ("System.Diagnostics.TextWriterTraceListener"),
169 FACADE_ASSEMBLY ("System.Diagnostics.Tools"),
170 FACADE_ASSEMBLY ("System.Diagnostics.TraceEvent"),
171 FACADE_ASSEMBLY ("System.Diagnostics.TraceSource"),
172 FACADE_ASSEMBLY ("System.Diagnostics.Tracing"),
173 {"System.DirectoryServices", 0},
174 {"System.DirectoryServices.Protocols", 0},
175 {"System.Drawing", 0},
176 FACADE_ASSEMBLY ("System.Drawing.Common"),
177 {"System.Drawing.Design", 0},
178 FACADE_ASSEMBLY ("System.Drawing.Primitives"),
179 {"System.Dynamic", 0},
180 FACADE_ASSEMBLY ("System.Dynamic.Runtime"),
181 {"System.EnterpriseServices", 0},
182 FACADE_ASSEMBLY ("System.Globalization"),
183 FACADE_ASSEMBLY ("System.Globalization.Calendars"),
184 FACADE_ASSEMBLY ("System.Globalization.Extensions"),
185 {"System.IdentityModel", 3},
186 {"System.IdentityModel.Selectors", 3},
187 FACADE_ASSEMBLY ("System.IO"),
188 {"System.IO.Compression", 2},
189 {"System.IO.Compression.FileSystem", 0},
190 FACADE_ASSEMBLY ("System.IO.Compression.ZipFile"),
191 FACADE_ASSEMBLY ("System.IO.FileSystem"),
192 FACADE_ASSEMBLY ("System.IO.FileSystem.AccessControl"),
193 FACADE_ASSEMBLY ("System.IO.FileSystem.DriveInfo"),
194 FACADE_ASSEMBLY ("System.IO.FileSystem.Primitives"),
195 FACADE_ASSEMBLY ("System.IO.FileSystem.Watcher"),
196 FACADE_ASSEMBLY ("System.IO.IsolatedStorage"),
197 FACADE_ASSEMBLY ("System.IO.MemoryMappedFiles"),
198 FACADE_ASSEMBLY ("System.IO.Packaging"),
199 FACADE_ASSEMBLY ("System.IO.Pipes"),
200 FACADE_ASSEMBLY ("System.IO.UnmanagedMemoryStream"),
201 FACADE_ASSEMBLY ("System.Linq"),
202 FACADE_ASSEMBLY ("System.Linq.Expressions"),
203 FACADE_ASSEMBLY ("System.Linq.Parallel"),
204 FACADE_ASSEMBLY ("System.Linq.Queryable"),
205 {"System.Management", 0},
206 FACADE_ASSEMBLY ("System.Memory"),
207 {"System.Messaging", 0},
209 FACADE_ASSEMBLY ("System.Net.AuthenticationManager"),
210 FACADE_ASSEMBLY ("System.Net.Cache"),
211 {"System.Net.Http", 4},
212 {"System.Net.Http.Rtc", 0},
213 {"System.Net.Http.WebRequest", 0},
214 FACADE_ASSEMBLY ("System.Net.HttpListener"),
215 FACADE_ASSEMBLY ("System.Net.Mail"),
216 FACADE_ASSEMBLY ("System.Net.NameResolution"),
217 FACADE_ASSEMBLY ("System.Net.NetworkInformation"),
218 FACADE_ASSEMBLY ("System.Net.Ping"),
219 FACADE_ASSEMBLY ("System.Net.Primitives"),
220 FACADE_ASSEMBLY ("System.Net.Requests"),
221 FACADE_ASSEMBLY ("System.Net.Security"),
222 FACADE_ASSEMBLY ("System.Net.ServicePoint"),
223 FACADE_ASSEMBLY ("System.Net.Sockets"),
224 FACADE_ASSEMBLY ("System.Net.Utilities"),
225 FACADE_ASSEMBLY ("System.Net.WebHeaderCollection"),
226 FACADE_ASSEMBLY ("System.Net.WebSockets"),
227 FACADE_ASSEMBLY ("System.Net.WebSockets.Client"),
228 {"System.Numerics", 3},
229 {"System.Numerics.Vectors", 3},
230 FACADE_ASSEMBLY ("System.ObjectModel"),
231 FACADE_ASSEMBLY ("System.Reflection"),
232 {"System.Reflection.Context", 0},
233 FACADE_ASSEMBLY ("System.Reflection.DispatchProxy"),
234 FACADE_ASSEMBLY ("System.Reflection.Emit"),
235 FACADE_ASSEMBLY ("System.Reflection.Emit.ILGeneration"),
236 FACADE_ASSEMBLY ("System.Reflection.Emit.Lightweight"),
237 FACADE_ASSEMBLY ("System.Reflection.Extensions"),
238 FACADE_ASSEMBLY ("System.Reflection.Primitives"),
239 FACADE_ASSEMBLY ("System.Reflection.TypeExtensions"),
240 FACADE_ASSEMBLY ("System.Resources.Reader"),
241 FACADE_ASSEMBLY ("System.Resources.ReaderWriter"),
242 FACADE_ASSEMBLY ("System.Resources.ResourceManager"),
243 FACADE_ASSEMBLY ("System.Resources.Writer"),
244 FACADE_ASSEMBLY ("System.Runtime"),
245 {"System.Runtime.Caching", 0},
246 FACADE_ASSEMBLY ("System.Runtime.CompilerServices.VisualC"),
247 {"System.Runtime.DurableInstancing", 0},
248 FACADE_ASSEMBLY ("System.Runtime.Extensions"),
249 FACADE_ASSEMBLY ("System.Runtime.Handles"),
250 FACADE_ASSEMBLY ("System.Runtime.InteropServices"),
251 FACADE_ASSEMBLY ("System.Runtime.InteropServices.RuntimeInformation"),
252 FACADE_ASSEMBLY ("System.Runtime.InteropServices.WindowsRuntime"),
253 FACADE_ASSEMBLY ("System.Runtime.Loader"),
254 FACADE_ASSEMBLY ("System.Runtime.Numerics"),
255 {"System.Runtime.Remoting", 0},
256 {"System.Runtime.Serialization", 3},
257 FACADE_ASSEMBLY ("System.Runtime.Serialization.Formatters"),
258 {"System.Runtime.Serialization.Formatters.Soap", 0},
259 FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"),
260 FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"),
261 FACADE_ASSEMBLY ("System.Runtime.Serialization.Xml"),
262 {"System.Security", 0},
263 FACADE_ASSEMBLY ("System.Security.AccessControl"),
264 FACADE_ASSEMBLY ("System.Security.Claims"),
265 FACADE_ASSEMBLY ("System.Security.Cryptography.Algorithms"),
266 FACADE_ASSEMBLY ("System.Security.Cryptography.Cng"),
267 FACADE_ASSEMBLY ("System.Security.Cryptography.Csp"),
268 FACADE_ASSEMBLY ("System.Security.Cryptography.DeriveBytes"),
269 FACADE_ASSEMBLY ("System.Security.Cryptography.Encoding"),
270 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption"),
271 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Aes"),
272 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDiffieHellman"),
273 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDsa"),
274 FACADE_ASSEMBLY ("System.Security.Cryptography.Hashing"),
275 FACADE_ASSEMBLY ("System.Security.Cryptography.Hashing.Algorithms"),
276 FACADE_ASSEMBLY ("System.Security.Cryptography.OpenSsl"),
277 FACADE_ASSEMBLY ("System.Security.Cryptography.Pkcs"),
278 FACADE_ASSEMBLY ("System.Security.Cryptography.Primitives"),
279 FACADE_ASSEMBLY ("System.Security.Cryptography.ProtectedData"),
280 FACADE_ASSEMBLY ("System.Security.Cryptography.RSA"),
281 FACADE_ASSEMBLY ("System.Security.Cryptography.RandomNumberGenerator"),
282 FACADE_ASSEMBLY ("System.Security.Cryptography.X509Certificates"),
283 FACADE_ASSEMBLY ("System.Security.Principal"),
284 FACADE_ASSEMBLY ("System.Security.Principal.Windows"),
285 FACADE_ASSEMBLY ("System.Security.SecureString"),
286 {"System.ServiceModel", 3},
287 {"System.ServiceModel.Activation", 0},
288 {"System.ServiceModel.Discovery", 0},
289 FACADE_ASSEMBLY ("System.ServiceModel.Duplex"),
290 FACADE_ASSEMBLY ("System.ServiceModel.Http"),
291 FACADE_ASSEMBLY ("System.ServiceModel.NetTcp"),
292 FACADE_ASSEMBLY ("System.ServiceModel.Primitives"),
293 {"System.ServiceModel.Routing", 0},
294 FACADE_ASSEMBLY ("System.ServiceModel.Security"),
295 {"System.ServiceModel.Web", 2},
296 {"System.ServiceProcess", 0},
297 FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"),
298 FACADE_ASSEMBLY ("System.Text.Encoding"),
299 FACADE_ASSEMBLY ("System.Text.Encoding.CodePages"),
300 FACADE_ASSEMBLY ("System.Text.Encoding.Extensions"),
301 FACADE_ASSEMBLY ("System.Text.RegularExpressions"),
302 FACADE_ASSEMBLY ("System.Threading"),
303 FACADE_ASSEMBLY ("System.Threading.AccessControl"),
304 FACADE_ASSEMBLY ("System.Threading.Overlapped"),
305 FACADE_ASSEMBLY ("System.Threading.Tasks"),
306 {"System.Threading.Tasks.Dataflow", 0},
307 FACADE_ASSEMBLY ("System.Threading.Tasks.Extensions"),
308 FACADE_ASSEMBLY ("System.Threading.Tasks.Parallel"),
309 FACADE_ASSEMBLY ("System.Threading.Thread"),
310 FACADE_ASSEMBLY ("System.Threading.ThreadPool"),
311 FACADE_ASSEMBLY ("System.Threading.Timer"),
312 {"System.Transactions", 0},
313 FACADE_ASSEMBLY ("System.ValueTuple"),
315 {"System.Web.Abstractions", 2},
316 {"System.Web.ApplicationServices", 0},
317 {"System.Web.DynamicData", 2},
318 {"System.Web.Extensions", 2},
319 {"System.Web.Extensions.Design", 0},
320 {"System.Web.Mobile", 0},
321 {"System.Web.RegularExpressions", 0},
322 {"System.Web.Routing", 2},
323 {"System.Web.Services", 0},
324 {"System.Windows", 0},
325 {"System.Windows.Forms", 0},
326 {"System.Windows.Forms.DataVisualization", 0},
327 {"System.Workflow.Activities", 0},
328 {"System.Workflow.ComponentModel", 0},
329 {"System.Workflow.Runtime", 0},
332 {"System.Xml.Linq", 2},
333 FACADE_ASSEMBLY ("System.Xml.ReaderWriter"),
334 {"System.Xml.Serialization", 0},
335 FACADE_ASSEMBLY ("System.Xml.XDocument"),
336 FACADE_ASSEMBLY ("System.Xml.XPath"),
337 FACADE_ASSEMBLY ("System.Xml.XPath.XmlDocument"),
338 FACADE_ASSEMBLY ("System.Xml.XPath.XDocument"),
339 FACADE_ASSEMBLY ("System.Xml.XmlDocument"),
340 FACADE_ASSEMBLY ("System.Xml.XmlSerializer"),
341 FACADE_ASSEMBLY ("System.Xml.Xsl.Primitives"),
345 FACADE_ASSEMBLY ("netstandard"),
350 * keeps track of loaded assemblies
352 static GList
*loaded_assemblies
= NULL
;
353 static MonoAssembly
*corlib
;
355 static char* unquote (const char *str
);
357 /* This protects loaded_assemblies and image->references */
358 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
359 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
360 static mono_mutex_t assemblies_mutex
;
362 /* If defined, points to the bundled assembly information */
363 static const MonoBundledAssembly
**bundles
;
365 static mono_mutex_t assembly_binding_mutex
;
367 /* Loaded assembly binding info */
368 static GSList
*loaded_assembly_bindings
= NULL
;
370 /* Class lazy loading functions */
371 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible
, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
373 mono_assembly_invoke_search_hook_internal (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, gboolean refonly
, gboolean postload
);
375 mono_assembly_request_byname_nosearch (MonoAssemblyName
*aname
, const MonoAssemblyByNameRequest
*req
, MonoImageOpenStatus
*status
);
377 mono_assembly_load_full_gac_base_default (MonoAssemblyName
*aname
, const char *basedir
, MonoAssemblyContextKind asmctx
, MonoImageOpenStatus
*status
);
379 chain_redirections_loadfrom (MonoImage
*image
, MonoImageOpenStatus
*status
);
381 mono_problematic_image_reprobe (MonoImage
*image
, MonoImageOpenStatus
*status
);
384 mono_assembly_is_in_gac (const gchar
*filanem
);
385 static MonoAssemblyName
*
386 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
);
389 prevent_reference_assembly_from_running (MonoAssembly
* candidate
, gboolean refonly
);
391 /* Assembly name matching */
393 exact_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
);
395 framework_assembly_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
);
398 mono_asmctx_get_name (const MonoAssemblyContext
*asmctx
);
401 assembly_loadfrom_asmctx_from_path (const char *filename
, MonoAssembly
*requesting_assembly
, gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
);
404 encode_public_tok (const guchar
*token
, gint32 len
)
406 const static gchar allowed
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
410 res
= (gchar
*)g_malloc (len
* 2 + 1);
411 for (i
= 0; i
< len
; i
++) {
412 res
[i
* 2] = allowed
[token
[i
] >> 4];
413 res
[i
* 2 + 1] = allowed
[token
[i
] & 0xF];
420 * mono_public_tokens_are_equal:
421 * \param pubt1 first public key token
422 * \param pubt2 second public key token
424 * Compare two public key tokens and return TRUE is they are equal and FALSE
428 mono_public_tokens_are_equal (const unsigned char *pubt1
, const unsigned char *pubt2
)
430 return memcmp (pubt1
, pubt2
, 16) == 0;
434 * mono_set_assemblies_path:
435 * \param path list of paths that contain directories where Mono will look for assemblies
437 * Use this method to override the standard assembly lookup system and
438 * override any assemblies coming from the GAC. This is the method
439 * that supports the \c MONO_PATH variable.
441 * Notice that \c MONO_PATH and this method are really a very bad idea as
442 * it prevents the GAC from working and it prevents the standard
443 * resolution mechanisms from working. Nonetheless, for some debugging
444 * situations and bootstrapping setups, this is useful to have.
447 mono_set_assemblies_path (const char* path
)
449 char **splitted
, **dest
;
451 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
453 g_strfreev (assemblies_path
);
454 assemblies_path
= dest
= splitted
;
456 char *tmp
= *splitted
;
458 *dest
++ = mono_path_canonicalize (tmp
);
464 if (g_hasenv ("MONO_DEBUG"))
467 splitted
= assemblies_path
;
469 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
470 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted
);
477 check_path_env (void)
479 if (assemblies_path
!= NULL
)
482 char* path
= g_getenv ("MONO_PATH");
486 mono_set_assemblies_path(path
);
491 check_extra_gac_path_env (void)
494 char **splitted
, **dest
;
496 path
= g_getenv ("MONO_GAC_PREFIX");
500 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
504 g_strfreev (extra_gac_paths
);
505 extra_gac_paths
= dest
= splitted
;
513 if (!g_hasenv ("MONO_DEBUG"))
517 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
518 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted
);
525 assembly_binding_maps_name (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
527 if (!info
|| !info
->name
)
530 if (strcmp (info
->name
, aname
->name
))
533 if (info
->major
!= aname
->major
|| info
->minor
!= aname
->minor
)
536 if ((info
->culture
!= NULL
&& info
->culture
[0]) != (aname
->culture
!= NULL
&& aname
->culture
[0]))
539 if (info
->culture
&& aname
->culture
&& strcmp (info
->culture
, aname
->culture
))
542 if (!mono_public_tokens_are_equal (info
->public_key_token
, aname
->public_key_token
))
549 mono_assembly_binding_info_free (MonoAssemblyBindingInfo
*info
)
555 g_free (info
->culture
);
559 get_publisher_policy_info (MonoImage
*image
, MonoAssemblyName
*aname
, MonoAssemblyBindingInfo
*binding_info
)
562 guint32 cols
[MONO_MANIFEST_SIZE
];
563 const gchar
*filename
;
564 gchar
*subpath
, *fullpath
;
566 t
= &image
->tables
[MONO_TABLE_MANIFESTRESOURCE
];
567 /* MS Impl. accepts policy assemblies with more than
568 * one manifest resource, and only takes the first one */
570 binding_info
->is_valid
= FALSE
;
574 mono_metadata_decode_row (t
, 0, cols
, MONO_MANIFEST_SIZE
);
575 if ((cols
[MONO_MANIFEST_IMPLEMENTATION
] & MONO_IMPLEMENTATION_MASK
) != MONO_IMPLEMENTATION_FILE
) {
576 binding_info
->is_valid
= FALSE
;
580 filename
= mono_metadata_string_heap (image
, cols
[MONO_MANIFEST_NAME
]);
581 g_assert (filename
!= NULL
);
583 subpath
= g_path_get_dirname (image
->name
);
584 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, subpath
, filename
, NULL
);
585 mono_config_parse_publisher_policy (fullpath
, binding_info
);
589 /* Define the optional elements/attributes before checking */
590 if (!binding_info
->culture
)
591 binding_info
->culture
= g_strdup ("");
593 /* Check that the most important elements/attributes exist */
594 if (!binding_info
->name
|| !binding_info
->public_key_token
[0] || !binding_info
->has_old_version_bottom
||
595 !binding_info
->has_new_version
|| !assembly_binding_maps_name (binding_info
, aname
)) {
596 mono_assembly_binding_info_free (binding_info
);
597 binding_info
->is_valid
= FALSE
;
601 binding_info
->is_valid
= TRUE
;
605 compare_versions (AssemblyVersionSet
*v
, MonoAssemblyName
*aname
)
607 if (v
->major
> aname
->major
)
609 else if (v
->major
< aname
->major
)
612 if (v
->minor
> aname
->minor
)
614 else if (v
->minor
< aname
->minor
)
617 if (v
->build
> aname
->build
)
619 else if (v
->build
< aname
->build
)
622 if (v
->revision
> aname
->revision
)
624 else if (v
->revision
< aname
->revision
)
631 check_policy_versions (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*name
)
636 /* If has_old_version_top doesn't exist, we don't have an interval */
637 if (!info
->has_old_version_top
) {
638 if (compare_versions (&info
->old_version_bottom
, name
) == 0)
644 /* Check that the version defined by name is valid for the interval */
645 if (compare_versions (&info
->old_version_top
, name
) < 0)
648 /* We should be greater or equal than the small version */
649 if (compare_versions (&info
->old_version_bottom
, name
) > 0)
656 * mono_assembly_names_equal:
657 * \param l first assembly
658 * \param r second assembly.
660 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
662 * This compares the names, the cultures, the release version and their
665 * \returns TRUE if both assembly names are equal.
668 mono_assembly_names_equal (MonoAssemblyName
*l
, MonoAssemblyName
*r
)
670 return mono_assembly_names_equal_flags (l
, r
, MONO_ANAME_EQ_NONE
);
674 * mono_assembly_names_equal_flags:
675 * \param l first assembly name
676 * \param r second assembly name
677 * \param flags flags that affect what is compared.
679 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
681 * This compares the simple names and cultures and optionally the versions and
682 * public key tokens, depending on the \c flags.
684 * \returns TRUE if both assembly names are equal.
687 mono_assembly_names_equal_flags (MonoAssemblyName
*l
, MonoAssemblyName
*r
, MonoAssemblyNameEqFlags flags
)
689 g_assert (l
!= NULL
);
690 g_assert (r
!= NULL
);
692 if (!l
->name
|| !r
->name
)
695 if ((flags
& MONO_ANAME_EQ_IGNORE_CASE
) != 0 && g_strcasecmp (l
->name
, r
->name
))
698 if ((flags
& MONO_ANAME_EQ_IGNORE_CASE
) == 0 && strcmp (l
->name
, r
->name
))
701 if (l
->culture
&& r
->culture
&& strcmp (l
->culture
, r
->culture
))
704 if ((l
->major
!= r
->major
|| l
->minor
!= r
->minor
||
705 l
->build
!= r
->build
|| l
->revision
!= r
->revision
) &&
706 (flags
& MONO_ANAME_EQ_IGNORE_VERSION
) == 0)
707 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)))
710 if (!l
->public_key_token
[0] || !r
->public_key_token
[0] || (flags
& MONO_ANAME_EQ_IGNORE_PUBKEY
) != 0)
713 if (!mono_public_tokens_are_equal (l
->public_key_token
, r
->public_key_token
))
720 * assembly_names_compare_versions:
721 * \param l left assembly name
722 * \param r right assembly name
723 * \param maxcomps how many version components to compare, or -1 to compare all.
725 * \returns a negative if \p l is a lower version than \p r; a positive value
726 * if \p r is a lower version than \p l, or zero if \p l and \p r are equal
727 * versions (comparing upto \p maxcomps components).
729 * Components are \c major, \c minor, \c revision, and \c build. \p maxcomps 1 means just compare
730 * majors. 2 means majors then minors. etc.
733 assembly_names_compare_versions (MonoAssemblyName
*l
, MonoAssemblyName
*r
, int maxcomps
)
736 if (maxcomps
< 0) maxcomps
= 4;
737 #define CMP(field) do { \
738 if (l-> field < r-> field && i < maxcomps) return -1; \
739 if (l-> field > r-> field && i < maxcomps) return 1; \
753 * mono_assembly_request_prepare:
754 * \param req the request to be initialized
755 * \param req_size the size of the request structure
756 * \param asmctx the assembly load context kind
758 * Initialize an assembly loader request. The passed structure \p req must be
759 * of size \p req_size. Its state will be reset and the assembly context kind will be prefilled with \p asmctx.
762 mono_assembly_request_prepare (MonoAssemblyLoadRequest
*req
, size_t req_size
, MonoAssemblyContextKind asmctx
)
764 memset (req
, 0, req_size
);
765 req
->asmctx
= asmctx
;
768 static MonoAssembly
*
769 load_in_path (const char *basename
, const char** search_path
, const MonoAssemblyOpenRequest
*req
, MonoImageOpenStatus
*status
)
773 MonoAssembly
*result
;
775 for (i
= 0; search_path
[i
]; ++i
) {
776 fullpath
= g_build_filename (search_path
[i
], basename
, NULL
);
777 result
= mono_assembly_request_open (fullpath
, req
, status
);
786 * mono_assembly_setrootdir:
787 * \param root_dir The pathname of the root directory where we will locate assemblies
789 * This routine sets the internal default root directory for looking up
792 * This is used by Windows installations to compute dynamically the
793 * place where the Mono assemblies are located.
797 mono_assembly_setrootdir (const char *root_dir
)
800 * Override the MONO_ASSEMBLIES directory configured at compile time.
802 if (default_path
[0])
803 g_free (default_path
[0]);
804 default_path
[0] = g_strdup (root_dir
);
808 * mono_assembly_getrootdir:
810 * Obtains the root directory used for looking up assemblies.
812 * Returns: a string with the directory, this string should not be freed.
814 G_CONST_RETURN gchar
*
815 mono_assembly_getrootdir (void)
817 return default_path
[0];
821 * mono_native_getrootdir:
823 * Obtains the root directory used for looking up native libs (.so, .dylib).
825 * Returns: a string with the directory, this string should be freed by
829 mono_native_getrootdir (void)
831 gchar
* fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL
);
837 * \param assembly_dir the base directory for assemblies
838 * \param config_dir the base directory for configuration files
840 * This routine is used internally and by developers embedding
841 * the runtime into their own applications.
843 * There are a number of cases to consider: Mono as a system-installed
844 * package that is available on the location preconfigured or Mono in
845 * a relocated location.
847 * If you are using a system-installed Mono, you can pass NULL
848 * to both parameters. If you are not, you should compute both
849 * directory values and call this routine.
851 * The values for a given PREFIX are:
853 * assembly_dir: PREFIX/lib
854 * config_dir: PREFIX/etc
856 * Notice that embedders that use Mono in a relocated way must
857 * compute the location at runtime, as they will be in control
858 * of where Mono is installed.
861 mono_set_dirs (const char *assembly_dir
, const char *config_dir
)
863 if (assembly_dir
== NULL
)
864 assembly_dir
= mono_config_get_assemblies_dir ();
865 if (config_dir
== NULL
)
866 config_dir
= mono_config_get_cfg_dir ();
867 mono_assembly_setrootdir (assembly_dir
);
868 mono_set_config_dir (config_dir
);
874 compute_base (char *path
)
876 char *p
= strrchr (path
, '/');
880 /* Not a well known Mono executable, we are embedded, cant guess the base */
881 if (strcmp (p
, "/mono") && strcmp (p
, "/mono-boehm") && strcmp (p
, "/mono-sgen") && strcmp (p
, "/pedump") && strcmp (p
, "/monodis"))
885 p
= strrchr (path
, '/');
889 if (strcmp (p
, "/bin") != 0)
898 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
901 static G_GNUC_UNUSED
void
905 char *config
, *lib
, *mono
;
910 * Only /usr prefix is treated specially
912 bindir
= mono_config_get_bin_dir ();
914 if (strncmp (exe
, bindir
, strlen (bindir
)) == 0 || (base
= compute_base (exe
)) == NULL
){
919 config
= g_build_filename (base
, "etc", NULL
);
920 lib
= g_build_filename (base
, "lib", NULL
);
921 mono
= g_build_filename (lib
, "mono/4.5", NULL
); // FIXME: stop hardcoding 4.5 here
922 if (stat (mono
, &buf
) == -1)
925 mono_set_dirs (lib
, config
);
933 #endif /* HOST_WIN32 */
938 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
939 * this auto-detects the prefix where Mono was installed.
942 mono_set_rootdir (void)
944 #if defined(HOST_WIN32) || (defined(HOST_DARWIN) && !defined(TARGET_ARM))
945 gchar
*bindir
, *installdir
, *root
, *name
, *resolvedname
, *config
;
948 name
= mono_get_module_file_name ((HMODULE
) &__ImageBase
);
952 * _NSGetExecutablePath may return -1 to indicate buf is not large
953 * enough, but we ignore that case to avoid having to do extra dynamic
954 * allocation for the path and hope that 4096 is enough - this is
955 * ok in the Linux/Solaris case below at least...
959 guint buf_size
= sizeof (buf
);
962 if (_NSGetExecutablePath (buf
, &buf_size
) == 0)
963 name
= g_strdup (buf
);
972 resolvedname
= mono_path_resolve_symlinks (name
);
974 bindir
= g_path_get_dirname (resolvedname
);
975 installdir
= g_path_get_dirname (bindir
);
976 root
= g_build_path (G_DIR_SEPARATOR_S
, installdir
, "lib", NULL
);
978 config
= g_build_filename (root
, "..", "etc", NULL
);
980 mono_set_dirs (root
, config
);
982 if (g_file_test (root
, G_FILE_TEST_EXISTS
) && g_file_test (config
, G_FILE_TEST_EXISTS
))
983 mono_set_dirs (root
, config
);
993 g_free (resolvedname
);
994 #elif defined(DISABLE_MONO_AUTODETECTION)
1001 #if defined(HAVE_READLINK)
1003 s
= readlink ("/proc/self/exe", buf
, sizeof (buf
)-1);
1014 /* Solaris 10 style */
1015 str
= g_strdup_printf ("/proc/%d/path/a.out", getpid ());
1017 #if defined(HAVE_READLINK)
1018 s
= readlink (str
, buf
, sizeof (buf
)-1);
1034 * mono_assemblies_init:
1036 * Initialize global variables used by this module.
1039 mono_assemblies_init (void)
1042 * Initialize our internal paths if we have not been initialized yet.
1043 * This happens when embedders use Mono.
1045 if (mono_assembly_getrootdir () == NULL
)
1046 mono_set_rootdir ();
1049 check_extra_gac_path_env ();
1051 mono_os_mutex_init_recursive (&assemblies_mutex
);
1052 mono_os_mutex_init (&assembly_binding_mutex
);
1054 #ifndef DISABLE_DESKTOP_LOADER
1055 assembly_remapping_table
= g_hash_table_new (g_str_hash
, g_str_equal
);
1058 for (i
= 0; i
< G_N_ELEMENTS (framework_assemblies
); ++i
)
1059 g_hash_table_insert (assembly_remapping_table
, (void*)framework_assemblies
[i
].assembly_name
, (void*)&framework_assemblies
[i
]);
1062 mono_install_assembly_asmctx_from_path_hook (assembly_loadfrom_asmctx_from_path
, NULL
);
1067 mono_assembly_binding_lock (void)
1069 mono_locks_os_acquire (&assembly_binding_mutex
, AssemblyBindingLock
);
1073 mono_assembly_binding_unlock (void)
1075 mono_locks_os_release (&assembly_binding_mutex
, AssemblyBindingLock
);
1079 mono_assembly_fill_assembly_name_full (MonoImage
*image
, MonoAssemblyName
*aname
, gboolean copyBlobs
)
1081 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLY
];
1082 guint32 cols
[MONO_ASSEMBLY_SIZE
];
1083 gint32 machine
, flags
;
1088 mono_metadata_decode_row (t
, 0, cols
, MONO_ASSEMBLY_SIZE
);
1090 aname
->hash_len
= 0;
1091 aname
->hash_value
= NULL
;
1092 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_NAME
]);
1094 aname
->name
= g_strdup (aname
->name
);
1095 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_CULTURE
]);
1097 aname
->culture
= g_strdup (aname
->culture
);
1098 aname
->flags
= cols
[MONO_ASSEMBLY_FLAGS
];
1099 aname
->major
= cols
[MONO_ASSEMBLY_MAJOR_VERSION
];
1100 aname
->minor
= cols
[MONO_ASSEMBLY_MINOR_VERSION
];
1101 aname
->build
= cols
[MONO_ASSEMBLY_BUILD_NUMBER
];
1102 aname
->revision
= cols
[MONO_ASSEMBLY_REV_NUMBER
];
1103 aname
->hash_alg
= cols
[MONO_ASSEMBLY_HASH_ALG
];
1104 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
1105 guchar
* token
= (guchar
*)g_malloc (8);
1110 pkey
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
1111 len
= mono_metadata_decode_blob_size (pkey
, &pkey
);
1112 aname
->public_key
= (guchar
*)pkey
;
1114 mono_digest_get_public_token (token
, aname
->public_key
, len
);
1115 encoded
= encode_public_tok (token
, 8);
1116 g_strlcpy ((char*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1122 aname
->public_key
= NULL
;
1123 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1126 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
1127 aname
->public_key
= (guchar
*)mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
1129 const gchar
*pkey_end
;
1130 int len
= mono_metadata_decode_blob_size ((const gchar
*) aname
->public_key
, &pkey_end
);
1131 pkey_end
+= len
; /* move to end */
1132 size_t size
= pkey_end
- (const gchar
*)aname
->public_key
;
1133 guchar
*tmp
= g_new (guchar
, size
);
1134 memcpy (tmp
, aname
->public_key
, size
);
1135 aname
->public_key
= tmp
;
1140 aname
->public_key
= 0;
1142 machine
= image
->image_info
->cli_header
.coff
.coff_machine
;
1143 flags
= image
->image_info
->cli_cli_header
.ch_flags
;
1145 case COFF_MACHINE_I386
:
1146 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1147 if (flags
& (CLI_FLAGS_32BITREQUIRED
|CLI_FLAGS_PREFERRED32BIT
))
1148 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_X86
;
1149 else if ((flags
& 0x70) == 0x70)
1150 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_NONE
;
1152 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_MSIL
;
1154 case COFF_MACHINE_IA64
:
1155 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_IA64
;
1157 case COFF_MACHINE_AMD64
:
1158 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_AMD64
;
1160 case COFF_MACHINE_ARM
:
1161 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_ARM
;
1171 * mono_assembly_fill_assembly_name:
1172 * \param image Image
1174 * \returns TRUE if successful
1177 mono_assembly_fill_assembly_name (MonoImage
*image
, MonoAssemblyName
*aname
)
1179 return mono_assembly_fill_assembly_name_full (image
, aname
, FALSE
);
1183 * mono_stringify_assembly_name:
1184 * \param aname the assembly name.
1186 * Convert \p aname into its string format. The returned string is dynamically
1187 * allocated and should be freed by the caller.
1189 * \returns a newly allocated string with a string representation of
1190 * the assembly name.
1193 mono_stringify_assembly_name (MonoAssemblyName
*aname
)
1195 const char *quote
= (aname
->name
&& g_ascii_isspace (aname
->name
[0])) ? "\"" : "";
1197 return g_strdup_printf (
1198 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1199 quote
, aname
->name
, quote
,
1200 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1201 aname
->culture
&& *aname
->culture
? aname
->culture
: "neutral",
1202 aname
->public_key_token
[0] ? (char *)aname
->public_key_token
: "null",
1203 (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
1207 assemblyref_public_tok (MonoImage
*image
, guint32 key_index
, guint32 flags
)
1209 const gchar
*public_tok
;
1212 public_tok
= mono_metadata_blob_heap (image
, key_index
);
1213 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
1215 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
1217 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
1218 return encode_public_tok (token
, 8);
1221 return encode_public_tok ((guchar
*)public_tok
, len
);
1225 assemblyref_public_tok_checked (MonoImage
*image
, guint32 key_index
, guint32 flags
, MonoError
*error
)
1227 const gchar
*public_tok
;
1230 public_tok
= mono_metadata_blob_heap_checked (image
, key_index
, error
);
1231 return_val_if_nok (error
, NULL
);
1232 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
1234 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
1236 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
1237 return encode_public_tok (token
, 8);
1239 return encode_public_tok ((guchar
*)public_tok
, len
);
1243 * mono_assembly_addref:
1244 * \param assembly the assembly to reference
1246 * This routine increments the reference count on a MonoAssembly.
1247 * The reference count is reduced every time the method mono_assembly_close() is
1251 mono_assembly_addref (MonoAssembly
*assembly
)
1253 mono_atomic_inc_i32 (&assembly
->ref_count
);
1257 * CAUTION: This table must be kept in sync with
1258 * ivkm/reflect/Fusion.cs
1261 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1262 #define WINFX_KEY "31bf3856ad364e35"
1263 #define ECMA_KEY "b77a5c561934e089"
1264 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1265 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1273 static KeyRemapEntry key_remap_table
[] = {
1274 { "CustomMarshalers", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1275 { "Microsoft.CSharp", WINFX_KEY
, MSFINAL_KEY
},
1276 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1277 { "System", SILVERLIGHT_KEY
, ECMA_KEY
},
1278 { "System", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1279 { "System.ComponentModel.Composition", WINFX_KEY
, ECMA_KEY
},
1280 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY
},
1281 { "System.Core", SILVERLIGHT_KEY
, ECMA_KEY
},
1282 { "System.Core", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1283 { "System.Data", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1284 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1285 { "System.Drawing", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1286 { "System.Messaging", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1287 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1288 { "System.Net", SILVERLIGHT_KEY
, MSFINAL_KEY
},
1289 { "System.Numerics", WINFX_KEY
, ECMA_KEY
},
1290 { "System.Runtime.Serialization", SILVERLIGHT_KEY
, ECMA_KEY
},
1291 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1292 { "System.ServiceModel", WINFX_KEY
, ECMA_KEY
},
1293 { "System.ServiceModel", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1294 { "System.ServiceModel.Web", SILVERLIGHT_KEY
, WINFX_KEY
},
1295 { "System.Web.Services", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1296 { "System.Windows", SILVERLIGHT_KEY
, MSFINAL_KEY
},
1297 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1298 { "System.Xml", SILVERLIGHT_KEY
, ECMA_KEY
},
1299 { "System.Xml", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1300 { "System.Xml.Linq", WINFX_KEY
, ECMA_KEY
},
1301 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1302 { "System.Xml.Serialization", WINFX_KEY
, ECMA_KEY
}
1306 remap_keys (MonoAssemblyName
*aname
)
1309 for (i
= 0; i
< G_N_ELEMENTS (key_remap_table
); i
++) {
1310 const KeyRemapEntry
*entry
= &key_remap_table
[i
];
1312 if (strcmp (aname
->name
, entry
->name
) ||
1313 !mono_public_tokens_are_equal (aname
->public_key_token
, (const unsigned char*) entry
->from
))
1316 memcpy (aname
->public_key_token
, entry
->to
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1318 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1319 "Remapped public key token of retargetable assembly %s from %s to %s",
1320 aname
->name
, entry
->from
, entry
->to
);
1325 static MonoAssemblyName
*
1326 mono_assembly_remap_version (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_aname
)
1328 const MonoRuntimeInfo
*current_runtime
;
1330 if (aname
->name
== NULL
) return aname
;
1332 current_runtime
= mono_get_runtime_info ();
1334 if (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) {
1335 const AssemblyVersionSet
* vset
;
1337 /* Remap to current runtime */
1338 vset
= ¤t_runtime
->version_sets
[0];
1340 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
1341 dest_aname
->major
= vset
->major
;
1342 dest_aname
->minor
= vset
->minor
;
1343 dest_aname
->build
= vset
->build
;
1344 dest_aname
->revision
= vset
->revision
;
1345 dest_aname
->flags
&= ~ASSEMBLYREF_RETARGETABLE_FLAG
;
1347 /* Remap assembly name */
1348 if (!strcmp (aname
->name
, "System.Net"))
1349 dest_aname
->name
= g_strdup ("System");
1351 remap_keys (dest_aname
);
1353 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1354 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1356 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1358 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1364 #ifndef DISABLE_DESKTOP_LOADER
1365 const AssemblyVersionMap
*vmap
= (AssemblyVersionMap
*)g_hash_table_lookup (assembly_remapping_table
, aname
->name
);
1367 const AssemblyVersionSet
* vset
;
1368 int index
= vmap
->version_set_index
;
1369 g_assert (index
< G_N_ELEMENTS (current_runtime
->version_sets
));
1370 vset
= ¤t_runtime
->version_sets
[index
];
1372 if (vmap
->framework_facade_assembly
) {
1373 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Assembly %s is a framework Facade asseembly",
1378 if (aname
->major
== vset
->major
&& aname
->minor
== vset
->minor
&&
1379 aname
->build
== vset
->build
&& aname
->revision
== vset
->revision
) {
1380 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1382 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
);
1386 if (vmap
->only_lower_versions
&& compare_versions ((AssemblyVersionSet
*)vset
, aname
) < 0) {
1387 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
,
1388 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1390 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1391 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1396 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0)
1397 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
1398 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1400 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1401 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1404 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
1405 dest_aname
->major
= vset
->major
;
1406 dest_aname
->minor
= vset
->minor
;
1407 dest_aname
->build
= vset
->build
;
1408 dest_aname
->revision
= vset
->revision
;
1409 if (vmap
->new_assembly_name
!= NULL
) {
1410 dest_aname
->name
= vmap
->new_assembly_name
;
1411 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
1412 "The assembly name %s was remapped to %s",
1424 * mono_assembly_get_assemblyref:
1425 * \param image pointer to the \c MonoImage to extract the information from.
1426 * \param index index to the assembly reference in the image.
1427 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1429 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1432 mono_assembly_get_assemblyref (MonoImage
*image
, int index
, MonoAssemblyName
*aname
)
1435 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
1438 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1440 mono_metadata_decode_row (t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
);
1442 hash
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
]);
1443 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
1444 aname
->hash_value
= hash
;
1445 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_NAME
]);
1446 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_CULTURE
]);
1447 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
1448 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
1449 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
1450 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
1451 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
1453 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
1454 gchar
*token
= assemblyref_public_tok (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
);
1455 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1458 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1462 static MonoAssembly
*
1463 load_reference_by_aname_refonly_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*assm
, MonoImageOpenStatus
*status
)
1465 MonoAssembly
*reference
= NULL
;
1466 g_assert (assm
!= NULL
);
1467 *status
= MONO_IMAGE_OK
;
1469 /* We use the loaded corlib */
1470 if (!strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
)) {
1471 MonoAssemblyByNameRequest req
;
1472 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
1473 req
.requesting_assembly
= assm
;
1474 req
.basedir
= assm
->basedir
;
1475 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1477 reference
= mono_assembly_loaded_full (aname
, TRUE
);
1479 /* Try a postload search hook */
1480 reference
= mono_assembly_invoke_search_hook_internal (aname
, assm
, TRUE
, TRUE
);
1484 * Here we must advice that the error was due to
1485 * a non loaded reference using the ReflectionOnly api
1488 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1493 static MonoAssembly
*
1494 load_reference_by_aname_default_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*assm
, MonoImageOpenStatus
*status
)
1496 MonoAssembly
*reference
= NULL
;
1497 *status
= MONO_IMAGE_OK
;
1499 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1500 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1501 * accordingly, it would fail on the MS runtime before).
1502 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1503 * example bug-349190.2.cs and who knows how much more code in the wild.
1505 MonoAssemblyByNameRequest req
;
1506 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
1507 req
.requesting_assembly
= assm
;
1508 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1509 if (!reference
&& assm
) {
1510 memset (&req
, 0, sizeof (req
));
1511 req
.request
.asmctx
= MONO_ASMCTX_DEFAULT
;
1512 req
.requesting_assembly
= assm
;
1513 req
.basedir
= assm
->basedir
;
1514 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1520 static MonoAssembly
*
1521 load_reference_by_aname_loadfrom_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, MonoImageOpenStatus
*status
)
1523 MonoAssembly
*reference
= NULL
;
1524 MonoAssemblyByNameRequest req
;
1525 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_LOADFROM
);
1526 req
.requesting_assembly
= requesting
;
1527 req
.basedir
= requesting
->basedir
;
1528 /* Just like default search, but look in the requesting assembly basedir right away */
1529 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1534 static MonoAssembly
*
1535 load_reference_by_aname_individual_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, MonoImageOpenStatus
*status
)
1537 /* For an individual assembly, all references must already be loaded or
1538 * else we fire the assembly resolve event - similar to refonly - but
1539 * subject to remaping and binding.
1542 MonoAssembly
*reference
= NULL
;
1543 *status
= MONO_IMAGE_OK
;
1544 MonoAssemblyName maped_aname
;
1545 MonoAssemblyName maped_name_pp
;
1547 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
1548 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
1550 reference
= mono_assembly_loaded_full (aname
, FALSE
);
1551 /* Still try to load from application base directory, MONO_PATH or the
1552 * GAC. This is consistent with what .NET Framework (4.7) actually
1553 * does, rather than what the documentation implies: If `LoadFile` is
1554 * used to load an assembly into "no context"/individual assembly
1555 * context, the runtime will still load assemblies from the GAC or the
1556 * application base directory (e.g. `System.Runtime` will be loaded if
1557 * it wasn't already).
1558 * Moreover, those referenced assemblies are loaded in the default context.
1561 MonoAssemblyByNameRequest req
;
1562 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
1563 req
.requesting_assembly
= requesting
;
1564 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1567 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1572 * mono_assembly_get_assemblyref:
1573 * \param image pointer to the \c MonoImage to extract the information from.
1574 * \param index index to the assembly reference in the image.
1575 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1576 * \param error set on error
1578 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1580 * \returns TRUE on success, otherwise sets \p error and returns FALSE
1583 mono_assembly_get_assemblyref_checked (MonoImage
*image
, int index
, MonoAssemblyName
*aname
, MonoError
*error
)
1586 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
1589 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1591 if (!mono_metadata_decode_row_checked (image
, t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
, error
))
1594 hash
= mono_metadata_blob_heap_checked (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
], error
);
1595 return_val_if_nok (error
, FALSE
);
1596 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
1597 aname
->hash_value
= hash
;
1598 aname
->name
= mono_metadata_string_heap_checked (image
, cols
[MONO_ASSEMBLYREF_NAME
], error
);
1599 return_val_if_nok (error
, FALSE
);
1600 aname
->culture
= mono_metadata_string_heap_checked (image
, cols
[MONO_ASSEMBLYREF_CULTURE
], error
);
1601 return_val_if_nok (error
, FALSE
);
1602 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
1603 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
1604 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
1605 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
1606 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
1607 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
1608 gchar
*token
= assemblyref_public_tok_checked (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
, error
);
1609 return_val_if_nok (error
, FALSE
);
1610 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1613 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1619 * mono_assembly_load_reference:
1622 mono_assembly_load_reference (MonoImage
*image
, int index
)
1624 MonoAssembly
*reference
;
1625 MonoAssemblyName aname
;
1626 MonoImageOpenStatus status
;
1629 * image->references is shared between threads, so we need to access
1630 * it inside a critical section.
1632 mono_assemblies_lock ();
1633 if (!image
->references
) {
1634 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1636 image
->references
= g_new0 (MonoAssembly
*, t
->rows
+ 1);
1637 image
->nreferences
= t
->rows
;
1639 reference
= image
->references
[index
];
1640 mono_assemblies_unlock ();
1644 mono_assembly_get_assemblyref (image
, index
, &aname
);
1646 if (image
->assembly
) {
1647 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
1648 char *aname_str
= mono_stringify_assembly_name (&aname
);
1649 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Loading reference %d of %s asmctx %s, looking for %s",
1650 index
, image
->name
, mono_asmctx_get_name (&image
->assembly
->context
),
1654 switch (mono_asmctx_get_kind (&image
->assembly
->context
)) {
1655 case MONO_ASMCTX_DEFAULT
:
1656 reference
= load_reference_by_aname_default_asmctx (&aname
, image
->assembly
, &status
);
1658 case MONO_ASMCTX_REFONLY
:
1659 reference
= load_reference_by_aname_refonly_asmctx (&aname
, image
->assembly
, &status
);
1661 case MONO_ASMCTX_LOADFROM
:
1662 reference
= load_reference_by_aname_loadfrom_asmctx (&aname
, image
->assembly
, &status
);
1664 case MONO_ASMCTX_INDIVIDUAL
:
1665 reference
= load_reference_by_aname_individual_asmctx (&aname
, image
->assembly
, &status
);
1668 g_error ("Unexpected assembly load context kind %d for image %s.", mono_asmctx_get_kind (&image
->assembly
->context
), image
->name
);
1672 /* FIXME: can we establish that image->assembly is never NULL and this code is dead? */
1673 reference
= load_reference_by_aname_default_asmctx (&aname
, image
->assembly
, &status
);
1676 if (reference
== NULL
){
1679 if (status
== MONO_IMAGE_ERROR_ERRNO
&& errno
== ENOENT
) {
1680 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
: "" );
1681 } else if (status
== MONO_IMAGE_ERROR_ERRNO
) {
1682 extra_msg
= g_strdup_printf ("System error: %s\n", strerror (errno
));
1683 } else if (status
== MONO_IMAGE_MISSING_ASSEMBLYREF
) {
1684 extra_msg
= g_strdup ("Cannot find an assembly referenced from this one.\n");
1685 } else if (status
== MONO_IMAGE_IMAGE_INVALID
) {
1686 extra_msg
= g_strdup ("The file exists but is not a valid assembly.\n");
1688 extra_msg
= g_strdup ("");
1691 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
, "The following assembly referenced from %s could not be loaded:\n"
1692 " Assembly: %s (assemblyref_index=%d)\n"
1693 " Version: %d.%d.%d.%d\n"
1694 " Public Key: %s\n%s",
1695 image
->name
, aname
.name
, index
,
1696 aname
.major
, aname
.minor
, aname
.build
, aname
.revision
,
1697 strlen ((char*)aname
.public_key_token
) == 0 ? "(none)" : (char*)aname
.public_key_token
, extra_msg
);
1702 mono_assemblies_lock ();
1703 if (reference
== NULL
) {
1704 /* Flag as not found */
1705 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1708 if (!image
->references
[index
]) {
1709 if (reference
!= REFERENCE_MISSING
){
1710 mono_assembly_addref (reference
);
1711 if (image
->assembly
)
1712 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1713 image
->assembly
->aname
.name
, image
->assembly
, reference
->aname
.name
, reference
, reference
->ref_count
);
1715 if (image
->assembly
)
1716 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Failed to load assembly %s[%p].",
1717 image
->assembly
->aname
.name
, image
->assembly
);
1720 image
->references
[index
] = reference
;
1722 mono_assemblies_unlock ();
1724 if (image
->references
[index
] != reference
) {
1725 /* Somebody loaded it before us */
1726 mono_assembly_close (reference
);
1731 * mono_assembly_load_references:
1734 * \deprecated There is no reason to use this method anymore, it does nothing
1736 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1739 mono_assembly_load_references (MonoImage
*image
, MonoImageOpenStatus
*status
)
1741 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1742 *status
= MONO_IMAGE_OK
;
1745 typedef struct AssemblyLoadHook AssemblyLoadHook
;
1746 struct AssemblyLoadHook
{
1747 AssemblyLoadHook
*next
;
1748 MonoAssemblyLoadFunc func
;
1752 static AssemblyLoadHook
*assembly_load_hook
= NULL
;
1755 * mono_assembly_invoke_load_hook:
1758 mono_assembly_invoke_load_hook (MonoAssembly
*ass
)
1760 AssemblyLoadHook
*hook
;
1762 for (hook
= assembly_load_hook
; hook
; hook
= hook
->next
) {
1763 hook
->func (ass
, hook
->user_data
);
1768 * mono_install_assembly_load_hook:
1771 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func
, gpointer user_data
)
1773 AssemblyLoadHook
*hook
;
1775 g_return_if_fail (func
!= NULL
);
1777 hook
= g_new0 (AssemblyLoadHook
, 1);
1779 hook
->user_data
= user_data
;
1780 hook
->next
= assembly_load_hook
;
1781 assembly_load_hook
= hook
;
1785 free_assembly_load_hooks (void)
1787 AssemblyLoadHook
*hook
, *next
;
1789 for (hook
= assembly_load_hook
; hook
; hook
= next
) {
1795 typedef struct AssemblySearchHook AssemblySearchHook
;
1796 struct AssemblySearchHook
{
1797 AssemblySearchHook
*next
;
1798 MonoAssemblySearchFunc func
;
1804 static AssemblySearchHook
*assembly_search_hook
= NULL
;
1806 static MonoAssembly
*
1807 mono_assembly_invoke_search_hook_internal (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, gboolean refonly
, gboolean postload
)
1809 AssemblySearchHook
*hook
;
1811 for (hook
= assembly_search_hook
; hook
; hook
= hook
->next
) {
1812 if ((hook
->refonly
== refonly
) && (hook
->postload
== postload
)) {
1815 * A little explanation is in order here.
1817 * The default postload search hook needs to know the requesting assembly to report it to managed code.
1818 * The embedding API exposes a search hook that doesn't take such argument.
1820 * The original fix would call the default search hook before all the registered ones and pass
1821 * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
1822 * rely on. Which is the ordering between user hooks and the default runtime hook.
1824 * Registering the hook after mono_jit_init would let your hook run before the default one and
1825 * when using it to handle non standard app layouts this could save your app from a massive amount
1826 * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
1827 * are all using this trick and if we broke this assumption they would be very disapointed at us.
1829 * So what's the fix? We register the default hook using regular means and special case it when iterating
1830 * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
1833 if (hook
->func
== (void*)mono_domain_assembly_postload_search
)
1834 ass
= mono_domain_assembly_postload_search (aname
, requesting
, refonly
);
1836 ass
= hook
->func (aname
, hook
->user_data
);
1846 * mono_assembly_invoke_search_hook:
1849 mono_assembly_invoke_search_hook (MonoAssemblyName
*aname
)
1851 return mono_assembly_invoke_search_hook_internal (aname
, NULL
, FALSE
, FALSE
);
1855 mono_install_assembly_search_hook_internal (MonoAssemblySearchFunc func
, gpointer user_data
, gboolean refonly
, gboolean postload
)
1857 AssemblySearchHook
*hook
;
1859 g_return_if_fail (func
!= NULL
);
1861 hook
= g_new0 (AssemblySearchHook
, 1);
1863 hook
->user_data
= user_data
;
1864 hook
->refonly
= refonly
;
1865 hook
->postload
= postload
;
1866 hook
->next
= assembly_search_hook
;
1867 assembly_search_hook
= hook
;
1871 * mono_install_assembly_search_hook:
1874 mono_install_assembly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1876 mono_install_assembly_search_hook_internal (func
, user_data
, FALSE
, FALSE
);
1880 free_assembly_search_hooks (void)
1882 AssemblySearchHook
*hook
, *next
;
1884 for (hook
= assembly_search_hook
; hook
; hook
= next
) {
1891 * mono_install_assembly_refonly_search_hook:
1894 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1896 mono_install_assembly_search_hook_internal (func
, user_data
, TRUE
, FALSE
);
1900 * mono_install_assembly_postload_search_hook:
1903 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1905 mono_install_assembly_search_hook_internal (func
, user_data
, FALSE
, TRUE
);
1909 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1911 mono_install_assembly_search_hook_internal (func
, user_data
, TRUE
, TRUE
);
1914 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook
;
1915 struct AssemblyPreLoadHook
{
1916 AssemblyPreLoadHook
*next
;
1917 MonoAssemblyPreLoadFunc func
;
1921 static AssemblyPreLoadHook
*assembly_preload_hook
= NULL
;
1922 static AssemblyPreLoadHook
*assembly_refonly_preload_hook
= NULL
;
1924 static MonoAssembly
*
1925 invoke_assembly_preload_hook (MonoAssemblyName
*aname
, gchar
**apath
)
1927 AssemblyPreLoadHook
*hook
;
1928 MonoAssembly
*assembly
;
1930 for (hook
= assembly_preload_hook
; hook
; hook
= hook
->next
) {
1931 assembly
= hook
->func (aname
, apath
, hook
->user_data
);
1932 if (assembly
!= NULL
)
1939 static MonoAssembly
*
1940 invoke_assembly_refonly_preload_hook (MonoAssemblyName
*aname
, gchar
**apath
)
1942 AssemblyPreLoadHook
*hook
;
1943 MonoAssembly
*assembly
;
1945 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= hook
->next
) {
1946 assembly
= hook
->func (aname
, apath
, hook
->user_data
);
1947 if (assembly
!= NULL
)
1955 * mono_install_assembly_preload_hook:
1958 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
1960 AssemblyPreLoadHook
*hook
;
1962 g_return_if_fail (func
!= NULL
);
1964 hook
= g_new0 (AssemblyPreLoadHook
, 1);
1966 hook
->user_data
= user_data
;
1967 hook
->next
= assembly_preload_hook
;
1968 assembly_preload_hook
= hook
;
1972 * mono_install_assembly_refonly_preload_hook:
1975 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
1977 AssemblyPreLoadHook
*hook
;
1979 g_return_if_fail (func
!= NULL
);
1981 hook
= g_new0 (AssemblyPreLoadHook
, 1);
1983 hook
->user_data
= user_data
;
1984 hook
->next
= assembly_refonly_preload_hook
;
1985 assembly_refonly_preload_hook
= hook
;
1989 free_assembly_preload_hooks (void)
1991 AssemblyPreLoadHook
*hook
, *next
;
1993 for (hook
= assembly_preload_hook
; hook
; hook
= next
) {
1998 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= next
) {
2004 typedef struct AssemblyAsmCtxFromPathHook AssemblyAsmCtxFromPathHook
;
2005 struct AssemblyAsmCtxFromPathHook
{
2006 AssemblyAsmCtxFromPathHook
*next
;
2007 MonoAssemblyAsmCtxFromPathFunc func
;
2011 static AssemblyAsmCtxFromPathHook
*assembly_asmctx_from_path_hook
= NULL
;
2014 * mono_install_assembly_asmctx_from_path_hook:
2016 * \param func Hook function
2017 * \param user_data User data
2019 * Installs a hook function \p func that when called with an absolute path name
2020 * returns \c TRUE and writes to \c out_asmctx if an assembly that name would
2021 * be found by that asmctx. The hooks are called in the order from most
2022 * recently added to oldest.
2026 mono_install_assembly_asmctx_from_path_hook (MonoAssemblyAsmCtxFromPathFunc func
, gpointer user_data
)
2028 g_return_if_fail (func
!= NULL
);
2030 AssemblyAsmCtxFromPathHook
*hook
= g_new0 (AssemblyAsmCtxFromPathHook
, 1);
2032 hook
->user_data
= user_data
;
2033 hook
->next
= assembly_asmctx_from_path_hook
;
2034 assembly_asmctx_from_path_hook
= hook
;
2038 * mono_assembly_invoke_asmctx_from_path_hook:
2040 * \param absfname absolute path name
2041 * \param requesting_assembly the \c MonoAssembly that requested the load, may be \c NULL
2042 * \param out_asmctx assembly context kind, written on output
2044 * Invokes hooks to find the assembly context that would have searched for the
2045 * given assembly name. Writes to \p out_asmctx the assembly context kind from
2046 * the first hook to return \c TRUE. \returns \c TRUE if any hook wrote to \p
2047 * out_asmctx, or \c FALSE otherwise.
2050 assembly_invoke_asmctx_from_path_hook (const char *absfname
, MonoAssembly
*requesting_assembly
, MonoAssemblyContextKind
*out_asmctx
)
2052 g_assert (absfname
);
2053 g_assert (out_asmctx
);
2054 AssemblyAsmCtxFromPathHook
*hook
;
2056 for (hook
= assembly_asmctx_from_path_hook
; hook
; hook
= hook
->next
) {
2057 *out_asmctx
= MONO_ASMCTX_INDIVIDUAL
;
2058 if (hook
->func (absfname
, requesting_assembly
, hook
->user_data
, out_asmctx
))
2066 free_assembly_asmctx_from_path_hooks (void)
2068 AssemblyAsmCtxFromPathHook
*hook
, *next
;
2070 for (hook
= assembly_asmctx_from_path_hook
; hook
; hook
= next
) {
2077 absolute_dir (const gchar
*filename
)
2088 if (g_path_is_absolute (filename
)) {
2089 part
= g_path_get_dirname (filename
);
2090 res
= g_strconcat (part
, G_DIR_SEPARATOR_S
, NULL
);
2095 cwd
= g_get_current_dir ();
2096 mixed
= g_build_filename (cwd
, filename
, NULL
);
2097 parts
= g_strsplit (mixed
, G_DIR_SEPARATOR_S
, 0);
2102 for (i
= 0; (part
= parts
[i
]) != NULL
; i
++) {
2103 if (!strcmp (part
, "."))
2106 if (!strcmp (part
, "..")) {
2107 if (list
&& list
->next
) /* Don't remove root */
2108 list
= g_list_delete_link (list
, list
);
2110 list
= g_list_prepend (list
, part
);
2114 result
= g_string_new ("");
2115 list
= g_list_reverse (list
);
2117 /* Ignores last data pointer, which should be the filename */
2118 for (tmp
= list
; tmp
&& tmp
->next
!= NULL
; tmp
= tmp
->next
){
2120 g_string_append_printf (result
, "%s%c", (char *) tmp
->data
,
2125 g_string_free (result
, FALSE
);
2130 return g_strdup (".");
2137 * mono_assembly_open_from_bundle:
2138 * \param filename Filename requested
2139 * \param status return status code
2141 * This routine tries to open the assembly specified by \p filename from the
2142 * defined bundles, if found, returns the MonoImage for it, if not found
2146 mono_assembly_open_from_bundle (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
2150 gchar
*lowercase_filename
;
2151 MonoImage
*image
= NULL
;
2152 gboolean is_satellite
= FALSE
;
2154 * we do a very simple search for bundled assemblies: it's not a general
2155 * purpose assembly loading mechanism.
2161 lowercase_filename
= g_utf8_strdown (filename
, -1);
2162 is_satellite
= g_str_has_suffix (lowercase_filename
, ".resources.dll");
2163 g_free (lowercase_filename
);
2164 name
= g_path_get_basename (filename
);
2165 mono_assemblies_lock ();
2166 for (i
= 0; !image
&& bundles
[i
]; ++i
) {
2167 if (strcmp (bundles
[i
]->name
, is_satellite
? filename
: name
) == 0) {
2168 image
= mono_image_open_from_data_internal ((char*)bundles
[i
]->data
, bundles
[i
]->size
, FALSE
, status
, refonly
, FALSE
, name
);
2172 mono_assemblies_unlock ();
2174 mono_image_addref (image
);
2175 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite
? filename
: name
);
2184 * mono_assembly_open_full:
2185 * \param filename the file to load
2186 * \param status return status code
2187 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2189 * This loads an assembly from the specified \p filename. The \p filename allows
2190 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2191 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2192 * is treated as a local path.
2194 * First, an attempt is made to load the assembly from the bundled executable (for those
2195 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2196 * assembly has been registered as an embedded assembly). If this is not the case, then
2197 * the assembly is loaded from disk using `api:mono_image_open_full`.
2199 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2200 * the assembly is made.
2202 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
2203 * the \c System.Reflection API.
2205 * \returns NULL on error, with the \p status set to an error code, or a pointer
2209 mono_assembly_open_full (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
2212 MONO_ENTER_GC_UNSAFE
;
2213 MonoAssemblyOpenRequest req
;
2214 mono_assembly_request_prepare (&req
.request
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
2215 res
= mono_assembly_request_open (filename
, &req
, status
);
2216 MONO_EXIT_GC_UNSAFE
;
2221 assembly_loadfrom_asmctx_from_path (const char *filename
, MonoAssembly
*requesting_assembly
,
2222 gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
) {
2223 if (requesting_assembly
&& mono_asmctx_get_kind (&requesting_assembly
->context
) == MONO_ASMCTX_LOADFROM
) {
2224 if (mono_path_filename_in_basedir (filename
, requesting_assembly
->basedir
)) {
2225 *out_asmctx
= MONO_ASMCTX_LOADFROM
;
2233 mono_assembly_request_open (const char *filename
, const MonoAssemblyOpenRequest
*open_req
,
2234 MonoImageOpenStatus
*status
)
2238 MonoImageOpenStatus def_status
;
2241 gboolean loaded_from_bundle
;
2243 MonoAssemblyLoadRequest load_req
;
2244 /* we will be overwriting the load request's asmctx.*/
2245 memcpy (&load_req
, &open_req
->request
, sizeof (load_req
));
2247 g_return_val_if_fail (filename
!= NULL
, NULL
);
2250 status
= &def_status
;
2251 *status
= MONO_IMAGE_OK
;
2253 if (strncmp (filename
, "file://", 7) == 0) {
2254 GError
*gerror
= NULL
;
2255 gchar
*uri
= (gchar
*) filename
;
2259 * MS allows file://c:/... and fails on file://localhost/c:/...
2260 * They also throw an IndexOutOfRangeException if "file://"
2263 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
2266 uri
= mono_escape_uri_string (tmpuri
);
2267 fname
= g_filename_from_uri (uri
, NULL
, &gerror
);
2270 if (tmpuri
!= filename
)
2273 if (gerror
!= NULL
) {
2274 g_warning ("%s\n", gerror
->message
);
2275 g_error_free (gerror
);
2276 fname
= g_strdup (filename
);
2279 fname
= g_strdup (filename
);
2282 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2283 "Assembly Loader probing location: '%s'.", fname
);
2286 if (!mono_assembly_is_in_gac (fname
)) {
2288 new_fname
= mono_make_shadow_copy (fname
, error
);
2289 if (!is_ok (error
)) {
2290 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2291 "Assembly Loader shadow copy error: %s.", mono_error_get_message (error
));
2292 mono_error_cleanup (error
);
2293 *status
= MONO_IMAGE_IMAGE_INVALID
;
2298 if (load_req
.asmctx
!= MONO_ASMCTX_REFONLY
) {
2299 MonoAssemblyContextKind out_asmctx
;
2300 /* If the path belongs to the appdomain base dir or the
2301 * base dir of the requesting assembly, load the
2302 * assembly in the corresponding asmctx.
2304 if (assembly_invoke_asmctx_from_path_hook (fname
, open_req
->requesting_assembly
, &out_asmctx
))
2305 load_req
.asmctx
= out_asmctx
;
2308 if (load_req
.asmctx
!= MONO_ASMCTX_REFONLY
) {
2309 /* GAC assemblies always in default context or refonly context. */
2310 load_req
.asmctx
= MONO_ASMCTX_DEFAULT
;
2313 if (new_fname
&& new_fname
!= fname
) {
2316 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2317 "Assembly Loader shadow-copied assembly to: '%s'.", fname
);
2322 const gboolean refonly
= load_req
.asmctx
== MONO_ASMCTX_REFONLY
;
2323 /* for LoadFrom(string), LoadFile(string) and Load(byte[]), allow them
2324 * to load problematic images. Not sure if ReflectionOnlyLoad(string)
2325 * and ReflectionOnlyLoadFrom(string) should also be allowed - let's
2328 const gboolean load_from_context
= load_req
.asmctx
== MONO_ASMCTX_LOADFROM
|| load_req
.asmctx
== MONO_ASMCTX_INDIVIDUAL
|| load_req
.asmctx
== MONO_ASMCTX_REFONLY
;
2330 // If VM built with mkbundle
2331 loaded_from_bundle
= FALSE
;
2332 if (bundles
!= NULL
) {
2333 image
= mono_assembly_open_from_bundle (fname
, status
, refonly
);
2334 loaded_from_bundle
= image
!= NULL
;
2338 image
= mono_image_open_a_lot (fname
, status
, refonly
, load_from_context
);
2341 if (*status
== MONO_IMAGE_OK
)
2342 *status
= MONO_IMAGE_ERROR_ERRNO
;
2347 if (load_req
.asmctx
== MONO_ASMCTX_LOADFROM
|| load_req
.asmctx
== MONO_ASMCTX_INDIVIDUAL
) {
2348 MonoAssembly
*redirected_asm
= NULL
;
2349 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2350 if ((redirected_asm
= chain_redirections_loadfrom (image
, &new_status
))) {
2351 mono_image_close (image
);
2352 image
= redirected_asm
->image
;
2353 mono_image_addref (image
); /* so that mono_image_close, below, has something to do */
2354 /* fall thru to if (image->assembly) below */
2355 } else if (new_status
!= MONO_IMAGE_OK
) {
2356 *status
= new_status
;
2357 mono_image_close (image
);
2363 if (image
->assembly
) {
2364 /* We want to return the MonoAssembly that's already loaded,
2365 * but if we're using the strict assembly loader, we also need
2366 * to check that the previously loaded assembly matches the
2367 * predicate. It could be that we previously loaded a
2368 * different version that happens to have the filename that
2369 * we're currently probing. */
2370 if (mono_loader_get_strict_strong_names () &&
2371 load_req
.predicate
&& !load_req
.predicate (image
->assembly
, load_req
.predicate_ud
)) {
2372 mono_image_close (image
);
2376 /* Already loaded by another appdomain */
2377 mono_assembly_invoke_load_hook (image
->assembly
);
2378 mono_image_close (image
);
2380 return image
->assembly
;
2384 ass
= mono_assembly_request_load_from (image
, fname
, &load_req
, status
);
2387 if (!loaded_from_bundle
)
2388 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2389 "Assembly Loader loaded assembly from location: '%s'.", filename
);
2391 mono_config_for_assembly (ass
->image
);
2394 /* Clear the reference added by mono_image_open */
2395 mono_image_close (image
);
2403 free_item (gpointer val
, gpointer user_data
)
2409 * mono_assembly_load_friends:
2410 * \param ass an assembly
2412 * Load the list of friend assemblies that are allowed to access
2413 * the assembly's internal types and members. They are stored as assembly
2414 * names in custom attributes.
2416 * This is an internal method, we need this because when we load mscorlib
2417 * we do not have the internals visible cattr loaded yet,
2418 * so we need to load these after we initialize the runtime.
2420 * LOCKING: Acquires the assemblies lock plus the loader lock.
2423 mono_assembly_load_friends (MonoAssembly
* ass
)
2427 MonoCustomAttrInfo
* attrs
;
2430 if (ass
->friend_assembly_names_inited
)
2433 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2434 mono_error_assert_ok (error
);
2436 mono_assemblies_lock ();
2437 ass
->friend_assembly_names_inited
= TRUE
;
2438 mono_assemblies_unlock ();
2442 mono_assemblies_lock ();
2443 if (ass
->friend_assembly_names_inited
) {
2444 mono_assemblies_unlock ();
2447 mono_assemblies_unlock ();
2451 * We build the list outside the assemblies lock, the worse that can happen
2452 * is that we'll need to free the allocated list.
2454 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2455 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2456 MonoAssemblyName
*aname
;
2458 uint32_t data_length
;
2459 gchar
*data_with_terminator
;
2460 /* Do some sanity checking */
2461 if (!attr
->ctor
|| attr
->ctor
->klass
!= mono_class_try_get_internals_visible_class ())
2463 if (attr
->data_size
< 4)
2465 data
= (const char*)attr
->data
;
2466 /* 0xFF means null string, see custom attr format */
2467 if (data
[0] != 1 || data
[1] != 0 || (data
[2] & 0xFF) == 0xFF)
2469 data_length
= mono_metadata_decode_value (data
+ 2, &data
);
2470 data_with_terminator
= (char *)g_memdup (data
, data_length
+ 1);
2471 data_with_terminator
[data_length
] = 0;
2472 aname
= g_new0 (MonoAssemblyName
, 1);
2473 /*g_print ("friend ass: %s\n", data);*/
2474 if (mono_assembly_name_parse_full (data_with_terminator
, aname
, TRUE
, NULL
, NULL
)) {
2475 list
= g_slist_prepend (list
, aname
);
2479 g_free (data_with_terminator
);
2481 mono_custom_attrs_free (attrs
);
2483 mono_assemblies_lock ();
2484 if (ass
->friend_assembly_names_inited
) {
2485 mono_assemblies_unlock ();
2486 g_slist_foreach (list
, free_item
, NULL
);
2487 g_slist_free (list
);
2490 ass
->friend_assembly_names
= list
;
2492 /* Because of the double checked locking pattern above */
2493 mono_memory_barrier ();
2494 ass
->friend_assembly_names_inited
= TRUE
;
2495 mono_assemblies_unlock ();
2498 struct HasReferenceAssemblyAttributeIterData
{
2503 has_reference_assembly_attribute_iterator (MonoImage
*image
, guint32 typeref_scope_token
, const char *nspace
, const char *name
, guint32 method_token
, gpointer user_data
)
2505 gboolean stop_scanning
= FALSE
;
2506 struct HasReferenceAssemblyAttributeIterData
*iter_data
= (struct HasReferenceAssemblyAttributeIterData
*)user_data
;
2508 if (!strcmp (name
, "ReferenceAssemblyAttribute") && !strcmp (nspace
, "System.Runtime.CompilerServices")) {
2509 /* Note we don't check the assembly name, same as coreCLR. */
2510 iter_data
->has_attr
= TRUE
;
2511 stop_scanning
= TRUE
;
2514 return stop_scanning
;
2518 * mono_assembly_has_reference_assembly_attribute:
2519 * \param assembly a MonoAssembly
2520 * \param error set on error.
2522 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2523 * On error returns FALSE and sets \p error.
2526 mono_assembly_has_reference_assembly_attribute (MonoAssembly
*assembly
, MonoError
*error
)
2528 g_assert (assembly
&& assembly
->image
);
2529 /* .NET Framework appears to ignore the attribute on dynamic
2530 * assemblies, so don't call this function for dynamic assemblies. */
2531 g_assert (!image_is_dynamic (assembly
->image
));
2535 * This might be called during assembly loading, so do everything using the low-level
2539 struct HasReferenceAssemblyAttributeIterData iter_data
= { FALSE
};
2541 mono_assembly_metadata_foreach_custom_attr (assembly
, &has_reference_assembly_attribute_iterator
, &iter_data
);
2543 return iter_data
.has_attr
;
2547 * chain_redirections_loadfrom:
2548 * \param image a MonoImage that we wanted to load using LoadFrom context
2549 * \param status set if there was an error opening the redirected image
2551 * Check if we need to open a different image instead of the given one for some reason.
2552 * Returns NULL and sets status to \c MONO_IMAGE_OK if the given image was good.
2554 * Otherwise returns the assembly that we opened instead or sets status if
2555 * there was a problem opening the redirected image.
2559 chain_redirections_loadfrom (MonoImage
*image
, MonoImageOpenStatus
*out_status
)
2561 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
2562 MonoAssembly
*redirected
= NULL
;
2564 redirected
= mono_assembly_binding_applies_to_image (image
, &status
);
2565 if (redirected
|| status
!= MONO_IMAGE_OK
) {
2566 *out_status
= status
;
2570 redirected
= mono_problematic_image_reprobe (image
, &status
);
2571 if (redirected
|| status
!= MONO_IMAGE_OK
) {
2572 *out_status
= status
;
2576 *out_status
= MONO_IMAGE_OK
;
2581 * mono_assembly_binding_applies_to_image:
2582 * \param image The image whose assembly name we should check
2583 * \param status sets on error;
2585 * Get the \c MonoAssemblyName from the given \p image metadata and apply binding redirects to it.
2586 * If the resulting name is different from the name in the image, load that \c MonoAssembly instead
2588 * \returns the loaded \c MonoAssembly, or NULL if no binding redirection applied.
2592 mono_assembly_binding_applies_to_image (MonoImage
* image
, MonoImageOpenStatus
*status
)
2594 /* This is a "fun" one now.
2595 * For LoadFrom ("/basedir/some.dll") or LoadFile("/basedir/some.dll") or Load(byte[])),
2596 * apparently what we're meant to do is:
2597 * 1. probe the assembly name from some.dll (or the byte array)
2598 * 2. apply binding redirects
2599 * 3. If we get some other different name, drop this image and use
2600 * the binding redirected name to probe.
2601 * 4. Return the new assembly.
2603 MonoAssemblyName probed_aname
, dest_name
;
2604 if (!mono_assembly_fill_assembly_name_full (image
, &probed_aname
, TRUE
)) {
2605 if (*status
== MONO_IMAGE_OK
)
2606 *status
= MONO_IMAGE_IMAGE_INVALID
;
2609 MonoAssembly
*result_ass
= NULL
;
2610 MonoAssemblyName
*result_name
= &probed_aname
;
2611 result_name
= mono_assembly_apply_binding (result_name
, &dest_name
);
2612 if (result_name
!= &probed_aname
&& !mono_assembly_names_equal (result_name
, &probed_aname
)) {
2613 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
2614 char *probed_fullname
= mono_stringify_assembly_name (&probed_aname
);
2615 char *result_fullname
= mono_stringify_assembly_name (result_name
);
2616 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
);
2617 g_free (probed_fullname
);
2618 g_free (result_fullname
);
2620 const char *new_basedir
= NULL
; /* FIXME: null? - do a test of this */
2621 MonoAssemblyContextKind new_asmctx
= MONO_ASMCTX_DEFAULT
; /* FIXME: default? or? */
2622 MonoAssembly
*new_requesting
= NULL
; /* this seems okay */
2623 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2625 MonoAssemblyByNameRequest new_req
;
2626 mono_assembly_request_prepare (&new_req
.request
, sizeof (new_req
), new_asmctx
);
2627 new_req
.requesting_assembly
= new_requesting
;
2628 new_req
.basedir
= new_basedir
;
2629 result_ass
= mono_assembly_request_byname (result_name
, &new_req
, &new_status
);
2631 if (result_ass
&& new_status
== MONO_IMAGE_OK
) {
2632 g_assert (result_ass
->image
->assembly
!= NULL
);
2634 *status
= new_status
;
2637 mono_assembly_name_free (&probed_aname
);
2642 * mono_problematic_image_reprobe:
2643 * \param image A MonoImage
2644 * \param status set on error
2646 * If the given image is problematic for mono (see image.c), then try to load
2647 * by assembly name in the default context (which should succeed with Mono's
2648 * own implementations of those assemblies).
2650 * Returns NULL and sets status to MONO_IMAGE_OK if no redirect is needed.
2652 * Otherwise returns the assembly we were redirected to, or NULL and sets a
2653 * non-ok status on failure.
2655 * IMPORTANT NOTE: Don't call this if \c image was found by probing the search
2656 * path, you will end up in a loop and a stack overflow.
2659 mono_problematic_image_reprobe (MonoImage
*image
, MonoImageOpenStatus
*status
)
2661 if (G_LIKELY (!mono_is_problematic_image (image
))) {
2662 *status
= MONO_IMAGE_OK
;
2665 MonoAssemblyName probed_aname
;
2666 if (!mono_assembly_fill_assembly_name_full (image
, &probed_aname
, TRUE
)) {
2667 *status
= MONO_IMAGE_IMAGE_INVALID
;
2670 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
2671 char *probed_fullname
= mono_stringify_assembly_name (&probed_aname
);
2672 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
);
2673 g_free (probed_fullname
);
2675 const char *new_basedir
= NULL
;
2676 MonoAssemblyContextKind new_asmctx
= MONO_ASMCTX_DEFAULT
;
2677 MonoAssembly
*new_requesting
= NULL
;
2678 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2679 MonoAssemblyByNameRequest new_req
;
2680 mono_assembly_request_prepare (&new_req
.request
, sizeof (new_req
), new_asmctx
);
2681 new_req
.requesting_assembly
= new_requesting
;
2682 new_req
.basedir
= new_basedir
;
2683 // Note: this interacts with mono_image_open_a_lot (). If the path from
2684 // which we tried to load the problematic image is among the probing
2685 // paths, the MonoImage will be in the hash of loaded images and we
2686 // would just get it back again here, except for the code there that
2687 // mitigates the situation. Instead
2688 MonoAssembly
*result_ass
= mono_assembly_request_byname (&probed_aname
, &new_req
, &new_status
);
2690 if (! (result_ass
&& new_status
== MONO_IMAGE_OK
)) {
2691 *status
= new_status
;
2693 mono_assembly_name_free (&probed_aname
);
2697 * mono_assembly_open:
2698 * \param filename Opens the assembly pointed out by this name
2699 * \param status return status code
2701 * This loads an assembly from the specified \p filename. The \p filename allows
2702 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2703 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2704 * is treated as a local path.
2706 * First, an attempt is made to load the assembly from the bundled executable (for those
2707 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2708 * assembly has been registered as an embedded assembly). If this is not the case, then
2709 * the assembly is loaded from disk using `api:mono_image_open_full`.
2711 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2712 * the assembly is made.
2714 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2715 * assembly or NULL on error. Details about the error are stored in the
2716 * \p status variable.
2719 mono_assembly_open (const char *filename
, MonoImageOpenStatus
*status
)
2722 MONO_ENTER_GC_UNSAFE
;
2723 MonoAssemblyOpenRequest req
;
2724 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
2725 res
= mono_assembly_request_open (filename
, &req
, status
);
2726 MONO_EXIT_GC_UNSAFE
;
2731 * mono_assembly_load_from_full:
2732 * \param image Image to load the assembly from
2733 * \param fname assembly name to associate with the assembly
2734 * \param status returns the status condition
2735 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2737 * If the provided \p image has an assembly reference, it will process the given
2738 * image as an assembly with the given name.
2740 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2742 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2743 * set to \c MONO_IMAGE_OK; or NULL on error.
2745 * If there is an error loading the assembly the \p status will indicate the
2746 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2747 * image did not contain an assembly reference table.
2750 mono_assembly_load_from_full (MonoImage
*image
, const char*fname
,
2751 MonoImageOpenStatus
*status
, gboolean refonly
)
2754 MONO_ENTER_GC_UNSAFE
;
2755 MonoAssemblyLoadRequest req
;
2756 mono_assembly_request_prepare (&req
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
2757 res
= mono_assembly_request_load_from (image
, fname
, &req
, status
);
2758 MONO_EXIT_GC_UNSAFE
;
2763 mono_assembly_request_load_from (MonoImage
*image
, const char *fname
,
2764 const MonoAssemblyLoadRequest
*req
,
2765 MonoImageOpenStatus
*status
)
2767 MonoAssemblyContextKind asmctx
;
2768 MonoAssemblyCandidatePredicate predicate
;
2771 MonoAssembly
*ass
, *ass2
;
2774 asmctx
= req
->asmctx
;
2775 predicate
= req
->predicate
;
2776 user_data
= req
->predicate_ud
;
2778 if (!image
->tables
[MONO_TABLE_ASSEMBLY
].rows
) {
2779 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2780 *status
= MONO_IMAGE_IMAGE_INVALID
;
2784 #if defined (HOST_WIN32)
2789 tmp_fn
= g_strdup (fname
);
2790 for (i
= strlen (tmp_fn
) - 1; i
>= 0; i
--) {
2791 if (tmp_fn
[i
] == '/')
2795 base_dir
= absolute_dir (tmp_fn
);
2799 base_dir
= absolute_dir (fname
);
2803 * Create assembly struct, and enter it into the assembly cache
2805 ass
= g_new0 (MonoAssembly
, 1);
2806 ass
->basedir
= base_dir
;
2807 ass
->context
.kind
= asmctx
;
2810 MONO_PROFILER_RAISE (assembly_loading
, (ass
));
2812 mono_assembly_fill_assembly_name (image
, &ass
->aname
);
2814 if (mono_defaults
.corlib
&& strcmp (ass
->aname
.name
, MONO_ASSEMBLY_CORLIB_NAME
) == 0) {
2815 // MS.NET doesn't support loading other mscorlibs
2818 mono_image_addref (mono_defaults
.corlib
);
2819 *status
= MONO_IMAGE_OK
;
2820 return mono_defaults
.corlib
->assembly
;
2823 /* Add a non-temporary reference because of ass->image */
2824 mono_image_addref (image
);
2826 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
);
2829 * The load hooks might take locks so we can't call them while holding the
2832 if (ass
->aname
.name
&& asmctx
!= MONO_ASMCTX_INDIVIDUAL
) {
2833 /* 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?) */
2834 ass2
= mono_assembly_invoke_search_hook_internal (&ass
->aname
, NULL
, asmctx
== MONO_ASMCTX_REFONLY
, FALSE
);
2836 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
);
2839 mono_image_close (image
);
2840 *status
= MONO_IMAGE_OK
;
2845 /* We need to check for ReferenceAssmeblyAttribute before we
2846 * mark the assembly as loaded and before we fire the load
2847 * hook. Otherwise mono_domain_fire_assembly_load () in
2848 * appdomain.c will cache a mapping from the assembly name to
2849 * this image and we won't be able to look for a different
2852 if (asmctx
!= MONO_ASMCTX_REFONLY
) {
2853 ERROR_DECL (refasm_error
);
2854 if (mono_assembly_has_reference_assembly_attribute (ass
, refasm_error
)) {
2855 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass
->aname
.name
, image
->name
);
2858 mono_image_close (image
);
2859 *status
= MONO_IMAGE_IMAGE_INVALID
;
2862 mono_error_cleanup (refasm_error
);
2865 if (predicate
&& !predicate (ass
, user_data
)) {
2866 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate returned FALSE, skipping '%s' (%s)\n", ass
->aname
.name
, image
->name
);
2869 mono_image_close (image
);
2870 *status
= MONO_IMAGE_IMAGE_INVALID
;
2874 mono_assemblies_lock ();
2876 /* If an assembly is loaded into an individual context, always return a
2877 * new MonoAssembly, even if another assembly with the same name has
2878 * already been loaded.
2880 if (image
->assembly
&& asmctx
!= MONO_ASMCTX_INDIVIDUAL
) {
2882 * This means another thread has already loaded the assembly, but not yet
2883 * called the load hooks so the search hook can't find the assembly.
2885 mono_assemblies_unlock ();
2886 ass2
= image
->assembly
;
2889 mono_image_close (image
);
2890 *status
= MONO_IMAGE_OK
;
2894 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Prepared to set up assembly '%s' (%s)", ass
->aname
.name
, image
->name
);
2896 /* If asmctx is INDIVIDUAL, image->assembly might not be NULL, so don't
2898 if (image
->assembly
== NULL
)
2899 image
->assembly
= ass
;
2901 loaded_assemblies
= g_list_prepend (loaded_assemblies
, ass
);
2902 mono_assemblies_unlock ();
2905 if (image
->is_module_handle
)
2906 mono_image_fixup_vtable (image
);
2909 mono_assembly_invoke_load_hook (ass
);
2911 MONO_PROFILER_RAISE (assembly_loaded
, (ass
));
2917 * mono_assembly_load_from:
2918 * \param image Image to load the assembly from
2919 * \param fname assembly name to associate with the assembly
2920 * \param status return status code
2922 * If the provided \p image has an assembly reference, it will process the given
2923 * image as an assembly with the given name.
2925 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2927 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2928 * \p refonly parameter set to FALSE.
2929 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2930 * set to \c MONO_IMAGE_OK; or NULL on error.
2932 * If there is an error loading the assembly the \p status will indicate the
2933 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2934 * image did not contain an assembly reference table.
2938 mono_assembly_load_from (MonoImage
*image
, const char *fname
,
2939 MonoImageOpenStatus
*status
)
2942 MONO_ENTER_GC_UNSAFE
;
2943 MonoAssemblyLoadRequest req
;
2944 mono_assembly_request_prepare (&req
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
2945 res
= mono_assembly_request_load_from (image
, fname
, &req
, status
);
2946 MONO_EXIT_GC_UNSAFE
;
2951 * mono_assembly_name_free:
2952 * \param aname assembly name to free
2954 * Frees the provided assembly name object.
2955 * (it does not frees the object itself, only the name members).
2958 mono_assembly_name_free (MonoAssemblyName
*aname
)
2960 MONO_ENTER_GC_UNSAFE
;
2961 mono_assembly_name_free_internal (aname
);
2962 MONO_EXIT_GC_UNSAFE
;
2966 mono_assembly_name_free_internal (MonoAssemblyName
*aname
)
2968 MONO_REQ_GC_UNSAFE_MODE
;
2973 g_free ((void *) aname
->name
);
2974 g_free ((void *) aname
->culture
);
2975 g_free ((void *) aname
->hash_value
);
2976 g_free ((guint8
*) aname
->public_key
);
2980 parse_public_key (const gchar
*key
, gchar
** pubkey
, gboolean
*is_ecma
)
2983 gchar header
[16], val
, *arr
, *endp
;
2984 gint i
, j
, offset
, bitlen
, keylen
, pkeylen
;
2986 //both pubkey and is_ecma are required arguments
2987 g_assert (pubkey
&& is_ecma
);
2989 keylen
= strlen (key
) >> 1;
2993 /* allow the ECMA standard key */
2994 if (strcmp (key
, "00000000000000000400000000000000") == 0) {
3000 val
= g_ascii_xdigit_value (key
[0]) << 4;
3001 val
|= g_ascii_xdigit_value (key
[1]);
3006 val
= g_ascii_xdigit_value (key
[24]);
3007 val
|= g_ascii_xdigit_value (key
[25]);
3019 /* We need the first 16 bytes
3020 * to check whether this key is valid or not */
3021 pkeylen
= strlen (pkey
) >> 1;
3025 for (i
= 0, j
= 0; i
< 16; i
++) {
3026 header
[i
] = g_ascii_xdigit_value (pkey
[j
++]) << 4;
3027 header
[i
] |= g_ascii_xdigit_value (pkey
[j
++]);
3030 if (header
[0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
3031 header
[1] != 0x02 || /* Version (0x02) */
3032 header
[2] != 0x00 || /* Reserved (word) */
3033 header
[3] != 0x00 ||
3034 (guint
)(read32 (header
+ 8)) != 0x31415352) /* DWORD magic = RSA1 */
3037 /* Based on this length, we _should_ be able to know if the length is right */
3038 bitlen
= read32 (header
+ 12) >> 3;
3039 if ((bitlen
+ 16 + 4) != pkeylen
)
3042 arr
= (gchar
*)g_malloc (keylen
+ 4);
3043 /* Encode the size of the blob */
3044 mono_metadata_encode_value (keylen
, &arr
[0], &endp
);
3045 offset
= (gint
)(endp
-arr
);
3047 for (i
= offset
, j
= 0; i
< keylen
+ offset
; i
++) {
3048 arr
[i
] = g_ascii_xdigit_value (key
[j
++]) << 4;
3049 arr
[i
] |= g_ascii_xdigit_value (key
[j
++]);
3058 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
)
3060 gint major
, minor
, build
, revision
;
3063 gchar
*pkeyptr
, *encoded
, tok
[8];
3065 memset (aname
, 0, sizeof (MonoAssemblyName
));
3068 version_parts
= sscanf (version
, "%u.%u.%u.%u", &major
, &minor
, &build
, &revision
);
3069 if (version_parts
< 2 || version_parts
> 4)
3072 /* FIXME: we should set build & revision to -1 (instead of 0)
3073 if these are not set in the version string. That way, later on,
3074 we can still determine if these were specified. */
3075 aname
->major
= major
;
3076 aname
->minor
= minor
;
3077 if (version_parts
>= 3)
3078 aname
->build
= build
;
3081 if (version_parts
== 4)
3082 aname
->revision
= revision
;
3084 aname
->revision
= 0;
3087 aname
->flags
= flags
;
3089 aname
->name
= g_strdup (name
);
3092 if (g_ascii_strcasecmp (culture
, "neutral") == 0)
3093 aname
->culture
= g_strdup ("");
3095 aname
->culture
= g_strdup (culture
);
3098 if (token
&& strncmp (token
, "null", 4) != 0) {
3101 /* the constant includes the ending NULL, hence the -1 */
3102 if (strlen (token
) != (MONO_PUBLIC_KEY_TOKEN_LENGTH
- 1)) {
3103 mono_assembly_name_free (aname
);
3106 lower
= g_ascii_strdown (token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3107 g_strlcpy ((char*)aname
->public_key_token
, lower
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3112 gboolean is_ecma
= FALSE
;
3114 if (strcmp (key
, "null") == 0 || !parse_public_key (key
, &pkey
, &is_ecma
)) {
3115 mono_assembly_name_free (aname
);
3120 g_assert (pkey
== NULL
);
3121 aname
->public_key
= NULL
;
3122 g_strlcpy ((gchar
*)aname
->public_key_token
, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3126 len
= mono_metadata_decode_blob_size ((const gchar
*) pkey
, (const gchar
**) &pkeyptr
);
3127 // We also need to generate the key token
3128 mono_digest_get_public_token ((guchar
*) tok
, (guint8
*) pkeyptr
, len
);
3129 encoded
= encode_public_tok ((guchar
*) tok
, 8);
3130 g_strlcpy ((gchar
*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3133 if (save_public_key
)
3134 aname
->public_key
= (guint8
*) pkey
;
3143 parse_assembly_directory_name (const char *name
, const char *dirname
, MonoAssemblyName
*aname
)
3148 parts
= g_strsplit (dirname
, "_", 3);
3149 if (!parts
|| !parts
[0] || !parts
[1] || !parts
[2]) {
3154 res
= build_assembly_name (name
, parts
[0], parts
[1], parts
[2], NULL
, 0, 0, aname
, FALSE
);
3160 split_key_value (const gchar
*pair
, gchar
**key
, guint32
*keylen
, gchar
**value
)
3162 char *eqsign
= (char*)strchr (pair
, '=');
3170 *key
= (gchar
*)pair
;
3171 *keylen
= eqsign
- *key
;
3172 while (*keylen
> 0 && g_ascii_isspace ((*key
) [*keylen
- 1]))
3174 *value
= g_strstrip (eqsign
+ 1);
3179 mono_assembly_name_parse_full (const char *name
, MonoAssemblyName
*aname
, gboolean save_public_key
, gboolean
*is_version_defined
, gboolean
*is_token_defined
)
3183 gchar
*version
= NULL
;
3185 gchar
*culture
= NULL
;
3187 gchar
*token
= NULL
;
3191 gchar
*retargetable
= NULL
;
3192 gchar
*retargetable_uq
;
3196 gchar
*value
, *part_name
;
3197 guint32 part_name_len
;
3200 gboolean version_defined
;
3201 gboolean token_defined
;
3203 guint32 arch
= MONO_PROCESSOR_ARCHITECTURE_NONE
;
3205 if (!is_version_defined
)
3206 is_version_defined
= &version_defined
;
3207 *is_version_defined
= FALSE
;
3208 if (!is_token_defined
)
3209 is_token_defined
= &token_defined
;
3210 *is_token_defined
= FALSE
;
3212 parts
= tmp
= g_strsplit (name
, ",", 6);
3213 if (!tmp
|| !*tmp
) {
3218 dllname
= g_strstrip (*tmp
);
3223 if (!split_key_value (g_strstrip (*tmp
), &part_name
, &part_name_len
, &value
))
3224 goto cleanup_and_fail
;
3226 if (part_name_len
== 7 && !g_ascii_strncasecmp (part_name
, "Version", part_name_len
)) {
3227 *is_version_defined
= TRUE
;
3229 if (strlen (version
) == 0) {
3230 goto cleanup_and_fail
;
3236 if (part_name_len
== 7 && !g_ascii_strncasecmp (part_name
, "Culture", part_name_len
)) {
3238 if (strlen (culture
) == 0) {
3239 goto cleanup_and_fail
;
3245 if (part_name_len
== 14 && !g_ascii_strncasecmp (part_name
, "PublicKeyToken", part_name_len
)) {
3246 *is_token_defined
= TRUE
;
3248 if (strlen (token
) == 0) {
3249 goto cleanup_and_fail
;
3255 if (part_name_len
== 9 && !g_ascii_strncasecmp (part_name
, "PublicKey", part_name_len
)) {
3257 if (strlen (key
) == 0) {
3258 goto cleanup_and_fail
;
3264 if (part_name_len
== 12 && !g_ascii_strncasecmp (part_name
, "Retargetable", part_name_len
)) {
3265 retargetable
= value
;
3266 retargetable_uq
= unquote (retargetable
);
3267 if (retargetable_uq
!= NULL
)
3268 retargetable
= retargetable_uq
;
3270 if (!g_ascii_strcasecmp (retargetable
, "yes")) {
3271 flags
|= ASSEMBLYREF_RETARGETABLE_FLAG
;
3272 } else if (g_ascii_strcasecmp (retargetable
, "no")) {
3273 g_free (retargetable_uq
);
3274 goto cleanup_and_fail
;
3277 g_free (retargetable_uq
);
3282 if (part_name_len
== 21 && !g_ascii_strncasecmp (part_name
, "ProcessorArchitecture", part_name_len
)) {
3284 procarch_uq
= unquote (procarch
);
3285 if (procarch_uq
!= NULL
)
3286 procarch
= procarch_uq
;
3288 if (!g_ascii_strcasecmp (procarch
, "MSIL"))
3289 arch
= MONO_PROCESSOR_ARCHITECTURE_MSIL
;
3290 else if (!g_ascii_strcasecmp (procarch
, "X86"))
3291 arch
= MONO_PROCESSOR_ARCHITECTURE_X86
;
3292 else if (!g_ascii_strcasecmp (procarch
, "IA64"))
3293 arch
= MONO_PROCESSOR_ARCHITECTURE_IA64
;
3294 else if (!g_ascii_strcasecmp (procarch
, "AMD64"))
3295 arch
= MONO_PROCESSOR_ARCHITECTURE_AMD64
;
3297 g_free (procarch_uq
);
3298 goto cleanup_and_fail
;
3301 g_free (procarch_uq
);
3310 /* if retargetable flag is set, then we must have a fully qualified name */
3311 if (retargetable
!= NULL
&& (version
== NULL
|| culture
== NULL
|| (key
== NULL
&& token
== NULL
))) {
3312 goto cleanup_and_fail
;
3315 dllname_uq
= unquote (dllname
);
3316 version_uq
= unquote (version
);
3317 culture_uq
= unquote (culture
);
3318 token_uq
= unquote (token
);
3319 key_uq
= unquote (key
);
3321 res
= build_assembly_name (
3322 dllname_uq
== NULL
? dllname
: dllname_uq
,
3323 version_uq
== NULL
? version
: version_uq
,
3324 culture_uq
== NULL
? culture
: culture_uq
,
3325 token_uq
== NULL
? token
: token_uq
,
3326 key_uq
== NULL
? key
: key_uq
,
3327 flags
, arch
, aname
, save_public_key
);
3329 g_free (dllname_uq
);
3330 g_free (version_uq
);
3331 g_free (culture_uq
);
3344 unquote (const char *str
)
3352 slen
= strlen (str
);
3356 if (*str
!= '\'' && *str
!= '\"')
3359 end
= str
+ slen
- 1;
3363 return g_strndup (str
+ 1, slen
- 2);
3367 * mono_assembly_name_parse:
3368 * \param name name to parse
3369 * \param aname the destination assembly name
3371 * Parses an assembly qualified type name and assigns the name,
3372 * version, culture and token to the provided assembly name object.
3374 * \returns TRUE if the name could be parsed.
3377 mono_assembly_name_parse (const char *name
, MonoAssemblyName
*aname
)
3379 return mono_assembly_name_parse_full (name
, aname
, FALSE
, NULL
, NULL
);
3383 * mono_assembly_name_new:
3384 * \param name name to parse
3386 * Allocate a new \c MonoAssemblyName and fill its values from the
3389 * \returns a newly allocated structure or NULL if there was any failure.
3392 mono_assembly_name_new (const char *name
)
3394 MonoAssemblyName
*result
= NULL
;
3395 MONO_ENTER_GC_UNSAFE
;
3396 MonoAssemblyName
*aname
= g_new0 (MonoAssemblyName
, 1);
3397 if (mono_assembly_name_parse (name
, aname
))
3401 MONO_EXIT_GC_UNSAFE
;
3406 * mono_assembly_name_get_name:
3409 mono_assembly_name_get_name (MonoAssemblyName
*aname
)
3411 const char *result
= NULL
;
3412 MONO_ENTER_GC_UNSAFE
;
3413 result
= aname
->name
;
3414 MONO_EXIT_GC_UNSAFE
;
3419 * mono_assembly_name_get_culture:
3422 mono_assembly_name_get_culture (MonoAssemblyName
*aname
)
3424 const char *result
= NULL
;
3425 MONO_ENTER_GC_UNSAFE
;
3426 result
= aname
->culture
;
3427 MONO_EXIT_GC_UNSAFE
;
3432 * mono_assembly_name_get_pubkeytoken:
3435 mono_assembly_name_get_pubkeytoken (MonoAssemblyName
*aname
)
3437 if (aname
->public_key_token
[0])
3438 return aname
->public_key_token
;
3443 * mono_assembly_name_get_version:
3446 mono_assembly_name_get_version (MonoAssemblyName
*aname
, uint16_t *minor
, uint16_t *build
, uint16_t *revision
)
3449 *minor
= aname
->minor
;
3451 *build
= aname
->build
;
3453 *revision
= aname
->revision
;
3454 return aname
->major
;
3457 static MonoAssembly
*
3458 probe_for_partial_name (const char *basepath
, const char *fullname
, MonoAssemblyName
*aname
, MonoImageOpenStatus
*status
)
3460 gchar
*fullpath
= NULL
;
3462 const char* direntry
;
3463 MonoAssemblyName gac_aname
;
3464 gint major
=-1, minor
=0, build
=0, revision
=0;
3465 gboolean exact_version
;
3467 dirhandle
= g_dir_open (basepath
, 0, NULL
);
3471 exact_version
= (aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0;
3473 while ((direntry
= g_dir_read_name (dirhandle
))) {
3474 gboolean match
= TRUE
;
3476 if(!parse_assembly_directory_name (aname
->name
, direntry
, &gac_aname
))
3479 if (aname
->culture
!= NULL
&& strcmp (aname
->culture
, gac_aname
.culture
) != 0)
3482 if (match
&& strlen ((char*)aname
->public_key_token
) > 0 &&
3483 !mono_public_tokens_are_equal (aname
->public_key_token
, gac_aname
.public_key_token
))
3487 if (exact_version
) {
3488 match
= (aname
->major
== gac_aname
.major
&& aname
->minor
== gac_aname
.minor
&&
3489 aname
->build
== gac_aname
.build
&& aname
->revision
== gac_aname
.revision
);
3491 else if (gac_aname
.major
< major
)
3493 else if (gac_aname
.major
== major
) {
3494 if (gac_aname
.minor
< minor
)
3496 else if (gac_aname
.minor
== minor
) {
3497 if (gac_aname
.build
< build
)
3499 else if (gac_aname
.build
== build
&& gac_aname
.revision
<= revision
)
3506 major
= gac_aname
.major
;
3507 minor
= gac_aname
.minor
;
3508 build
= gac_aname
.build
;
3509 revision
= gac_aname
.revision
;
3511 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, basepath
, direntry
, fullname
, NULL
);
3514 mono_assembly_name_free (&gac_aname
);
3517 g_dir_close (dirhandle
);
3519 if (fullpath
== NULL
)
3522 MonoAssemblyOpenRequest req
;
3523 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
3524 MonoAssembly
*res
= mono_assembly_request_open (fullpath
, &req
, status
);
3531 * mono_assembly_load_with_partial_name:
3532 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
3533 * \param status return status code
3535 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
3536 * so it might contain a qualified type name, version, culture and token.
3538 * This will load the assembly from the file whose name is derived from the assembly name
3539 * by appending the \c .dll extension.
3541 * The assembly is loaded from either one of the extra Global Assembly Caches specified
3542 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
3543 * if that fails from the GAC.
3545 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
3548 mono_assembly_load_with_partial_name (const char *name
, MonoImageOpenStatus
*status
)
3550 MonoAssembly
*result
;
3551 MONO_ENTER_GC_UNSAFE
;
3552 result
= mono_assembly_load_with_partial_name_internal (name
, status
);
3553 MONO_EXIT_GC_UNSAFE
;
3558 mono_assembly_load_with_partial_name_internal (const char *name
, MonoImageOpenStatus
*status
)
3562 MonoAssemblyName
*aname
, base_name
;
3563 MonoAssemblyName mapped_aname
;
3564 gchar
*fullname
, *gacpath
;
3567 MONO_REQ_GC_UNSAFE_MODE
;
3569 memset (&base_name
, 0, sizeof (MonoAssemblyName
));
3572 if (!mono_assembly_name_parse (name
, aname
))
3576 * If no specific version has been requested, make sure we load the
3577 * correct version for system assemblies.
3579 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) == 0)
3580 aname
= mono_assembly_remap_version (aname
, &mapped_aname
);
3582 res
= mono_assembly_loaded_full (aname
, FALSE
);
3584 mono_assembly_name_free (aname
);
3588 res
= invoke_assembly_preload_hook (aname
, assemblies_path
);
3590 res
->in_gac
= FALSE
;
3591 mono_assembly_name_free (aname
);
3595 fullname
= g_strdup_printf ("%s.dll", aname
->name
);
3597 if (extra_gac_paths
) {
3598 paths
= extra_gac_paths
;
3599 while (!res
&& *paths
) {
3600 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", aname
->name
, NULL
);
3601 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
3610 mono_assembly_name_free (aname
);
3614 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), "mono", "gac", aname
->name
, NULL
);
3615 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
3619 mono_assembly_name_free (aname
);
3624 MonoDomain
*domain
= mono_domain_get ();
3626 res
= mono_try_assembly_resolve (domain
, name
, NULL
, FALSE
, error
);
3627 if (!is_ok (error
)) {
3628 mono_error_cleanup (error
);
3629 if (*status
== MONO_IMAGE_OK
)
3630 *status
= MONO_IMAGE_IMAGE_INVALID
;
3638 mono_assembly_is_in_gac (const gchar
*filename
)
3640 const gchar
*rootdir
;
3644 if (filename
== NULL
)
3647 for (paths
= extra_gac_paths
; paths
&& *paths
; paths
++) {
3648 if (strstr (*paths
, filename
) != *paths
)
3651 gp
= (gchar
*) (filename
+ strlen (*paths
));
3652 if (*gp
!= G_DIR_SEPARATOR
)
3655 if (strncmp (gp
, "lib", 3))
3658 if (*gp
!= G_DIR_SEPARATOR
)
3661 if (strncmp (gp
, "mono", 4))
3664 if (*gp
!= G_DIR_SEPARATOR
)
3667 if (strncmp (gp
, "gac", 3))
3670 if (*gp
!= G_DIR_SEPARATOR
)
3676 rootdir
= mono_assembly_getrootdir ();
3677 if (strstr (filename
, rootdir
) != filename
)
3680 gp
= (gchar
*) (filename
+ strlen (rootdir
));
3681 if (*gp
!= G_DIR_SEPARATOR
)
3684 if (strncmp (gp
, "mono", 4))
3687 if (*gp
!= G_DIR_SEPARATOR
)
3690 if (strncmp (gp
, "gac", 3))
3693 if (*gp
!= G_DIR_SEPARATOR
)
3699 mono_assembly_load_publisher_policy (MonoAssemblyName
*aname
)
3702 gchar
*filename
, *pname
, *name
, *culture
, *version
, *fullpath
, *subpath
;
3706 if (strstr (aname
->name
, ".dll")) {
3707 len
= strlen (aname
->name
) - 4;
3708 name
= (gchar
*)g_malloc (len
+ 1);
3709 memcpy (name
, aname
->name
, len
);
3712 name
= g_strdup (aname
->name
);
3715 culture
= g_utf8_strdown (aname
->culture
, -1);
3717 culture
= g_strdup ("");
3719 pname
= g_strdup_printf ("policy.%d.%d.%s", aname
->major
, aname
->minor
, name
);
3720 version
= g_strdup_printf ("0.0.0.0_%s_%s", culture
, aname
->public_key_token
);
3724 filename
= g_strconcat (pname
, ".dll", NULL
);
3725 subpath
= g_build_path (G_DIR_SEPARATOR_S
, pname
, version
, filename
, NULL
);
3731 if (extra_gac_paths
) {
3732 paths
= extra_gac_paths
;
3733 while (!image
&& *paths
) {
3734 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
,
3735 "lib", "mono", "gac", subpath
, NULL
);
3736 image
= mono_image_open (fullpath
, NULL
);
3747 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
3748 "mono", "gac", subpath
, NULL
);
3749 image
= mono_image_open (fullpath
, NULL
);
3756 static MonoAssemblyName
*
3757 mono_assembly_bind_version (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
3759 memcpy (dest_name
, aname
, sizeof (MonoAssemblyName
));
3760 dest_name
->major
= info
->new_version
.major
;
3761 dest_name
->minor
= info
->new_version
.minor
;
3762 dest_name
->build
= info
->new_version
.build
;
3763 dest_name
->revision
= info
->new_version
.revision
;
3768 /* LOCKING: assembly_binding lock must be held */
3769 static MonoAssemblyBindingInfo
*
3770 search_binding_loaded (MonoAssemblyName
*aname
)
3774 for (tmp
= loaded_assembly_bindings
; tmp
; tmp
= tmp
->next
) {
3775 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)tmp
->data
;
3776 if (assembly_binding_maps_name (info
, aname
))
3783 static inline gboolean
3784 info_compare_versions (AssemblyVersionSet
*left
, AssemblyVersionSet
*right
)
3786 if (left
->major
!= right
->major
|| left
->minor
!= right
->minor
||
3787 left
->build
!= right
->build
|| left
->revision
!= right
->revision
)
3793 static inline gboolean
3794 info_versions_equal (MonoAssemblyBindingInfo
*left
, MonoAssemblyBindingInfo
*right
)
3796 if (left
->has_old_version_bottom
!= right
->has_old_version_bottom
)
3799 if (left
->has_old_version_top
!= right
->has_old_version_top
)
3802 if (left
->has_new_version
!= right
->has_new_version
)
3805 if (left
->has_old_version_bottom
&& !info_compare_versions (&left
->old_version_bottom
, &right
->old_version_bottom
))
3808 if (left
->has_old_version_top
&& !info_compare_versions (&left
->old_version_top
, &right
->old_version_top
))
3811 if (left
->has_new_version
&& !info_compare_versions (&left
->new_version
, &right
->new_version
))
3817 /* LOCKING: assumes all the necessary locks are held */
3819 assembly_binding_info_parsed (MonoAssemblyBindingInfo
*info
, void *user_data
)
3821 MonoAssemblyBindingInfo
*info_copy
;
3823 MonoAssemblyBindingInfo
*info_tmp
;
3824 MonoDomain
*domain
= (MonoDomain
*)user_data
;
3829 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
)) {
3830 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3831 info
->name
, info
->new_version
.major
, info
->new_version
.minor
, info
->new_version
.build
, info
->new_version
.revision
);
3835 for (tmp
= domain
->assembly_bindings
; tmp
; tmp
= tmp
->next
) {
3836 info_tmp
= (MonoAssemblyBindingInfo
*)tmp
->data
;
3837 if (strcmp (info
->name
, info_tmp
->name
) == 0 && info_versions_equal (info
, info_tmp
))
3841 info_copy
= (MonoAssemblyBindingInfo
*)mono_mempool_alloc0 (domain
->mp
, sizeof (MonoAssemblyBindingInfo
));
3842 memcpy (info_copy
, info
, sizeof (MonoAssemblyBindingInfo
));
3844 info_copy
->name
= mono_mempool_strdup (domain
->mp
, info
->name
);
3846 info_copy
->culture
= mono_mempool_strdup (domain
->mp
, info
->culture
);
3848 domain
->assembly_bindings
= g_slist_append_mempool (domain
->mp
, domain
->assembly_bindings
, info_copy
);
3852 get_version_number (int major
, int minor
)
3854 return major
* 256 + minor
;
3857 static inline gboolean
3858 info_major_minor_in_range (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
3860 int aname_version_number
= get_version_number (aname
->major
, aname
->minor
);
3861 if (!info
->has_old_version_bottom
)
3864 if (get_version_number (info
->old_version_bottom
.major
, info
->old_version_bottom
.minor
) > aname_version_number
)
3867 if (info
->has_old_version_top
&& get_version_number (info
->old_version_top
.major
, info
->old_version_top
.minor
) < aname_version_number
)
3870 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
3871 info
->major
= aname
->major
;
3872 info
->minor
= aname
->minor
;
3877 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
3878 static MonoAssemblyBindingInfo
*
3879 get_per_domain_assembly_binding_info (MonoDomain
*domain
, MonoAssemblyName
*aname
)
3881 MonoAssemblyBindingInfo
*info
;
3884 if (!domain
->assembly_bindings
)
3888 for (list
= domain
->assembly_bindings
; list
; list
= list
->next
) {
3889 info
= (MonoAssemblyBindingInfo
*)list
->data
;
3890 if (info
&& !strcmp (aname
->name
, info
->name
) && info_major_minor_in_range (info
, aname
))
3896 if (info
->name
&& info
->public_key_token
[0] && info
->has_old_version_bottom
&&
3897 info
->has_new_version
&& assembly_binding_maps_name (info
, aname
))
3898 info
->is_valid
= TRUE
;
3900 info
->is_valid
= FALSE
;
3907 mono_domain_parse_assembly_bindings (MonoDomain
*domain
, int amajor
, int aminor
, gchar
*domain_config_file_name
)
3909 if (domain
->assembly_bindings_parsed
)
3911 mono_domain_lock (domain
);
3912 if (!domain
->assembly_bindings_parsed
) {
3914 gchar
*domain_config_file_path
= mono_portability_find_file (domain_config_file_name
, TRUE
);
3916 if (!domain_config_file_path
)
3917 domain_config_file_path
= domain_config_file_name
;
3919 mono_config_parse_assembly_bindings (domain_config_file_path
, amajor
, aminor
, domain
, assembly_binding_info_parsed
);
3920 domain
->assembly_bindings_parsed
= TRUE
;
3921 if (domain_config_file_name
!= domain_config_file_path
)
3922 g_free (domain_config_file_path
);
3925 mono_domain_unlock (domain
);
3928 static MonoAssemblyName
*
3929 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
3931 HANDLE_FUNCTION_ENTER ();
3934 MonoAssemblyBindingInfo
*info
, *info2
;
3938 if (aname
->public_key_token
[0] == 0)
3941 domain
= mono_domain_get ();
3943 mono_assembly_binding_lock ();
3944 info
= search_binding_loaded (aname
);
3945 mono_assembly_binding_unlock ();
3948 mono_domain_lock (domain
);
3949 info
= get_per_domain_assembly_binding_info (domain
, aname
);
3950 mono_domain_unlock (domain
);
3954 if (!check_policy_versions (info
, aname
))
3957 mono_assembly_bind_version (info
, aname
, dest_name
);
3958 goto return_dest_name
;
3961 MonoAppDomainSetupHandle setup
;
3962 MonoStringHandle configuration_file
;
3965 && !MONO_HANDLE_IS_NULL (setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, domain
->setup
))
3966 && !MONO_HANDLE_IS_NULL (configuration_file
= MONO_HANDLE_NEW_GET (MonoString
, setup
, configuration_file
))) {
3967 char *domain_config_file_name
= mono_string_handle_to_utf8 (configuration_file
, error
);
3968 /* expect this to succeed because mono_domain_set_options_from_config () did
3969 * the same thing when the domain was created. */
3970 mono_error_assert_ok (error
);
3971 mono_domain_parse_assembly_bindings (domain
, aname
->major
, aname
->minor
, domain_config_file_name
);
3972 g_free (domain_config_file_name
);
3974 mono_domain_lock (domain
);
3975 info2
= get_per_domain_assembly_binding_info (domain
, aname
);
3978 info
= (MonoAssemblyBindingInfo
*)g_memdup (info2
, sizeof (MonoAssemblyBindingInfo
));
3979 info
->name
= g_strdup (info2
->name
);
3980 info
->culture
= g_strdup (info2
->culture
);
3981 info
->domain_id
= domain
->domain_id
;
3984 mono_domain_unlock (domain
);
3988 info
= g_new0 (MonoAssemblyBindingInfo
, 1);
3989 info
->major
= aname
->major
;
3990 info
->minor
= aname
->minor
;
3993 if (!info
->is_valid
) {
3994 ppimage
= mono_assembly_load_publisher_policy (aname
);
3996 get_publisher_policy_info (ppimage
, aname
, info
);
3997 mono_image_close (ppimage
);
4001 /* Define default error value if needed */
4002 if (!info
->is_valid
) {
4003 info
->name
= g_strdup (aname
->name
);
4004 info
->culture
= g_strdup (aname
->culture
);
4005 g_strlcpy ((char *)info
->public_key_token
, (const char *)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
4008 mono_assembly_binding_lock ();
4009 info2
= search_binding_loaded (aname
);
4011 /* This binding was added by another thread
4013 mono_assembly_binding_info_free (info
);
4018 loaded_assembly_bindings
= g_slist_prepend (loaded_assembly_bindings
, info
);
4020 mono_assembly_binding_unlock ();
4022 if (!info
->is_valid
|| !check_policy_versions (info
, aname
))
4025 mono_assembly_bind_version (info
, aname
, dest_name
);
4026 goto return_dest_name
;
4028 MonoAssemblyName
* result
;
4038 HANDLE_FUNCTION_RETURN_VAL (result
);
4042 * mono_assembly_load_from_gac
4044 * \param aname The assembly name object
4046 static MonoAssembly
*
4047 mono_assembly_load_from_gac (MonoAssemblyName
*aname
, gchar
*filename
, MonoImageOpenStatus
*status
, MonoBoolean refonly
)
4049 MonoAssembly
*result
= NULL
;
4050 gchar
*name
, *version
, *culture
, *fullpath
, *subpath
;
4055 if (aname
->public_key_token
[0] == 0) {
4059 if (strstr (aname
->name
, ".dll")) {
4060 len
= strlen (filename
) - 4;
4061 name
= (gchar
*)g_malloc (len
+ 1);
4062 memcpy (name
, aname
->name
, len
);
4065 name
= g_strdup (aname
->name
);
4068 if (aname
->culture
) {
4069 culture
= g_utf8_strdown (aname
->culture
, -1);
4071 culture
= g_strdup ("");
4074 pubtok
= g_ascii_strdown ((char*)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
4075 version
= g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname
->major
,
4076 aname
->minor
, aname
->build
, aname
->revision
,
4080 subpath
= g_build_path (G_DIR_SEPARATOR_S
, name
, version
, filename
, NULL
);
4085 MonoAssemblyOpenRequest req
;
4086 mono_assembly_request_prepare (&req
.request
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
4088 if (extra_gac_paths
) {
4089 paths
= extra_gac_paths
;
4090 while (!result
&& *paths
) {
4091 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", subpath
, NULL
);
4092 result
= mono_assembly_request_open (fullpath
, &req
, status
);
4099 result
->in_gac
= TRUE
;
4104 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
4105 "mono", "gac", subpath
, NULL
);
4106 result
= mono_assembly_request_open (fullpath
, &req
, status
);
4110 result
->in_gac
= TRUE
;
4118 mono_assembly_load_corlib (const MonoRuntimeInfo
*runtime
, MonoImageOpenStatus
*status
)
4120 MonoAssemblyName
*aname
;
4121 MonoAssemblyOpenRequest req
;
4122 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
4125 /* g_print ("corlib already loaded\n"); */
4129 #ifdef ENABLE_NETCORE
4130 aname
= mono_assembly_name_new (MONO_ASSEMBLY_CORLIB_NAME
);
4131 corlib
= invoke_assembly_preload_hook (aname
, NULL
);
4132 /* MonoCore preload hook should know how to find it */
4133 /* FIXME: AOT compiler comes here without an installed hook. */
4136 // A nonstandard preload hook may provide a special mscorlib assembly
4137 aname
= mono_assembly_name_new ("mscorlib.dll");
4138 corlib
= invoke_assembly_preload_hook (aname
, assemblies_path
);
4139 mono_assembly_name_free (aname
);
4142 goto return_corlib_and_facades
;
4144 // This unusual directory layout can occur if mono is being built and run out of its own source repo
4145 if (assemblies_path
) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
4146 corlib
= load_in_path ("mscorlib.dll", (const char**)assemblies_path
, &req
, status
);
4148 goto return_corlib_and_facades
;
4151 /* Normal case: Load corlib from mono/<version> */
4153 corlib_file
= g_build_filename ("mono", runtime
->framework_version
, "mscorlib.dll", NULL
);
4154 if (assemblies_path
) { // Custom assemblies path
4155 corlib
= load_in_path (corlib_file
, (const char**)assemblies_path
, &req
, status
);
4157 g_free (corlib_file
);
4158 goto return_corlib_and_facades
;
4161 corlib
= load_in_path (corlib_file
, (const char**) default_path
, &req
, status
);
4162 g_free (corlib_file
);
4164 return_corlib_and_facades
:
4165 if (corlib
) // FIXME: stop hardcoding 4.5 here
4166 default_path
[1] = g_strdup_printf ("%s/Facades", corlib
->basedir
);
4167 #endif /*!ENABLE_NETCORE*/
4172 static MonoAssembly
*
4173 prevent_reference_assembly_from_running (MonoAssembly
* candidate
, gboolean refonly
)
4175 ERROR_DECL (refasm_error
);
4176 if (candidate
&& !refonly
) {
4177 /* .NET Framework seems to not check for ReferenceAssemblyAttribute on dynamic assemblies */
4178 if (!image_is_dynamic (candidate
->image
) &&
4179 mono_assembly_has_reference_assembly_attribute (candidate
, refasm_error
))
4182 mono_error_cleanup (refasm_error
);
4187 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly
*candidate
, gpointer ud
)
4189 MonoAssemblyName
*wanted_name
= (MonoAssemblyName
*)ud
;
4190 MonoAssemblyName
*candidate_name
= &candidate
->aname
;
4192 g_assert (wanted_name
!= NULL
);
4193 g_assert (candidate_name
!= NULL
);
4195 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
4196 char * s
= mono_stringify_assembly_name (wanted_name
);
4197 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: wanted = %s\n", s
);
4199 s
= mono_stringify_assembly_name (candidate_name
);
4200 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate = %s\n", s
);
4205 /* Wanted name has no token, not strongly named: always matches. */
4206 if (0 == wanted_name
->public_key_token
[0]) {
4207 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: wanted has no token, returning TRUE\n");
4211 /* Candidate name has no token, not strongly named: never matches */
4212 if (0 == candidate_name
->public_key_token
[0]) {
4213 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate has no token, returning FALSE\n");
4217 return exact_sn_match (wanted_name
, candidate_name
) ||
4218 framework_assembly_sn_match (wanted_name
, candidate_name
);
4222 exact_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
)
4224 gboolean result
= mono_assembly_names_equal (wanted_name
, candidate_name
);
4226 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s\n",
4227 result
? "match, returning TRUE" : "don't match, returning FALSE");
4233 framework_assembly_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
)
4235 #ifndef DISABLE_DESKTOP_LOADER
4236 g_assert (wanted_name
!= NULL
);
4237 g_assert (candidate_name
!= NULL
);
4238 const AssemblyVersionMap
*vmap
= (AssemblyVersionMap
*)g_hash_table_lookup (assembly_remapping_table
, wanted_name
->name
);
4240 if (!vmap
->framework_facade_assembly
) {
4241 /* 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. */
4242 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_PUBKEY
);
4243 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");
4246 /* For facades, the name and public key token should
4247 * match, but the version doesn't matter as long as the
4248 * candidate is not older. */
4249 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_VERSION
);
4250 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s (ignoring version)", result
? "match" : "don't match, returning FALSE");
4252 // compare major of candidate and wanted
4253 int c
= assembly_names_compare_versions (candidate_name
, wanted_name
, 1);
4254 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"),
4255 (c
>= 0) ? "TRUE" : "FALSE");
4256 return (c
>= 0); // don't accept a candidate that's older than wanted.
4266 static MonoAssembly
*
4267 mono_assembly_request_byname_nosearch (MonoAssemblyName
*aname
,
4268 const MonoAssemblyByNameRequest
*req
,
4269 MonoImageOpenStatus
*status
)
4271 MonoAssembly
*result
;
4272 MonoAssemblyName maped_aname
;
4273 MonoAssemblyName maped_name_pp
;
4275 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
4277 const gboolean refonly
= req
->request
.asmctx
== MONO_ASMCTX_REFONLY
;
4279 /* Reflection only assemblies don't get assembly binding */
4281 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
4283 result
= mono_assembly_loaded_full (aname
, refonly
);
4287 result
= refonly
? invoke_assembly_refonly_preload_hook (aname
, assemblies_path
) : invoke_assembly_preload_hook (aname
, assemblies_path
);
4289 result
->in_gac
= FALSE
;
4293 return mono_assembly_load_full_gac_base_default (aname
, req
->basedir
, req
->request
.asmctx
, status
);
4296 /* Like mono_assembly_request_byname_nosearch, but don't ask the preload look (ie,
4297 * the appdomain) to run. Just looks in the gac, the specified base dir or the
4298 * default_path. Does NOT look in the appdomain application base or in the
4302 mono_assembly_load_full_gac_base_default (MonoAssemblyName
*aname
,
4303 const char *basedir
,
4304 MonoAssemblyContextKind asmctx
,
4305 MonoImageOpenStatus
*status
)
4307 MonoAssembly
*result
;
4308 char *fullpath
, *filename
;
4313 /* Currently we retrieve the loaded corlib for reflection
4314 * only requests, like a common reflection only assembly
4316 gboolean name_is_corlib
= strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
) == 0;
4317 /* Assembly.Load (new AssemblyName ("mscorlib.dll")) (respectively,
4318 * "System.Private.CoreLib.dll" for netcore) is treated the same as
4319 * "mscorlib" (resp "System.Private.CoreLib"). */
4320 name_is_corlib
= name_is_corlib
|| strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
".dll") == 0;
4321 if (name_is_corlib
) {
4322 return mono_assembly_load_corlib (mono_get_runtime_info (), status
);
4325 MonoAssemblyCandidatePredicate predicate
= NULL
;
4326 void* predicate_ud
= NULL
;
4327 #if !defined(DISABLE_DESKTOP_LOADER)
4328 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
4329 predicate
= &mono_assembly_candidate_predicate_sn_same_name
;
4330 predicate_ud
= aname
;
4334 const gboolean refonly
= asmctx
== MONO_ASMCTX_REFONLY
;
4336 MonoAssemblyOpenRequest req
;
4337 mono_assembly_request_prepare (&req
.request
, sizeof (req
), asmctx
);
4338 req
.request
.predicate
= predicate
;
4339 req
.request
.predicate_ud
= predicate_ud
;
4341 len
= strlen (aname
->name
);
4342 for (ext_index
= 0; ext_index
< 2; ext_index
++) {
4343 ext
= ext_index
== 0 ? ".dll" : ".exe";
4344 if (len
> 4 && (!strcmp (aname
->name
+ len
- 4, ".dll") || !strcmp (aname
->name
+ len
- 4, ".exe"))) {
4345 filename
= g_strdup (aname
->name
);
4346 /* Don't try appending .dll/.exe if it already has one of those extensions */
4349 filename
= g_strconcat (aname
->name
, ext
, NULL
);
4352 result
= mono_assembly_load_from_gac (aname
, filename
, status
, refonly
);
4359 fullpath
= g_build_filename (basedir
, filename
, NULL
);
4360 result
= mono_assembly_request_open (fullpath
, &req
, status
);
4363 result
->in_gac
= FALSE
;
4369 result
= load_in_path (filename
, (const char**) default_path
, &req
, status
);
4371 result
->in_gac
= FALSE
;
4381 mono_assembly_request_byname (MonoAssemblyName
*aname
, const MonoAssemblyByNameRequest
*req
, MonoImageOpenStatus
*status
)
4383 MonoAssembly
*result
= mono_assembly_request_byname_nosearch (aname
, req
, status
);
4384 const gboolean refonly
= req
->request
.asmctx
== MONO_ASMCTX_REFONLY
;
4386 if (!result
&& !req
->no_postload_search
) {
4387 /* Try a postload search hook */
4388 result
= mono_assembly_invoke_search_hook_internal (aname
, req
->requesting_assembly
, refonly
, TRUE
);
4389 result
= prevent_reference_assembly_from_running (result
, refonly
);
4395 * mono_assembly_load_full:
4396 * \param aname A MonoAssemblyName with the assembly name to load.
4397 * \param basedir A directory to look up the assembly at.
4398 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
4399 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
4401 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
4402 * attempts to load the assembly from that directory before probing the standard locations.
4404 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
4405 * assembly binding takes place.
4407 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
4408 * value pointed by \p status is updated with an error code.
4411 mono_assembly_load_full (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
, gboolean refonly
)
4414 MONO_ENTER_GC_UNSAFE
;
4415 MonoAssemblyByNameRequest req
;
4416 mono_assembly_request_prepare (&req
.request
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
4417 req
.requesting_assembly
= NULL
;
4418 req
.basedir
= basedir
;
4419 res
= mono_assembly_request_byname (aname
, &req
, status
);
4420 MONO_EXIT_GC_UNSAFE
;
4425 * mono_assembly_load:
4426 * \param aname A MonoAssemblyName with the assembly name to load.
4427 * \param basedir A directory to look up the assembly at.
4428 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
4430 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
4431 * attempts to load the assembly from that directory before probing the standard locations.
4433 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
4434 * value pointed by \p status is updated with an error code.
4437 mono_assembly_load (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
)
4439 MonoAssemblyByNameRequest req
;
4440 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
4441 req
.requesting_assembly
= NULL
;
4442 req
.basedir
= basedir
;
4443 return mono_assembly_request_byname (aname
, &req
, status
);
4447 * mono_assembly_loaded_full:
4448 * \param aname an assembly to look for.
4449 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
4451 * This is used to determine if the specified assembly has been loaded
4452 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
4453 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
4456 mono_assembly_loaded_full (MonoAssemblyName
*aname
, gboolean refonly
)
4459 MonoAssemblyName maped_aname
;
4461 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
4463 res
= mono_assembly_invoke_search_hook_internal (aname
, NULL
, refonly
, FALSE
);
4469 * mono_assembly_loaded:
4470 * \param aname an assembly to look for.
4472 * This is used to determine if the specified assembly has been loaded
4474 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
4475 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
4478 mono_assembly_loaded (MonoAssemblyName
*aname
)
4481 MONO_ENTER_GC_UNSAFE
;
4482 res
= mono_assembly_loaded_full (aname
, FALSE
);
4483 MONO_EXIT_GC_UNSAFE
;
4488 mono_assembly_release_gc_roots (MonoAssembly
*assembly
)
4490 if (assembly
== NULL
|| assembly
== REFERENCE_MISSING
)
4493 if (assembly_is_dynamic (assembly
)) {
4495 MonoDynamicImage
*dynimg
= (MonoDynamicImage
*)assembly
->image
;
4496 for (i
= 0; i
< dynimg
->image
.module_count
; ++i
)
4497 mono_dynamic_image_release_gc_roots ((MonoDynamicImage
*)dynimg
->image
.modules
[i
]);
4498 mono_dynamic_image_release_gc_roots (dynimg
);
4503 * Returns whether mono_assembly_close_finish() must be called as
4504 * well. See comment for mono_image_close_except_pools() for why we
4505 * unload in two steps.
4508 mono_assembly_close_except_image_pools (MonoAssembly
*assembly
)
4511 g_return_val_if_fail (assembly
!= NULL
, FALSE
);
4513 if (assembly
== REFERENCE_MISSING
)
4516 /* Might be 0 already */
4517 if (mono_atomic_dec_i32 (&assembly
->ref_count
) > 0)
4520 MONO_PROFILER_RAISE (assembly_unloading
, (assembly
));
4522 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Unloading assembly %s [%p].", assembly
->aname
.name
, assembly
);
4524 mono_debug_close_image (assembly
->image
);
4526 mono_assemblies_lock ();
4527 loaded_assemblies
= g_list_remove (loaded_assemblies
, assembly
);
4528 mono_assemblies_unlock ();
4530 assembly
->image
->assembly
= NULL
;
4532 if (!mono_image_close_except_pools (assembly
->image
))
4533 assembly
->image
= NULL
;
4535 for (tmp
= assembly
->friend_assembly_names
; tmp
; tmp
= tmp
->next
) {
4536 MonoAssemblyName
*fname
= (MonoAssemblyName
*)tmp
->data
;
4537 mono_assembly_name_free (fname
);
4540 g_slist_free (assembly
->friend_assembly_names
);
4541 g_free (assembly
->basedir
);
4543 MONO_PROFILER_RAISE (assembly_unloaded
, (assembly
));
4549 mono_assembly_close_finish (MonoAssembly
*assembly
)
4551 g_assert (assembly
&& assembly
!= REFERENCE_MISSING
);
4553 if (assembly
->image
)
4554 mono_image_close_finish (assembly
->image
);
4556 if (assembly_is_dynamic (assembly
)) {
4557 g_free ((char*)assembly
->aname
.culture
);
4564 * mono_assembly_close:
4565 * \param assembly the assembly to release.
4567 * This method releases a reference to the \p assembly. The assembly is
4568 * only released when all the outstanding references to it are released.
4571 mono_assembly_close (MonoAssembly
*assembly
)
4573 if (mono_assembly_close_except_image_pools (assembly
))
4574 mono_assembly_close_finish (assembly
);
4578 * mono_assembly_load_module:
4581 mono_assembly_load_module (MonoAssembly
*assembly
, guint32 idx
)
4584 MonoImage
*result
= mono_assembly_load_module_checked (assembly
, idx
, error
);
4585 mono_error_assert_ok (error
);
4590 mono_assembly_load_module_checked (MonoAssembly
*assembly
, uint32_t idx
, MonoError
*error
)
4592 return mono_image_load_file_for_image_checked (assembly
->image
, idx
, error
);
4597 * mono_assembly_foreach:
4598 * \param func function to invoke for each assembly loaded
4599 * \param user_data data passed to the callback
4601 * Invokes the provided \p func callback for each assembly loaded into
4602 * the runtime. The first parameter passed to the callback is the
4603 * \c MonoAssembly*, and the second parameter is the \p user_data.
4605 * This is done for all assemblies loaded in the runtime, not just
4606 * those loaded in the current application domain.
4609 mono_assembly_foreach (GFunc func
, gpointer user_data
)
4614 * We make a copy of the list to avoid calling the callback inside the
4615 * lock, which could lead to deadlocks.
4617 mono_assemblies_lock ();
4618 copy
= g_list_copy (loaded_assemblies
);
4619 mono_assemblies_unlock ();
4621 g_list_foreach (loaded_assemblies
, func
, user_data
);
4627 * mono_assemblies_cleanup:
4629 * Free all resources used by this module.
4632 mono_assemblies_cleanup (void)
4636 mono_os_mutex_destroy (&assemblies_mutex
);
4637 mono_os_mutex_destroy (&assembly_binding_mutex
);
4639 for (l
= loaded_assembly_bindings
; l
; l
= l
->next
) {
4640 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)l
->data
;
4642 mono_assembly_binding_info_free (info
);
4645 g_slist_free (loaded_assembly_bindings
);
4647 free_assembly_asmctx_from_path_hooks ();
4648 free_assembly_load_hooks ();
4649 free_assembly_search_hooks ();
4650 free_assembly_preload_hooks ();
4653 /*LOCKING takes the assembly_binding lock*/
4655 mono_assembly_cleanup_domain_bindings (guint32 domain_id
)
4659 mono_assembly_binding_lock ();
4660 iter
= &loaded_assembly_bindings
;
4663 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)l
->data
;
4665 if (info
->domain_id
== domain_id
) {
4667 mono_assembly_binding_info_free (info
);
4674 mono_assembly_binding_unlock ();
4678 * Holds the assembly of the application, for
4679 * System.Diagnostics.Process::MainModule
4681 static MonoAssembly
*main_assembly
=NULL
;
4684 * mono_assembly_set_main:
4687 mono_assembly_set_main (MonoAssembly
*assembly
)
4689 main_assembly
= assembly
;
4693 * mono_assembly_get_main:
4695 * Returns: the assembly for the application, the first assembly that is loaded by the VM
4698 mono_assembly_get_main (void)
4700 return (main_assembly
);
4704 * mono_assembly_get_image:
4705 * \param assembly The assembly to retrieve the image from
4707 * \returns the \c MonoImage associated with this assembly.
4710 mono_assembly_get_image (MonoAssembly
*assembly
)
4713 MONO_ENTER_GC_UNSAFE
;
4714 res
= mono_assembly_get_image_internal (assembly
);
4715 MONO_EXIT_GC_UNSAFE
;
4720 mono_assembly_get_image_internal (MonoAssembly
*assembly
)
4722 MONO_REQ_GC_UNSAFE_MODE
;
4723 return assembly
->image
;
4727 * mono_assembly_get_name:
4728 * \param assembly The assembly to retrieve the name from
4730 * The returned name's lifetime is the same as \p assembly's.
4732 * \returns the \c MonoAssemblyName associated with this assembly.
4735 mono_assembly_get_name (MonoAssembly
*assembly
)
4737 MonoAssemblyName
*res
;
4738 MONO_ENTER_GC_UNSAFE
;
4739 res
= mono_assembly_get_name_internal (assembly
);
4740 MONO_EXIT_GC_UNSAFE
;
4745 mono_assembly_get_name_internal (MonoAssembly
*assembly
)
4747 MONO_REQ_GC_UNSAFE_MODE
;
4748 return &assembly
->aname
;
4752 * mono_register_bundled_assemblies:
4755 mono_register_bundled_assemblies (const MonoBundledAssembly
**assemblies
)
4757 bundles
= assemblies
;
4760 #define MONO_DECLSEC_FORMAT_10 0x3C
4761 #define MONO_DECLSEC_FORMAT_20 0x2E
4762 #define MONO_DECLSEC_FIELD 0x53
4763 #define MONO_DECLSEC_PROPERTY 0x54
4765 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4766 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4767 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4768 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4769 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4772 mono_assembly_try_decode_skip_verification_param (const char *p
, const char **resp
, gboolean
*abort_decoding
)
4776 case MONO_DECLSEC_PROPERTY
:
4778 case MONO_DECLSEC_FIELD
:
4780 *abort_decoding
= TRUE
;
4785 if (*p
++ != MONO_TYPE_BOOLEAN
) {
4786 *abort_decoding
= TRUE
;
4790 /* property name length */
4791 len
= mono_metadata_decode_value (p
, &p
);
4793 if (len
>= SKIP_VISIBILITY_PROPERTY_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_PROPERTY_NAME
, SKIP_VISIBILITY_PROPERTY_SIZE
)) {
4804 mono_assembly_try_decode_skip_verification (const char *p
, const char *endn
)
4806 int i
, j
, num
, len
, params_len
;
4808 if (*p
== MONO_DECLSEC_FORMAT_10
) {
4809 gsize read
, written
;
4810 char *res
= g_convert (p
, endn
- p
, "UTF-8", "UTF-16LE", &read
, &written
, NULL
);
4812 gboolean found
= strstr (res
, SKIP_VISIBILITY_XML_ATTRIBUTE
) != NULL
;
4818 if (*p
++ != MONO_DECLSEC_FORMAT_20
)
4821 /* number of encoded permission attributes */
4822 num
= mono_metadata_decode_value (p
, &p
);
4823 for (i
= 0; i
< num
; ++i
) {
4824 gboolean is_valid
= FALSE
;
4825 gboolean abort_decoding
= FALSE
;
4827 /* attribute name length */
4828 len
= mono_metadata_decode_value (p
, &p
);
4830 /* We don't really need to fully decode the type. Comparing the name is enough */
4831 is_valid
= len
>= SKIP_VISIBILITY_ATTRIBUTE_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_ATTRIBUTE_NAME
, SKIP_VISIBILITY_ATTRIBUTE_SIZE
);
4835 /*size of the params table*/
4836 params_len
= mono_metadata_decode_value (p
, &p
);
4838 const char *params_end
= p
+ params_len
;
4840 /* number of parameters */
4841 len
= mono_metadata_decode_value (p
, &p
);
4843 for (j
= 0; j
< len
; ++j
) {
4844 if (mono_assembly_try_decode_skip_verification_param (p
, &p
, &abort_decoding
))
4860 mono_assembly_has_skip_verification (MonoAssembly
*assembly
)
4863 guint32 cols
[MONO_DECL_SECURITY_SIZE
];
4867 if (MONO_SECMAN_FLAG_INIT (assembly
->skipverification
))
4868 return MONO_SECMAN_FLAG_GET_VALUE (assembly
->skipverification
);
4870 t
= &assembly
->image
->tables
[MONO_TABLE_DECLSECURITY
];
4872 for (i
= 0; i
< t
->rows
; ++i
) {
4873 mono_metadata_decode_row (t
, i
, cols
, MONO_DECL_SECURITY_SIZE
);
4874 if ((cols
[MONO_DECL_SECURITY_PARENT
] & MONO_HAS_DECL_SECURITY_MASK
) != MONO_HAS_DECL_SECURITY_ASSEMBLY
)
4876 if (cols
[MONO_DECL_SECURITY_ACTION
] != SECURITY_ACTION_REQMIN
)
4879 blob
= mono_metadata_blob_heap (assembly
->image
, cols
[MONO_DECL_SECURITY_PERMISSIONSET
]);
4880 len
= mono_metadata_decode_blob_size (blob
, &blob
);
4884 if (mono_assembly_try_decode_skip_verification (blob
, blob
+ len
)) {
4885 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, TRUE
);
4890 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, FALSE
);
4894 MonoAssemblyContextKind
4895 mono_asmctx_get_kind (const MonoAssemblyContext
*ctx
)
4901 mono_asmctx_get_name (const MonoAssemblyContext
*asmctx
)
4903 static const char* names
[] = {
4909 g_assert (asmctx
->kind
>= 0 && asmctx
->kind
<= MONO_ASMCTX_LAST
);
4910 return names
[asmctx
->kind
];