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/exception-internals.h>
32 #include <mono/metadata/reflection-internals.h>
33 #include <mono/metadata/mono-endian.h>
34 #include <mono/metadata/mono-debug.h>
35 #include <mono/utils/mono-uri.h>
36 #include <mono/metadata/mono-config.h>
37 #include <mono/metadata/mono-config-internals.h>
38 #include <mono/metadata/mono-config-dirs.h>
39 #include <mono/utils/mono-digest.h>
40 #include <mono/utils/mono-logger-internals.h>
41 #include <mono/utils/mono-path.h>
42 #include <mono/metadata/reflection.h>
43 #include <mono/metadata/coree.h>
44 #include <mono/metadata/cil-coff.h>
45 #include <mono/utils/mono-io-portability.h>
46 #include <mono/utils/atomic.h>
47 #include <mono/utils/mono-os-mutex.h>
50 #include <sys/types.h>
56 #include <mach-o/dyld.h>
59 /* 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 */
61 const char* assembly_name
;
62 guint8 version_set_index
;
63 const char* new_assembly_name
;
64 gboolean only_lower_versions
;
65 gboolean framework_facade_assembly
;
68 /* the default search path is empty, the first slot is replaced with the computed value */
76 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
77 static char **assemblies_path
= NULL
;
80 /* Contains the list of directories that point to auxiliary GACs */
81 static char **extra_gac_paths
= NULL
;
84 #ifndef DISABLE_DESKTOP_LOADER
86 #define FACADE_ASSEMBLY(str) {str, 0, NULL, FALSE, TRUE}
88 static GHashTable
* assembly_remapping_table
;
89 /* The list of system assemblies what will be remapped to the running
91 * This list is stored in @assembly_remapping_table during initialization.
92 * Keep it sorted just to make maintenance easier.
94 * The integer number is an index in the MonoRuntimeInfo structure, whose
95 * values can be found in domain.c - supported_runtimes. Look there
96 * to understand what remapping will be made.
98 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
101 static const AssemblyVersionMap framework_assemblies
[] = {
102 {"Accessibility", 0},
103 {"Commons.Xml.Relaxng", 0},
104 {"CustomMarshalers", 0},
111 {"Microsoft.Build.Engine", 2, NULL
, TRUE
},
112 {"Microsoft.Build.Framework", 2, NULL
, TRUE
},
113 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
114 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
115 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
116 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
117 {"Microsoft.CSharp", 0},
118 {"Microsoft.VisualBasic", 1},
119 {"Microsoft.VisualC", 1},
120 FACADE_ASSEMBLY ("Microsoft.Win32.Primitives"),
121 FACADE_ASSEMBLY ("Microsoft.Win32.Registry"),
122 FACADE_ASSEMBLY ("Microsoft.Win32.Registry.AccessControl"),
124 {"Mono.CompilerServices.SymbolWriter", 0},
126 {"Mono.Data.SybaseClient", 0},
127 {"Mono.Data.Tds", 0},
128 {"Mono.Data.TdsClient", 0},
129 {"Mono.GetOptions", 0},
132 {"Mono.Security", 0},
133 {"Mono.Security.Win32", 0},
135 {"Novell.Directory.Ldap", 0},
138 FACADE_ASSEMBLY ("System.AppContext"),
139 FACADE_ASSEMBLY ("System.Buffers"),
140 FACADE_ASSEMBLY ("System.Collections"),
141 FACADE_ASSEMBLY ("System.Collections.Concurrent"),
142 FACADE_ASSEMBLY ("System.Collections.NonGeneric"),
143 FACADE_ASSEMBLY ("System.Collections.Specialized"),
144 FACADE_ASSEMBLY ("System.ComponentModel"),
145 FACADE_ASSEMBLY ("System.ComponentModel.Annotations"),
146 {"System.ComponentModel.Composition", 2},
147 {"System.ComponentModel.DataAnnotations", 2},
148 FACADE_ASSEMBLY ("System.ComponentModel.EventBasedAsync"),
149 FACADE_ASSEMBLY ("System.ComponentModel.Primitives"),
150 FACADE_ASSEMBLY ("System.ComponentModel.TypeConverter"),
151 {"System.Configuration", 0},
152 {"System.Configuration.Install", 0},
153 FACADE_ASSEMBLY ("System.Console"),
156 FACADE_ASSEMBLY ("System.Data.Common"),
157 {"System.Data.DataSetExtensions", 0},
158 {"System.Data.Entity", 0},
159 {"System.Data.Linq", 2},
160 {"System.Data.OracleClient", 0},
161 {"System.Data.Services", 2},
162 {"System.Data.Services.Client", 2},
163 FACADE_ASSEMBLY ("System.Data.SqlClient"),
164 {"System.Data.SqlXml", 0},
165 {"System.Deployment", 0},
166 {"System.Design", 0},
167 FACADE_ASSEMBLY ("System.Diagnostics.Contracts"),
168 FACADE_ASSEMBLY ("System.Diagnostics.Debug"),
169 FACADE_ASSEMBLY ("System.Diagnostics.FileVersionInfo"),
170 FACADE_ASSEMBLY ("System.Diagnostics.Process"),
171 FACADE_ASSEMBLY ("System.Diagnostics.StackTrace"),
172 FACADE_ASSEMBLY ("System.Diagnostics.TextWriterTraceListener"),
173 FACADE_ASSEMBLY ("System.Diagnostics.Tools"),
174 FACADE_ASSEMBLY ("System.Diagnostics.TraceEvent"),
175 FACADE_ASSEMBLY ("System.Diagnostics.TraceSource"),
176 FACADE_ASSEMBLY ("System.Diagnostics.Tracing"),
177 {"System.DirectoryServices", 0},
178 {"System.DirectoryServices.Protocols", 0},
179 {"System.Drawing", 0},
180 FACADE_ASSEMBLY ("System.Drawing.Common"),
181 {"System.Drawing.Design", 0},
182 FACADE_ASSEMBLY ("System.Drawing.Primitives"),
183 {"System.Dynamic", 0},
184 FACADE_ASSEMBLY ("System.Dynamic.Runtime"),
185 {"System.EnterpriseServices", 0},
186 FACADE_ASSEMBLY ("System.Globalization"),
187 FACADE_ASSEMBLY ("System.Globalization.Calendars"),
188 FACADE_ASSEMBLY ("System.Globalization.Extensions"),
189 {"System.IdentityModel", 3},
190 {"System.IdentityModel.Selectors", 3},
191 FACADE_ASSEMBLY ("System.IO"),
192 {"System.IO.Compression", 2},
193 {"System.IO.Compression.FileSystem", 0},
194 FACADE_ASSEMBLY ("System.IO.Compression.ZipFile"),
195 FACADE_ASSEMBLY ("System.IO.FileSystem"),
196 FACADE_ASSEMBLY ("System.IO.FileSystem.AccessControl"),
197 FACADE_ASSEMBLY ("System.IO.FileSystem.DriveInfo"),
198 FACADE_ASSEMBLY ("System.IO.FileSystem.Primitives"),
199 FACADE_ASSEMBLY ("System.IO.FileSystem.Watcher"),
200 FACADE_ASSEMBLY ("System.IO.IsolatedStorage"),
201 FACADE_ASSEMBLY ("System.IO.MemoryMappedFiles"),
202 FACADE_ASSEMBLY ("System.IO.Packaging"),
203 FACADE_ASSEMBLY ("System.IO.Pipes"),
204 FACADE_ASSEMBLY ("System.IO.UnmanagedMemoryStream"),
205 FACADE_ASSEMBLY ("System.Linq"),
206 FACADE_ASSEMBLY ("System.Linq.Expressions"),
207 FACADE_ASSEMBLY ("System.Linq.Parallel"),
208 FACADE_ASSEMBLY ("System.Linq.Queryable"),
209 {"System.Management", 0},
210 FACADE_ASSEMBLY ("System.Memory"),
211 {"System.Messaging", 0},
213 FACADE_ASSEMBLY ("System.Net.AuthenticationManager"),
214 FACADE_ASSEMBLY ("System.Net.Cache"),
215 {"System.Net.Http", 4},
216 {"System.Net.Http.Rtc", 0},
217 {"System.Net.Http.WebRequest", 0},
218 FACADE_ASSEMBLY ("System.Net.HttpListener"),
219 FACADE_ASSEMBLY ("System.Net.Mail"),
220 FACADE_ASSEMBLY ("System.Net.NameResolution"),
221 FACADE_ASSEMBLY ("System.Net.NetworkInformation"),
222 FACADE_ASSEMBLY ("System.Net.Ping"),
223 FACADE_ASSEMBLY ("System.Net.Primitives"),
224 FACADE_ASSEMBLY ("System.Net.Requests"),
225 FACADE_ASSEMBLY ("System.Net.Security"),
226 FACADE_ASSEMBLY ("System.Net.ServicePoint"),
227 FACADE_ASSEMBLY ("System.Net.Sockets"),
228 FACADE_ASSEMBLY ("System.Net.Utilities"),
229 FACADE_ASSEMBLY ("System.Net.WebHeaderCollection"),
230 FACADE_ASSEMBLY ("System.Net.WebSockets"),
231 FACADE_ASSEMBLY ("System.Net.WebSockets.Client"),
232 {"System.Numerics", 3},
233 {"System.Numerics.Vectors", 3},
234 FACADE_ASSEMBLY ("System.ObjectModel"),
235 FACADE_ASSEMBLY ("System.Reflection"),
236 {"System.Reflection.Context", 0},
237 FACADE_ASSEMBLY ("System.Reflection.DispatchProxy"),
238 FACADE_ASSEMBLY ("System.Reflection.Emit"),
239 FACADE_ASSEMBLY ("System.Reflection.Emit.ILGeneration"),
240 FACADE_ASSEMBLY ("System.Reflection.Emit.Lightweight"),
241 FACADE_ASSEMBLY ("System.Reflection.Extensions"),
242 FACADE_ASSEMBLY ("System.Reflection.Primitives"),
243 FACADE_ASSEMBLY ("System.Reflection.TypeExtensions"),
244 FACADE_ASSEMBLY ("System.Resources.Reader"),
245 FACADE_ASSEMBLY ("System.Resources.ReaderWriter"),
246 FACADE_ASSEMBLY ("System.Resources.ResourceManager"),
247 FACADE_ASSEMBLY ("System.Resources.Writer"),
248 FACADE_ASSEMBLY ("System.Runtime"),
249 {"System.Runtime.Caching", 0},
250 FACADE_ASSEMBLY ("System.Runtime.CompilerServices.VisualC"),
251 {"System.Runtime.DurableInstancing", 0},
252 FACADE_ASSEMBLY ("System.Runtime.Extensions"),
253 FACADE_ASSEMBLY ("System.Runtime.Handles"),
254 FACADE_ASSEMBLY ("System.Runtime.InteropServices"),
255 FACADE_ASSEMBLY ("System.Runtime.InteropServices.RuntimeInformation"),
256 FACADE_ASSEMBLY ("System.Runtime.InteropServices.WindowsRuntime"),
257 FACADE_ASSEMBLY ("System.Runtime.Loader"),
258 FACADE_ASSEMBLY ("System.Runtime.Numerics"),
259 {"System.Runtime.Remoting", 0},
260 {"System.Runtime.Serialization", 3},
261 FACADE_ASSEMBLY ("System.Runtime.Serialization.Formatters"),
262 {"System.Runtime.Serialization.Formatters.Soap", 0},
263 FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"),
264 FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"),
265 FACADE_ASSEMBLY ("System.Runtime.Serialization.Xml"),
266 {"System.Security", 0},
267 FACADE_ASSEMBLY ("System.Security.AccessControl"),
268 FACADE_ASSEMBLY ("System.Security.Claims"),
269 FACADE_ASSEMBLY ("System.Security.Cryptography.Algorithms"),
270 FACADE_ASSEMBLY ("System.Security.Cryptography.Cng"),
271 FACADE_ASSEMBLY ("System.Security.Cryptography.Csp"),
272 FACADE_ASSEMBLY ("System.Security.Cryptography.DeriveBytes"),
273 FACADE_ASSEMBLY ("System.Security.Cryptography.Encoding"),
274 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption"),
275 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Aes"),
276 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDiffieHellman"),
277 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDsa"),
278 FACADE_ASSEMBLY ("System.Security.Cryptography.Hashing"),
279 FACADE_ASSEMBLY ("System.Security.Cryptography.Hashing.Algorithms"),
280 FACADE_ASSEMBLY ("System.Security.Cryptography.OpenSsl"),
281 FACADE_ASSEMBLY ("System.Security.Cryptography.Pkcs"),
282 FACADE_ASSEMBLY ("System.Security.Cryptography.Primitives"),
283 FACADE_ASSEMBLY ("System.Security.Cryptography.ProtectedData"),
284 FACADE_ASSEMBLY ("System.Security.Cryptography.RSA"),
285 FACADE_ASSEMBLY ("System.Security.Cryptography.RandomNumberGenerator"),
286 FACADE_ASSEMBLY ("System.Security.Cryptography.X509Certificates"),
287 FACADE_ASSEMBLY ("System.Security.Principal"),
288 FACADE_ASSEMBLY ("System.Security.Principal.Windows"),
289 FACADE_ASSEMBLY ("System.Security.SecureString"),
290 {"System.ServiceModel", 3},
291 {"System.ServiceModel.Activation", 0},
292 {"System.ServiceModel.Discovery", 0},
293 FACADE_ASSEMBLY ("System.ServiceModel.Duplex"),
294 FACADE_ASSEMBLY ("System.ServiceModel.Http"),
295 FACADE_ASSEMBLY ("System.ServiceModel.NetTcp"),
296 FACADE_ASSEMBLY ("System.ServiceModel.Primitives"),
297 {"System.ServiceModel.Routing", 0},
298 FACADE_ASSEMBLY ("System.ServiceModel.Security"),
299 {"System.ServiceModel.Web", 2},
300 {"System.ServiceProcess", 0},
301 FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"),
302 FACADE_ASSEMBLY ("System.Text.Encoding"),
303 FACADE_ASSEMBLY ("System.Text.Encoding.CodePages"),
304 FACADE_ASSEMBLY ("System.Text.Encoding.Extensions"),
305 FACADE_ASSEMBLY ("System.Text.RegularExpressions"),
306 FACADE_ASSEMBLY ("System.Threading"),
307 FACADE_ASSEMBLY ("System.Threading.AccessControl"),
308 FACADE_ASSEMBLY ("System.Threading.Overlapped"),
309 FACADE_ASSEMBLY ("System.Threading.Tasks"),
310 {"System.Threading.Tasks.Dataflow", 0, NULL
, TRUE
},
311 FACADE_ASSEMBLY ("System.Threading.Tasks.Extensions"),
312 FACADE_ASSEMBLY ("System.Threading.Tasks.Parallel"),
313 FACADE_ASSEMBLY ("System.Threading.Thread"),
314 FACADE_ASSEMBLY ("System.Threading.ThreadPool"),
315 FACADE_ASSEMBLY ("System.Threading.Timer"),
316 {"System.Transactions", 0},
317 FACADE_ASSEMBLY ("System.ValueTuple"),
319 {"System.Web.Abstractions", 2},
320 {"System.Web.ApplicationServices", 0},
321 {"System.Web.DynamicData", 2},
322 {"System.Web.Extensions", 2},
323 {"System.Web.Extensions.Design", 0},
324 {"System.Web.Mobile", 0},
325 {"System.Web.RegularExpressions", 0},
326 {"System.Web.Routing", 2},
327 {"System.Web.Services", 0},
328 {"System.Windows", 0},
329 {"System.Windows.Forms", 0},
330 {"System.Windows.Forms.DataVisualization", 0},
331 {"System.Workflow.Activities", 0},
332 {"System.Workflow.ComponentModel", 0},
333 {"System.Workflow.Runtime", 0},
336 {"System.Xml.Linq", 2},
337 FACADE_ASSEMBLY ("System.Xml.ReaderWriter"),
338 {"System.Xml.Serialization", 0},
339 FACADE_ASSEMBLY ("System.Xml.XDocument"),
340 FACADE_ASSEMBLY ("System.Xml.XPath"),
341 FACADE_ASSEMBLY ("System.Xml.XPath.XmlDocument"),
342 FACADE_ASSEMBLY ("System.Xml.XPath.XDocument"),
343 FACADE_ASSEMBLY ("System.Xml.XmlDocument"),
344 FACADE_ASSEMBLY ("System.Xml.XmlSerializer"),
345 FACADE_ASSEMBLY ("System.Xml.Xsl.Primitives"),
349 FACADE_ASSEMBLY ("netstandard"),
353 /* keeps track of loaded assemblies, excluding dynamic ones */
354 static GList
*loaded_assemblies
= NULL
;
355 static MonoAssembly
*corlib
;
357 static char* unquote (const char *str
);
359 // This protects loaded_assemblies
360 static mono_mutex_t assemblies_mutex
;
363 mono_assemblies_lock ()
365 mono_os_mutex_lock (&assemblies_mutex
);
369 mono_assemblies_unlock ()
371 mono_os_mutex_unlock (&assemblies_mutex
);
374 /* If defined, points to the bundled assembly information */
375 static const MonoBundledAssembly
**bundles
;
377 static mono_mutex_t assembly_binding_mutex
;
379 /* Loaded assembly binding info */
380 static GSList
*loaded_assembly_bindings
= NULL
;
382 /* Class lazy loading functions */
383 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible
, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
385 mono_assembly_invoke_search_hook_internal (MonoAssemblyLoadContext
*alc
, MonoAssembly
*requesting
, MonoAssemblyName
*aname
, gboolean refonly
, gboolean postload
);
387 mono_assembly_request_byname_nosearch (MonoAssemblyName
*aname
, const MonoAssemblyByNameRequest
*req
, MonoImageOpenStatus
*status
);
389 mono_assembly_load_full_gac_base_default (MonoAssemblyName
*aname
, const char *basedir
, MonoAssemblyLoadContext
*alc
, MonoAssemblyContextKind asmctx
, MonoImageOpenStatus
*status
);
391 chain_redirections_loadfrom (MonoAssemblyLoadContext
*alc
, MonoImage
*image
, MonoImageOpenStatus
*out_status
);
393 mono_problematic_image_reprobe (MonoAssemblyLoadContext
*alc
, MonoImage
*image
, MonoImageOpenStatus
*status
);
395 static MonoAssembly
*
396 invoke_assembly_preload_hook (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
, gchar
**apath
);
399 mono_assembly_is_in_gac (const gchar
*filanem
);
400 static MonoAssemblyName
*
401 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
);
404 prevent_reference_assembly_from_running (MonoAssembly
* candidate
, gboolean refonly
);
406 /* Assembly name matching */
408 framework_assembly_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
);
411 mono_asmctx_get_name (const MonoAssemblyContext
*asmctx
);
414 assembly_loadfrom_asmctx_from_path (const char *filename
, MonoAssembly
*requesting_assembly
, gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
);
417 encode_public_tok (const guchar
*token
, gint32 len
)
419 const static gchar allowed
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
423 res
= (gchar
*)g_malloc (len
* 2 + 1);
424 for (i
= 0; i
< len
; i
++) {
425 res
[i
* 2] = allowed
[token
[i
] >> 4];
426 res
[i
* 2 + 1] = allowed
[token
[i
] & 0xF];
433 * mono_public_tokens_are_equal:
434 * \param pubt1 first public key token
435 * \param pubt2 second public key token
437 * Compare two public key tokens and return TRUE is they are equal and FALSE
441 mono_public_tokens_are_equal (const unsigned char *pubt1
, const unsigned char *pubt2
)
443 return g_ascii_strncasecmp ((const char*) pubt1
, (const char*) pubt2
, 16) == 0;
447 * mono_set_assemblies_path:
448 * \param path list of paths that contain directories where Mono will look for assemblies
450 * Use this method to override the standard assembly lookup system and
451 * override any assemblies coming from the GAC. This is the method
452 * that supports the \c MONO_PATH variable.
454 * Notice that \c MONO_PATH and this method are really a very bad idea as
455 * it prevents the GAC from working and it prevents the standard
456 * resolution mechanisms from working. Nonetheless, for some debugging
457 * situations and bootstrapping setups, this is useful to have.
460 mono_set_assemblies_path (const char* path
)
462 char **splitted
, **dest
;
464 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
466 g_strfreev (assemblies_path
);
467 assemblies_path
= dest
= splitted
;
469 char *tmp
= *splitted
;
471 *dest
++ = mono_path_canonicalize (tmp
);
477 if (g_hasenv ("MONO_DEBUG"))
480 splitted
= assemblies_path
;
482 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
483 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted
);
490 mono_set_assemblies_path_direct (char **path
)
492 g_strfreev (assemblies_path
);
493 assemblies_path
= path
;
497 check_path_env (void)
499 if (assemblies_path
!= NULL
)
502 char* path
= g_getenv ("MONO_PATH");
506 mono_set_assemblies_path(path
);
512 check_extra_gac_path_env (void)
515 char **splitted
, **dest
;
517 path
= g_getenv ("MONO_GAC_PREFIX");
521 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
525 g_strfreev (extra_gac_paths
);
526 extra_gac_paths
= dest
= splitted
;
534 if (!g_hasenv ("MONO_DEBUG"))
538 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
539 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted
);
544 #endif /* DISABLE_GAC */
547 assembly_binding_maps_name (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
549 if (!info
|| !info
->name
)
552 if (strcmp (info
->name
, aname
->name
))
555 if (info
->major
!= aname
->major
|| info
->minor
!= aname
->minor
)
558 if ((info
->culture
!= NULL
&& info
->culture
[0]) != (aname
->culture
!= NULL
&& aname
->culture
[0]))
561 if (info
->culture
&& aname
->culture
&& strcmp (info
->culture
, aname
->culture
))
564 if (!mono_public_tokens_are_equal (info
->public_key_token
, aname
->public_key_token
))
571 mono_assembly_binding_info_free (MonoAssemblyBindingInfo
*info
)
577 g_free (info
->culture
);
581 get_publisher_policy_info (MonoImage
*image
, MonoAssemblyName
*aname
, MonoAssemblyBindingInfo
*binding_info
)
584 guint32 cols
[MONO_MANIFEST_SIZE
];
585 const gchar
*filename
;
586 gchar
*subpath
, *fullpath
;
588 t
= &image
->tables
[MONO_TABLE_MANIFESTRESOURCE
];
589 /* MS Impl. accepts policy assemblies with more than
590 * one manifest resource, and only takes the first one */
592 binding_info
->is_valid
= FALSE
;
596 mono_metadata_decode_row (t
, 0, cols
, MONO_MANIFEST_SIZE
);
597 if ((cols
[MONO_MANIFEST_IMPLEMENTATION
] & MONO_IMPLEMENTATION_MASK
) != MONO_IMPLEMENTATION_FILE
) {
598 binding_info
->is_valid
= FALSE
;
602 filename
= mono_metadata_string_heap (image
, cols
[MONO_MANIFEST_NAME
]);
603 g_assert (filename
!= NULL
);
605 subpath
= g_path_get_dirname (image
->name
);
606 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, subpath
, filename
, (const char*)NULL
);
607 mono_config_parse_publisher_policy (fullpath
, binding_info
);
611 /* Define the optional elements/attributes before checking */
612 if (!binding_info
->culture
)
613 binding_info
->culture
= g_strdup ("");
615 /* Check that the most important elements/attributes exist */
616 if (!binding_info
->name
|| !binding_info
->public_key_token
[0] || !binding_info
->has_old_version_bottom
||
617 !binding_info
->has_new_version
|| !assembly_binding_maps_name (binding_info
, aname
)) {
618 mono_assembly_binding_info_free (binding_info
);
619 binding_info
->is_valid
= FALSE
;
623 binding_info
->is_valid
= TRUE
;
627 compare_versions (AssemblyVersionSet
*v
, MonoAssemblyName
*aname
)
629 if (v
->major
> aname
->major
)
631 else if (v
->major
< aname
->major
)
634 if (v
->minor
> aname
->minor
)
636 else if (v
->minor
< aname
->minor
)
639 if (v
->build
> aname
->build
)
641 else if (v
->build
< aname
->build
)
644 if (v
->revision
> aname
->revision
)
646 else if (v
->revision
< aname
->revision
)
653 check_policy_versions (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*name
)
658 /* If has_old_version_top doesn't exist, we don't have an interval */
659 if (!info
->has_old_version_top
) {
660 if (compare_versions (&info
->old_version_bottom
, name
) == 0)
666 /* Check that the version defined by name is valid for the interval */
667 if (compare_versions (&info
->old_version_top
, name
) < 0)
670 /* We should be greater or equal than the small version */
671 if (compare_versions (&info
->old_version_bottom
, name
) > 0)
678 * mono_assembly_names_equal:
679 * \param l first assembly
680 * \param r second assembly.
682 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
684 * This compares the names, the cultures, the release version and their
687 * \returns TRUE if both assembly names are equal.
690 mono_assembly_names_equal (MonoAssemblyName
*l
, MonoAssemblyName
*r
)
692 return mono_assembly_names_equal_flags (l
, r
, MONO_ANAME_EQ_NONE
);
696 * mono_assembly_names_equal_flags:
697 * \param l first assembly name
698 * \param r second assembly name
699 * \param flags flags that affect what is compared.
701 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
703 * This compares the simple names and cultures and optionally the versions and
704 * public key tokens, depending on the \c flags.
706 * \returns TRUE if both assembly names are equal.
709 mono_assembly_names_equal_flags (MonoAssemblyName
*l
, MonoAssemblyName
*r
, MonoAssemblyNameEqFlags flags
)
711 g_assert (l
!= NULL
);
712 g_assert (r
!= NULL
);
714 if (!l
->name
|| !r
->name
)
717 if ((flags
& MONO_ANAME_EQ_IGNORE_CASE
) != 0 && g_strcasecmp (l
->name
, r
->name
))
720 if ((flags
& MONO_ANAME_EQ_IGNORE_CASE
) == 0 && strcmp (l
->name
, r
->name
))
723 if (l
->culture
&& r
->culture
&& strcmp (l
->culture
, r
->culture
))
726 if ((l
->major
!= r
->major
|| l
->minor
!= r
->minor
||
727 l
->build
!= r
->build
|| l
->revision
!= r
->revision
) &&
728 (flags
& MONO_ANAME_EQ_IGNORE_VERSION
) == 0)
729 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)))
732 if (!l
->public_key_token
[0] || !r
->public_key_token
[0] || (flags
& MONO_ANAME_EQ_IGNORE_PUBKEY
) != 0)
735 if (!mono_public_tokens_are_equal (l
->public_key_token
, r
->public_key_token
))
742 * assembly_names_compare_versions:
743 * \param l left assembly name
744 * \param r right assembly name
745 * \param maxcomps how many version components to compare, or -1 to compare all.
747 * \returns a negative if \p l is a lower version than \p r; a positive value
748 * if \p r is a lower version than \p l, or zero if \p l and \p r are equal
749 * versions (comparing upto \p maxcomps components).
751 * Components are \c major, \c minor, \c revision, and \c build. \p maxcomps 1 means just compare
752 * majors. 2 means majors then minors. etc.
755 assembly_names_compare_versions (MonoAssemblyName
*l
, MonoAssemblyName
*r
, int maxcomps
)
758 if (maxcomps
< 0) maxcomps
= 4;
759 #define CMP(field) do { \
760 if (l-> field < r-> field && i < maxcomps) return -1; \
761 if (l-> field > r-> field && i < maxcomps) return 1; \
775 * mono_assembly_request_prepare_load:
776 * \param req the load request to be initialized
777 * \param asmctx the assembly load context kind
778 * \param alc the AssemblyLoadContext in netcore
780 * Initialize an assembly loader request. Its state will be reset and the assembly context kind will be prefilled with \p asmctx.
783 mono_assembly_request_prepare_load (MonoAssemblyLoadRequest
*req
, MonoAssemblyContextKind asmctx
, MonoAssemblyLoadContext
*alc
)
785 memset (req
, 0, sizeof (MonoAssemblyLoadRequest
));
786 req
->asmctx
= asmctx
;
791 * mono_assembly_request_prepare_open:
792 * \param req the open request to be initialized
793 * \param asmctx the assembly load context kind
794 * \param alc the AssemblyLoadContext in netcore
796 * Initialize an assembly loader request intended to be used for open operations. Its state will be reset and the assembly context kind will be prefilled with \p asmctx.
799 mono_assembly_request_prepare_open (MonoAssemblyOpenRequest
*req
, MonoAssemblyContextKind asmctx
, MonoAssemblyLoadContext
*alc
)
801 memset (req
, 0, sizeof (MonoAssemblyOpenRequest
));
802 req
->request
.asmctx
= asmctx
;
803 req
->request
.alc
= alc
;
807 * mono_assembly_request_prepare_byname:
808 * \param req the byname request to be initialized
809 * \param asmctx the assembly load context kind
810 * \param alc the AssemblyLoadContext in netcore
812 * Initialize an assembly load by name request. Its state will be reset and the assembly context kind will be prefilled with \p asmctx.
815 mono_assembly_request_prepare_byname (MonoAssemblyByNameRequest
*req
, MonoAssemblyContextKind asmctx
, MonoAssemblyLoadContext
*alc
)
817 memset (req
, 0, sizeof (MonoAssemblyByNameRequest
));
818 req
->request
.asmctx
= asmctx
;
819 req
->request
.alc
= alc
;
822 static MonoAssembly
*
823 load_in_path (const char *basename
, const char** search_path
, const MonoAssemblyOpenRequest
*req
, MonoImageOpenStatus
*status
)
827 MonoAssembly
*result
;
829 for (i
= 0; search_path
[i
]; ++i
) {
830 fullpath
= g_build_filename (search_path
[i
], basename
, (const char*)NULL
);
831 result
= mono_assembly_request_open (fullpath
, req
, status
);
840 * mono_assembly_setrootdir:
841 * \param root_dir The pathname of the root directory where we will locate assemblies
843 * This routine sets the internal default root directory for looking up
846 * This is used by Windows installations to compute dynamically the
847 * place where the Mono assemblies are located.
851 mono_assembly_setrootdir (const char *root_dir
)
854 * Override the MONO_ASSEMBLIES directory configured at compile time.
856 if (default_path
[0])
857 g_free (default_path
[0]);
858 default_path
[0] = g_strdup (root_dir
);
862 * mono_assembly_getrootdir:
864 * Obtains the root directory used for looking up assemblies.
866 * Returns: a string with the directory, this string should not be freed.
868 G_CONST_RETURN gchar
*
869 mono_assembly_getrootdir (void)
871 return default_path
[0];
875 * mono_native_getrootdir:
877 * Obtains the root directory used for looking up native libs (.so, .dylib).
879 * Returns: a string with the directory, this string should be freed by
883 mono_native_getrootdir (void)
885 gchar
* fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), (const char*)NULL
);
891 * \param assembly_dir the base directory for assemblies
892 * \param config_dir the base directory for configuration files
894 * This routine is used internally and by developers embedding
895 * the runtime into their own applications.
897 * There are a number of cases to consider: Mono as a system-installed
898 * package that is available on the location preconfigured or Mono in
899 * a relocated location.
901 * If you are using a system-installed Mono, you can pass NULL
902 * to both parameters. If you are not, you should compute both
903 * directory values and call this routine.
905 * The values for a given PREFIX are:
907 * assembly_dir: PREFIX/lib
908 * config_dir: PREFIX/etc
910 * Notice that embedders that use Mono in a relocated way must
911 * compute the location at runtime, as they will be in control
912 * of where Mono is installed.
915 mono_set_dirs (const char *assembly_dir
, const char *config_dir
)
917 if (assembly_dir
== NULL
)
918 assembly_dir
= mono_config_get_assemblies_dir ();
919 if (config_dir
== NULL
)
920 config_dir
= mono_config_get_cfg_dir ();
921 mono_assembly_setrootdir (assembly_dir
);
922 mono_set_config_dir (config_dir
);
928 compute_base (char *path
)
930 char *p
= strrchr (path
, '/');
934 /* Not a well known Mono executable, we are embedded, cant guess the base */
935 if (strcmp (p
, "/mono") && strcmp (p
, "/mono-boehm") && strcmp (p
, "/mono-sgen") && strcmp (p
, "/pedump") && strcmp (p
, "/monodis"))
939 p
= strrchr (path
, '/');
943 if (strcmp (p
, "/bin") != 0)
952 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
955 static G_GNUC_UNUSED
void
959 char *config
, *lib
, *mono
;
964 * Only /usr prefix is treated specially
966 bindir
= mono_config_get_bin_dir ();
968 if (strncmp (exe
, bindir
, strlen (bindir
)) == 0 || (base
= compute_base (exe
)) == NULL
){
973 config
= g_build_filename (base
, "etc", (const char*)NULL
);
974 lib
= g_build_filename (base
, "lib", (const char*)NULL
);
975 mono
= g_build_filename (lib
, "mono/4.5", (const char*)NULL
); // FIXME: stop hardcoding 4.5 here
976 if (stat (mono
, &buf
) == -1)
979 mono_set_dirs (lib
, config
);
987 #endif /* HOST_WIN32 */
992 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
993 * this auto-detects the prefix where Mono was installed.
996 mono_set_rootdir (void)
998 #if defined(HOST_WIN32) || (defined(HOST_DARWIN) && !defined(TARGET_ARM))
999 gchar
*bindir
, *installdir
, *root
, *name
, *resolvedname
, *config
;
1002 name
= mono_get_module_file_name ((HMODULE
) &__ImageBase
);
1006 * _NSGetExecutablePath may return -1 to indicate buf is not large
1007 * enough, but we ignore that case to avoid having to do extra dynamic
1008 * allocation for the path and hope that 4096 is enough - this is
1009 * ok in the Linux/Solaris case below at least...
1013 guint buf_size
= sizeof (buf
);
1016 if (_NSGetExecutablePath (buf
, &buf_size
) == 0)
1017 name
= g_strdup (buf
);
1026 resolvedname
= mono_path_resolve_symlinks (name
);
1028 bindir
= g_path_get_dirname (resolvedname
);
1029 installdir
= g_path_get_dirname (bindir
);
1030 root
= g_build_path (G_DIR_SEPARATOR_S
, installdir
, "lib", (const char*)NULL
);
1032 config
= g_build_filename (root
, "..", "etc", (const char*)NULL
);
1034 mono_set_dirs (root
, config
);
1036 if (g_file_test (root
, G_FILE_TEST_EXISTS
) && g_file_test (config
, G_FILE_TEST_EXISTS
))
1037 mono_set_dirs (root
, config
);
1044 g_free (installdir
);
1047 g_free (resolvedname
);
1048 #elif defined(DISABLE_MONO_AUTODETECTION)
1055 #if defined(HAVE_READLINK)
1057 s
= readlink ("/proc/self/exe", buf
, sizeof (buf
)-1);
1068 /* Solaris 10 style */
1069 str
= g_strdup_printf ("/proc/%d/path/a.out", getpid ());
1071 #if defined(HAVE_READLINK)
1072 s
= readlink (str
, buf
, sizeof (buf
)-1);
1088 * mono_assemblies_init:
1090 * Initialize global variables used by this module.
1093 mono_assemblies_init (void)
1096 * Initialize our internal paths if we have not been initialized yet.
1097 * This happens when embedders use Mono.
1099 if (mono_assembly_getrootdir () == NULL
)
1100 mono_set_rootdir ();
1104 check_extra_gac_path_env ();
1107 mono_os_mutex_init_recursive (&assemblies_mutex
);
1108 mono_os_mutex_init (&assembly_binding_mutex
);
1110 #ifndef DISABLE_DESKTOP_LOADER
1111 assembly_remapping_table
= g_hash_table_new (g_str_hash
, g_str_equal
);
1114 for (i
= 0; i
< G_N_ELEMENTS (framework_assemblies
); ++i
)
1115 g_hash_table_insert (assembly_remapping_table
, (void*)framework_assemblies
[i
].assembly_name
, (void*)&framework_assemblies
[i
]);
1118 mono_install_assembly_asmctx_from_path_hook (assembly_loadfrom_asmctx_from_path
, NULL
);
1123 mono_assembly_binding_lock (void)
1125 mono_locks_os_acquire (&assembly_binding_mutex
, AssemblyBindingLock
);
1129 mono_assembly_binding_unlock (void)
1131 mono_locks_os_release (&assembly_binding_mutex
, AssemblyBindingLock
);
1135 mono_assembly_fill_assembly_name_full (MonoImage
*image
, MonoAssemblyName
*aname
, gboolean copyBlobs
)
1137 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLY
];
1138 guint32 cols
[MONO_ASSEMBLY_SIZE
];
1139 gint32 machine
, flags
;
1144 mono_metadata_decode_row (t
, 0, cols
, MONO_ASSEMBLY_SIZE
);
1146 aname
->hash_len
= 0;
1147 aname
->hash_value
= NULL
;
1148 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_NAME
]);
1150 aname
->name
= g_strdup (aname
->name
);
1151 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_CULTURE
]);
1153 aname
->culture
= g_strdup (aname
->culture
);
1154 aname
->flags
= cols
[MONO_ASSEMBLY_FLAGS
];
1155 aname
->major
= cols
[MONO_ASSEMBLY_MAJOR_VERSION
];
1156 aname
->minor
= cols
[MONO_ASSEMBLY_MINOR_VERSION
];
1157 aname
->build
= cols
[MONO_ASSEMBLY_BUILD_NUMBER
];
1158 aname
->revision
= cols
[MONO_ASSEMBLY_REV_NUMBER
];
1159 aname
->hash_alg
= cols
[MONO_ASSEMBLY_HASH_ALG
];
1160 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
1161 guchar
* token
= (guchar
*)g_malloc (8);
1166 pkey
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
1167 len
= mono_metadata_decode_blob_size (pkey
, &pkey
);
1168 aname
->public_key
= (guchar
*)pkey
;
1170 mono_digest_get_public_token (token
, aname
->public_key
, len
);
1171 encoded
= encode_public_tok (token
, 8);
1172 g_strlcpy ((char*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1178 aname
->public_key
= NULL
;
1179 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1182 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
1183 aname
->public_key
= (guchar
*)mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
1185 const gchar
*pkey_end
;
1186 int len
= mono_metadata_decode_blob_size ((const gchar
*) aname
->public_key
, &pkey_end
);
1187 pkey_end
+= len
; /* move to end */
1188 size_t size
= pkey_end
- (const gchar
*)aname
->public_key
;
1189 guchar
*tmp
= g_new (guchar
, size
);
1190 memcpy (tmp
, aname
->public_key
, size
);
1191 aname
->public_key
= tmp
;
1196 aname
->public_key
= 0;
1198 machine
= image
->image_info
->cli_header
.coff
.coff_machine
;
1199 flags
= image
->image_info
->cli_cli_header
.ch_flags
;
1201 case COFF_MACHINE_I386
:
1202 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1203 if (flags
& (CLI_FLAGS_32BITREQUIRED
|CLI_FLAGS_PREFERRED32BIT
))
1204 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_X86
;
1205 else if ((flags
& 0x70) == 0x70)
1206 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_NONE
;
1208 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_MSIL
;
1210 case COFF_MACHINE_IA64
:
1211 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_IA64
;
1213 case COFF_MACHINE_AMD64
:
1214 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_AMD64
;
1216 case COFF_MACHINE_ARM
:
1217 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_ARM
;
1227 * mono_assembly_fill_assembly_name:
1228 * \param image Image
1230 * \returns TRUE if successful
1233 mono_assembly_fill_assembly_name (MonoImage
*image
, MonoAssemblyName
*aname
)
1235 return mono_assembly_fill_assembly_name_full (image
, aname
, FALSE
);
1239 * mono_stringify_assembly_name:
1240 * \param aname the assembly name.
1242 * Convert \p aname into its string format. The returned string is dynamically
1243 * allocated and should be freed by the caller.
1245 * \returns a newly allocated string with a string representation of
1246 * the assembly name.
1249 mono_stringify_assembly_name (MonoAssemblyName
*aname
)
1251 const char *quote
= (aname
->name
&& g_ascii_isspace (aname
->name
[0])) ? "\"" : "";
1253 return g_strdup_printf (
1254 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1255 quote
, aname
->name
, quote
,
1256 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1257 aname
->culture
&& *aname
->culture
? aname
->culture
: "neutral",
1258 aname
->public_key_token
[0] ? (char *)aname
->public_key_token
: "null",
1259 (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
1263 assemblyref_public_tok (MonoImage
*image
, guint32 key_index
, guint32 flags
)
1265 const gchar
*public_tok
;
1268 public_tok
= mono_metadata_blob_heap (image
, key_index
);
1269 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
1271 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
1273 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
1274 return encode_public_tok (token
, 8);
1277 return encode_public_tok ((guchar
*)public_tok
, len
);
1281 assemblyref_public_tok_checked (MonoImage
*image
, guint32 key_index
, guint32 flags
, MonoError
*error
)
1283 const gchar
*public_tok
;
1286 public_tok
= mono_metadata_blob_heap_checked (image
, key_index
, error
);
1287 return_val_if_nok (error
, NULL
);
1289 mono_error_set_bad_image (error
, image
, "expected public key token (index = %d) in assembly reference, but the Blob heap is NULL", key_index
);
1292 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
1294 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
1296 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
1297 return encode_public_tok (token
, 8);
1299 return encode_public_tok ((guchar
*)public_tok
, len
);
1303 * mono_assembly_addref:
1304 * \param assembly the assembly to reference
1306 * This routine increments the reference count on a MonoAssembly.
1307 * The reference count is reduced every time the method mono_assembly_close() is
1311 mono_assembly_addref (MonoAssembly
*assembly
)
1313 mono_atomic_inc_i32 (&assembly
->ref_count
);
1317 * CAUTION: This table must be kept in sync with
1318 * ivkm/reflect/Fusion.cs
1321 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1322 #define WINFX_KEY "31bf3856ad364e35"
1323 #define ECMA_KEY "b77a5c561934e089"
1324 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1325 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1333 static KeyRemapEntry key_remap_table
[] = {
1334 { "CustomMarshalers", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1335 { "Microsoft.CSharp", WINFX_KEY
, MSFINAL_KEY
},
1336 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1337 { "System", SILVERLIGHT_KEY
, ECMA_KEY
},
1338 { "System", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1339 { "System.ComponentModel.Composition", WINFX_KEY
, ECMA_KEY
},
1340 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY
},
1341 { "System.Core", SILVERLIGHT_KEY
, ECMA_KEY
},
1342 { "System.Core", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1343 { "System.Data", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1344 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1345 { "System.Drawing", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1346 { "System.Messaging", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1347 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1348 { "System.Net", SILVERLIGHT_KEY
, MSFINAL_KEY
},
1349 { "System.Numerics", WINFX_KEY
, ECMA_KEY
},
1350 { "System.Runtime.Serialization", SILVERLIGHT_KEY
, ECMA_KEY
},
1351 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1352 { "System.ServiceModel", WINFX_KEY
, ECMA_KEY
},
1353 { "System.ServiceModel", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1354 { "System.ServiceModel.Web", SILVERLIGHT_KEY
, WINFX_KEY
},
1355 { "System.Web.Services", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1356 { "System.Windows", SILVERLIGHT_KEY
, MSFINAL_KEY
},
1357 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1358 { "System.Xml", SILVERLIGHT_KEY
, ECMA_KEY
},
1359 { "System.Xml", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1360 { "System.Xml.Linq", WINFX_KEY
, ECMA_KEY
},
1361 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1362 { "System.Xml.Serialization", WINFX_KEY
, ECMA_KEY
}
1366 remap_keys (MonoAssemblyName
*aname
)
1369 for (i
= 0; i
< G_N_ELEMENTS (key_remap_table
); i
++) {
1370 const KeyRemapEntry
*entry
= &key_remap_table
[i
];
1372 if (strcmp (aname
->name
, entry
->name
) ||
1373 !mono_public_tokens_are_equal (aname
->public_key_token
, (const unsigned char*) entry
->from
))
1376 memcpy (aname
->public_key_token
, entry
->to
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1378 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
,
1379 "Remapped public key token of retargetable assembly %s from %s to %s",
1380 aname
->name
, entry
->from
, entry
->to
);
1385 static MonoAssemblyName
*
1386 mono_assembly_remap_version (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_aname
)
1388 const MonoRuntimeInfo
*current_runtime
;
1390 if (aname
->name
== NULL
) return aname
;
1392 current_runtime
= mono_get_runtime_info ();
1394 if (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) {
1395 const AssemblyVersionSet
* vset
;
1397 /* Remap to current runtime */
1398 vset
= ¤t_runtime
->version_sets
[0];
1400 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
1401 dest_aname
->major
= vset
->major
;
1402 dest_aname
->minor
= vset
->minor
;
1403 dest_aname
->build
= vset
->build
;
1404 dest_aname
->revision
= vset
->revision
;
1405 dest_aname
->flags
&= ~ASSEMBLYREF_RETARGETABLE_FLAG
;
1407 /* Remap assembly name */
1408 if (!strcmp (aname
->name
, "System.Net"))
1409 dest_aname
->name
= g_strdup ("System");
1411 remap_keys (dest_aname
);
1413 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
,
1414 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1416 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1418 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1424 #ifndef DISABLE_DESKTOP_LOADER
1425 const AssemblyVersionMap
*vmap
= (AssemblyVersionMap
*)g_hash_table_lookup (assembly_remapping_table
, aname
->name
);
1427 const AssemblyVersionSet
* vset
;
1428 int index
= vmap
->version_set_index
;
1429 g_assert (index
< G_N_ELEMENTS (current_runtime
->version_sets
));
1430 vset
= ¤t_runtime
->version_sets
[index
];
1432 if (vmap
->framework_facade_assembly
) {
1433 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Assembly %s is a framework Facade asseembly",
1438 if (aname
->major
== vset
->major
&& aname
->minor
== vset
->minor
&&
1439 aname
->build
== vset
->build
&& aname
->revision
== vset
->revision
) {
1440 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1442 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
);
1446 if (vmap
->only_lower_versions
&& compare_versions ((AssemblyVersionSet
*)vset
, aname
) < 0) {
1447 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
,
1448 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1450 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1451 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1456 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0)
1457 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
1458 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1460 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1461 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1464 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
1465 dest_aname
->major
= vset
->major
;
1466 dest_aname
->minor
= vset
->minor
;
1467 dest_aname
->build
= vset
->build
;
1468 dest_aname
->revision
= vset
->revision
;
1469 if (vmap
->new_assembly_name
!= NULL
) {
1470 dest_aname
->name
= vmap
->new_assembly_name
;
1471 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
1472 "The assembly name %s was remapped to %s",
1484 * mono_assembly_get_assemblyref:
1485 * \param image pointer to the \c MonoImage to extract the information from.
1486 * \param index index to the assembly reference in the image.
1487 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1489 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1492 mono_assembly_get_assemblyref (MonoImage
*image
, int index
, MonoAssemblyName
*aname
)
1495 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
1498 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1500 mono_metadata_decode_row (t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
);
1502 // ECMA-335: II.22.5 - AssemblyRef
1503 // HashValue can be null or non-null. If non-null it's an index into the blob heap
1504 // Sometimes ILasm can create an image without a Blob heap.
1505 hash
= mono_metadata_blob_heap_null_ok (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
]);
1507 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
1508 aname
->hash_value
= hash
;
1510 aname
->hash_len
= 0;
1511 aname
->hash_value
= NULL
;
1513 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_NAME
]);
1514 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_CULTURE
]);
1515 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
1516 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
1517 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
1518 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
1519 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
1521 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
1522 gchar
*token
= assemblyref_public_tok (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
);
1523 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1526 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1530 #ifndef ENABLE_NETCORE
1531 static MonoAssembly
*
1532 load_reference_by_aname_refonly_asmctx (MonoAssemblyName
*aname
, MonoAssemblyLoadContext
*alc
, MonoAssembly
*assm
, MonoImageOpenStatus
*status
)
1534 MonoAssembly
*reference
= NULL
;
1535 g_assert (assm
!= NULL
);
1536 g_assert (status
!= NULL
);
1537 *status
= MONO_IMAGE_OK
;
1539 /* We use the loaded corlib */
1540 if (!strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
)) {
1541 MonoAssemblyByNameRequest req
;
1542 mono_assembly_request_prepare_byname (&req
, MONO_ASMCTX_DEFAULT
, alc
);
1543 req
.requesting_assembly
= assm
;
1544 req
.basedir
= assm
->basedir
;
1545 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1547 reference
= mono_assembly_loaded_internal (alc
, aname
, TRUE
);
1549 /* Try a postload search hook */
1550 reference
= mono_assembly_invoke_search_hook_internal (NULL
, assm
, aname
, TRUE
, TRUE
);
1554 * Here we must advice that the error was due to
1555 * a non loaded reference using the ReflectionOnly api
1558 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1563 static MonoAssembly
*
1564 load_reference_by_aname_default_asmctx (MonoAssemblyName
*aname
, MonoAssemblyLoadContext
*alc
, MonoAssembly
*assm
, MonoImageOpenStatus
*status
)
1566 MonoAssembly
*reference
= NULL
;
1567 g_assert (status
!= NULL
);
1568 *status
= MONO_IMAGE_OK
;
1570 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1571 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1572 * accordingly, it would fail on the MS runtime before).
1573 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1574 * example bug-349190.2.cs and who knows how much more code in the wild.
1576 MonoAssemblyByNameRequest req
;
1577 mono_assembly_request_prepare_byname (&req
, MONO_ASMCTX_DEFAULT
, alc
);
1578 req
.requesting_assembly
= assm
;
1579 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1580 if (!reference
&& assm
) {
1581 memset (&req
, 0, sizeof (req
));
1582 req
.request
.asmctx
= MONO_ASMCTX_DEFAULT
;
1583 req
.requesting_assembly
= assm
;
1584 req
.basedir
= assm
->basedir
;
1585 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1591 static MonoAssembly
*
1592 load_reference_by_aname_loadfrom_asmctx (MonoAssemblyName
*aname
, MonoAssemblyLoadContext
*alc
, MonoAssembly
*requesting
, MonoImageOpenStatus
*status
)
1594 MonoAssembly
*reference
= NULL
;
1595 MonoAssemblyByNameRequest req
;
1596 mono_assembly_request_prepare_byname (&req
, MONO_ASMCTX_LOADFROM
, alc
);
1597 req
.requesting_assembly
= requesting
;
1598 req
.basedir
= requesting
->basedir
;
1599 /* Just like default search, but look in the requesting assembly basedir right away */
1600 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1605 static MonoAssembly
*
1606 load_reference_by_aname_individual_asmctx (MonoAssemblyName
*aname
, MonoAssemblyLoadContext
*alc
, MonoAssembly
*requesting
, MonoImageOpenStatus
*status
)
1608 /* For an individual assembly, all references must already be loaded or
1609 * else we fire the assembly resolve event - similar to refonly - but
1610 * subject to remaping and binding.
1613 g_assert (status
!= NULL
);
1615 MonoAssembly
*reference
= NULL
;
1616 *status
= MONO_IMAGE_OK
;
1617 MonoAssemblyName maped_aname
;
1618 MonoAssemblyName maped_name_pp
;
1620 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
1621 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
1623 reference
= mono_assembly_loaded_internal (alc
, aname
, FALSE
);
1624 /* Still try to load from application base directory, MONO_PATH or the
1625 * GAC. This is consistent with what .NET Framework (4.7) actually
1626 * does, rather than what the documentation implies: If `LoadFile` is
1627 * used to load an assembly into "no context"/individual assembly
1628 * context, the runtime will still load assemblies from the GAC or the
1629 * application base directory (e.g. `System.Runtime` will be loaded if
1630 * it wasn't already).
1631 * Moreover, those referenced assemblies are loaded in the default context.
1634 MonoAssemblyByNameRequest req
;
1635 mono_assembly_request_prepare_byname (&req
, MONO_ASMCTX_DEFAULT
, mono_domain_default_alc (mono_alc_domain (alc
)));
1636 req
.requesting_assembly
= requesting
;
1637 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1640 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1644 static MonoAssembly
*
1645 netcore_load_reference (MonoAssemblyName
*aname
, MonoAssemblyLoadContext
*alc
, MonoAssembly
*requesting
, gboolean postload
)
1647 g_assert (alc
!= NULL
);
1649 MonoAssemblyName mapped_aname
;
1650 MonoAssemblyName mapped_name_pp
;
1652 aname
= mono_assembly_remap_version (aname
, &mapped_aname
);
1653 /* FIXME: netcore doesn't have binding redirects */
1654 aname
= mono_assembly_apply_binding (aname
, &mapped_name_pp
);
1656 MonoAssembly
*reference
= NULL
;
1658 gboolean is_satellite
= !mono_assembly_name_culture_is_neutral (aname
);
1659 gboolean is_default
= mono_alc_is_default (alc
);
1662 * Try these until one of them succeeds (by returning a non-NULL reference):
1663 * 1. Check if it's already loaded by the ALC.
1665 * 2. If it's a non-default ALC, call the Load() method.
1667 * 3. If the ALC is not the default and this is not a satellite request,
1668 * check if it's already loaded by the default ALC.
1670 * 4. If the ALC is not the default or this is not a satellite request,
1671 * check the TPA paths and ApplicationBase.
1673 * 5. If this is a satellite request, call the ALC ResolveSatelliteAssembly method.
1675 * 6. Call the ALC Resolving event.
1677 * 7. Call the ALC AssemblyResolve event (except for corlib satellite assemblies).
1682 reference
= mono_assembly_loaded_internal (alc
, aname
, FALSE
);
1687 reference
= mono_alc_invoke_resolve_using_load_nofail (alc
, aname
);
1692 if (!is_default
&& !is_satellite
) {
1693 reference
= mono_assembly_loaded_internal (mono_domain_default_alc (mono_alc_domain (alc
)), aname
, FALSE
);
1698 if (is_default
|| !is_satellite
) {
1699 reference
= invoke_assembly_preload_hook (mono_domain_default_alc (mono_alc_domain (alc
)), aname
, assemblies_path
);
1705 reference
= mono_alc_invoke_resolve_using_resolve_satellite_nofail (alc
, aname
);
1710 reference
= mono_alc_invoke_resolve_using_resolving_event_nofail (alc
, aname
);
1714 // See: https://github.com/dotnet/coreclr/blob/0a762eb2f3a299489c459da1ddeb69e042008f07/src/vm/appdomain.cpp#L5178-L5239
1715 if (!(strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
) == 0 && is_satellite
) && postload
) {
1716 reference
= mono_assembly_invoke_search_hook_internal (alc
, requesting
, aname
, FALSE
, TRUE
);
1725 #endif /* ENABLE_NETCORE */
1728 * mono_assembly_get_assemblyref_checked:
1729 * \param image pointer to the \c MonoImage to extract the information from.
1730 * \param index index to the assembly reference in the image.
1731 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1732 * \param error set on error
1734 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1736 * \returns TRUE on success, otherwise sets \p error and returns FALSE
1739 mono_assembly_get_assemblyref_checked (MonoImage
*image
, int index
, MonoAssemblyName
*aname
, MonoError
*error
)
1742 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
1745 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1747 if (!mono_metadata_decode_row_checked (image
, t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
, error
))
1750 // ECMA-335: II.22.5 - AssemblyRef
1751 // HashValue can be null or non-null. If non-null it's an index into the blob heap
1752 // Sometimes ILasm can create an image without a Blob heap.
1753 hash
= mono_metadata_blob_heap_checked (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
], error
);
1754 return_val_if_nok (error
, FALSE
);
1756 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
1757 aname
->hash_value
= hash
;
1759 aname
->hash_len
= 0;
1760 aname
->hash_value
= NULL
;
1762 aname
->name
= mono_metadata_string_heap_checked (image
, cols
[MONO_ASSEMBLYREF_NAME
], error
);
1763 return_val_if_nok (error
, FALSE
);
1764 aname
->culture
= mono_metadata_string_heap_checked (image
, cols
[MONO_ASSEMBLYREF_CULTURE
], error
);
1765 return_val_if_nok (error
, FALSE
);
1766 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
1767 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
1768 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
1769 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
1770 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
1771 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
1772 gchar
*token
= assemblyref_public_tok_checked (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
, error
);
1773 return_val_if_nok (error
, FALSE
);
1774 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1777 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1783 * mono_assembly_load_reference:
1786 mono_assembly_load_reference (MonoImage
*image
, int index
)
1788 MonoAssembly
*reference
;
1789 MonoAssemblyName aname
;
1790 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
1793 * image->references is shared between threads, so we need to access
1794 * it inside a critical section.
1796 mono_image_lock (image
);
1797 if (!image
->references
) {
1798 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1800 image
->references
= g_new0 (MonoAssembly
*, t
->rows
+ 1);
1801 image
->nreferences
= t
->rows
;
1803 reference
= image
->references
[index
];
1804 mono_image_unlock (image
);
1808 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Requesting loading reference %d (of %d) of %s", index
, image
->nreferences
, image
->name
);
1810 ERROR_DECL (local_error
);
1811 mono_assembly_get_assemblyref_checked (image
, index
, &aname
, local_error
);
1812 if (!is_ok (local_error
)) {
1813 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
, "Decoding assembly reference %d (of %d) of %s failed due to: %s", index
, image
->nreferences
, image
->name
, mono_error_get_message (local_error
));
1814 mono_error_cleanup (local_error
);
1815 goto commit_reference
;
1818 if (image
->assembly
) {
1819 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
1820 char *aname_str
= mono_stringify_assembly_name (&aname
);
1821 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Loading reference %d of %s asmctx %s, looking for %s",
1822 index
, image
->name
, mono_asmctx_get_name (&image
->assembly
->context
),
1826 #ifndef ENABLE_NETCORE
1827 switch (mono_asmctx_get_kind (&image
->assembly
->context
)) {
1828 case MONO_ASMCTX_DEFAULT
:
1829 reference
= load_reference_by_aname_default_asmctx (&aname
, mono_image_get_alc (image
), image
->assembly
, &status
);
1831 case MONO_ASMCTX_REFONLY
:
1832 reference
= load_reference_by_aname_refonly_asmctx (&aname
, mono_image_get_alc (image
), image
->assembly
, &status
);
1834 case MONO_ASMCTX_LOADFROM
:
1835 reference
= load_reference_by_aname_loadfrom_asmctx (&aname
, mono_image_get_alc (image
), image
->assembly
, &status
);
1837 case MONO_ASMCTX_INDIVIDUAL
:
1838 reference
= load_reference_by_aname_individual_asmctx (&aname
, mono_image_get_alc (image
), image
->assembly
, &status
);
1841 g_error ("Unexpected assembly load context kind %d for image %s.", mono_asmctx_get_kind (&image
->assembly
->context
), image
->name
);
1845 MonoAssemblyByNameRequest req
;
1846 mono_assembly_request_prepare_byname (&req
, MONO_ASMCTX_DEFAULT
, mono_image_get_alc (image
));
1847 req
.requesting_assembly
= image
->assembly
;
1848 //req.no_postload_search = TRUE; // FIXME: should this be set?
1849 reference
= mono_assembly_request_byname (&aname
, &req
, NULL
);
1852 #ifndef ENABLE_NETCORE
1853 /* FIXME: can we establish that image->assembly is never NULL and this code is dead? */
1854 reference
= load_reference_by_aname_default_asmctx (&aname
, mono_image_get_alc (image
), image
->assembly
, &status
);
1856 g_assertf (image
->assembly
, "While loading reference %d MonoImage %s doesn't have a MonoAssembly", index
, image
->name
);
1860 if (reference
== NULL
){
1863 if (status
== MONO_IMAGE_ERROR_ERRNO
&& errno
== ENOENT
) {
1864 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
: "" );
1865 } else if (status
== MONO_IMAGE_ERROR_ERRNO
) {
1866 extra_msg
= g_strdup_printf ("System error: %s\n", strerror (errno
));
1867 } else if (status
== MONO_IMAGE_MISSING_ASSEMBLYREF
) {
1868 extra_msg
= g_strdup ("Cannot find an assembly referenced from this one.\n");
1869 } else if (status
== MONO_IMAGE_IMAGE_INVALID
) {
1870 extra_msg
= g_strdup ("The file exists but is not a valid assembly.\n");
1872 extra_msg
= g_strdup ("");
1875 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
, "The following assembly referenced from %s could not be loaded:\n"
1876 " Assembly: %s (assemblyref_index=%d)\n"
1877 " Version: %d.%d.%d.%d\n"
1878 " Public Key: %s\n%s",
1879 image
->name
, aname
.name
, index
,
1880 aname
.major
, aname
.minor
, aname
.build
, aname
.revision
,
1881 strlen ((char*)aname
.public_key_token
) == 0 ? "(none)" : (char*)aname
.public_key_token
, extra_msg
);
1887 mono_image_lock (image
);
1888 if (reference
== NULL
) {
1889 /* Flag as not found */
1890 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1893 if (!image
->references
[index
]) {
1894 if (reference
!= REFERENCE_MISSING
){
1895 mono_assembly_addref (reference
);
1896 if (image
->assembly
)
1897 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1898 image
->assembly
->aname
.name
, image
->assembly
, reference
->aname
.name
, reference
, reference
->ref_count
);
1900 if (image
->assembly
)
1901 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Failed to load assembly %s[%p].",
1902 image
->assembly
->aname
.name
, image
->assembly
);
1905 image
->references
[index
] = reference
;
1907 mono_image_unlock (image
);
1909 if (image
->references
[index
] != reference
) {
1910 /* Somebody loaded it before us */
1911 mono_assembly_close (reference
);
1916 * mono_assembly_load_references:
1919 * \deprecated There is no reason to use this method anymore, it does nothing
1921 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1924 mono_assembly_load_references (MonoImage
*image
, MonoImageOpenStatus
*status
)
1926 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1928 *status
= MONO_IMAGE_OK
;
1931 typedef struct AssemblyLoadHook AssemblyLoadHook
;
1932 struct AssemblyLoadHook
{
1933 AssemblyLoadHook
*next
;
1935 MonoAssemblyLoadFunc v1
;
1936 MonoAssemblyLoadFuncV2 v2
;
1942 static AssemblyLoadHook
*assembly_load_hook
= NULL
;
1945 mono_assembly_invoke_load_hook_internal (MonoAssemblyLoadContext
*alc
, MonoAssembly
*ass
)
1947 AssemblyLoadHook
*hook
;
1949 for (hook
= assembly_load_hook
; hook
; hook
= hook
->next
) {
1950 if (hook
->version
== 1) {
1951 hook
->func
.v1 (ass
, hook
->user_data
);
1953 ERROR_DECL (hook_error
);
1954 g_assert (hook
->version
== 2);
1955 hook
->func
.v2 (alc
, ass
, hook
->user_data
, hook_error
);
1956 mono_error_assert_ok (hook_error
); /* FIXME: proper error handling */
1962 * mono_assembly_invoke_load_hook:
1965 mono_assembly_invoke_load_hook (MonoAssembly
*ass
)
1967 mono_assembly_invoke_load_hook_internal (mono_domain_default_alc (mono_domain_get ()), ass
);
1971 mono_install_assembly_load_hook_v1 (MonoAssemblyLoadFunc func
, gpointer user_data
)
1973 AssemblyLoadHook
*hook
;
1975 g_return_if_fail (func
!= NULL
);
1977 hook
= g_new0 (AssemblyLoadHook
, 1);
1979 hook
->func
.v1
= func
;
1980 hook
->user_data
= user_data
;
1981 hook
->next
= assembly_load_hook
;
1982 assembly_load_hook
= hook
;
1986 mono_install_assembly_load_hook_v2 (MonoAssemblyLoadFuncV2 func
, gpointer user_data
)
1988 g_return_if_fail (func
!= NULL
);
1990 AssemblyLoadHook
*hook
= g_new0 (AssemblyLoadHook
, 1);
1992 hook
->func
.v2
= func
;
1993 hook
->user_data
= user_data
;
1994 hook
->next
= assembly_load_hook
;
1995 assembly_load_hook
= hook
;
1999 * mono_install_assembly_load_hook:
2002 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func
, gpointer user_data
)
2004 mono_install_assembly_load_hook_v1 (func
, user_data
);
2008 free_assembly_load_hooks (void)
2010 AssemblyLoadHook
*hook
, *next
;
2012 for (hook
= assembly_load_hook
; hook
; hook
= next
) {
2018 typedef struct AssemblySearchHook AssemblySearchHook
;
2019 struct AssemblySearchHook
{
2020 AssemblySearchHook
*next
;
2022 MonoAssemblySearchFunc v1
;
2023 MonoAssemblySearchFuncV2 v2
;
2031 static AssemblySearchHook
*assembly_search_hook
= NULL
;
2033 static MonoAssembly
*
2034 mono_assembly_invoke_search_hook_internal (MonoAssemblyLoadContext
*alc
, MonoAssembly
*requesting
, MonoAssemblyName
*aname
, gboolean refonly
, gboolean postload
)
2036 AssemblySearchHook
*hook
;
2038 for (hook
= assembly_search_hook
; hook
; hook
= hook
->next
) {
2039 if ((hook
->refonly
== refonly
) && (hook
->postload
== postload
)) {
2041 if (hook
->version
== 1) {
2042 ass
= hook
->func
.v1 (aname
, hook
->user_data
);
2044 ERROR_DECL (hook_error
);
2045 g_assert (hook
->version
== 2);
2046 ass
= hook
->func
.v2 (alc
, requesting
, aname
, refonly
, postload
, hook
->user_data
, hook_error
);
2047 mono_error_assert_ok (hook_error
); /* FIXME: proper error handling */
2058 * mono_assembly_invoke_search_hook:
2061 mono_assembly_invoke_search_hook (MonoAssemblyName
*aname
)
2063 return mono_assembly_invoke_search_hook_internal (NULL
, NULL
, aname
, FALSE
, FALSE
);
2067 mono_install_assembly_search_hook_internal_v1 (MonoAssemblySearchFunc func
, gpointer user_data
, gboolean refonly
, gboolean postload
)
2069 AssemblySearchHook
*hook
;
2071 g_return_if_fail (func
!= NULL
);
2073 hook
= g_new0 (AssemblySearchHook
, 1);
2075 hook
->func
.v1
= func
;
2076 hook
->user_data
= user_data
;
2077 hook
->refonly
= refonly
;
2078 hook
->postload
= postload
;
2079 hook
->next
= assembly_search_hook
;
2080 assembly_search_hook
= hook
;
2084 mono_install_assembly_search_hook_v2 (MonoAssemblySearchFuncV2 func
, gpointer user_data
, gboolean refonly
, gboolean postload
)
2089 AssemblySearchHook
*hook
= g_new0 (AssemblySearchHook
, 1);
2091 hook
->func
.v2
= func
;
2092 hook
->user_data
= user_data
;
2093 hook
->refonly
= refonly
;
2094 hook
->postload
= postload
;
2095 hook
->next
= assembly_search_hook
;
2096 assembly_search_hook
= hook
;
2100 * mono_install_assembly_search_hook:
2103 mono_install_assembly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
2105 mono_install_assembly_search_hook_internal_v1 (func
, user_data
, FALSE
, FALSE
);
2109 free_assembly_search_hooks (void)
2111 AssemblySearchHook
*hook
, *next
;
2113 for (hook
= assembly_search_hook
; hook
; hook
= next
) {
2120 * mono_install_assembly_refonly_search_hook:
2123 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
2125 mono_install_assembly_search_hook_internal_v1 (func
, user_data
, TRUE
, FALSE
);
2129 * mono_install_assembly_postload_search_hook:
2132 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
2134 mono_install_assembly_search_hook_internal_v1 (func
, user_data
, FALSE
, TRUE
);
2138 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
2140 mono_install_assembly_search_hook_internal_v1 (func
, user_data
, TRUE
, TRUE
);
2144 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook
;
2145 struct AssemblyPreLoadHook
{
2146 AssemblyPreLoadHook
*next
;
2148 MonoAssemblyPreLoadFunc v1
;
2149 MonoAssemblyPreLoadFuncV2 v2
;
2155 static AssemblyPreLoadHook
*assembly_preload_hook
= NULL
;
2156 static AssemblyPreLoadHook
*assembly_refonly_preload_hook
= NULL
;
2158 static MonoAssembly
*
2159 invoke_assembly_preload_hook (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
, gchar
**apath
)
2161 AssemblyPreLoadHook
*hook
;
2162 MonoAssembly
*assembly
;
2164 for (hook
= assembly_preload_hook
; hook
; hook
= hook
->next
) {
2165 if (hook
->version
== 1)
2166 assembly
= hook
->func
.v1 (aname
, apath
, hook
->user_data
);
2169 g_assert (hook
->version
== 2);
2170 assembly
= hook
->func
.v2 (alc
, aname
, apath
, FALSE
, hook
->user_data
, error
);
2171 /* TODO: propagage error out to callers */
2172 mono_error_assert_ok (error
);
2174 if (assembly
!= NULL
)
2181 static MonoAssembly
*
2182 invoke_assembly_refonly_preload_hook (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
, gchar
**apath
)
2184 AssemblyPreLoadHook
*hook
;
2185 MonoAssembly
*assembly
;
2187 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= hook
->next
) {
2188 if (hook
->version
== 1)
2189 assembly
= hook
->func
.v1 (aname
, apath
, hook
->user_data
);
2192 g_assert (hook
->version
== 2);
2193 assembly
= hook
->func
.v2 (alc
, aname
, apath
, TRUE
, hook
->user_data
, error
);
2194 /* TODO: propagate error out to callers */
2195 mono_error_assert_ok (error
);
2197 if (assembly
!= NULL
)
2205 * mono_install_assembly_preload_hook:
2208 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
2210 AssemblyPreLoadHook
*hook
;
2212 g_return_if_fail (func
!= NULL
);
2214 hook
= g_new0 (AssemblyPreLoadHook
, 1);
2216 hook
->func
.v1
= func
;
2217 hook
->user_data
= user_data
;
2218 hook
->next
= assembly_preload_hook
;
2219 assembly_preload_hook
= hook
;
2223 * mono_install_assembly_refonly_preload_hook:
2226 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
2228 AssemblyPreLoadHook
*hook
;
2230 g_return_if_fail (func
!= NULL
);
2232 hook
= g_new0 (AssemblyPreLoadHook
, 1);
2234 hook
->func
.v1
= func
;
2235 hook
->user_data
= user_data
;
2236 hook
->next
= assembly_refonly_preload_hook
;
2237 assembly_refonly_preload_hook
= hook
;
2241 mono_install_assembly_preload_hook_v2 (MonoAssemblyPreLoadFuncV2 func
, gpointer user_data
, gboolean refonly
)
2243 AssemblyPreLoadHook
*hook
;
2245 g_return_if_fail (func
!= NULL
);
2247 AssemblyPreLoadHook
**hooks
= refonly
? &assembly_refonly_preload_hook
: &assembly_preload_hook
;
2249 hook
= g_new0 (AssemblyPreLoadHook
, 1);
2251 hook
->func
.v2
= func
;
2252 hook
->user_data
= user_data
;
2253 hook
->next
= *hooks
;
2259 free_assembly_preload_hooks (void)
2261 AssemblyPreLoadHook
*hook
, *next
;
2263 for (hook
= assembly_preload_hook
; hook
; hook
= next
) {
2268 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= next
) {
2274 typedef struct AssemblyAsmCtxFromPathHook AssemblyAsmCtxFromPathHook
;
2275 struct AssemblyAsmCtxFromPathHook
{
2276 AssemblyAsmCtxFromPathHook
*next
;
2277 MonoAssemblyAsmCtxFromPathFunc func
;
2281 static AssemblyAsmCtxFromPathHook
*assembly_asmctx_from_path_hook
= NULL
;
2284 * mono_install_assembly_asmctx_from_path_hook:
2286 * \param func Hook function
2287 * \param user_data User data
2289 * Installs a hook function \p func that when called with an absolute path name
2290 * returns \c TRUE and writes to \c out_asmctx if an assembly that name would
2291 * be found by that asmctx. The hooks are called in the order from most
2292 * recently added to oldest.
2296 mono_install_assembly_asmctx_from_path_hook (MonoAssemblyAsmCtxFromPathFunc func
, gpointer user_data
)
2298 g_return_if_fail (func
!= NULL
);
2300 AssemblyAsmCtxFromPathHook
*hook
= g_new0 (AssemblyAsmCtxFromPathHook
, 1);
2302 hook
->user_data
= user_data
;
2303 hook
->next
= assembly_asmctx_from_path_hook
;
2304 assembly_asmctx_from_path_hook
= hook
;
2308 * mono_assembly_invoke_asmctx_from_path_hook:
2310 * \param absfname absolute path name
2311 * \param requesting_assembly the \c MonoAssembly that requested the load, may be \c NULL
2312 * \param out_asmctx assembly context kind, written on output
2314 * Invokes hooks to find the assembly context that would have searched for the
2315 * given assembly name. Writes to \p out_asmctx the assembly context kind from
2316 * the first hook to return \c TRUE. \returns \c TRUE if any hook wrote to \p
2317 * out_asmctx, or \c FALSE otherwise.
2320 assembly_invoke_asmctx_from_path_hook (const char *absfname
, MonoAssembly
*requesting_assembly
, MonoAssemblyContextKind
*out_asmctx
)
2322 g_assert (absfname
);
2323 g_assert (out_asmctx
);
2324 AssemblyAsmCtxFromPathHook
*hook
;
2326 for (hook
= assembly_asmctx_from_path_hook
; hook
; hook
= hook
->next
) {
2327 *out_asmctx
= MONO_ASMCTX_INDIVIDUAL
;
2328 if (hook
->func (absfname
, requesting_assembly
, hook
->user_data
, out_asmctx
))
2336 free_assembly_asmctx_from_path_hooks (void)
2338 AssemblyAsmCtxFromPathHook
*hook
, *next
;
2340 for (hook
= assembly_asmctx_from_path_hook
; hook
; hook
= next
) {
2347 absolute_dir (const gchar
*filename
)
2358 if (g_path_is_absolute (filename
)) {
2359 part
= g_path_get_dirname (filename
);
2360 res
= g_strconcat (part
, G_DIR_SEPARATOR_S
, (const char*)NULL
);
2365 cwd
= g_get_current_dir ();
2366 mixed
= g_build_filename (cwd
, filename
, (const char*)NULL
);
2367 parts
= g_strsplit (mixed
, G_DIR_SEPARATOR_S
, 0);
2372 for (i
= 0; (part
= parts
[i
]) != NULL
; i
++) {
2373 if (!strcmp (part
, "."))
2376 if (!strcmp (part
, "..")) {
2377 if (list
&& list
->next
) /* Don't remove root */
2378 list
= g_list_delete_link (list
, list
);
2380 list
= g_list_prepend (list
, part
);
2384 result
= g_string_new ("");
2385 list
= g_list_reverse (list
);
2387 /* Ignores last data pointer, which should be the filename */
2388 for (tmp
= list
; tmp
&& tmp
->next
!= NULL
; tmp
= tmp
->next
){
2390 g_string_append_printf (result
, "%s%c", (char *) tmp
->data
,
2395 g_string_free (result
, FALSE
);
2400 return g_strdup (".");
2407 * mono_assembly_open_from_bundle:
2408 * \param filename Filename requested
2409 * \param status return status code
2411 * This routine tries to open the assembly specified by \p filename from the
2412 * defined bundles, if found, returns the MonoImage for it, if not found
2416 mono_assembly_open_from_bundle (MonoAssemblyLoadContext
*alc
, const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
2420 gchar
*lowercase_filename
;
2421 MonoImage
*image
= NULL
;
2422 gboolean is_satellite
= FALSE
;
2424 * we do a very simple search for bundled assemblies: it's not a general
2425 * purpose assembly loading mechanism.
2431 lowercase_filename
= g_utf8_strdown (filename
, -1);
2432 is_satellite
= g_str_has_suffix (lowercase_filename
, ".resources.dll");
2433 g_free (lowercase_filename
);
2434 name
= g_path_get_basename (filename
);
2435 for (i
= 0; !image
&& bundles
[i
]; ++i
) {
2436 if (strcmp (bundles
[i
]->name
, is_satellite
? filename
: name
) == 0) {
2437 image
= mono_image_open_from_data_internal (alc
, (char*)bundles
[i
]->data
, bundles
[i
]->size
, FALSE
, status
, refonly
, FALSE
, name
);
2442 mono_image_addref (image
);
2443 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite
? filename
: name
);
2452 * mono_assembly_open_full:
2453 * \param filename the file to load
2454 * \param status return status code
2455 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2457 * This loads an assembly from the specified \p filename. The \p filename allows
2458 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2459 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2460 * is treated as a local path.
2462 * First, an attempt is made to load the assembly from the bundled executable (for those
2463 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2464 * assembly has been registered as an embedded assembly). If this is not the case, then
2465 * the assembly is loaded from disk using `api:mono_image_open_full`.
2467 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2468 * the assembly is made.
2470 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
2471 * the \c System.Reflection API.
2473 * \returns NULL on error, with the \p status set to an error code, or a pointer
2477 mono_assembly_open_full (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
2480 MONO_ENTER_GC_UNSAFE
;
2481 MonoAssemblyOpenRequest req
;
2482 mono_assembly_request_prepare_open (&req
,
2483 refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
,
2484 mono_domain_default_alc (mono_domain_get ()));
2485 res
= mono_assembly_request_open (filename
, &req
, status
);
2486 MONO_EXIT_GC_UNSAFE
;
2491 assembly_loadfrom_asmctx_from_path (const char *filename
, MonoAssembly
*requesting_assembly
,
2492 gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
) {
2493 if (requesting_assembly
&& mono_asmctx_get_kind (&requesting_assembly
->context
) == MONO_ASMCTX_LOADFROM
) {
2494 if (mono_path_filename_in_basedir (filename
, requesting_assembly
->basedir
)) {
2495 *out_asmctx
= MONO_ASMCTX_LOADFROM
;
2503 mono_assembly_request_open (const char *filename
, const MonoAssemblyOpenRequest
*open_req
,
2504 MonoImageOpenStatus
*status
)
2508 MonoImageOpenStatus def_status
;
2511 gboolean loaded_from_bundle
;
2513 MonoAssemblyLoadRequest load_req
;
2514 /* we will be overwriting the load request's asmctx.*/
2515 memcpy (&load_req
, &open_req
->request
, sizeof (load_req
));
2517 g_return_val_if_fail (filename
!= NULL
, NULL
);
2520 status
= &def_status
;
2521 *status
= MONO_IMAGE_OK
;
2523 if (strncmp (filename
, "file://", 7) == 0) {
2524 GError
*gerror
= NULL
;
2525 gchar
*uri
= (gchar
*) filename
;
2529 * MS allows file://c:/... and fails on file://localhost/c:/...
2530 * They also throw an IndexOutOfRangeException if "file://"
2533 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
2536 uri
= mono_escape_uri_string (tmpuri
);
2537 fname
= g_filename_from_uri (uri
, NULL
, &gerror
);
2540 if (tmpuri
!= filename
)
2543 if (gerror
!= NULL
) {
2544 g_warning ("%s\n", gerror
->message
);
2545 g_error_free (gerror
);
2546 fname
= g_strdup (filename
);
2549 fname
= g_strdup (filename
);
2552 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
,
2553 "Assembly Loader probing location: '%s'.", fname
);
2556 if (!mono_assembly_is_in_gac (fname
)) {
2558 new_fname
= mono_make_shadow_copy (fname
, error
);
2559 if (!is_ok (error
)) {
2560 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2561 "Assembly Loader shadow copy error: %s.", mono_error_get_message (error
));
2562 mono_error_cleanup (error
);
2563 *status
= MONO_IMAGE_IMAGE_INVALID
;
2568 if (load_req
.asmctx
!= MONO_ASMCTX_REFONLY
) {
2569 MonoAssemblyContextKind out_asmctx
;
2570 /* If the path belongs to the appdomain base dir or the
2571 * base dir of the requesting assembly, load the
2572 * assembly in the corresponding asmctx.
2574 if (assembly_invoke_asmctx_from_path_hook (fname
, open_req
->requesting_assembly
, &out_asmctx
))
2575 load_req
.asmctx
= out_asmctx
;
2578 if (load_req
.asmctx
!= MONO_ASMCTX_REFONLY
) {
2579 /* GAC assemblies always in default context or refonly context. */
2580 load_req
.asmctx
= MONO_ASMCTX_DEFAULT
;
2583 if (new_fname
&& new_fname
!= fname
) {
2586 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
,
2587 "Assembly Loader shadow-copied assembly to: '%s'.", fname
);
2592 const gboolean refonly
= load_req
.asmctx
== MONO_ASMCTX_REFONLY
;
2593 /* for LoadFrom(string), LoadFile(string) and Load(byte[]), allow them
2594 * to load problematic images. Not sure if ReflectionOnlyLoad(string)
2595 * and ReflectionOnlyLoadFrom(string) should also be allowed - let's
2598 const gboolean load_from_context
= load_req
.asmctx
== MONO_ASMCTX_LOADFROM
|| load_req
.asmctx
== MONO_ASMCTX_INDIVIDUAL
|| load_req
.asmctx
== MONO_ASMCTX_REFONLY
;
2600 // If VM built with mkbundle
2601 loaded_from_bundle
= FALSE
;
2602 if (bundles
!= NULL
) {
2603 image
= mono_assembly_open_from_bundle (load_req
.alc
, fname
, status
, refonly
);
2604 loaded_from_bundle
= image
!= NULL
;
2608 image
= mono_image_open_a_lot (load_req
.alc
, fname
, status
, refonly
, load_from_context
);
2611 if (*status
== MONO_IMAGE_OK
)
2612 *status
= MONO_IMAGE_ERROR_ERRNO
;
2617 if (load_req
.asmctx
== MONO_ASMCTX_LOADFROM
|| load_req
.asmctx
== MONO_ASMCTX_INDIVIDUAL
) {
2618 MonoAssembly
*redirected_asm
= NULL
;
2619 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2620 if ((redirected_asm
= chain_redirections_loadfrom (load_req
.alc
, image
, &new_status
))) {
2621 mono_image_close (image
);
2622 image
= redirected_asm
->image
;
2623 mono_image_addref (image
); /* so that mono_image_close, below, has something to do */
2624 /* fall thru to if (image->assembly) below */
2625 } else if (new_status
!= MONO_IMAGE_OK
) {
2626 *status
= new_status
;
2627 mono_image_close (image
);
2633 if (image
->assembly
) {
2634 /* We want to return the MonoAssembly that's already loaded,
2635 * but if we're using the strict assembly loader, we also need
2636 * to check that the previously loaded assembly matches the
2637 * predicate. It could be that we previously loaded a
2638 * different version that happens to have the filename that
2639 * we're currently probing. */
2640 if (mono_loader_get_strict_assembly_name_check () &&
2641 load_req
.predicate
&& !load_req
.predicate (image
->assembly
, load_req
.predicate_ud
)) {
2642 mono_image_close (image
);
2646 /* Already loaded by another appdomain */
2647 mono_assembly_invoke_load_hook_internal (load_req
.alc
, image
->assembly
);
2648 mono_image_close (image
);
2650 return image
->assembly
;
2654 ass
= mono_assembly_request_load_from (image
, fname
, &load_req
, status
);
2657 if (!loaded_from_bundle
)
2658 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
,
2659 "Assembly Loader loaded assembly from location: '%s'.", filename
);
2661 mono_config_for_assembly_internal (ass
->image
);
2664 /* Clear the reference added by mono_image_open */
2665 mono_image_close (image
);
2673 free_item (gpointer val
, gpointer user_data
)
2679 * mono_assembly_load_friends:
2680 * \param ass an assembly
2682 * Load the list of friend assemblies that are allowed to access
2683 * the assembly's internal types and members. They are stored as assembly
2684 * names in custom attributes.
2686 * This is an internal method, we need this because when we load mscorlib
2687 * we do not have the internals visible cattr loaded yet,
2688 * so we need to load these after we initialize the runtime.
2690 * LOCKING: Acquires the assemblies lock plus the loader lock.
2693 mono_assembly_load_friends (MonoAssembly
* ass
)
2697 MonoCustomAttrInfo
* attrs
;
2700 if (ass
->friend_assembly_names_inited
)
2703 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2704 mono_error_assert_ok (error
);
2706 mono_assemblies_lock ();
2707 ass
->friend_assembly_names_inited
= TRUE
;
2708 mono_assemblies_unlock ();
2712 mono_assemblies_lock ();
2713 if (ass
->friend_assembly_names_inited
) {
2714 mono_assemblies_unlock ();
2717 mono_assemblies_unlock ();
2721 * We build the list outside the assemblies lock, the worse that can happen
2722 * is that we'll need to free the allocated list.
2724 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2725 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2726 MonoAssemblyName
*aname
;
2728 uint32_t data_length
;
2729 gchar
*data_with_terminator
;
2730 /* Do some sanity checking */
2731 if (!attr
->ctor
|| attr
->ctor
->klass
!= mono_class_try_get_internals_visible_class ())
2733 if (attr
->data_size
< 4)
2735 data
= (const char*)attr
->data
;
2736 /* 0xFF means null string, see custom attr format */
2737 if (data
[0] != 1 || data
[1] != 0 || (data
[2] & 0xFF) == 0xFF)
2739 data_length
= mono_metadata_decode_value (data
+ 2, &data
);
2740 data_with_terminator
= (char *)g_memdup (data
, data_length
+ 1);
2741 data_with_terminator
[data_length
] = 0;
2742 aname
= g_new0 (MonoAssemblyName
, 1);
2743 /*g_print ("friend ass: %s\n", data);*/
2744 if (mono_assembly_name_parse_full (data_with_terminator
, aname
, TRUE
, NULL
, NULL
)) {
2745 list
= g_slist_prepend (list
, aname
);
2749 g_free (data_with_terminator
);
2751 mono_custom_attrs_free (attrs
);
2753 mono_assemblies_lock ();
2754 if (ass
->friend_assembly_names_inited
) {
2755 mono_assemblies_unlock ();
2756 g_slist_foreach (list
, free_item
, NULL
);
2757 g_slist_free (list
);
2760 ass
->friend_assembly_names
= list
;
2762 /* Because of the double checked locking pattern above */
2763 mono_memory_barrier ();
2764 ass
->friend_assembly_names_inited
= TRUE
;
2765 mono_assemblies_unlock ();
2768 struct HasReferenceAssemblyAttributeIterData
{
2773 has_reference_assembly_attribute_iterator (MonoImage
*image
, guint32 typeref_scope_token
, const char *nspace
, const char *name
, guint32 method_token
, gpointer user_data
)
2775 gboolean stop_scanning
= FALSE
;
2776 struct HasReferenceAssemblyAttributeIterData
*iter_data
= (struct HasReferenceAssemblyAttributeIterData
*)user_data
;
2778 if (!strcmp (name
, "ReferenceAssemblyAttribute") && !strcmp (nspace
, "System.Runtime.CompilerServices")) {
2779 /* Note we don't check the assembly name, same as coreCLR. */
2780 iter_data
->has_attr
= TRUE
;
2781 stop_scanning
= TRUE
;
2784 return stop_scanning
;
2788 * mono_assembly_has_reference_assembly_attribute:
2789 * \param assembly a MonoAssembly
2790 * \param error set on error.
2792 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2793 * On error returns FALSE and sets \p error.
2796 mono_assembly_has_reference_assembly_attribute (MonoAssembly
*assembly
, MonoError
*error
)
2798 g_assert (assembly
&& assembly
->image
);
2799 /* .NET Framework appears to ignore the attribute on dynamic
2800 * assemblies, so don't call this function for dynamic assemblies. */
2801 g_assert (!image_is_dynamic (assembly
->image
));
2805 * This might be called during assembly loading, so do everything using the low-level
2809 struct HasReferenceAssemblyAttributeIterData iter_data
= { FALSE
};
2811 mono_assembly_metadata_foreach_custom_attr (assembly
, &has_reference_assembly_attribute_iterator
, &iter_data
);
2813 return iter_data
.has_attr
;
2817 * chain_redirections_loadfrom:
2818 * \param alc AssemblyLoadContext to load into
2819 * \param image a MonoImage that we wanted to load using LoadFrom context
2820 * \param status set if there was an error opening the redirected image
2822 * Check if we need to open a different image instead of the given one for some reason.
2823 * Returns NULL and sets status to \c MONO_IMAGE_OK if the given image was good.
2825 * Otherwise returns the assembly that we opened instead or sets status if
2826 * there was a problem opening the redirected image.
2830 chain_redirections_loadfrom (MonoAssemblyLoadContext
*alc
, MonoImage
*image
, MonoImageOpenStatus
*out_status
)
2832 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
2833 MonoAssembly
*redirected
= NULL
;
2835 redirected
= mono_assembly_binding_applies_to_image (alc
, image
, &status
);
2836 if (redirected
|| status
!= MONO_IMAGE_OK
) {
2837 *out_status
= status
;
2841 redirected
= mono_problematic_image_reprobe (alc
, image
, &status
);
2842 if (redirected
|| status
!= MONO_IMAGE_OK
) {
2843 *out_status
= status
;
2847 *out_status
= MONO_IMAGE_OK
;
2852 * mono_assembly_binding_applies_to_image:
2853 * \param alc AssemblyLoadContext to load into
2854 * \param image The image whose assembly name we should check
2855 * \param status sets on error;
2857 * Get the \c MonoAssemblyName from the given \p image metadata and apply binding redirects to it.
2858 * If the resulting name is different from the name in the image, load that \c MonoAssembly instead
2860 * \returns the loaded \c MonoAssembly, or NULL if no binding redirection applied.
2864 mono_assembly_binding_applies_to_image (MonoAssemblyLoadContext
*alc
, MonoImage
* image
, MonoImageOpenStatus
*status
)
2866 g_assert (status
!= NULL
);
2868 /* This is a "fun" one now.
2869 * For LoadFrom ("/basedir/some.dll") or LoadFile("/basedir/some.dll") or Load(byte[])),
2870 * apparently what we're meant to do is:
2871 * 1. probe the assembly name from some.dll (or the byte array)
2872 * 2. apply binding redirects
2873 * 3. If we get some other different name, drop this image and use
2874 * the binding redirected name to probe.
2875 * 4. Return the new assembly.
2877 MonoAssemblyName probed_aname
, dest_name
;
2878 if (!mono_assembly_fill_assembly_name_full (image
, &probed_aname
, TRUE
)) {
2879 if (*status
== MONO_IMAGE_OK
)
2880 *status
= MONO_IMAGE_IMAGE_INVALID
;
2883 MonoAssembly
*result_ass
= NULL
;
2884 MonoAssemblyName
*result_name
= &probed_aname
;
2885 result_name
= mono_assembly_apply_binding (result_name
, &dest_name
);
2886 if (result_name
!= &probed_aname
&& !mono_assembly_names_equal (result_name
, &probed_aname
)) {
2887 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
)) {
2888 char *probed_fullname
= mono_stringify_assembly_name (&probed_aname
);
2889 char *result_fullname
= mono_stringify_assembly_name (result_name
);
2890 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Request to load from %s in (%s) remapped to %s", probed_fullname
, image
->name
, result_fullname
);
2891 g_free (probed_fullname
);
2892 g_free (result_fullname
);
2894 const char *new_basedir
= NULL
; /* FIXME: null? - do a test of this */
2895 MonoAssemblyContextKind new_asmctx
= MONO_ASMCTX_DEFAULT
; /* FIXME: default? or? */
2896 MonoAssembly
*new_requesting
= NULL
; /* this seems okay */
2897 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2899 MonoAssemblyByNameRequest new_req
;
2900 mono_assembly_request_prepare_byname (&new_req
, new_asmctx
, alc
);
2901 new_req
.requesting_assembly
= new_requesting
;
2902 new_req
.basedir
= new_basedir
;
2903 result_ass
= mono_assembly_request_byname (result_name
, &new_req
, &new_status
);
2905 if (result_ass
&& new_status
== MONO_IMAGE_OK
) {
2906 g_assert (result_ass
->image
->assembly
!= NULL
);
2908 *status
= new_status
;
2911 mono_assembly_name_free_internal (&probed_aname
);
2916 * mono_problematic_image_reprobe:
2917 * \param alc AssemblyLoadContex to load into
2918 * \param image A MonoImage
2919 * \param status set on error
2921 * If the given image is problematic for mono (see image.c), then try to load
2922 * by assembly name in the default context (which should succeed with Mono's
2923 * own implementations of those assemblies).
2925 * Returns NULL and sets status to MONO_IMAGE_OK if no redirect is needed.
2927 * Otherwise returns the assembly we were redirected to, or NULL and sets a
2928 * non-ok status on failure.
2930 * IMPORTANT NOTE: Don't call this if \c image was found by probing the search
2931 * path, you will end up in a loop and a stack overflow.
2934 mono_problematic_image_reprobe (MonoAssemblyLoadContext
*alc
, MonoImage
*image
, MonoImageOpenStatus
*status
)
2936 g_assert (status
!= NULL
);
2938 if (G_LIKELY (!mono_is_problematic_image (image
))) {
2939 *status
= MONO_IMAGE_OK
;
2942 MonoAssemblyName probed_aname
;
2943 if (!mono_assembly_fill_assembly_name_full (image
, &probed_aname
, TRUE
)) {
2944 *status
= MONO_IMAGE_IMAGE_INVALID
;
2947 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
)) {
2948 char *probed_fullname
= mono_stringify_assembly_name (&probed_aname
);
2949 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Requested to load from problematic image %s, probing instead for assembly with name %s", image
->name
, probed_fullname
);
2950 g_free (probed_fullname
);
2952 const char *new_basedir
= NULL
;
2953 MonoAssemblyContextKind new_asmctx
= MONO_ASMCTX_DEFAULT
;
2954 MonoAssembly
*new_requesting
= NULL
;
2955 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2956 MonoAssemblyByNameRequest new_req
;
2957 mono_assembly_request_prepare_byname (&new_req
, new_asmctx
, alc
);
2958 new_req
.requesting_assembly
= new_requesting
;
2959 new_req
.basedir
= new_basedir
;
2960 // Note: this interacts with mono_image_open_a_lot (). If the path from
2961 // which we tried to load the problematic image is among the probing
2962 // paths, the MonoImage will be in the hash of loaded images and we
2963 // would just get it back again here, except for the code there that
2964 // mitigates the situation. Instead
2965 MonoAssembly
*result_ass
= mono_assembly_request_byname (&probed_aname
, &new_req
, &new_status
);
2967 if (! (result_ass
&& new_status
== MONO_IMAGE_OK
)) {
2968 *status
= new_status
;
2970 mono_assembly_name_free_internal (&probed_aname
);
2974 * mono_assembly_open:
2975 * \param filename Opens the assembly pointed out by this name
2976 * \param status return status code
2978 * This loads an assembly from the specified \p filename. The \p filename allows
2979 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2980 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2981 * is treated as a local path.
2983 * First, an attempt is made to load the assembly from the bundled executable (for those
2984 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2985 * assembly has been registered as an embedded assembly). If this is not the case, then
2986 * the assembly is loaded from disk using `api:mono_image_open_full`.
2988 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2989 * the assembly is made.
2991 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2992 * assembly or NULL on error. Details about the error are stored in the
2993 * \p status variable.
2996 mono_assembly_open (const char *filename
, MonoImageOpenStatus
*status
)
2999 MONO_ENTER_GC_UNSAFE
;
3000 MonoAssemblyOpenRequest req
;
3001 mono_assembly_request_prepare_open (&req
, MONO_ASMCTX_DEFAULT
, mono_domain_default_alc (mono_domain_get ()));
3002 res
= mono_assembly_request_open (filename
, &req
, status
);
3003 MONO_EXIT_GC_UNSAFE
;
3008 * mono_assembly_load_from_full:
3009 * \param image Image to load the assembly from
3010 * \param fname assembly name to associate with the assembly
3011 * \param status returns the status condition
3012 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
3014 * If the provided \p image has an assembly reference, it will process the given
3015 * image as an assembly with the given name.
3017 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
3019 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
3020 * set to \c MONO_IMAGE_OK; or NULL on error.
3022 * If there is an error loading the assembly the \p status will indicate the
3023 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
3024 * image did not contain an assembly reference table.
3027 mono_assembly_load_from_full (MonoImage
*image
, const char*fname
,
3028 MonoImageOpenStatus
*status
, gboolean refonly
)
3031 MONO_ENTER_GC_UNSAFE
;
3032 MonoAssemblyLoadRequest req
;
3033 MonoImageOpenStatus def_status
;
3035 status
= &def_status
;
3036 mono_assembly_request_prepare_load (&req
, refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
, mono_domain_default_alc (mono_domain_get ()));
3037 res
= mono_assembly_request_load_from (image
, fname
, &req
, status
);
3038 MONO_EXIT_GC_UNSAFE
;
3043 mono_assembly_request_load_from (MonoImage
*image
, const char *fname
,
3044 const MonoAssemblyLoadRequest
*req
,
3045 MonoImageOpenStatus
*status
)
3047 MonoAssemblyContextKind asmctx
;
3048 MonoAssemblyCandidatePredicate predicate
;
3051 MonoAssembly
*ass
, *ass2
;
3054 g_assert (status
!= NULL
);
3056 asmctx
= req
->asmctx
;
3057 predicate
= req
->predicate
;
3058 user_data
= req
->predicate_ud
;
3060 if (!image
->tables
[MONO_TABLE_ASSEMBLY
].rows
) {
3061 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
3062 *status
= MONO_IMAGE_IMAGE_INVALID
;
3066 #if defined (HOST_WIN32)
3071 tmp_fn
= g_strdup (fname
);
3072 for (i
= strlen (tmp_fn
) - 1; i
>= 0; i
--) {
3073 if (tmp_fn
[i
] == '/')
3077 base_dir
= absolute_dir (tmp_fn
);
3081 base_dir
= absolute_dir (fname
);
3085 * Create assembly struct, and enter it into the assembly cache
3087 ass
= g_new0 (MonoAssembly
, 1);
3088 ass
->basedir
= base_dir
;
3089 ass
->context
.kind
= asmctx
;
3092 MONO_PROFILER_RAISE (assembly_loading
, (ass
));
3094 mono_assembly_fill_assembly_name (image
, &ass
->aname
);
3096 if (mono_defaults
.corlib
&& strcmp (ass
->aname
.name
, MONO_ASSEMBLY_CORLIB_NAME
) == 0) {
3097 // MS.NET doesn't support loading other mscorlibs
3100 mono_image_addref (mono_defaults
.corlib
);
3101 *status
= MONO_IMAGE_OK
;
3102 return mono_defaults
.corlib
->assembly
;
3105 /* Add a non-temporary reference because of ass->image */
3106 mono_image_addref (image
);
3108 mono_trace (G_LOG_LEVEL_DEBUG
, 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
);
3111 * The load hooks might take locks so we can't call them while holding the
3114 if (ass
->aname
.name
&& asmctx
!= MONO_ASMCTX_INDIVIDUAL
) {
3115 /* 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?) */
3116 ass2
= mono_assembly_invoke_search_hook_internal (req
->alc
, NULL
, &ass
->aname
, asmctx
== MONO_ASMCTX_REFONLY
, FALSE
);
3118 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
);
3121 mono_image_close (image
);
3122 *status
= MONO_IMAGE_OK
;
3127 /* We need to check for ReferenceAssemblyAttribute before we
3128 * mark the assembly as loaded and before we fire the load
3129 * hook. Otherwise mono_domain_fire_assembly_load () in
3130 * appdomain.c will cache a mapping from the assembly name to
3131 * this image and we won't be able to look for a different
3134 if (asmctx
!= MONO_ASMCTX_REFONLY
) {
3135 ERROR_DECL (refasm_error
);
3136 if (mono_assembly_has_reference_assembly_attribute (ass
, refasm_error
)) {
3137 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass
->aname
.name
, image
->name
);
3140 mono_image_close (image
);
3141 *status
= MONO_IMAGE_IMAGE_INVALID
;
3144 mono_error_cleanup (refasm_error
);
3147 if (predicate
&& !predicate (ass
, user_data
)) {
3148 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Predicate returned FALSE, skipping '%s' (%s)\n", ass
->aname
.name
, image
->name
);
3151 mono_image_close (image
);
3152 *status
= MONO_IMAGE_IMAGE_INVALID
;
3156 mono_assemblies_lock ();
3158 /* If an assembly is loaded into an individual context, always return a
3159 * new MonoAssembly, even if another assembly with the same name has
3160 * already been loaded.
3162 if (image
->assembly
&& asmctx
!= MONO_ASMCTX_INDIVIDUAL
) {
3164 * This means another thread has already loaded the assembly, but not yet
3165 * called the load hooks so the search hook can't find the assembly.
3167 mono_assemblies_unlock ();
3168 ass2
= image
->assembly
;
3171 mono_image_close (image
);
3172 *status
= MONO_IMAGE_OK
;
3176 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Prepared to set up assembly '%s' (%s)", ass
->aname
.name
, image
->name
);
3178 /* If asmctx is INDIVIDUAL, image->assembly might not be NULL, so don't
3180 if (image
->assembly
== NULL
)
3181 image
->assembly
= ass
;
3183 loaded_assemblies
= g_list_prepend (loaded_assemblies
, ass
);
3184 mono_assemblies_unlock ();
3187 if (m_image_is_module_handle (image
))
3188 mono_image_fixup_vtable (image
);
3191 mono_assembly_invoke_load_hook_internal (req
->alc
, ass
);
3193 MONO_PROFILER_RAISE (assembly_loaded
, (ass
));
3199 * mono_assembly_load_from:
3200 * \param image Image to load the assembly from
3201 * \param fname assembly name to associate with the assembly
3202 * \param status return status code
3204 * If the provided \p image has an assembly reference, it will process the given
3205 * image as an assembly with the given name.
3207 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
3209 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
3210 * \p refonly parameter set to FALSE.
3211 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
3212 * set to \c MONO_IMAGE_OK; or NULL on error.
3214 * If there is an error loading the assembly the \p status will indicate the
3215 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
3216 * image did not contain an assembly reference table.
3220 mono_assembly_load_from (MonoImage
*image
, const char *fname
,
3221 MonoImageOpenStatus
*status
)
3224 MONO_ENTER_GC_UNSAFE
;
3225 MonoAssemblyLoadRequest req
;
3226 MonoImageOpenStatus def_status
;
3228 status
= &def_status
;
3229 mono_assembly_request_prepare_load (&req
, MONO_ASMCTX_DEFAULT
, mono_domain_default_alc (mono_domain_get ()));
3230 res
= mono_assembly_request_load_from (image
, fname
, &req
, status
);
3231 MONO_EXIT_GC_UNSAFE
;
3236 * mono_assembly_name_free_internal:
3237 * \param aname assembly name to free
3239 * Frees the provided assembly name object.
3240 * (it does not frees the object itself, only the name members).
3243 mono_assembly_name_free_internal (MonoAssemblyName
*aname
)
3245 MONO_REQ_GC_UNSAFE_MODE
;
3250 g_free ((void *) aname
->name
);
3251 g_free ((void *) aname
->culture
);
3252 g_free ((void *) aname
->hash_value
);
3253 g_free ((guint8
*) aname
->public_key
);
3257 parse_public_key (const gchar
*key
, gchar
** pubkey
, gboolean
*is_ecma
)
3260 gchar header
[16], val
, *arr
, *endp
;
3261 gint i
, j
, offset
, bitlen
, keylen
, pkeylen
;
3263 //both pubkey and is_ecma are required arguments
3264 g_assert (pubkey
&& is_ecma
);
3266 keylen
= strlen (key
) >> 1;
3270 /* allow the ECMA standard key */
3271 if (strcmp (key
, "00000000000000000400000000000000") == 0) {
3277 val
= g_ascii_xdigit_value (key
[0]) << 4;
3278 val
|= g_ascii_xdigit_value (key
[1]);
3283 val
= g_ascii_xdigit_value (key
[24]);
3284 val
|= g_ascii_xdigit_value (key
[25]);
3296 /* We need the first 16 bytes
3297 * to check whether this key is valid or not */
3298 pkeylen
= strlen (pkey
) >> 1;
3302 for (i
= 0, j
= 0; i
< 16; i
++) {
3303 header
[i
] = g_ascii_xdigit_value (pkey
[j
++]) << 4;
3304 header
[i
] |= g_ascii_xdigit_value (pkey
[j
++]);
3307 if (header
[0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
3308 header
[1] != 0x02 || /* Version (0x02) */
3309 header
[2] != 0x00 || /* Reserved (word) */
3310 header
[3] != 0x00 ||
3311 (guint
)(read32 (header
+ 8)) != 0x31415352) /* DWORD magic = RSA1 */
3314 /* Based on this length, we _should_ be able to know if the length is right */
3315 bitlen
= read32 (header
+ 12) >> 3;
3316 if ((bitlen
+ 16 + 4) != pkeylen
)
3319 arr
= (gchar
*)g_malloc (keylen
+ 4);
3320 /* Encode the size of the blob */
3321 mono_metadata_encode_value (keylen
, &arr
[0], &endp
);
3322 offset
= (gint
)(endp
-arr
);
3324 for (i
= offset
, j
= 0; i
< keylen
+ offset
; i
++) {
3325 arr
[i
] = g_ascii_xdigit_value (key
[j
++]) << 4;
3326 arr
[i
] |= g_ascii_xdigit_value (key
[j
++]);
3335 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
)
3339 gchar
*pkeyptr
, *encoded
, tok
[8];
3341 memset (aname
, 0, sizeof (MonoAssemblyName
));
3344 #ifdef ENABLE_NETCORE
3351 const char *s
= version
;
3353 for (i
= 0; i
< 4; ++i
) {
3354 int n
= sscanf (s
, "%u%n", &parts
[i
], &part_len
);
3357 if (parts
[i
] < 0 || parts
[i
] > 65535)
3359 if (i
< 2 && parts
[i
] == 65535)
3373 if (version_parts
< 2 || version_parts
> 4)
3375 aname
->major
= parts
[0];
3376 aname
->minor
= parts
[1];
3377 if (version_parts
>= 3)
3378 aname
->build
= parts
[2];
3381 if (version_parts
== 4)
3382 aname
->revision
= parts
[3];
3384 aname
->revision
= -1;
3386 gint major
, minor
, build
, revision
;
3388 version_parts
= sscanf (version
, "%u.%u.%u.%u", &major
, &minor
, &build
, &revision
);
3389 if (version_parts
< 2 || version_parts
> 4)
3392 /* FIXME: we should set build & revision to -1 (instead of 0)
3393 if these are not set in the version string. That way, later on,
3394 we can still determine if these were specified. */
3395 aname
->major
= major
;
3396 aname
->minor
= minor
;
3397 if (version_parts
>= 3)
3398 aname
->build
= build
;
3401 if (version_parts
== 4)
3402 aname
->revision
= revision
;
3404 aname
->revision
= 0;
3408 aname
->flags
= flags
;
3410 aname
->name
= g_strdup (name
);
3413 if (g_ascii_strcasecmp (culture
, "neutral") == 0)
3414 aname
->culture
= g_strdup ("");
3416 aname
->culture
= g_strdup (culture
);
3419 if (token
&& strncmp (token
, "null", 4) != 0) {
3422 /* the constant includes the ending NULL, hence the -1 */
3423 if (strlen (token
) != (MONO_PUBLIC_KEY_TOKEN_LENGTH
- 1)) {
3424 mono_assembly_name_free_internal (aname
);
3427 lower
= g_ascii_strdown (token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3428 g_strlcpy ((char*)aname
->public_key_token
, lower
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3433 gboolean is_ecma
= FALSE
;
3435 if (strcmp (key
, "null") == 0 || !parse_public_key (key
, &pkey
, &is_ecma
)) {
3436 mono_assembly_name_free_internal (aname
);
3441 g_assert (pkey
== NULL
);
3442 aname
->public_key
= NULL
;
3443 g_strlcpy ((gchar
*)aname
->public_key_token
, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3447 len
= mono_metadata_decode_blob_size ((const gchar
*) pkey
, (const gchar
**) &pkeyptr
);
3448 // We also need to generate the key token
3449 mono_digest_get_public_token ((guchar
*) tok
, (guint8
*) pkeyptr
, len
);
3450 encoded
= encode_public_tok ((guchar
*) tok
, 8);
3451 g_strlcpy ((gchar
*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3454 if (save_public_key
)
3455 aname
->public_key
= (guint8
*) pkey
;
3464 parse_assembly_directory_name (const char *name
, const char *dirname
, MonoAssemblyName
*aname
)
3469 parts
= g_strsplit (dirname
, "_", 3);
3470 if (!parts
|| !parts
[0] || !parts
[1] || !parts
[2]) {
3475 res
= build_assembly_name (name
, parts
[0], parts
[1], parts
[2], NULL
, 0, 0, aname
, FALSE
);
3481 split_key_value (const gchar
*pair
, gchar
**key
, guint32
*keylen
, gchar
**value
)
3483 char *eqsign
= (char*)strchr (pair
, '=');
3491 *key
= (gchar
*)pair
;
3492 *keylen
= eqsign
- *key
;
3493 while (*keylen
> 0 && g_ascii_isspace ((*key
) [*keylen
- 1]))
3495 *value
= g_strstrip (eqsign
+ 1);
3500 mono_assembly_name_parse_full (const char *name
, MonoAssemblyName
*aname
, gboolean save_public_key
, gboolean
*is_version_defined
, gboolean
*is_token_defined
)
3504 gchar
*version
= NULL
;
3506 gchar
*culture
= NULL
;
3508 gchar
*token
= NULL
;
3512 gchar
*retargetable
= NULL
;
3513 gchar
*retargetable_uq
;
3517 gchar
*value
, *part_name
;
3518 guint32 part_name_len
;
3521 gboolean version_defined
;
3522 gboolean token_defined
;
3524 guint32 arch
= MONO_PROCESSOR_ARCHITECTURE_NONE
;
3526 if (!is_version_defined
)
3527 is_version_defined
= &version_defined
;
3528 *is_version_defined
= FALSE
;
3529 if (!is_token_defined
)
3530 is_token_defined
= &token_defined
;
3531 *is_token_defined
= FALSE
;
3533 parts
= tmp
= g_strsplit (name
, ",", 6);
3534 if (!tmp
|| !*tmp
) {
3535 goto cleanup_and_fail
;
3538 dllname
= g_strstrip (*tmp
);
3539 // Simple name cannot be empty
3541 goto cleanup_and_fail
;
3543 // Characters /, :, and \ not allowed in simple names
3545 gchar tmp_char
= *dllname
;
3546 if (tmp_char
== '/' || tmp_char
== ':' || tmp_char
== '\\')
3547 goto cleanup_and_fail
;
3555 if (!split_key_value (g_strstrip (*tmp
), &part_name
, &part_name_len
, &value
))
3556 goto cleanup_and_fail
;
3558 if (part_name_len
== 7 && !g_ascii_strncasecmp (part_name
, "Version", part_name_len
)) {
3559 *is_version_defined
= TRUE
;
3561 if (strlen (version
) == 0) {
3562 goto cleanup_and_fail
;
3568 if (part_name_len
== 7 && !g_ascii_strncasecmp (part_name
, "Culture", part_name_len
)) {
3570 if (strlen (culture
) == 0) {
3571 goto cleanup_and_fail
;
3577 if (part_name_len
== 14 && !g_ascii_strncasecmp (part_name
, "PublicKeyToken", part_name_len
)) {
3578 *is_token_defined
= TRUE
;
3580 if (strlen (token
) == 0) {
3581 goto cleanup_and_fail
;
3587 if (part_name_len
== 9 && !g_ascii_strncasecmp (part_name
, "PublicKey", part_name_len
)) {
3589 if (strlen (key
) == 0) {
3590 goto cleanup_and_fail
;
3596 if (part_name_len
== 12 && !g_ascii_strncasecmp (part_name
, "Retargetable", part_name_len
)) {
3597 retargetable
= value
;
3598 retargetable_uq
= unquote (retargetable
);
3599 if (retargetable_uq
!= NULL
)
3600 retargetable
= retargetable_uq
;
3602 if (!g_ascii_strcasecmp (retargetable
, "yes")) {
3603 flags
|= ASSEMBLYREF_RETARGETABLE_FLAG
;
3604 } else if (g_ascii_strcasecmp (retargetable
, "no")) {
3605 g_free (retargetable_uq
);
3606 goto cleanup_and_fail
;
3609 g_free (retargetable_uq
);
3614 if (part_name_len
== 21 && !g_ascii_strncasecmp (part_name
, "ProcessorArchitecture", part_name_len
)) {
3616 procarch_uq
= unquote (procarch
);
3617 if (procarch_uq
!= NULL
)
3618 procarch
= procarch_uq
;
3620 if (!g_ascii_strcasecmp (procarch
, "MSIL"))
3621 arch
= MONO_PROCESSOR_ARCHITECTURE_MSIL
;
3622 else if (!g_ascii_strcasecmp (procarch
, "X86"))
3623 arch
= MONO_PROCESSOR_ARCHITECTURE_X86
;
3624 else if (!g_ascii_strcasecmp (procarch
, "IA64"))
3625 arch
= MONO_PROCESSOR_ARCHITECTURE_IA64
;
3626 else if (!g_ascii_strcasecmp (procarch
, "AMD64"))
3627 arch
= MONO_PROCESSOR_ARCHITECTURE_AMD64
;
3628 else if (!g_ascii_strcasecmp (procarch
, "ARM"))
3629 arch
= MONO_PROCESSOR_ARCHITECTURE_ARM
;
3631 g_free (procarch_uq
);
3632 goto cleanup_and_fail
;
3635 #ifdef ENABLE_NETCORE
3639 g_free (procarch_uq
);
3644 goto cleanup_and_fail
;
3647 /* if retargetable flag is set, then we must have a fully qualified name */
3648 if (retargetable
!= NULL
&& (version
== NULL
|| culture
== NULL
|| (key
== NULL
&& token
== NULL
))) {
3649 goto cleanup_and_fail
;
3652 dllname_uq
= unquote (dllname
);
3653 version_uq
= unquote (version
);
3654 culture_uq
= unquote (culture
);
3655 token_uq
= unquote (token
);
3656 key_uq
= unquote (key
);
3658 res
= build_assembly_name (
3659 dllname_uq
== NULL
? dllname
: dllname_uq
,
3660 version_uq
== NULL
? version
: version_uq
,
3661 culture_uq
== NULL
? culture
: culture_uq
,
3662 token_uq
== NULL
? token
: token_uq
,
3663 key_uq
== NULL
? key
: key_uq
,
3664 flags
, arch
, aname
, save_public_key
);
3666 g_free (dllname_uq
);
3667 g_free (version_uq
);
3668 g_free (culture_uq
);
3681 unquote (const char *str
)
3689 slen
= strlen (str
);
3693 if (*str
!= '\'' && *str
!= '\"')
3696 end
= str
+ slen
- 1;
3700 return g_strndup (str
+ 1, slen
- 2);
3704 * mono_assembly_name_parse:
3705 * \param name name to parse
3706 * \param aname the destination assembly name
3708 * Parses an assembly qualified type name and assigns the name,
3709 * version, culture and token to the provided assembly name object.
3711 * \returns TRUE if the name could be parsed.
3714 mono_assembly_name_parse (const char *name
, MonoAssemblyName
*aname
)
3716 return mono_assembly_name_parse_full (name
, aname
, FALSE
, NULL
, NULL
);
3720 * mono_assembly_name_new:
3721 * \param name name to parse
3723 * Allocate a new \c MonoAssemblyName and fill its values from the
3726 * \returns a newly allocated structure or NULL if there was any failure.
3729 mono_assembly_name_new (const char *name
)
3731 MonoAssemblyName
*result
= NULL
;
3732 MONO_ENTER_GC_UNSAFE
;
3733 MonoAssemblyName
*aname
= g_new0 (MonoAssemblyName
, 1);
3734 if (mono_assembly_name_parse (name
, aname
))
3738 MONO_EXIT_GC_UNSAFE
;
3743 * mono_assembly_name_get_name:
3746 mono_assembly_name_get_name (MonoAssemblyName
*aname
)
3748 const char *result
= NULL
;
3749 MONO_ENTER_GC_UNSAFE
;
3750 result
= aname
->name
;
3751 MONO_EXIT_GC_UNSAFE
;
3756 * mono_assembly_name_get_culture:
3759 mono_assembly_name_get_culture (MonoAssemblyName
*aname
)
3761 const char *result
= NULL
;
3762 MONO_ENTER_GC_UNSAFE
;
3763 result
= aname
->culture
;
3764 MONO_EXIT_GC_UNSAFE
;
3769 * mono_assembly_name_get_pubkeytoken:
3772 mono_assembly_name_get_pubkeytoken (MonoAssemblyName
*aname
)
3774 if (aname
->public_key_token
[0])
3775 return aname
->public_key_token
;
3780 * mono_assembly_name_get_version:
3783 mono_assembly_name_get_version (MonoAssemblyName
*aname
, uint16_t *minor
, uint16_t *build
, uint16_t *revision
)
3786 *minor
= aname
->minor
;
3788 *build
= aname
->build
;
3790 *revision
= aname
->revision
;
3791 return aname
->major
;
3795 mono_assembly_name_culture_is_neutral (const MonoAssemblyName
*aname
)
3797 return (!aname
->culture
|| aname
->culture
[0] == 0);
3800 static MonoAssembly
*
3801 probe_for_partial_name (const char *basepath
, const char *fullname
, MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
, MonoImageOpenStatus
*status
)
3803 gchar
*fullpath
= NULL
;
3805 const char* direntry
;
3806 MonoAssemblyName gac_aname
;
3807 gint major
=-1, minor
=0, build
=0, revision
=0;
3808 gboolean exact_version
;
3810 dirhandle
= g_dir_open (basepath
, 0, NULL
);
3814 exact_version
= (aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0;
3816 while ((direntry
= g_dir_read_name (dirhandle
))) {
3817 gboolean match
= TRUE
;
3819 if(!parse_assembly_directory_name (aname
->name
, direntry
, &gac_aname
))
3822 if (aname
->culture
!= NULL
&& strcmp (aname
->culture
, gac_aname
.culture
) != 0)
3825 if (match
&& strlen ((char*)aname
->public_key_token
) > 0 &&
3826 !mono_public_tokens_are_equal (aname
->public_key_token
, gac_aname
.public_key_token
))
3830 if (exact_version
) {
3831 match
= (aname
->major
== gac_aname
.major
&& aname
->minor
== gac_aname
.minor
&&
3832 aname
->build
== gac_aname
.build
&& aname
->revision
== gac_aname
.revision
);
3834 else if (gac_aname
.major
< major
)
3836 else if (gac_aname
.major
== major
) {
3837 if (gac_aname
.minor
< minor
)
3839 else if (gac_aname
.minor
== minor
) {
3840 if (gac_aname
.build
< build
)
3842 else if (gac_aname
.build
== build
&& gac_aname
.revision
<= revision
)
3849 major
= gac_aname
.major
;
3850 minor
= gac_aname
.minor
;
3851 build
= gac_aname
.build
;
3852 revision
= gac_aname
.revision
;
3854 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, basepath
, direntry
, fullname
, (const char*)NULL
);
3857 mono_assembly_name_free_internal (&gac_aname
);
3860 g_dir_close (dirhandle
);
3862 if (fullpath
== NULL
)
3865 MonoAssemblyOpenRequest req
;
3866 mono_assembly_request_prepare_open (&req
, MONO_ASMCTX_DEFAULT
, alc
);
3867 MonoAssembly
*res
= mono_assembly_request_open (fullpath
, &req
, status
);
3874 * mono_assembly_load_with_partial_name:
3875 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
3876 * \param status return status code
3878 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
3879 * so it might contain a qualified type name, version, culture and token.
3881 * This will load the assembly from the file whose name is derived from the assembly name
3882 * by appending the \c .dll extension.
3884 * The assembly is loaded from either one of the extra Global Assembly Caches specified
3885 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
3886 * if that fails from the GAC.
3888 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
3891 mono_assembly_load_with_partial_name (const char *name
, MonoImageOpenStatus
*status
)
3893 MonoAssembly
*result
;
3894 MONO_ENTER_GC_UNSAFE
;
3895 MonoImageOpenStatus def_status
;
3897 status
= &def_status
;
3898 result
= mono_assembly_load_with_partial_name_internal (name
, mono_domain_default_alc (mono_domain_get ()), status
);
3899 MONO_EXIT_GC_UNSAFE
;
3904 mono_assembly_load_with_partial_name_internal (const char *name
, MonoAssemblyLoadContext
*alc
, MonoImageOpenStatus
*status
)
3908 MonoAssemblyName
*aname
, base_name
;
3909 MonoAssemblyName mapped_aname
;
3911 MONO_REQ_GC_UNSAFE_MODE
;
3913 g_assert (status
!= NULL
);
3915 memset (&base_name
, 0, sizeof (MonoAssemblyName
));
3918 if (!mono_assembly_name_parse (name
, aname
))
3922 * If no specific version has been requested, make sure we load the
3923 * correct version for system assemblies.
3925 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) == 0)
3926 aname
= mono_assembly_remap_version (aname
, &mapped_aname
);
3928 res
= mono_assembly_loaded_internal (alc
, aname
, FALSE
);
3930 mono_assembly_name_free_internal (aname
);
3934 res
= invoke_assembly_preload_hook (alc
, aname
, assemblies_path
);
3936 res
->in_gac
= FALSE
;
3937 mono_assembly_name_free_internal (aname
);
3942 gchar
*fullname
, *gacpath
;
3944 fullname
= g_strdup_printf ("%s.dll", aname
->name
);
3946 if (extra_gac_paths
) {
3947 paths
= extra_gac_paths
;
3948 while (!res
&& *paths
) {
3949 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", aname
->name
, (const char*)NULL
);
3950 res
= probe_for_partial_name (gacpath
, fullname
, alc
, aname
, status
);
3959 mono_assembly_name_free_internal (aname
);
3963 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), "mono", "gac", aname
->name
, (const char*)NULL
);
3964 res
= probe_for_partial_name (gacpath
, fullname
, alc
, aname
, status
);
3972 mono_assembly_name_free_internal (aname
);
3975 res
= mono_try_assembly_resolve (alc
, name
, NULL
, FALSE
, error
);
3976 if (!is_ok (error
)) {
3977 mono_error_cleanup (error
);
3978 if (*status
== MONO_IMAGE_OK
)
3979 *status
= MONO_IMAGE_IMAGE_INVALID
;
3987 mono_assembly_is_in_gac (const gchar
*filename
)
3990 const gchar
*rootdir
;
3994 if (filename
== NULL
)
3997 for (paths
= extra_gac_paths
; paths
&& *paths
; paths
++) {
3998 if (strstr (*paths
, filename
) != *paths
)
4001 gp
= (gchar
*) (filename
+ strlen (*paths
));
4002 if (*gp
!= G_DIR_SEPARATOR
)
4005 if (strncmp (gp
, "lib", 3))
4008 if (*gp
!= G_DIR_SEPARATOR
)
4011 if (strncmp (gp
, "mono", 4))
4014 if (*gp
!= G_DIR_SEPARATOR
)
4017 if (strncmp (gp
, "gac", 3))
4020 if (*gp
!= G_DIR_SEPARATOR
)
4026 rootdir
= mono_assembly_getrootdir ();
4027 if (strstr (filename
, rootdir
) != filename
)
4030 gp
= (gchar
*) (filename
+ strlen (rootdir
));
4031 if (*gp
!= G_DIR_SEPARATOR
)
4034 if (strncmp (gp
, "mono", 4))
4037 if (*gp
!= G_DIR_SEPARATOR
)
4040 if (strncmp (gp
, "gac", 3))
4043 if (*gp
!= G_DIR_SEPARATOR
)
4048 #endif /* DISABLE_GAC */
4052 mono_assembly_load_publisher_policy (MonoAssemblyName
*aname
)
4054 MonoImage
*image
= NULL
;
4056 gchar
*filename
, *pname
, *name
, *culture
, *version
, *fullpath
, *subpath
;
4060 if (strstr (aname
->name
, ".dll")) {
4061 len
= strlen (aname
->name
) - 4;
4062 name
= (gchar
*)g_malloc (len
+ 1);
4063 memcpy (name
, aname
->name
, len
);
4066 name
= g_strdup (aname
->name
);
4069 culture
= g_utf8_strdown (aname
->culture
, -1);
4071 culture
= g_strdup ("");
4073 pname
= g_strdup_printf ("policy.%d.%d.%s", aname
->major
, aname
->minor
, name
);
4074 version
= g_strdup_printf ("0.0.0.0_%s_%s", culture
, aname
->public_key_token
);
4078 filename
= g_strconcat (pname
, ".dll", (const char*)NULL
);
4079 subpath
= g_build_path (G_DIR_SEPARATOR_S
, pname
, version
, filename
, (const char*)NULL
);
4085 if (extra_gac_paths
) {
4086 paths
= extra_gac_paths
;
4087 while (!image
&& *paths
) {
4088 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
,
4089 "lib", "mono", "gac", subpath
, (const char*)NULL
);
4090 image
= mono_image_open (fullpath
, NULL
);
4101 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
4102 "mono", "gac", subpath
, NULL
);
4103 image
= mono_image_open (fullpath
, NULL
);
4111 static MonoAssemblyName
*
4112 mono_assembly_bind_version (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
4114 memcpy (dest_name
, aname
, sizeof (MonoAssemblyName
));
4115 dest_name
->major
= info
->new_version
.major
;
4116 dest_name
->minor
= info
->new_version
.minor
;
4117 dest_name
->build
= info
->new_version
.build
;
4118 dest_name
->revision
= info
->new_version
.revision
;
4123 /* LOCKING: assembly_binding lock must be held */
4124 static MonoAssemblyBindingInfo
*
4125 search_binding_loaded (MonoAssemblyName
*aname
)
4129 for (tmp
= loaded_assembly_bindings
; tmp
; tmp
= tmp
->next
) {
4130 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)tmp
->data
;
4131 if (assembly_binding_maps_name (info
, aname
))
4139 info_compare_versions (AssemblyVersionSet
*left
, AssemblyVersionSet
*right
)
4141 if (left
->major
!= right
->major
|| left
->minor
!= right
->minor
||
4142 left
->build
!= right
->build
|| left
->revision
!= right
->revision
)
4149 info_versions_equal (MonoAssemblyBindingInfo
*left
, MonoAssemblyBindingInfo
*right
)
4151 if (left
->has_old_version_bottom
!= right
->has_old_version_bottom
)
4154 if (left
->has_old_version_top
!= right
->has_old_version_top
)
4157 if (left
->has_new_version
!= right
->has_new_version
)
4160 if (left
->has_old_version_bottom
&& !info_compare_versions (&left
->old_version_bottom
, &right
->old_version_bottom
))
4163 if (left
->has_old_version_top
&& !info_compare_versions (&left
->old_version_top
, &right
->old_version_top
))
4166 if (left
->has_new_version
&& !info_compare_versions (&left
->new_version
, &right
->new_version
))
4172 /* LOCKING: assumes all the necessary locks are held */
4174 assembly_binding_info_parsed (MonoAssemblyBindingInfo
*info
, void *user_data
)
4176 MonoAssemblyBindingInfo
*info_copy
;
4178 MonoAssemblyBindingInfo
*info_tmp
;
4179 MonoDomain
*domain
= (MonoDomain
*)user_data
;
4184 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
)) {
4185 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
4186 info
->name
, info
->new_version
.major
, info
->new_version
.minor
, info
->new_version
.build
, info
->new_version
.revision
);
4190 for (tmp
= domain
->assembly_bindings
; tmp
; tmp
= tmp
->next
) {
4191 info_tmp
= (MonoAssemblyBindingInfo
*)tmp
->data
;
4192 if (strcmp (info
->name
, info_tmp
->name
) == 0 && info_versions_equal (info
, info_tmp
))
4196 info_copy
= (MonoAssemblyBindingInfo
*)mono_mempool_alloc0 (domain
->mp
, sizeof (MonoAssemblyBindingInfo
));
4197 memcpy (info_copy
, info
, sizeof (MonoAssemblyBindingInfo
));
4199 info_copy
->name
= mono_mempool_strdup (domain
->mp
, info
->name
);
4201 info_copy
->culture
= mono_mempool_strdup (domain
->mp
, info
->culture
);
4203 domain
->assembly_bindings
= g_slist_append_mempool (domain
->mp
, domain
->assembly_bindings
, info_copy
);
4207 get_version_number (int major
, int minor
)
4209 return major
* 256 + minor
;
4213 info_major_minor_in_range (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
4215 int aname_version_number
= get_version_number (aname
->major
, aname
->minor
);
4216 if (!info
->has_old_version_bottom
)
4219 if (get_version_number (info
->old_version_bottom
.major
, info
->old_version_bottom
.minor
) > aname_version_number
)
4222 if (info
->has_old_version_top
&& get_version_number (info
->old_version_top
.major
, info
->old_version_top
.minor
) < aname_version_number
)
4225 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
4226 info
->major
= aname
->major
;
4227 info
->minor
= aname
->minor
;
4232 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
4233 static MonoAssemblyBindingInfo
*
4234 get_per_domain_assembly_binding_info (MonoDomain
*domain
, MonoAssemblyName
*aname
)
4236 MonoAssemblyBindingInfo
*info
;
4239 if (!domain
->assembly_bindings
)
4243 for (list
= domain
->assembly_bindings
; list
; list
= list
->next
) {
4244 info
= (MonoAssemblyBindingInfo
*)list
->data
;
4245 if (info
&& !strcmp (aname
->name
, info
->name
) && info_major_minor_in_range (info
, aname
))
4251 if (info
->name
&& info
->public_key_token
[0] && info
->has_old_version_bottom
&&
4252 info
->has_new_version
&& assembly_binding_maps_name (info
, aname
))
4253 info
->is_valid
= TRUE
;
4255 info
->is_valid
= FALSE
;
4262 mono_domain_parse_assembly_bindings (MonoDomain
*domain
, int amajor
, int aminor
, gchar
*domain_config_file_name
)
4264 if (domain
->assembly_bindings_parsed
)
4266 mono_domain_lock (domain
);
4267 if (!domain
->assembly_bindings_parsed
) {
4269 gchar
*domain_config_file_path
= mono_portability_find_file (domain_config_file_name
, TRUE
);
4271 if (!domain_config_file_path
)
4272 domain_config_file_path
= domain_config_file_name
;
4274 mono_config_parse_assembly_bindings (domain_config_file_path
, amajor
, aminor
, domain
, assembly_binding_info_parsed
);
4275 domain
->assembly_bindings_parsed
= TRUE
;
4276 if (domain_config_file_name
!= domain_config_file_path
)
4277 g_free (domain_config_file_path
);
4280 mono_domain_unlock (domain
);
4283 static MonoAssemblyName
*
4284 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
4286 HANDLE_FUNCTION_ENTER ();
4289 MonoAssemblyBindingInfo
*info
, *info2
;
4293 if (aname
->public_key_token
[0] == 0)
4296 domain
= mono_domain_get ();
4298 mono_assembly_binding_lock ();
4299 info
= search_binding_loaded (aname
);
4300 mono_assembly_binding_unlock ();
4303 mono_domain_lock (domain
);
4304 info
= get_per_domain_assembly_binding_info (domain
, aname
);
4305 mono_domain_unlock (domain
);
4309 if (!check_policy_versions (info
, aname
))
4312 mono_assembly_bind_version (info
, aname
, dest_name
);
4313 goto return_dest_name
;
4316 MonoAppDomainSetupHandle setup
;
4317 MonoStringHandle configuration_file
;
4320 && !MONO_HANDLE_IS_NULL (setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, domain
->setup
))
4321 && !MONO_HANDLE_IS_NULL (configuration_file
= MONO_HANDLE_NEW_GET (MonoString
, setup
, configuration_file
))) {
4322 char *domain_config_file_name
= mono_string_handle_to_utf8 (configuration_file
, error
);
4323 /* expect this to succeed because mono_domain_set_options_from_config () did
4324 * the same thing when the domain was created. */
4325 mono_error_assert_ok (error
);
4326 mono_domain_parse_assembly_bindings (domain
, aname
->major
, aname
->minor
, domain_config_file_name
);
4327 g_free (domain_config_file_name
);
4329 mono_domain_lock (domain
);
4330 info2
= get_per_domain_assembly_binding_info (domain
, aname
);
4333 info
= (MonoAssemblyBindingInfo
*)g_memdup (info2
, sizeof (MonoAssemblyBindingInfo
));
4334 info
->name
= g_strdup (info2
->name
);
4335 info
->culture
= g_strdup (info2
->culture
);
4336 info
->domain_id
= domain
->domain_id
;
4339 mono_domain_unlock (domain
);
4343 info
= g_new0 (MonoAssemblyBindingInfo
, 1);
4344 info
->major
= aname
->major
;
4345 info
->minor
= aname
->minor
;
4348 if (!info
->is_valid
) {
4349 ppimage
= mono_assembly_load_publisher_policy (aname
);
4351 get_publisher_policy_info (ppimage
, aname
, info
);
4352 mono_image_close (ppimage
);
4356 /* Define default error value if needed */
4357 if (!info
->is_valid
) {
4358 info
->name
= g_strdup (aname
->name
);
4359 info
->culture
= g_strdup (aname
->culture
);
4360 g_strlcpy ((char *)info
->public_key_token
, (const char *)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
4363 mono_assembly_binding_lock ();
4364 info2
= search_binding_loaded (aname
);
4366 /* This binding was added by another thread
4368 mono_assembly_binding_info_free (info
);
4373 loaded_assembly_bindings
= g_slist_prepend (loaded_assembly_bindings
, info
);
4375 mono_assembly_binding_unlock ();
4377 if (!info
->is_valid
|| !check_policy_versions (info
, aname
))
4380 mono_assembly_bind_version (info
, aname
, dest_name
);
4381 goto return_dest_name
;
4383 MonoAssemblyName
* result
;
4393 HANDLE_FUNCTION_RETURN_VAL (result
);
4398 * mono_assembly_load_from_gac
4400 * \param aname The assembly name object
4402 static MonoAssembly
*
4403 mono_assembly_load_from_gac (MonoAssemblyName
*aname
, gchar
*filename
, MonoImageOpenStatus
*status
, MonoBoolean refonly
)
4405 MonoAssembly
*result
= NULL
;
4406 gchar
*name
, *version
, *culture
, *fullpath
, *subpath
;
4411 if (aname
->public_key_token
[0] == 0) {
4415 if (strstr (aname
->name
, ".dll")) {
4416 len
= strlen (filename
) - 4;
4417 name
= (gchar
*)g_malloc (len
+ 1);
4418 memcpy (name
, aname
->name
, len
);
4421 name
= g_strdup (aname
->name
);
4424 if (aname
->culture
) {
4425 culture
= g_utf8_strdown (aname
->culture
, -1);
4427 culture
= g_strdup ("");
4430 pubtok
= g_ascii_strdown ((char*)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
4431 version
= g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname
->major
,
4432 aname
->minor
, aname
->build
, aname
->revision
,
4436 subpath
= g_build_path (G_DIR_SEPARATOR_S
, name
, version
, filename
, (const char*)NULL
);
4441 MonoAssemblyOpenRequest req
;
4442 mono_assembly_request_prepare_open (&req
,
4443 refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
,
4444 mono_domain_default_alc (mono_domain_get ()));
4446 if (extra_gac_paths
) {
4447 paths
= extra_gac_paths
;
4448 while (!result
&& *paths
) {
4449 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", subpath
, (const char*)NULL
);
4450 result
= mono_assembly_request_open (fullpath
, &req
, status
);
4457 result
->in_gac
= TRUE
;
4462 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
4463 "mono", "gac", subpath
, (const char*)NULL
);
4464 result
= mono_assembly_request_open (fullpath
, &req
, status
);
4468 result
->in_gac
= TRUE
;
4474 #endif /* DISABLE_GAC */
4477 mono_assembly_load_corlib (const MonoRuntimeInfo
*runtime
, MonoImageOpenStatus
*status
)
4479 MonoAssemblyName
*aname
;
4480 MonoAssemblyOpenRequest req
;
4481 mono_assembly_request_prepare_open (&req
, MONO_ASMCTX_DEFAULT
, mono_domain_default_alc (mono_domain_get ()));
4484 /* g_print ("corlib already loaded\n"); */
4488 #ifdef ENABLE_NETCORE
4489 aname
= mono_assembly_name_new (MONO_ASSEMBLY_CORLIB_NAME
);
4490 corlib
= invoke_assembly_preload_hook (req
.request
.alc
, aname
, NULL
);
4491 /* MonoCore preload hook should know how to find it */
4492 /* FIXME: AOT compiler comes here without an installed hook. */
4494 if (assemblies_path
) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
4495 char *corlib_name
= g_strdup_printf ("%s.dll", MONO_ASSEMBLY_CORLIB_NAME
);
4496 corlib
= load_in_path (corlib_name
, (const char**)assemblies_path
, &req
, status
);
4500 /* Maybe its in a bundle */
4501 char *corlib_name
= g_strdup_printf ("%s.dll", MONO_ASSEMBLY_CORLIB_NAME
);
4502 corlib
= mono_assembly_request_open (corlib_name
, &req
, status
);
4506 // A nonstandard preload hook may provide a special mscorlib assembly
4507 aname
= mono_assembly_name_new ("mscorlib.dll");
4508 corlib
= invoke_assembly_preload_hook (req
.request
.alc
, aname
, assemblies_path
);
4509 mono_assembly_name_free_internal (aname
);
4512 goto return_corlib_and_facades
;
4514 // This unusual directory layout can occur if mono is being built and run out of its own source repo
4515 if (assemblies_path
) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
4516 corlib
= load_in_path ("mscorlib.dll", (const char**)assemblies_path
, &req
, status
);
4518 goto return_corlib_and_facades
;
4521 /* Normal case: Load corlib from mono/<version> */
4523 corlib_file
= g_build_filename ("mono", runtime
->framework_version
, "mscorlib.dll", (const char*)NULL
);
4524 if (assemblies_path
) { // Custom assemblies path
4525 corlib
= load_in_path (corlib_file
, (const char**)assemblies_path
, &req
, status
);
4527 g_free (corlib_file
);
4528 goto return_corlib_and_facades
;
4531 corlib
= load_in_path (corlib_file
, (const char**) default_path
, &req
, status
);
4532 g_free (corlib_file
);
4534 return_corlib_and_facades
:
4535 if (corlib
) // FIXME: stop hardcoding 4.5 here
4536 default_path
[1] = g_strdup_printf ("%s/Facades", corlib
->basedir
);
4537 #endif /*!ENABLE_NETCORE*/
4542 static MonoAssembly
*
4543 prevent_reference_assembly_from_running (MonoAssembly
* candidate
, gboolean refonly
)
4545 ERROR_DECL (refasm_error
);
4546 if (candidate
&& !refonly
) {
4547 /* .NET Framework seems to not check for ReferenceAssemblyAttribute on dynamic assemblies */
4548 if (!image_is_dynamic (candidate
->image
) &&
4549 mono_assembly_has_reference_assembly_attribute (candidate
, refasm_error
))
4552 mono_error_cleanup (refasm_error
);
4557 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly
*candidate
, gpointer ud
)
4559 MonoAssemblyName
*wanted_name
= (MonoAssemblyName
*)ud
;
4560 MonoAssemblyName
*candidate_name
= &candidate
->aname
;
4562 g_assert (wanted_name
!= NULL
);
4563 g_assert (candidate_name
!= NULL
);
4565 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
4566 char * s
= mono_stringify_assembly_name (wanted_name
);
4567 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Predicate: wanted = %s", s
);
4569 s
= mono_stringify_assembly_name (candidate_name
);
4570 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate = %s", s
);
4574 #ifdef ENABLE_NETCORE
4575 return mono_assembly_check_name_match (wanted_name
, candidate_name
);
4577 /* Wanted name has no token, not strongly named: always matches. */
4578 if (0 == wanted_name
->public_key_token
[0]) {
4579 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Predicate: wanted has no token, returning TRUE");
4583 /* Candidate name has no token, not strongly named: never matches */
4584 if (0 == candidate_name
->public_key_token
[0]) {
4585 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate has no token, returning FALSE");
4589 return mono_assembly_check_name_match (wanted_name
, candidate_name
) ||
4590 framework_assembly_sn_match (wanted_name
, candidate_name
);
4595 mono_assembly_check_name_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
)
4598 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_VERSION
| MONO_ANAME_EQ_IGNORE_PUBKEY
);
4599 if (result
&& assembly_names_compare_versions (wanted_name
, candidate_name
, -1) > 0)
4602 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_NONE
);
4605 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s",
4606 result
? "match, returning TRUE" : "don't match, returning FALSE");
4612 framework_assembly_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
)
4614 #ifndef DISABLE_DESKTOP_LOADER
4615 g_assert (wanted_name
!= NULL
);
4616 g_assert (candidate_name
!= NULL
);
4617 const AssemblyVersionMap
*vmap
= (AssemblyVersionMap
*)g_hash_table_lookup (assembly_remapping_table
, wanted_name
->name
);
4619 if (!vmap
->framework_facade_assembly
) {
4620 /* 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. */
4621 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_PUBKEY
);
4622 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s (ignoring the public key token)", result
? "match, returning TRUE" : "don't match, returning FALSE");
4625 /* For facades, the name and public key token should
4626 * match, but the version doesn't matter as long as the
4627 * candidate is not older. */
4628 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_VERSION
);
4629 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s (ignoring version)", result
? "match" : "don't match, returning FALSE");
4631 // compare major of candidate and wanted
4632 int c
= assembly_names_compare_versions (candidate_name
, wanted_name
, 1);
4633 mono_trace (G_LOG_LEVEL_DEBUG
, 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"),
4634 (c
>= 0) ? "TRUE" : "FALSE");
4635 return (c
>= 0); // don't accept a candidate that's older than wanted.
4645 static MonoAssembly
*
4646 mono_assembly_request_byname_nosearch (MonoAssemblyName
*aname
,
4647 const MonoAssemblyByNameRequest
*req
,
4648 MonoImageOpenStatus
*status
)
4650 MonoAssembly
*result
= NULL
;
4651 MonoAssemblyName maped_aname
;
4652 MonoAssemblyName maped_name_pp
;
4654 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
4656 const gboolean refonly
= req
->request
.asmctx
== MONO_ASMCTX_REFONLY
;
4658 /* Reflection only assemblies don't get assembly binding */
4660 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
4662 result
= mono_assembly_loaded_internal (req
->request
.alc
, aname
, refonly
);
4666 result
= refonly
? invoke_assembly_refonly_preload_hook (req
->request
.alc
, aname
, assemblies_path
) : invoke_assembly_preload_hook (req
->request
.alc
, aname
, assemblies_path
);
4668 result
->in_gac
= FALSE
;
4672 #ifndef ENABLE_NETCORE
4673 result
= mono_assembly_load_full_gac_base_default (aname
, req
->basedir
, req
->request
.alc
, req
->request
.asmctx
, status
);
4678 /* Like mono_assembly_request_byname_nosearch, but don't ask the preload look (ie,
4679 * the appdomain) to run. Just looks in the gac, the specified base dir or the
4680 * default_path. Does NOT look in the appdomain application base or in the
4684 mono_assembly_load_full_gac_base_default (MonoAssemblyName
*aname
,
4685 const char *basedir
,
4686 MonoAssemblyLoadContext
*alc
,
4687 MonoAssemblyContextKind asmctx
,
4688 MonoImageOpenStatus
*status
)
4690 MonoAssembly
*result
;
4691 MonoAssemblyName maped_aname
;
4692 char *fullpath
, *filename
;
4697 /* If we remap e.g. 4.1.3.0 to 4.0.0.0, look in the 4.0.0.0
4698 * GAC directory, not 4.1.3.0 */
4699 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
4701 /* Currently we retrieve the loaded corlib for reflection
4702 * only requests, like a common reflection only assembly
4704 gboolean name_is_corlib
= strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
) == 0;
4705 /* Assembly.Load (new AssemblyName ("mscorlib.dll")) (respectively,
4706 * "System.Private.CoreLib.dll" for netcore) is treated the same as
4707 * "mscorlib" (resp "System.Private.CoreLib"). */
4708 name_is_corlib
= name_is_corlib
|| strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
".dll") == 0;
4709 if (name_is_corlib
) {
4710 return mono_assembly_load_corlib (mono_get_runtime_info (), status
);
4713 MonoAssemblyCandidatePredicate predicate
= NULL
;
4714 void* predicate_ud
= NULL
;
4715 if (mono_loader_get_strict_assembly_name_check ()) {
4716 predicate
= &mono_assembly_candidate_predicate_sn_same_name
;
4717 predicate_ud
= aname
;
4720 MonoAssemblyOpenRequest req
;
4721 mono_assembly_request_prepare_open (&req
, asmctx
, alc
);
4722 req
.request
.predicate
= predicate
;
4723 req
.request
.predicate_ud
= predicate_ud
;
4725 len
= strlen (aname
->name
);
4726 for (ext_index
= 0; ext_index
< 2; ext_index
++) {
4727 ext
= ext_index
== 0 ? ".dll" : ".exe";
4728 if (len
> 4 && (!strcmp (aname
->name
+ len
- 4, ".dll") || !strcmp (aname
->name
+ len
- 4, ".exe"))) {
4729 filename
= g_strdup (aname
->name
);
4730 /* Don't try appending .dll/.exe if it already has one of those extensions */
4733 filename
= g_strconcat (aname
->name
, ext
, (const char*)NULL
);
4737 const gboolean refonly
= asmctx
== MONO_ASMCTX_REFONLY
;
4739 result
= mono_assembly_load_from_gac (aname
, filename
, status
, refonly
);
4747 fullpath
= g_build_filename (basedir
, filename
, (const char*)NULL
);
4748 result
= mono_assembly_request_open (fullpath
, &req
, status
);
4751 result
->in_gac
= FALSE
;
4757 result
= load_in_path (filename
, (const char**) default_path
, &req
, status
);
4759 result
->in_gac
= FALSE
;
4769 mono_assembly_request_byname (MonoAssemblyName
*aname
, const MonoAssemblyByNameRequest
*req
, MonoImageOpenStatus
*status
)
4771 MonoDomain
*domain
= mono_alc_domain (req
->request
.alc
);
4772 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Request to load %s in (domain %p, alc %p)", aname
->name
, domain
, (gpointer
)req
->request
.alc
);
4773 MonoAssembly
*result
;
4775 *status
= MONO_IMAGE_OK
;
4776 #ifndef ENABLE_NETCORE
4777 result
= mono_assembly_request_byname_nosearch (aname
, req
, status
);
4778 const gboolean refonly
= req
->request
.asmctx
== MONO_ASMCTX_REFONLY
;
4780 if (!result
&& !req
->no_postload_search
) {
4781 /* Try a postload search hook */
4782 result
= mono_assembly_invoke_search_hook_internal (req
->request
.alc
, req
->requesting_assembly
, aname
, refonly
, TRUE
);
4783 result
= prevent_reference_assembly_from_running (result
, refonly
);
4786 result
= netcore_load_reference (aname
, req
->request
.alc
, req
->requesting_assembly
, !req
->no_postload_search
);
4788 if (!result
&& bundles
!= NULL
) {
4789 MonoImageOpenStatus status
;
4791 image
= mono_assembly_open_from_bundle (req
->request
.alc
, aname
->name
, &status
, FALSE
);
4793 char *name
= g_strdup_printf ("%s.dll", aname
->name
);
4794 image
= mono_assembly_open_from_bundle (req
->request
.alc
, name
, &status
, FALSE
);
4797 result
= mono_assembly_request_load_from (image
, aname
->name
, &req
->request
, &status
);
4804 * mono_assembly_load_full:
4805 * \param aname A MonoAssemblyName with the assembly name to load.
4806 * \param basedir A directory to look up the assembly at.
4807 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
4808 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
4810 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
4811 * attempts to load the assembly from that directory before probing the standard locations.
4813 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
4814 * assembly binding takes place.
4816 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
4817 * value pointed by \p status is updated with an error code.
4820 mono_assembly_load_full (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
, gboolean refonly
)
4823 MONO_ENTER_GC_UNSAFE
;
4824 MonoAssemblyByNameRequest req
;
4825 mono_assembly_request_prepare_byname (&req
,
4826 refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
,
4827 mono_domain_default_alc (mono_domain_get ()));
4828 req
.requesting_assembly
= NULL
;
4829 req
.basedir
= basedir
;
4830 res
= mono_assembly_request_byname (aname
, &req
, status
);
4831 MONO_EXIT_GC_UNSAFE
;
4836 * mono_assembly_load:
4837 * \param aname A MonoAssemblyName with the assembly name to load.
4838 * \param basedir A directory to look up the assembly at.
4839 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
4841 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
4842 * attempts to load the assembly from that directory before probing the standard locations.
4844 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
4845 * value pointed by \p status is updated with an error code.
4848 mono_assembly_load (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
)
4850 MonoAssemblyByNameRequest req
;
4851 mono_assembly_request_prepare_byname (&req
, MONO_ASMCTX_DEFAULT
, mono_domain_default_alc (mono_domain_get ()));
4852 req
.requesting_assembly
= NULL
;
4853 req
.basedir
= basedir
;
4854 return mono_assembly_request_byname (aname
, &req
, status
);
4858 * mono_assembly_loaded_full:
4859 * \param aname an assembly to look for.
4860 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
4862 * This is used to determine if the specified assembly has been loaded
4863 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
4864 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
4867 mono_assembly_loaded_full (MonoAssemblyName
*aname
, gboolean refonly
)
4869 MonoAssemblyLoadContext
*alc
= mono_domain_default_alc (mono_domain_get ());
4870 return mono_assembly_loaded_internal (alc
, aname
, refonly
);
4874 mono_assembly_loaded_internal (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
, gboolean refonly
)
4877 MonoAssemblyName mapped_aname
;
4879 aname
= mono_assembly_remap_version (aname
, &mapped_aname
);
4881 res
= mono_assembly_invoke_search_hook_internal (alc
, NULL
, aname
, refonly
, FALSE
);
4887 * mono_assembly_loaded:
4888 * \param aname an assembly to look for.
4890 * This is used to determine if the specified assembly has been loaded
4892 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
4893 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
4896 mono_assembly_loaded (MonoAssemblyName
*aname
)
4899 MONO_ENTER_GC_UNSAFE
;
4900 res
= mono_assembly_loaded_internal (mono_domain_default_alc (mono_domain_get ()), aname
, FALSE
);
4901 MONO_EXIT_GC_UNSAFE
;
4906 mono_assembly_release_gc_roots (MonoAssembly
*assembly
)
4908 if (assembly
== NULL
|| assembly
== REFERENCE_MISSING
)
4911 if (assembly_is_dynamic (assembly
)) {
4913 MonoDynamicImage
*dynimg
= (MonoDynamicImage
*)assembly
->image
;
4914 for (i
= 0; i
< dynimg
->image
.module_count
; ++i
)
4915 mono_dynamic_image_release_gc_roots ((MonoDynamicImage
*)dynimg
->image
.modules
[i
]);
4916 mono_dynamic_image_release_gc_roots (dynimg
);
4921 * Returns whether mono_assembly_close_finish() must be called as
4922 * well. See comment for mono_image_close_except_pools() for why we
4923 * unload in two steps.
4926 mono_assembly_close_except_image_pools (MonoAssembly
*assembly
)
4929 g_return_val_if_fail (assembly
!= NULL
, FALSE
);
4931 if (assembly
== REFERENCE_MISSING
)
4934 /* Might be 0 already */
4935 if (mono_atomic_dec_i32 (&assembly
->ref_count
) > 0)
4938 MONO_PROFILER_RAISE (assembly_unloading
, (assembly
));
4940 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Unloading assembly %s [%p].", assembly
->aname
.name
, assembly
);
4942 mono_debug_close_image (assembly
->image
);
4944 mono_assemblies_lock ();
4945 loaded_assemblies
= g_list_remove (loaded_assemblies
, assembly
);
4946 mono_assemblies_unlock ();
4948 assembly
->image
->assembly
= NULL
;
4950 if (!mono_image_close_except_pools (assembly
->image
))
4951 assembly
->image
= NULL
;
4953 for (tmp
= assembly
->friend_assembly_names
; tmp
; tmp
= tmp
->next
) {
4954 MonoAssemblyName
*fname
= (MonoAssemblyName
*)tmp
->data
;
4955 mono_assembly_name_free_internal (fname
);
4958 g_slist_free (assembly
->friend_assembly_names
);
4959 g_free (assembly
->basedir
);
4961 MONO_PROFILER_RAISE (assembly_unloaded
, (assembly
));
4967 mono_assembly_close_finish (MonoAssembly
*assembly
)
4969 g_assert (assembly
&& assembly
!= REFERENCE_MISSING
);
4971 if (assembly
->image
)
4972 mono_image_close_finish (assembly
->image
);
4974 if (assembly_is_dynamic (assembly
)) {
4975 g_free ((char*)assembly
->aname
.culture
);
4982 * mono_assembly_close:
4983 * \param assembly the assembly to release.
4985 * This method releases a reference to the \p assembly. The assembly is
4986 * only released when all the outstanding references to it are released.
4989 mono_assembly_close (MonoAssembly
*assembly
)
4991 if (mono_assembly_close_except_image_pools (assembly
))
4992 mono_assembly_close_finish (assembly
);
4996 * mono_assembly_load_module:
4999 mono_assembly_load_module (MonoAssembly
*assembly
, guint32 idx
)
5002 MonoImage
*result
= mono_assembly_load_module_checked (assembly
, idx
, error
);
5003 mono_error_assert_ok (error
);
5008 mono_assembly_load_module_checked (MonoAssembly
*assembly
, uint32_t idx
, MonoError
*error
)
5010 return mono_image_load_file_for_image_checked (assembly
->image
, idx
, error
);
5015 * mono_assembly_foreach:
5016 * \param func function to invoke for each assembly loaded
5017 * \param user_data data passed to the callback
5019 * Invokes the provided \p func callback for each assembly loaded into
5020 * the runtime. The first parameter passed to the callback is the
5021 * \c MonoAssembly*, and the second parameter is the \p user_data.
5023 * This is done for all assemblies loaded in the runtime, not just
5024 * those loaded in the current application domain.
5027 mono_assembly_foreach (GFunc func
, gpointer user_data
)
5032 * We make a copy of the list to avoid calling the callback inside the
5033 * lock, which could lead to deadlocks.
5035 mono_assemblies_lock ();
5036 copy
= g_list_copy (loaded_assemblies
);
5037 mono_assemblies_unlock ();
5039 g_list_foreach (loaded_assemblies
, func
, user_data
);
5045 * mono_assemblies_cleanup:
5047 * Free all resources used by this module.
5050 mono_assemblies_cleanup (void)
5054 mono_os_mutex_destroy (&assemblies_mutex
);
5055 mono_os_mutex_destroy (&assembly_binding_mutex
);
5057 for (l
= loaded_assembly_bindings
; l
; l
= l
->next
) {
5058 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)l
->data
;
5060 mono_assembly_binding_info_free (info
);
5063 g_slist_free (loaded_assembly_bindings
);
5065 free_assembly_asmctx_from_path_hooks ();
5066 free_assembly_load_hooks ();
5067 free_assembly_search_hooks ();
5068 free_assembly_preload_hooks ();
5071 /*LOCKING takes the assembly_binding lock*/
5073 mono_assembly_cleanup_domain_bindings (guint32 domain_id
)
5077 mono_assembly_binding_lock ();
5078 iter
= &loaded_assembly_bindings
;
5081 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)l
->data
;
5083 if (info
->domain_id
== domain_id
) {
5085 mono_assembly_binding_info_free (info
);
5092 mono_assembly_binding_unlock ();
5096 * Holds the assembly of the application, for
5097 * System.Diagnostics.Process::MainModule
5099 static MonoAssembly
*main_assembly
=NULL
;
5102 * mono_assembly_set_main:
5105 mono_assembly_set_main (MonoAssembly
*assembly
)
5107 main_assembly
= assembly
;
5111 * mono_assembly_get_main:
5113 * Returns: the assembly for the application, the first assembly that is loaded by the VM
5116 mono_assembly_get_main (void)
5118 return (main_assembly
);
5122 * mono_assembly_get_image:
5123 * \param assembly The assembly to retrieve the image from
5125 * \returns the \c MonoImage associated with this assembly.
5128 mono_assembly_get_image (MonoAssembly
*assembly
)
5131 MONO_ENTER_GC_UNSAFE
;
5132 res
= mono_assembly_get_image_internal (assembly
);
5133 MONO_EXIT_GC_UNSAFE
;
5138 mono_assembly_get_image_internal (MonoAssembly
*assembly
)
5140 MONO_REQ_GC_UNSAFE_MODE
;
5141 return assembly
->image
;
5145 * mono_assembly_get_name:
5146 * \param assembly The assembly to retrieve the name from
5148 * The returned name's lifetime is the same as \p assembly's.
5150 * \returns the \c MonoAssemblyName associated with this assembly.
5153 mono_assembly_get_name (MonoAssembly
*assembly
)
5155 MonoAssemblyName
*res
;
5156 MONO_ENTER_GC_UNSAFE
;
5157 res
= mono_assembly_get_name_internal (assembly
);
5158 MONO_EXIT_GC_UNSAFE
;
5163 mono_assembly_get_name_internal (MonoAssembly
*assembly
)
5165 MONO_REQ_GC_UNSAFE_MODE
;
5166 return &assembly
->aname
;
5170 * mono_register_bundled_assemblies:
5173 mono_register_bundled_assemblies (const MonoBundledAssembly
**assemblies
)
5175 bundles
= assemblies
;
5178 #define MONO_DECLSEC_FORMAT_10 0x3C
5179 #define MONO_DECLSEC_FORMAT_20 0x2E
5180 #define MONO_DECLSEC_FIELD 0x53
5181 #define MONO_DECLSEC_PROPERTY 0x54
5183 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
5184 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
5185 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
5186 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
5187 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
5190 mono_assembly_try_decode_skip_verification_param (const char *p
, const char **resp
, gboolean
*abort_decoding
)
5194 case MONO_DECLSEC_PROPERTY
:
5196 case MONO_DECLSEC_FIELD
:
5198 *abort_decoding
= TRUE
;
5203 if (*p
++ != MONO_TYPE_BOOLEAN
) {
5204 *abort_decoding
= TRUE
;
5208 /* property name length */
5209 len
= mono_metadata_decode_value (p
, &p
);
5211 if (len
>= SKIP_VISIBILITY_PROPERTY_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_PROPERTY_NAME
, SKIP_VISIBILITY_PROPERTY_SIZE
)) {
5222 mono_assembly_try_decode_skip_verification (const char *p
, const char *endn
)
5224 int i
, j
, num
, len
, params_len
;
5226 if (*p
== MONO_DECLSEC_FORMAT_10
) {
5227 gsize read
, written
;
5228 char *res
= g_convert (p
, endn
- p
, "UTF-8", "UTF-16LE", &read
, &written
, NULL
);
5230 gboolean found
= strstr (res
, SKIP_VISIBILITY_XML_ATTRIBUTE
) != NULL
;
5236 if (*p
++ != MONO_DECLSEC_FORMAT_20
)
5239 /* number of encoded permission attributes */
5240 num
= mono_metadata_decode_value (p
, &p
);
5241 for (i
= 0; i
< num
; ++i
) {
5242 gboolean is_valid
= FALSE
;
5243 gboolean abort_decoding
= FALSE
;
5245 /* attribute name length */
5246 len
= mono_metadata_decode_value (p
, &p
);
5248 /* We don't really need to fully decode the type. Comparing the name is enough */
5249 is_valid
= len
>= SKIP_VISIBILITY_ATTRIBUTE_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_ATTRIBUTE_NAME
, SKIP_VISIBILITY_ATTRIBUTE_SIZE
);
5253 /*size of the params table*/
5254 params_len
= mono_metadata_decode_value (p
, &p
);
5256 const char *params_end
= p
+ params_len
;
5258 /* number of parameters */
5259 len
= mono_metadata_decode_value (p
, &p
);
5261 for (j
= 0; j
< len
; ++j
) {
5262 if (mono_assembly_try_decode_skip_verification_param (p
, &p
, &abort_decoding
))
5278 mono_assembly_has_skip_verification (MonoAssembly
*assembly
)
5281 guint32 cols
[MONO_DECL_SECURITY_SIZE
];
5285 if (MONO_SECMAN_FLAG_INIT (assembly
->skipverification
))
5286 return MONO_SECMAN_FLAG_GET_VALUE (assembly
->skipverification
);
5288 t
= &assembly
->image
->tables
[MONO_TABLE_DECLSECURITY
];
5290 for (i
= 0; i
< t
->rows
; ++i
) {
5291 mono_metadata_decode_row (t
, i
, cols
, MONO_DECL_SECURITY_SIZE
);
5292 if ((cols
[MONO_DECL_SECURITY_PARENT
] & MONO_HAS_DECL_SECURITY_MASK
) != MONO_HAS_DECL_SECURITY_ASSEMBLY
)
5294 if (cols
[MONO_DECL_SECURITY_ACTION
] != SECURITY_ACTION_REQMIN
)
5297 blob
= mono_metadata_blob_heap (assembly
->image
, cols
[MONO_DECL_SECURITY_PERMISSIONSET
]);
5298 len
= mono_metadata_decode_blob_size (blob
, &blob
);
5302 if (mono_assembly_try_decode_skip_verification (blob
, blob
+ len
)) {
5303 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, TRUE
);
5308 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, FALSE
);
5312 MonoAssemblyContextKind
5313 mono_asmctx_get_kind (const MonoAssemblyContext
*ctx
)
5319 mono_asmctx_get_name (const MonoAssemblyContext
*asmctx
)
5321 static const char* names
[] = {
5327 g_assert (asmctx
->kind
>= 0 && asmctx
->kind
<= MONO_ASMCTX_LAST
);
5328 return names
[asmctx
->kind
];