3 * Routines for loading assemblies.
6 * Miguel de Icaza (miguel@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "assembly-internals.h"
22 #include "image-internals.h"
23 #include "object-internals.h"
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/tabledefs.h>
26 #include <mono/metadata/custom-attrs-internals.h>
27 #include <mono/metadata/metadata-internals.h>
28 #include <mono/metadata/profiler-private.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/domain-internals.h>
31 #include <mono/metadata/reflection-internals.h>
32 #include <mono/metadata/mono-endian.h>
33 #include <mono/metadata/mono-debug.h>
34 #include <mono/utils/mono-uri.h>
35 #include <mono/metadata/mono-config.h>
36 #include <mono/metadata/mono-config-internals.h>
37 #include <mono/metadata/mono-config-dirs.h>
38 #include <mono/utils/mono-digest.h>
39 #include <mono/utils/mono-logger-internals.h>
40 #include <mono/utils/mono-path.h>
41 #include <mono/metadata/reflection.h>
42 #include <mono/metadata/coree.h>
43 #include <mono/metadata/cil-coff.h>
44 #include <mono/utils/mono-io-portability.h>
45 #include <mono/utils/atomic.h>
46 #include <mono/utils/mono-os-mutex.h>
49 #include <sys/types.h>
55 #include <mach-o/dyld.h>
58 /* 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 */
60 const char* assembly_name
;
61 guint8 version_set_index
;
62 const char* new_assembly_name
;
63 gboolean only_lower_versions
;
64 gboolean framework_facade_assembly
;
67 /* the default search path is empty, the first slot is replaced with the computed value */
75 /* Contains the list of directories to be searched for assemblies (MONO_PATH) */
76 static char **assemblies_path
= NULL
;
79 /* Contains the list of directories that point to auxiliary GACs */
80 static char **extra_gac_paths
= NULL
;
83 #ifndef DISABLE_DESKTOP_LOADER
85 #define FACADE_ASSEMBLY(str) {str, 0, NULL, FALSE, TRUE}
87 static GHashTable
* assembly_remapping_table
;
88 /* The list of system assemblies what will be remapped to the running
90 * This list is stored in @assembly_remapping_table during initialization.
91 * Keep it sorted just to make maintenance easier.
93 * The integer number is an index in the MonoRuntimeInfo structure, whose
94 * values can be found in domain.c - supported_runtimes. Look there
95 * to understand what remapping will be made.
97 * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
100 static const AssemblyVersionMap framework_assemblies
[] = {
101 {"Accessibility", 0},
102 {"Commons.Xml.Relaxng", 0},
103 {"CustomMarshalers", 0},
110 {"Microsoft.Build.Engine", 2, NULL
, TRUE
},
111 {"Microsoft.Build.Framework", 2, NULL
, TRUE
},
112 {"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
113 {"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
114 {"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
115 {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
116 {"Microsoft.CSharp", 0},
117 {"Microsoft.VisualBasic", 1},
118 {"Microsoft.VisualC", 1},
119 FACADE_ASSEMBLY ("Microsoft.Win32.Primitives"),
120 FACADE_ASSEMBLY ("Microsoft.Win32.Registry"),
121 FACADE_ASSEMBLY ("Microsoft.Win32.Registry.AccessControl"),
123 {"Mono.CompilerServices.SymbolWriter", 0},
125 {"Mono.Data.SybaseClient", 0},
126 {"Mono.Data.Tds", 0},
127 {"Mono.Data.TdsClient", 0},
128 {"Mono.GetOptions", 0},
131 {"Mono.Security", 0},
132 {"Mono.Security.Win32", 0},
134 {"Novell.Directory.Ldap", 0},
137 FACADE_ASSEMBLY ("System.AppContext"),
138 FACADE_ASSEMBLY ("System.Buffers"),
139 FACADE_ASSEMBLY ("System.Collections"),
140 FACADE_ASSEMBLY ("System.Collections.Concurrent"),
141 FACADE_ASSEMBLY ("System.Collections.NonGeneric"),
142 FACADE_ASSEMBLY ("System.Collections.Specialized"),
143 FACADE_ASSEMBLY ("System.ComponentModel"),
144 FACADE_ASSEMBLY ("System.ComponentModel.Annotations"),
145 {"System.ComponentModel.Composition", 2},
146 {"System.ComponentModel.DataAnnotations", 2},
147 FACADE_ASSEMBLY ("System.ComponentModel.EventBasedAsync"),
148 FACADE_ASSEMBLY ("System.ComponentModel.Primitives"),
149 FACADE_ASSEMBLY ("System.ComponentModel.TypeConverter"),
150 {"System.Configuration", 0},
151 {"System.Configuration.Install", 0},
152 FACADE_ASSEMBLY ("System.Console"),
155 FACADE_ASSEMBLY ("System.Data.Common"),
156 {"System.Data.DataSetExtensions", 0},
157 {"System.Data.Entity", 0},
158 {"System.Data.Linq", 2},
159 {"System.Data.OracleClient", 0},
160 {"System.Data.Services", 2},
161 {"System.Data.Services.Client", 2},
162 FACADE_ASSEMBLY ("System.Data.SqlClient"),
163 {"System.Data.SqlXml", 0},
164 {"System.Deployment", 0},
165 {"System.Design", 0},
166 FACADE_ASSEMBLY ("System.Diagnostics.Contracts"),
167 FACADE_ASSEMBLY ("System.Diagnostics.Debug"),
168 FACADE_ASSEMBLY ("System.Diagnostics.FileVersionInfo"),
169 FACADE_ASSEMBLY ("System.Diagnostics.Process"),
170 FACADE_ASSEMBLY ("System.Diagnostics.StackTrace"),
171 FACADE_ASSEMBLY ("System.Diagnostics.TextWriterTraceListener"),
172 FACADE_ASSEMBLY ("System.Diagnostics.Tools"),
173 FACADE_ASSEMBLY ("System.Diagnostics.TraceEvent"),
174 FACADE_ASSEMBLY ("System.Diagnostics.TraceSource"),
175 FACADE_ASSEMBLY ("System.Diagnostics.Tracing"),
176 {"System.DirectoryServices", 0},
177 {"System.DirectoryServices.Protocols", 0},
178 {"System.Drawing", 0},
179 FACADE_ASSEMBLY ("System.Drawing.Common"),
180 {"System.Drawing.Design", 0},
181 FACADE_ASSEMBLY ("System.Drawing.Primitives"),
182 {"System.Dynamic", 0},
183 FACADE_ASSEMBLY ("System.Dynamic.Runtime"),
184 {"System.EnterpriseServices", 0},
185 FACADE_ASSEMBLY ("System.Globalization"),
186 FACADE_ASSEMBLY ("System.Globalization.Calendars"),
187 FACADE_ASSEMBLY ("System.Globalization.Extensions"),
188 {"System.IdentityModel", 3},
189 {"System.IdentityModel.Selectors", 3},
190 FACADE_ASSEMBLY ("System.IO"),
191 {"System.IO.Compression", 2},
192 {"System.IO.Compression.FileSystem", 0},
193 FACADE_ASSEMBLY ("System.IO.Compression.ZipFile"),
194 FACADE_ASSEMBLY ("System.IO.FileSystem"),
195 FACADE_ASSEMBLY ("System.IO.FileSystem.AccessControl"),
196 FACADE_ASSEMBLY ("System.IO.FileSystem.DriveInfo"),
197 FACADE_ASSEMBLY ("System.IO.FileSystem.Primitives"),
198 FACADE_ASSEMBLY ("System.IO.FileSystem.Watcher"),
199 FACADE_ASSEMBLY ("System.IO.IsolatedStorage"),
200 FACADE_ASSEMBLY ("System.IO.MemoryMappedFiles"),
201 FACADE_ASSEMBLY ("System.IO.Packaging"),
202 FACADE_ASSEMBLY ("System.IO.Pipes"),
203 FACADE_ASSEMBLY ("System.IO.UnmanagedMemoryStream"),
204 FACADE_ASSEMBLY ("System.Linq"),
205 FACADE_ASSEMBLY ("System.Linq.Expressions"),
206 FACADE_ASSEMBLY ("System.Linq.Parallel"),
207 FACADE_ASSEMBLY ("System.Linq.Queryable"),
208 {"System.Management", 0},
209 FACADE_ASSEMBLY ("System.Memory"),
210 {"System.Messaging", 0},
212 FACADE_ASSEMBLY ("System.Net.AuthenticationManager"),
213 FACADE_ASSEMBLY ("System.Net.Cache"),
214 {"System.Net.Http", 4},
215 {"System.Net.Http.Rtc", 0},
216 {"System.Net.Http.WebRequest", 0},
217 FACADE_ASSEMBLY ("System.Net.HttpListener"),
218 FACADE_ASSEMBLY ("System.Net.Mail"),
219 FACADE_ASSEMBLY ("System.Net.NameResolution"),
220 FACADE_ASSEMBLY ("System.Net.NetworkInformation"),
221 FACADE_ASSEMBLY ("System.Net.Ping"),
222 FACADE_ASSEMBLY ("System.Net.Primitives"),
223 FACADE_ASSEMBLY ("System.Net.Requests"),
224 FACADE_ASSEMBLY ("System.Net.Security"),
225 FACADE_ASSEMBLY ("System.Net.ServicePoint"),
226 FACADE_ASSEMBLY ("System.Net.Sockets"),
227 FACADE_ASSEMBLY ("System.Net.Utilities"),
228 FACADE_ASSEMBLY ("System.Net.WebHeaderCollection"),
229 FACADE_ASSEMBLY ("System.Net.WebSockets"),
230 FACADE_ASSEMBLY ("System.Net.WebSockets.Client"),
231 {"System.Numerics", 3},
232 {"System.Numerics.Vectors", 3},
233 FACADE_ASSEMBLY ("System.ObjectModel"),
234 FACADE_ASSEMBLY ("System.Reflection"),
235 {"System.Reflection.Context", 0},
236 FACADE_ASSEMBLY ("System.Reflection.DispatchProxy"),
237 FACADE_ASSEMBLY ("System.Reflection.Emit"),
238 FACADE_ASSEMBLY ("System.Reflection.Emit.ILGeneration"),
239 FACADE_ASSEMBLY ("System.Reflection.Emit.Lightweight"),
240 FACADE_ASSEMBLY ("System.Reflection.Extensions"),
241 FACADE_ASSEMBLY ("System.Reflection.Primitives"),
242 FACADE_ASSEMBLY ("System.Reflection.TypeExtensions"),
243 FACADE_ASSEMBLY ("System.Resources.Reader"),
244 FACADE_ASSEMBLY ("System.Resources.ReaderWriter"),
245 FACADE_ASSEMBLY ("System.Resources.ResourceManager"),
246 FACADE_ASSEMBLY ("System.Resources.Writer"),
247 FACADE_ASSEMBLY ("System.Runtime"),
248 {"System.Runtime.Caching", 0},
249 FACADE_ASSEMBLY ("System.Runtime.CompilerServices.VisualC"),
250 {"System.Runtime.DurableInstancing", 0},
251 FACADE_ASSEMBLY ("System.Runtime.Extensions"),
252 FACADE_ASSEMBLY ("System.Runtime.Handles"),
253 FACADE_ASSEMBLY ("System.Runtime.InteropServices"),
254 FACADE_ASSEMBLY ("System.Runtime.InteropServices.RuntimeInformation"),
255 FACADE_ASSEMBLY ("System.Runtime.InteropServices.WindowsRuntime"),
256 FACADE_ASSEMBLY ("System.Runtime.Loader"),
257 FACADE_ASSEMBLY ("System.Runtime.Numerics"),
258 {"System.Runtime.Remoting", 0},
259 {"System.Runtime.Serialization", 3},
260 FACADE_ASSEMBLY ("System.Runtime.Serialization.Formatters"),
261 {"System.Runtime.Serialization.Formatters.Soap", 0},
262 FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"),
263 FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"),
264 FACADE_ASSEMBLY ("System.Runtime.Serialization.Xml"),
265 {"System.Security", 0},
266 FACADE_ASSEMBLY ("System.Security.AccessControl"),
267 FACADE_ASSEMBLY ("System.Security.Claims"),
268 FACADE_ASSEMBLY ("System.Security.Cryptography.Algorithms"),
269 FACADE_ASSEMBLY ("System.Security.Cryptography.Cng"),
270 FACADE_ASSEMBLY ("System.Security.Cryptography.Csp"),
271 FACADE_ASSEMBLY ("System.Security.Cryptography.DeriveBytes"),
272 FACADE_ASSEMBLY ("System.Security.Cryptography.Encoding"),
273 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption"),
274 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.Aes"),
275 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDiffieHellman"),
276 FACADE_ASSEMBLY ("System.Security.Cryptography.Encryption.ECDsa"),
277 FACADE_ASSEMBLY ("System.Security.Cryptography.Hashing"),
278 FACADE_ASSEMBLY ("System.Security.Cryptography.Hashing.Algorithms"),
279 FACADE_ASSEMBLY ("System.Security.Cryptography.OpenSsl"),
280 FACADE_ASSEMBLY ("System.Security.Cryptography.Pkcs"),
281 FACADE_ASSEMBLY ("System.Security.Cryptography.Primitives"),
282 FACADE_ASSEMBLY ("System.Security.Cryptography.ProtectedData"),
283 FACADE_ASSEMBLY ("System.Security.Cryptography.RSA"),
284 FACADE_ASSEMBLY ("System.Security.Cryptography.RandomNumberGenerator"),
285 FACADE_ASSEMBLY ("System.Security.Cryptography.X509Certificates"),
286 FACADE_ASSEMBLY ("System.Security.Principal"),
287 FACADE_ASSEMBLY ("System.Security.Principal.Windows"),
288 FACADE_ASSEMBLY ("System.Security.SecureString"),
289 {"System.ServiceModel", 3},
290 {"System.ServiceModel.Activation", 0},
291 {"System.ServiceModel.Discovery", 0},
292 FACADE_ASSEMBLY ("System.ServiceModel.Duplex"),
293 FACADE_ASSEMBLY ("System.ServiceModel.Http"),
294 FACADE_ASSEMBLY ("System.ServiceModel.NetTcp"),
295 FACADE_ASSEMBLY ("System.ServiceModel.Primitives"),
296 {"System.ServiceModel.Routing", 0},
297 FACADE_ASSEMBLY ("System.ServiceModel.Security"),
298 {"System.ServiceModel.Web", 2},
299 {"System.ServiceProcess", 0},
300 FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"),
301 FACADE_ASSEMBLY ("System.Text.Encoding"),
302 FACADE_ASSEMBLY ("System.Text.Encoding.CodePages"),
303 FACADE_ASSEMBLY ("System.Text.Encoding.Extensions"),
304 FACADE_ASSEMBLY ("System.Text.RegularExpressions"),
305 FACADE_ASSEMBLY ("System.Threading"),
306 FACADE_ASSEMBLY ("System.Threading.AccessControl"),
307 FACADE_ASSEMBLY ("System.Threading.Overlapped"),
308 FACADE_ASSEMBLY ("System.Threading.Tasks"),
309 {"System.Threading.Tasks.Dataflow", 0, NULL
, TRUE
},
310 FACADE_ASSEMBLY ("System.Threading.Tasks.Extensions"),
311 FACADE_ASSEMBLY ("System.Threading.Tasks.Parallel"),
312 FACADE_ASSEMBLY ("System.Threading.Thread"),
313 FACADE_ASSEMBLY ("System.Threading.ThreadPool"),
314 FACADE_ASSEMBLY ("System.Threading.Timer"),
315 {"System.Transactions", 0},
316 FACADE_ASSEMBLY ("System.ValueTuple"),
318 {"System.Web.Abstractions", 2},
319 {"System.Web.ApplicationServices", 0},
320 {"System.Web.DynamicData", 2},
321 {"System.Web.Extensions", 2},
322 {"System.Web.Extensions.Design", 0},
323 {"System.Web.Mobile", 0},
324 {"System.Web.RegularExpressions", 0},
325 {"System.Web.Routing", 2},
326 {"System.Web.Services", 0},
327 {"System.Windows", 0},
328 {"System.Windows.Forms", 0},
329 {"System.Windows.Forms.DataVisualization", 0},
330 {"System.Workflow.Activities", 0},
331 {"System.Workflow.ComponentModel", 0},
332 {"System.Workflow.Runtime", 0},
335 {"System.Xml.Linq", 2},
336 FACADE_ASSEMBLY ("System.Xml.ReaderWriter"),
337 {"System.Xml.Serialization", 0},
338 FACADE_ASSEMBLY ("System.Xml.XDocument"),
339 FACADE_ASSEMBLY ("System.Xml.XPath"),
340 FACADE_ASSEMBLY ("System.Xml.XPath.XmlDocument"),
341 FACADE_ASSEMBLY ("System.Xml.XPath.XDocument"),
342 FACADE_ASSEMBLY ("System.Xml.XmlDocument"),
343 FACADE_ASSEMBLY ("System.Xml.XmlSerializer"),
344 FACADE_ASSEMBLY ("System.Xml.Xsl.Primitives"),
348 FACADE_ASSEMBLY ("netstandard"),
352 /* keeps track of loaded assemblies, excluding dynamic ones */
353 static GList
*loaded_assemblies
= NULL
;
354 static MonoAssembly
*corlib
;
356 static char* unquote (const char *str
);
358 /* This protects loaded_assemblies and image->references */
359 #define mono_assemblies_lock() mono_os_mutex_lock (&assemblies_mutex)
360 #define mono_assemblies_unlock() mono_os_mutex_unlock (&assemblies_mutex)
361 static mono_mutex_t assemblies_mutex
;
363 /* If defined, points to the bundled assembly information */
364 static const MonoBundledAssembly
**bundles
;
366 static mono_mutex_t assembly_binding_mutex
;
368 /* Loaded assembly binding info */
369 static GSList
*loaded_assembly_bindings
= NULL
;
371 /* Class lazy loading functions */
372 static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible
, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
374 mono_assembly_invoke_search_hook_internal (MonoAssemblyLoadContext
*alc
, MonoAssembly
*requesting
, MonoAssemblyName
*aname
, gboolean refonly
, gboolean postload
);
376 mono_assembly_request_byname_nosearch (MonoAssemblyName
*aname
, const MonoAssemblyByNameRequest
*req
, MonoImageOpenStatus
*status
);
378 mono_assembly_load_full_gac_base_default (MonoAssemblyName
*aname
, const char *basedir
, MonoAssemblyLoadContext
*alc
, MonoAssemblyContextKind asmctx
, MonoImageOpenStatus
*status
);
380 chain_redirections_loadfrom (MonoImage
*image
, MonoImageOpenStatus
*status
);
382 mono_problematic_image_reprobe (MonoImage
*image
, MonoImageOpenStatus
*status
);
385 mono_assembly_is_in_gac (const gchar
*filanem
);
386 static MonoAssemblyName
*
387 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
);
390 prevent_reference_assembly_from_running (MonoAssembly
* candidate
, gboolean refonly
);
392 /* Assembly name matching */
394 exact_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
);
396 framework_assembly_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
);
399 mono_asmctx_get_name (const MonoAssemblyContext
*asmctx
);
402 assembly_loadfrom_asmctx_from_path (const char *filename
, MonoAssembly
*requesting_assembly
, gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
);
405 encode_public_tok (const guchar
*token
, gint32 len
)
407 const static gchar allowed
[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
411 res
= (gchar
*)g_malloc (len
* 2 + 1);
412 for (i
= 0; i
< len
; i
++) {
413 res
[i
* 2] = allowed
[token
[i
] >> 4];
414 res
[i
* 2 + 1] = allowed
[token
[i
] & 0xF];
421 * mono_public_tokens_are_equal:
422 * \param pubt1 first public key token
423 * \param pubt2 second public key token
425 * Compare two public key tokens and return TRUE is they are equal and FALSE
429 mono_public_tokens_are_equal (const unsigned char *pubt1
, const unsigned char *pubt2
)
431 return g_ascii_strncasecmp ((const char*) pubt1
, (const char*) pubt2
, 16) == 0;
435 * mono_set_assemblies_path:
436 * \param path list of paths that contain directories where Mono will look for assemblies
438 * Use this method to override the standard assembly lookup system and
439 * override any assemblies coming from the GAC. This is the method
440 * that supports the \c MONO_PATH variable.
442 * Notice that \c MONO_PATH and this method are really a very bad idea as
443 * it prevents the GAC from working and it prevents the standard
444 * resolution mechanisms from working. Nonetheless, for some debugging
445 * situations and bootstrapping setups, this is useful to have.
448 mono_set_assemblies_path (const char* path
)
450 char **splitted
, **dest
;
452 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
454 g_strfreev (assemblies_path
);
455 assemblies_path
= dest
= splitted
;
457 char *tmp
= *splitted
;
459 *dest
++ = mono_path_canonicalize (tmp
);
465 if (g_hasenv ("MONO_DEBUG"))
468 splitted
= assemblies_path
;
470 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
471 g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted
);
478 check_path_env (void)
480 if (assemblies_path
!= NULL
)
483 char* path
= g_getenv ("MONO_PATH");
487 mono_set_assemblies_path(path
);
493 check_extra_gac_path_env (void)
496 char **splitted
, **dest
;
498 path
= g_getenv ("MONO_GAC_PREFIX");
502 splitted
= g_strsplit (path
, G_SEARCHPATH_SEPARATOR_S
, 1000);
506 g_strfreev (extra_gac_paths
);
507 extra_gac_paths
= dest
= splitted
;
515 if (!g_hasenv ("MONO_DEBUG"))
519 if (**splitted
&& !g_file_test (*splitted
, G_FILE_TEST_IS_DIR
))
520 g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted
);
525 #endif /* DISABLE_GAC */
528 assembly_binding_maps_name (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
530 if (!info
|| !info
->name
)
533 if (strcmp (info
->name
, aname
->name
))
536 if (info
->major
!= aname
->major
|| info
->minor
!= aname
->minor
)
539 if ((info
->culture
!= NULL
&& info
->culture
[0]) != (aname
->culture
!= NULL
&& aname
->culture
[0]))
542 if (info
->culture
&& aname
->culture
&& strcmp (info
->culture
, aname
->culture
))
545 if (!mono_public_tokens_are_equal (info
->public_key_token
, aname
->public_key_token
))
552 mono_assembly_binding_info_free (MonoAssemblyBindingInfo
*info
)
558 g_free (info
->culture
);
562 get_publisher_policy_info (MonoImage
*image
, MonoAssemblyName
*aname
, MonoAssemblyBindingInfo
*binding_info
)
565 guint32 cols
[MONO_MANIFEST_SIZE
];
566 const gchar
*filename
;
567 gchar
*subpath
, *fullpath
;
569 t
= &image
->tables
[MONO_TABLE_MANIFESTRESOURCE
];
570 /* MS Impl. accepts policy assemblies with more than
571 * one manifest resource, and only takes the first one */
573 binding_info
->is_valid
= FALSE
;
577 mono_metadata_decode_row (t
, 0, cols
, MONO_MANIFEST_SIZE
);
578 if ((cols
[MONO_MANIFEST_IMPLEMENTATION
] & MONO_IMPLEMENTATION_MASK
) != MONO_IMPLEMENTATION_FILE
) {
579 binding_info
->is_valid
= FALSE
;
583 filename
= mono_metadata_string_heap (image
, cols
[MONO_MANIFEST_NAME
]);
584 g_assert (filename
!= NULL
);
586 subpath
= g_path_get_dirname (image
->name
);
587 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, subpath
, filename
, NULL
);
588 mono_config_parse_publisher_policy (fullpath
, binding_info
);
592 /* Define the optional elements/attributes before checking */
593 if (!binding_info
->culture
)
594 binding_info
->culture
= g_strdup ("");
596 /* Check that the most important elements/attributes exist */
597 if (!binding_info
->name
|| !binding_info
->public_key_token
[0] || !binding_info
->has_old_version_bottom
||
598 !binding_info
->has_new_version
|| !assembly_binding_maps_name (binding_info
, aname
)) {
599 mono_assembly_binding_info_free (binding_info
);
600 binding_info
->is_valid
= FALSE
;
604 binding_info
->is_valid
= TRUE
;
608 compare_versions (AssemblyVersionSet
*v
, MonoAssemblyName
*aname
)
610 if (v
->major
> aname
->major
)
612 else if (v
->major
< aname
->major
)
615 if (v
->minor
> aname
->minor
)
617 else if (v
->minor
< aname
->minor
)
620 if (v
->build
> aname
->build
)
622 else if (v
->build
< aname
->build
)
625 if (v
->revision
> aname
->revision
)
627 else if (v
->revision
< aname
->revision
)
634 check_policy_versions (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*name
)
639 /* If has_old_version_top doesn't exist, we don't have an interval */
640 if (!info
->has_old_version_top
) {
641 if (compare_versions (&info
->old_version_bottom
, name
) == 0)
647 /* Check that the version defined by name is valid for the interval */
648 if (compare_versions (&info
->old_version_top
, name
) < 0)
651 /* We should be greater or equal than the small version */
652 if (compare_versions (&info
->old_version_bottom
, name
) > 0)
659 * mono_assembly_names_equal:
660 * \param l first assembly
661 * \param r second assembly.
663 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
665 * This compares the names, the cultures, the release version and their
668 * \returns TRUE if both assembly names are equal.
671 mono_assembly_names_equal (MonoAssemblyName
*l
, MonoAssemblyName
*r
)
673 return mono_assembly_names_equal_flags (l
, r
, MONO_ANAME_EQ_NONE
);
677 * mono_assembly_names_equal_flags:
678 * \param l first assembly name
679 * \param r second assembly name
680 * \param flags flags that affect what is compared.
682 * Compares two \c MonoAssemblyName instances and returns whether they are equal.
684 * This compares the simple names and cultures and optionally the versions and
685 * public key tokens, depending on the \c flags.
687 * \returns TRUE if both assembly names are equal.
690 mono_assembly_names_equal_flags (MonoAssemblyName
*l
, MonoAssemblyName
*r
, MonoAssemblyNameEqFlags flags
)
692 g_assert (l
!= NULL
);
693 g_assert (r
!= NULL
);
695 if (!l
->name
|| !r
->name
)
698 if ((flags
& MONO_ANAME_EQ_IGNORE_CASE
) != 0 && g_strcasecmp (l
->name
, r
->name
))
701 if ((flags
& MONO_ANAME_EQ_IGNORE_CASE
) == 0 && strcmp (l
->name
, r
->name
))
704 if (l
->culture
&& r
->culture
&& strcmp (l
->culture
, r
->culture
))
707 if ((l
->major
!= r
->major
|| l
->minor
!= r
->minor
||
708 l
->build
!= r
->build
|| l
->revision
!= r
->revision
) &&
709 (flags
& MONO_ANAME_EQ_IGNORE_VERSION
) == 0)
710 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)))
713 if (!l
->public_key_token
[0] || !r
->public_key_token
[0] || (flags
& MONO_ANAME_EQ_IGNORE_PUBKEY
) != 0)
716 if (!mono_public_tokens_are_equal (l
->public_key_token
, r
->public_key_token
))
723 * assembly_names_compare_versions:
724 * \param l left assembly name
725 * \param r right assembly name
726 * \param maxcomps how many version components to compare, or -1 to compare all.
728 * \returns a negative if \p l is a lower version than \p r; a positive value
729 * if \p r is a lower version than \p l, or zero if \p l and \p r are equal
730 * versions (comparing upto \p maxcomps components).
732 * Components are \c major, \c minor, \c revision, and \c build. \p maxcomps 1 means just compare
733 * majors. 2 means majors then minors. etc.
736 assembly_names_compare_versions (MonoAssemblyName
*l
, MonoAssemblyName
*r
, int maxcomps
)
739 if (maxcomps
< 0) maxcomps
= 4;
740 #define CMP(field) do { \
741 if (l-> field < r-> field && i < maxcomps) return -1; \
742 if (l-> field > r-> field && i < maxcomps) return 1; \
756 * mono_assembly_request_prepare:
757 * \param req the request to be initialized
758 * \param req_size the size of the request structure
759 * \param asmctx the assembly load context kind
761 * Initialize an assembly loader request. The passed structure \p req must be
762 * of size \p req_size. Its state will be reset and the assembly context kind will be prefilled with \p asmctx.
765 mono_assembly_request_prepare (MonoAssemblyLoadRequest
*req
, size_t req_size
, MonoAssemblyContextKind asmctx
)
767 memset (req
, 0, req_size
);
768 req
->asmctx
= asmctx
;
771 static MonoAssembly
*
772 load_in_path (const char *basename
, const char** search_path
, const MonoAssemblyOpenRequest
*req
, MonoImageOpenStatus
*status
)
776 MonoAssembly
*result
;
778 for (i
= 0; search_path
[i
]; ++i
) {
779 fullpath
= g_build_filename (search_path
[i
], basename
, NULL
);
780 result
= mono_assembly_request_open (fullpath
, req
, status
);
789 * mono_assembly_setrootdir:
790 * \param root_dir The pathname of the root directory where we will locate assemblies
792 * This routine sets the internal default root directory for looking up
795 * This is used by Windows installations to compute dynamically the
796 * place where the Mono assemblies are located.
800 mono_assembly_setrootdir (const char *root_dir
)
803 * Override the MONO_ASSEMBLIES directory configured at compile time.
805 if (default_path
[0])
806 g_free (default_path
[0]);
807 default_path
[0] = g_strdup (root_dir
);
811 * mono_assembly_getrootdir:
813 * Obtains the root directory used for looking up assemblies.
815 * Returns: a string with the directory, this string should not be freed.
817 G_CONST_RETURN gchar
*
818 mono_assembly_getrootdir (void)
820 return default_path
[0];
824 * mono_native_getrootdir:
826 * Obtains the root directory used for looking up native libs (.so, .dylib).
828 * Returns: a string with the directory, this string should be freed by
832 mono_native_getrootdir (void)
834 gchar
* fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL
);
840 * \param assembly_dir the base directory for assemblies
841 * \param config_dir the base directory for configuration files
843 * This routine is used internally and by developers embedding
844 * the runtime into their own applications.
846 * There are a number of cases to consider: Mono as a system-installed
847 * package that is available on the location preconfigured or Mono in
848 * a relocated location.
850 * If you are using a system-installed Mono, you can pass NULL
851 * to both parameters. If you are not, you should compute both
852 * directory values and call this routine.
854 * The values for a given PREFIX are:
856 * assembly_dir: PREFIX/lib
857 * config_dir: PREFIX/etc
859 * Notice that embedders that use Mono in a relocated way must
860 * compute the location at runtime, as they will be in control
861 * of where Mono is installed.
864 mono_set_dirs (const char *assembly_dir
, const char *config_dir
)
866 if (assembly_dir
== NULL
)
867 assembly_dir
= mono_config_get_assemblies_dir ();
868 if (config_dir
== NULL
)
869 config_dir
= mono_config_get_cfg_dir ();
870 mono_assembly_setrootdir (assembly_dir
);
871 mono_set_config_dir (config_dir
);
877 compute_base (char *path
)
879 char *p
= strrchr (path
, '/');
883 /* Not a well known Mono executable, we are embedded, cant guess the base */
884 if (strcmp (p
, "/mono") && strcmp (p
, "/mono-boehm") && strcmp (p
, "/mono-sgen") && strcmp (p
, "/pedump") && strcmp (p
, "/monodis"))
888 p
= strrchr (path
, '/');
892 if (strcmp (p
, "/bin") != 0)
901 mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
904 static G_GNUC_UNUSED
void
908 char *config
, *lib
, *mono
;
913 * Only /usr prefix is treated specially
915 bindir
= mono_config_get_bin_dir ();
917 if (strncmp (exe
, bindir
, strlen (bindir
)) == 0 || (base
= compute_base (exe
)) == NULL
){
922 config
= g_build_filename (base
, "etc", NULL
);
923 lib
= g_build_filename (base
, "lib", NULL
);
924 mono
= g_build_filename (lib
, "mono/4.5", NULL
); // FIXME: stop hardcoding 4.5 here
925 if (stat (mono
, &buf
) == -1)
928 mono_set_dirs (lib
, config
);
936 #endif /* HOST_WIN32 */
941 * Registers the root directory for the Mono runtime, for Linux and Solaris 10,
942 * this auto-detects the prefix where Mono was installed.
945 mono_set_rootdir (void)
947 #if defined(HOST_WIN32) || (defined(HOST_DARWIN) && !defined(TARGET_ARM))
948 gchar
*bindir
, *installdir
, *root
, *name
, *resolvedname
, *config
;
951 name
= mono_get_module_file_name ((HMODULE
) &__ImageBase
);
955 * _NSGetExecutablePath may return -1 to indicate buf is not large
956 * enough, but we ignore that case to avoid having to do extra dynamic
957 * allocation for the path and hope that 4096 is enough - this is
958 * ok in the Linux/Solaris case below at least...
962 guint buf_size
= sizeof (buf
);
965 if (_NSGetExecutablePath (buf
, &buf_size
) == 0)
966 name
= g_strdup (buf
);
975 resolvedname
= mono_path_resolve_symlinks (name
);
977 bindir
= g_path_get_dirname (resolvedname
);
978 installdir
= g_path_get_dirname (bindir
);
979 root
= g_build_path (G_DIR_SEPARATOR_S
, installdir
, "lib", NULL
);
981 config
= g_build_filename (root
, "..", "etc", NULL
);
983 mono_set_dirs (root
, config
);
985 if (g_file_test (root
, G_FILE_TEST_EXISTS
) && g_file_test (config
, G_FILE_TEST_EXISTS
))
986 mono_set_dirs (root
, config
);
996 g_free (resolvedname
);
997 #elif defined(DISABLE_MONO_AUTODETECTION)
1004 #if defined(HAVE_READLINK)
1006 s
= readlink ("/proc/self/exe", buf
, sizeof (buf
)-1);
1017 /* Solaris 10 style */
1018 str
= g_strdup_printf ("/proc/%d/path/a.out", getpid ());
1020 #if defined(HAVE_READLINK)
1021 s
= readlink (str
, buf
, sizeof (buf
)-1);
1037 * mono_assemblies_init:
1039 * Initialize global variables used by this module.
1042 mono_assemblies_init (void)
1045 * Initialize our internal paths if we have not been initialized yet.
1046 * This happens when embedders use Mono.
1048 if (mono_assembly_getrootdir () == NULL
)
1049 mono_set_rootdir ();
1053 check_extra_gac_path_env ();
1056 mono_os_mutex_init_recursive (&assemblies_mutex
);
1057 mono_os_mutex_init (&assembly_binding_mutex
);
1059 #ifndef DISABLE_DESKTOP_LOADER
1060 assembly_remapping_table
= g_hash_table_new (g_str_hash
, g_str_equal
);
1063 for (i
= 0; i
< G_N_ELEMENTS (framework_assemblies
); ++i
)
1064 g_hash_table_insert (assembly_remapping_table
, (void*)framework_assemblies
[i
].assembly_name
, (void*)&framework_assemblies
[i
]);
1067 mono_install_assembly_asmctx_from_path_hook (assembly_loadfrom_asmctx_from_path
, NULL
);
1072 mono_assembly_binding_lock (void)
1074 mono_locks_os_acquire (&assembly_binding_mutex
, AssemblyBindingLock
);
1078 mono_assembly_binding_unlock (void)
1080 mono_locks_os_release (&assembly_binding_mutex
, AssemblyBindingLock
);
1084 mono_assembly_fill_assembly_name_full (MonoImage
*image
, MonoAssemblyName
*aname
, gboolean copyBlobs
)
1086 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLY
];
1087 guint32 cols
[MONO_ASSEMBLY_SIZE
];
1088 gint32 machine
, flags
;
1093 mono_metadata_decode_row (t
, 0, cols
, MONO_ASSEMBLY_SIZE
);
1095 aname
->hash_len
= 0;
1096 aname
->hash_value
= NULL
;
1097 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_NAME
]);
1099 aname
->name
= g_strdup (aname
->name
);
1100 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLY_CULTURE
]);
1102 aname
->culture
= g_strdup (aname
->culture
);
1103 aname
->flags
= cols
[MONO_ASSEMBLY_FLAGS
];
1104 aname
->major
= cols
[MONO_ASSEMBLY_MAJOR_VERSION
];
1105 aname
->minor
= cols
[MONO_ASSEMBLY_MINOR_VERSION
];
1106 aname
->build
= cols
[MONO_ASSEMBLY_BUILD_NUMBER
];
1107 aname
->revision
= cols
[MONO_ASSEMBLY_REV_NUMBER
];
1108 aname
->hash_alg
= cols
[MONO_ASSEMBLY_HASH_ALG
];
1109 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
1110 guchar
* token
= (guchar
*)g_malloc (8);
1115 pkey
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
1116 len
= mono_metadata_decode_blob_size (pkey
, &pkey
);
1117 aname
->public_key
= (guchar
*)pkey
;
1119 mono_digest_get_public_token (token
, aname
->public_key
, len
);
1120 encoded
= encode_public_tok (token
, 8);
1121 g_strlcpy ((char*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1127 aname
->public_key
= NULL
;
1128 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1131 if (cols
[MONO_ASSEMBLY_PUBLIC_KEY
]) {
1132 aname
->public_key
= (guchar
*)mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLY_PUBLIC_KEY
]);
1134 const gchar
*pkey_end
;
1135 int len
= mono_metadata_decode_blob_size ((const gchar
*) aname
->public_key
, &pkey_end
);
1136 pkey_end
+= len
; /* move to end */
1137 size_t size
= pkey_end
- (const gchar
*)aname
->public_key
;
1138 guchar
*tmp
= g_new (guchar
, size
);
1139 memcpy (tmp
, aname
->public_key
, size
);
1140 aname
->public_key
= tmp
;
1145 aname
->public_key
= 0;
1147 machine
= image
->image_info
->cli_header
.coff
.coff_machine
;
1148 flags
= image
->image_info
->cli_cli_header
.ch_flags
;
1150 case COFF_MACHINE_I386
:
1151 /* https://bugzilla.xamarin.com/show_bug.cgi?id=17632 */
1152 if (flags
& (CLI_FLAGS_32BITREQUIRED
|CLI_FLAGS_PREFERRED32BIT
))
1153 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_X86
;
1154 else if ((flags
& 0x70) == 0x70)
1155 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_NONE
;
1157 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_MSIL
;
1159 case COFF_MACHINE_IA64
:
1160 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_IA64
;
1162 case COFF_MACHINE_AMD64
:
1163 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_AMD64
;
1165 case COFF_MACHINE_ARM
:
1166 aname
->arch
= MONO_PROCESSOR_ARCHITECTURE_ARM
;
1176 * mono_assembly_fill_assembly_name:
1177 * \param image Image
1179 * \returns TRUE if successful
1182 mono_assembly_fill_assembly_name (MonoImage
*image
, MonoAssemblyName
*aname
)
1184 return mono_assembly_fill_assembly_name_full (image
, aname
, FALSE
);
1188 * mono_stringify_assembly_name:
1189 * \param aname the assembly name.
1191 * Convert \p aname into its string format. The returned string is dynamically
1192 * allocated and should be freed by the caller.
1194 * \returns a newly allocated string with a string representation of
1195 * the assembly name.
1198 mono_stringify_assembly_name (MonoAssemblyName
*aname
)
1200 const char *quote
= (aname
->name
&& g_ascii_isspace (aname
->name
[0])) ? "\"" : "";
1202 return g_strdup_printf (
1203 "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
1204 quote
, aname
->name
, quote
,
1205 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1206 aname
->culture
&& *aname
->culture
? aname
->culture
: "neutral",
1207 aname
->public_key_token
[0] ? (char *)aname
->public_key_token
: "null",
1208 (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
1212 assemblyref_public_tok (MonoImage
*image
, guint32 key_index
, guint32 flags
)
1214 const gchar
*public_tok
;
1217 public_tok
= mono_metadata_blob_heap (image
, key_index
);
1218 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
1220 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
1222 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
1223 return encode_public_tok (token
, 8);
1226 return encode_public_tok ((guchar
*)public_tok
, len
);
1230 assemblyref_public_tok_checked (MonoImage
*image
, guint32 key_index
, guint32 flags
, MonoError
*error
)
1232 const gchar
*public_tok
;
1235 public_tok
= mono_metadata_blob_heap_checked (image
, key_index
, error
);
1236 return_val_if_nok (error
, NULL
);
1237 len
= mono_metadata_decode_blob_size (public_tok
, &public_tok
);
1239 if (flags
& ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG
) {
1241 mono_digest_get_public_token (token
, (guchar
*)public_tok
, len
);
1242 return encode_public_tok (token
, 8);
1244 return encode_public_tok ((guchar
*)public_tok
, len
);
1248 * mono_assembly_addref:
1249 * \param assembly the assembly to reference
1251 * This routine increments the reference count on a MonoAssembly.
1252 * The reference count is reduced every time the method mono_assembly_close() is
1256 mono_assembly_addref (MonoAssembly
*assembly
)
1258 mono_atomic_inc_i32 (&assembly
->ref_count
);
1262 * CAUTION: This table must be kept in sync with
1263 * ivkm/reflect/Fusion.cs
1266 #define SILVERLIGHT_KEY "7cec85d7bea7798e"
1267 #define WINFX_KEY "31bf3856ad364e35"
1268 #define ECMA_KEY "b77a5c561934e089"
1269 #define MSFINAL_KEY "b03f5f7f11d50a3a"
1270 #define COMPACTFRAMEWORK_KEY "969db8053d3322ac"
1278 static KeyRemapEntry key_remap_table
[] = {
1279 { "CustomMarshalers", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1280 { "Microsoft.CSharp", WINFX_KEY
, MSFINAL_KEY
},
1281 { "Microsoft.VisualBasic", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1282 { "System", SILVERLIGHT_KEY
, ECMA_KEY
},
1283 { "System", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1284 { "System.ComponentModel.Composition", WINFX_KEY
, ECMA_KEY
},
1285 { "System.ComponentModel.DataAnnotations", "ddd0da4d3e678217", WINFX_KEY
},
1286 { "System.Core", SILVERLIGHT_KEY
, ECMA_KEY
},
1287 { "System.Core", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1288 { "System.Data", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1289 { "System.Data.DataSetExtensions", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1290 { "System.Drawing", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1291 { "System.Messaging", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1292 // FIXME: MS uses MSFINAL_KEY for .NET 4.5
1293 { "System.Net", SILVERLIGHT_KEY
, MSFINAL_KEY
},
1294 { "System.Numerics", WINFX_KEY
, ECMA_KEY
},
1295 { "System.Runtime.Serialization", SILVERLIGHT_KEY
, ECMA_KEY
},
1296 { "System.Runtime.Serialization", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1297 { "System.ServiceModel", WINFX_KEY
, ECMA_KEY
},
1298 { "System.ServiceModel", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1299 { "System.ServiceModel.Web", SILVERLIGHT_KEY
, WINFX_KEY
},
1300 { "System.Web.Services", COMPACTFRAMEWORK_KEY
, MSFINAL_KEY
},
1301 { "System.Windows", SILVERLIGHT_KEY
, MSFINAL_KEY
},
1302 { "System.Windows.Forms", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1303 { "System.Xml", SILVERLIGHT_KEY
, ECMA_KEY
},
1304 { "System.Xml", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1305 { "System.Xml.Linq", WINFX_KEY
, ECMA_KEY
},
1306 { "System.Xml.Linq", COMPACTFRAMEWORK_KEY
, ECMA_KEY
},
1307 { "System.Xml.Serialization", WINFX_KEY
, ECMA_KEY
}
1311 remap_keys (MonoAssemblyName
*aname
)
1314 for (i
= 0; i
< G_N_ELEMENTS (key_remap_table
); i
++) {
1315 const KeyRemapEntry
*entry
= &key_remap_table
[i
];
1317 if (strcmp (aname
->name
, entry
->name
) ||
1318 !mono_public_tokens_are_equal (aname
->public_key_token
, (const unsigned char*) entry
->from
))
1321 memcpy (aname
->public_key_token
, entry
->to
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1323 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1324 "Remapped public key token of retargetable assembly %s from %s to %s",
1325 aname
->name
, entry
->from
, entry
->to
);
1330 static MonoAssemblyName
*
1331 mono_assembly_remap_version (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_aname
)
1333 const MonoRuntimeInfo
*current_runtime
;
1335 if (aname
->name
== NULL
) return aname
;
1337 current_runtime
= mono_get_runtime_info ();
1339 if (aname
->flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) {
1340 const AssemblyVersionSet
* vset
;
1342 /* Remap to current runtime */
1343 vset
= ¤t_runtime
->version_sets
[0];
1345 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
1346 dest_aname
->major
= vset
->major
;
1347 dest_aname
->minor
= vset
->minor
;
1348 dest_aname
->build
= vset
->build
;
1349 dest_aname
->revision
= vset
->revision
;
1350 dest_aname
->flags
&= ~ASSEMBLYREF_RETARGETABLE_FLAG
;
1352 /* Remap assembly name */
1353 if (!strcmp (aname
->name
, "System.Net"))
1354 dest_aname
->name
= g_strdup ("System");
1356 remap_keys (dest_aname
);
1358 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
1359 "The request to load the retargetable assembly %s v%d.%d.%d.%d was remapped to %s v%d.%d.%d.%d",
1361 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1363 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1369 #ifndef DISABLE_DESKTOP_LOADER
1370 const AssemblyVersionMap
*vmap
= (AssemblyVersionMap
*)g_hash_table_lookup (assembly_remapping_table
, aname
->name
);
1372 const AssemblyVersionSet
* vset
;
1373 int index
= vmap
->version_set_index
;
1374 g_assert (index
< G_N_ELEMENTS (current_runtime
->version_sets
));
1375 vset
= ¤t_runtime
->version_sets
[index
];
1377 if (vmap
->framework_facade_assembly
) {
1378 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Assembly %s is a framework Facade asseembly",
1383 if (aname
->major
== vset
->major
&& aname
->minor
== vset
->minor
&&
1384 aname
->build
== vset
->build
&& aname
->revision
== vset
->revision
) {
1385 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
1387 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
);
1391 if (vmap
->only_lower_versions
&& compare_versions ((AssemblyVersionSet
*)vset
, aname
) < 0) {
1392 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
,
1393 "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
1395 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1396 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1401 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0)
1402 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
1403 "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
1405 aname
->major
, aname
->minor
, aname
->build
, aname
->revision
,
1406 vset
->major
, vset
->minor
, vset
->build
, vset
->revision
1409 memcpy (dest_aname
, aname
, sizeof(MonoAssemblyName
));
1410 dest_aname
->major
= vset
->major
;
1411 dest_aname
->minor
= vset
->minor
;
1412 dest_aname
->build
= vset
->build
;
1413 dest_aname
->revision
= vset
->revision
;
1414 if (vmap
->new_assembly_name
!= NULL
) {
1415 dest_aname
->name
= vmap
->new_assembly_name
;
1416 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
,
1417 "The assembly name %s was remapped to %s",
1429 * mono_assembly_get_assemblyref:
1430 * \param image pointer to the \c MonoImage to extract the information from.
1431 * \param index index to the assembly reference in the image.
1432 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1434 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1437 mono_assembly_get_assemblyref (MonoImage
*image
, int index
, MonoAssemblyName
*aname
)
1440 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
1443 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1445 mono_metadata_decode_row (t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
);
1447 hash
= mono_metadata_blob_heap (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
]);
1448 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
1449 aname
->hash_value
= hash
;
1450 aname
->name
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_NAME
]);
1451 aname
->culture
= mono_metadata_string_heap (image
, cols
[MONO_ASSEMBLYREF_CULTURE
]);
1452 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
1453 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
1454 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
1455 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
1456 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
1458 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
1459 gchar
*token
= assemblyref_public_tok (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
);
1460 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1463 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1467 static MonoAssembly
*
1468 load_reference_by_aname_refonly_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*assm
, MonoImageOpenStatus
*status
)
1470 MonoAssembly
*reference
= NULL
;
1471 g_assert (assm
!= NULL
);
1472 g_assert (status
!= NULL
);
1473 *status
= MONO_IMAGE_OK
;
1475 /* We use the loaded corlib */
1476 if (!strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
)) {
1477 MonoAssemblyByNameRequest req
;
1478 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
1479 req
.requesting_assembly
= assm
;
1480 req
.basedir
= assm
->basedir
;
1481 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1483 reference
= mono_assembly_loaded_internal (NULL
, aname
, TRUE
);
1485 /* Try a postload search hook */
1486 reference
= mono_assembly_invoke_search_hook_internal (NULL
, assm
, aname
, TRUE
, TRUE
);
1490 * Here we must advice that the error was due to
1491 * a non loaded reference using the ReflectionOnly api
1494 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1499 static MonoAssembly
*
1500 load_reference_by_aname_default_asmctx (MonoAssemblyName
*aname
, MonoAssemblyLoadContext
*alc
, MonoAssembly
*assm
, MonoImageOpenStatus
*status
)
1502 MonoAssembly
*reference
= NULL
;
1503 g_assert (status
!= NULL
);
1504 *status
= MONO_IMAGE_OK
;
1506 /* we first try without setting the basedir: this can eventually result in a ResolveAssembly
1507 * event which is the MS .net compatible behaviour (the assemblyresolve_event3.cs test has been fixed
1508 * accordingly, it would fail on the MS runtime before).
1509 * The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
1510 * example bug-349190.2.cs and who knows how much more code in the wild.
1512 MonoAssemblyByNameRequest req
;
1513 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
1514 req
.request
.alc
= alc
;
1515 req
.requesting_assembly
= assm
;
1516 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1517 if (!reference
&& assm
) {
1518 memset (&req
, 0, sizeof (req
));
1519 req
.request
.asmctx
= MONO_ASMCTX_DEFAULT
;
1520 req
.request
.alc
= alc
;
1521 req
.requesting_assembly
= assm
;
1522 req
.basedir
= assm
->basedir
;
1523 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1529 static MonoAssembly
*
1530 load_reference_by_aname_loadfrom_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, MonoImageOpenStatus
*status
)
1532 MonoAssembly
*reference
= NULL
;
1533 MonoAssemblyByNameRequest req
;
1534 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_LOADFROM
);
1535 req
.requesting_assembly
= requesting
;
1536 req
.basedir
= requesting
->basedir
;
1537 /* Just like default search, but look in the requesting assembly basedir right away */
1538 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1543 static MonoAssembly
*
1544 load_reference_by_aname_individual_asmctx (MonoAssemblyName
*aname
, MonoAssembly
*requesting
, MonoImageOpenStatus
*status
)
1546 /* For an individual assembly, all references must already be loaded or
1547 * else we fire the assembly resolve event - similar to refonly - but
1548 * subject to remaping and binding.
1551 g_assert (status
!= NULL
);
1553 MonoAssembly
*reference
= NULL
;
1554 *status
= MONO_IMAGE_OK
;
1555 MonoAssemblyName maped_aname
;
1556 MonoAssemblyName maped_name_pp
;
1558 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
1559 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
1561 reference
= mono_assembly_loaded_internal (mono_domain_ambient_alc (mono_domain_get ()), aname
, FALSE
);
1562 /* Still try to load from application base directory, MONO_PATH or the
1563 * GAC. This is consistent with what .NET Framework (4.7) actually
1564 * does, rather than what the documentation implies: If `LoadFile` is
1565 * used to load an assembly into "no context"/individual assembly
1566 * context, the runtime will still load assemblies from the GAC or the
1567 * application base directory (e.g. `System.Runtime` will be loaded if
1568 * it wasn't already).
1569 * Moreover, those referenced assemblies are loaded in the default context.
1572 MonoAssemblyByNameRequest req
;
1573 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
1574 req
.requesting_assembly
= requesting
;
1575 reference
= mono_assembly_request_byname (aname
, &req
, status
);
1578 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1583 * mono_assembly_get_assemblyref:
1584 * \param image pointer to the \c MonoImage to extract the information from.
1585 * \param index index to the assembly reference in the image.
1586 * \param aname pointer to a \c MonoAssemblyName that will hold the returned value.
1587 * \param error set on error
1589 * Fills out the \p aname with the assembly name of the \p index assembly reference in \p image.
1591 * \returns TRUE on success, otherwise sets \p error and returns FALSE
1594 mono_assembly_get_assemblyref_checked (MonoImage
*image
, int index
, MonoAssemblyName
*aname
, MonoError
*error
)
1597 guint32 cols
[MONO_ASSEMBLYREF_SIZE
];
1600 t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1602 if (!mono_metadata_decode_row_checked (image
, t
, index
, cols
, MONO_ASSEMBLYREF_SIZE
, error
))
1605 hash
= mono_metadata_blob_heap_checked (image
, cols
[MONO_ASSEMBLYREF_HASH_VALUE
], error
);
1606 return_val_if_nok (error
, FALSE
);
1607 aname
->hash_len
= mono_metadata_decode_blob_size (hash
, &hash
);
1608 aname
->hash_value
= hash
;
1609 aname
->name
= mono_metadata_string_heap_checked (image
, cols
[MONO_ASSEMBLYREF_NAME
], error
);
1610 return_val_if_nok (error
, FALSE
);
1611 aname
->culture
= mono_metadata_string_heap_checked (image
, cols
[MONO_ASSEMBLYREF_CULTURE
], error
);
1612 return_val_if_nok (error
, FALSE
);
1613 aname
->flags
= cols
[MONO_ASSEMBLYREF_FLAGS
];
1614 aname
->major
= cols
[MONO_ASSEMBLYREF_MAJOR_VERSION
];
1615 aname
->minor
= cols
[MONO_ASSEMBLYREF_MINOR_VERSION
];
1616 aname
->build
= cols
[MONO_ASSEMBLYREF_BUILD_NUMBER
];
1617 aname
->revision
= cols
[MONO_ASSEMBLYREF_REV_NUMBER
];
1618 if (cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
]) {
1619 gchar
*token
= assemblyref_public_tok_checked (image
, cols
[MONO_ASSEMBLYREF_PUBLIC_KEY
], aname
->flags
, error
);
1620 return_val_if_nok (error
, FALSE
);
1621 g_strlcpy ((char*)aname
->public_key_token
, token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1624 memset (aname
->public_key_token
, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
1630 * mono_assembly_load_reference:
1633 mono_assembly_load_reference (MonoImage
*image
, int index
)
1635 MonoAssembly
*reference
;
1636 MonoAssemblyName aname
;
1637 MonoImageOpenStatus status
;
1640 * image->references is shared between threads, so we need to access
1641 * it inside a critical section.
1643 mono_assemblies_lock ();
1644 if (!image
->references
) {
1645 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_ASSEMBLYREF
];
1647 image
->references
= g_new0 (MonoAssembly
*, t
->rows
+ 1);
1648 image
->nreferences
= t
->rows
;
1650 reference
= image
->references
[index
];
1651 mono_assemblies_unlock ();
1655 mono_assembly_get_assemblyref (image
, index
, &aname
);
1657 if (image
->assembly
) {
1658 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
1659 char *aname_str
= mono_stringify_assembly_name (&aname
);
1660 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Loading reference %d of %s asmctx %s, looking for %s",
1661 index
, image
->name
, mono_asmctx_get_name (&image
->assembly
->context
),
1665 switch (mono_asmctx_get_kind (&image
->assembly
->context
)) {
1666 case MONO_ASMCTX_DEFAULT
:
1667 reference
= load_reference_by_aname_default_asmctx (&aname
, mono_image_get_alc (image
), image
->assembly
, &status
);
1669 case MONO_ASMCTX_REFONLY
:
1670 reference
= load_reference_by_aname_refonly_asmctx (&aname
, image
->assembly
, &status
);
1672 case MONO_ASMCTX_LOADFROM
:
1673 reference
= load_reference_by_aname_loadfrom_asmctx (&aname
, image
->assembly
, &status
);
1675 case MONO_ASMCTX_INDIVIDUAL
:
1676 reference
= load_reference_by_aname_individual_asmctx (&aname
, image
->assembly
, &status
);
1679 g_error ("Unexpected assembly load context kind %d for image %s.", mono_asmctx_get_kind (&image
->assembly
->context
), image
->name
);
1683 /* FIXME: can we establish that image->assembly is never NULL and this code is dead? */
1684 reference
= load_reference_by_aname_default_asmctx (&aname
, mono_image_get_alc (image
), image
->assembly
, &status
);
1687 if (reference
== NULL
){
1690 if (status
== MONO_IMAGE_ERROR_ERRNO
&& errno
== ENOENT
) {
1691 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
: "" );
1692 } else if (status
== MONO_IMAGE_ERROR_ERRNO
) {
1693 extra_msg
= g_strdup_printf ("System error: %s\n", strerror (errno
));
1694 } else if (status
== MONO_IMAGE_MISSING_ASSEMBLYREF
) {
1695 extra_msg
= g_strdup ("Cannot find an assembly referenced from this one.\n");
1696 } else if (status
== MONO_IMAGE_IMAGE_INVALID
) {
1697 extra_msg
= g_strdup ("The file exists but is not a valid assembly.\n");
1699 extra_msg
= g_strdup ("");
1702 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_ASSEMBLY
, "The following assembly referenced from %s could not be loaded:\n"
1703 " Assembly: %s (assemblyref_index=%d)\n"
1704 " Version: %d.%d.%d.%d\n"
1705 " Public Key: %s\n%s",
1706 image
->name
, aname
.name
, index
,
1707 aname
.major
, aname
.minor
, aname
.build
, aname
.revision
,
1708 strlen ((char*)aname
.public_key_token
) == 0 ? "(none)" : (char*)aname
.public_key_token
, extra_msg
);
1713 mono_assemblies_lock ();
1714 if (reference
== NULL
) {
1715 /* Flag as not found */
1716 reference
= (MonoAssembly
*)REFERENCE_MISSING
;
1719 if (!image
->references
[index
]) {
1720 if (reference
!= REFERENCE_MISSING
){
1721 mono_assembly_addref (reference
);
1722 if (image
->assembly
)
1723 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly Ref addref %s[%p] -> %s[%p]: %d",
1724 image
->assembly
->aname
.name
, image
->assembly
, reference
->aname
.name
, reference
, reference
->ref_count
);
1726 if (image
->assembly
)
1727 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Failed to load assembly %s[%p].",
1728 image
->assembly
->aname
.name
, image
->assembly
);
1731 image
->references
[index
] = reference
;
1733 mono_assemblies_unlock ();
1735 if (image
->references
[index
] != reference
) {
1736 /* Somebody loaded it before us */
1737 mono_assembly_close (reference
);
1742 * mono_assembly_load_references:
1745 * \deprecated There is no reason to use this method anymore, it does nothing
1747 * This method is now a no-op, it does nothing other than setting the \p status to \c MONO_IMAGE_OK
1750 mono_assembly_load_references (MonoImage
*image
, MonoImageOpenStatus
*status
)
1752 /* This is a no-op now but it is part of the embedding API so we can't remove it */
1754 *status
= MONO_IMAGE_OK
;
1757 typedef struct AssemblyLoadHook AssemblyLoadHook
;
1758 struct AssemblyLoadHook
{
1759 AssemblyLoadHook
*next
;
1760 MonoAssemblyLoadFunc func
;
1764 static AssemblyLoadHook
*assembly_load_hook
= NULL
;
1767 * mono_assembly_invoke_load_hook:
1770 mono_assembly_invoke_load_hook (MonoAssembly
*ass
)
1772 AssemblyLoadHook
*hook
;
1774 for (hook
= assembly_load_hook
; hook
; hook
= hook
->next
) {
1775 hook
->func (ass
, hook
->user_data
);
1780 * mono_install_assembly_load_hook:
1783 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func
, gpointer user_data
)
1785 AssemblyLoadHook
*hook
;
1787 g_return_if_fail (func
!= NULL
);
1789 hook
= g_new0 (AssemblyLoadHook
, 1);
1791 hook
->user_data
= user_data
;
1792 hook
->next
= assembly_load_hook
;
1793 assembly_load_hook
= hook
;
1797 free_assembly_load_hooks (void)
1799 AssemblyLoadHook
*hook
, *next
;
1801 for (hook
= assembly_load_hook
; hook
; hook
= next
) {
1807 typedef struct AssemblySearchHook AssemblySearchHook
;
1808 struct AssemblySearchHook
{
1809 AssemblySearchHook
*next
;
1811 MonoAssemblySearchFunc v1
;
1812 MonoAssemblySearchFuncV2 v2
;
1820 static AssemblySearchHook
*assembly_search_hook
= NULL
;
1822 static MonoAssembly
*
1823 mono_assembly_invoke_search_hook_internal (MonoAssemblyLoadContext
*alc
, MonoAssembly
*requesting
, MonoAssemblyName
*aname
, gboolean refonly
, gboolean postload
)
1825 AssemblySearchHook
*hook
;
1827 for (hook
= assembly_search_hook
; hook
; hook
= hook
->next
) {
1828 if ((hook
->refonly
== refonly
) && (hook
->postload
== postload
)) {
1830 if (hook
->version
== 1) {
1831 ass
= hook
->func
.v1 (aname
, hook
->user_data
);
1833 ERROR_DECL (hook_error
);
1834 g_assert (hook
->version
== 2);
1835 ass
= hook
->func
.v2 (alc
, requesting
, aname
, refonly
, postload
, hook
->user_data
, hook_error
);
1836 mono_error_assert_ok (hook_error
); /* FIXME: proper error handling */
1847 * mono_assembly_invoke_search_hook:
1850 mono_assembly_invoke_search_hook (MonoAssemblyName
*aname
)
1852 return mono_assembly_invoke_search_hook_internal (NULL
, NULL
, aname
, FALSE
, FALSE
);
1856 mono_install_assembly_search_hook_internal_v1 (MonoAssemblySearchFunc func
, gpointer user_data
, gboolean refonly
, gboolean postload
)
1858 AssemblySearchHook
*hook
;
1860 g_return_if_fail (func
!= NULL
);
1862 hook
= g_new0 (AssemblySearchHook
, 1);
1864 hook
->func
.v1
= func
;
1865 hook
->user_data
= user_data
;
1866 hook
->refonly
= refonly
;
1867 hook
->postload
= postload
;
1868 hook
->next
= assembly_search_hook
;
1869 assembly_search_hook
= hook
;
1873 mono_install_assembly_search_hook_v2 (MonoAssemblySearchFuncV2 func
, void *user_data
, gboolean refonly
, gboolean postload
)
1878 AssemblySearchHook
*hook
= g_new0 (AssemblySearchHook
, 1);
1880 hook
->func
.v2
= func
;
1881 hook
->user_data
= user_data
;
1882 hook
->refonly
= refonly
;
1883 hook
->postload
= postload
;
1884 hook
->next
= assembly_search_hook
;
1885 assembly_search_hook
= hook
;
1889 * mono_install_assembly_search_hook:
1892 mono_install_assembly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1894 mono_install_assembly_search_hook_internal_v1 (func
, user_data
, FALSE
, FALSE
);
1898 free_assembly_search_hooks (void)
1900 AssemblySearchHook
*hook
, *next
;
1902 for (hook
= assembly_search_hook
; hook
; hook
= next
) {
1909 * mono_install_assembly_refonly_search_hook:
1912 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1914 mono_install_assembly_search_hook_internal_v1 (func
, user_data
, TRUE
, FALSE
);
1918 * mono_install_assembly_postload_search_hook:
1921 mono_install_assembly_postload_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1923 mono_install_assembly_search_hook_internal_v1 (func
, user_data
, FALSE
, TRUE
);
1927 mono_install_assembly_postload_refonly_search_hook (MonoAssemblySearchFunc func
, gpointer user_data
)
1929 mono_install_assembly_search_hook_internal_v1 (func
, user_data
, TRUE
, TRUE
);
1933 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook
;
1934 struct AssemblyPreLoadHook
{
1935 AssemblyPreLoadHook
*next
;
1937 MonoAssemblyPreLoadFunc v1
;
1938 MonoAssemblyPreLoadFuncV2 v2
;
1944 static AssemblyPreLoadHook
*assembly_preload_hook
= NULL
;
1945 static AssemblyPreLoadHook
*assembly_refonly_preload_hook
= NULL
;
1947 static MonoAssembly
*
1948 invoke_assembly_preload_hook (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
, gchar
**apath
)
1950 AssemblyPreLoadHook
*hook
;
1951 MonoAssembly
*assembly
;
1953 for (hook
= assembly_preload_hook
; hook
; hook
= hook
->next
) {
1954 if (hook
->version
== 1)
1955 assembly
= hook
->func
.v1 (aname
, apath
, hook
->user_data
);
1958 g_assert (hook
->version
== 2);
1959 assembly
= hook
->func
.v2 (alc
, aname
, apath
, FALSE
, hook
->user_data
, error
);
1960 /* TODO: propagage error out to callers */
1961 mono_error_assert_ok (error
);
1963 if (assembly
!= NULL
)
1970 static MonoAssembly
*
1971 invoke_assembly_refonly_preload_hook (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
, gchar
**apath
)
1973 AssemblyPreLoadHook
*hook
;
1974 MonoAssembly
*assembly
;
1976 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= hook
->next
) {
1977 if (hook
->version
== 1)
1978 assembly
= hook
->func
.v1 (aname
, apath
, hook
->user_data
);
1981 g_assert (hook
->version
== 2);
1982 assembly
= hook
->func
.v2 (alc
, aname
, apath
, TRUE
, hook
->user_data
, error
);
1983 /* TODO: propagate error out to callers */
1984 mono_error_assert_ok (error
);
1986 if (assembly
!= NULL
)
1994 * mono_install_assembly_preload_hook:
1997 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
1999 AssemblyPreLoadHook
*hook
;
2001 g_return_if_fail (func
!= NULL
);
2003 hook
= g_new0 (AssemblyPreLoadHook
, 1);
2005 hook
->func
.v1
= func
;
2006 hook
->user_data
= user_data
;
2007 hook
->next
= assembly_preload_hook
;
2008 assembly_preload_hook
= hook
;
2012 * mono_install_assembly_refonly_preload_hook:
2015 mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func
, gpointer user_data
)
2017 AssemblyPreLoadHook
*hook
;
2019 g_return_if_fail (func
!= NULL
);
2021 hook
= g_new0 (AssemblyPreLoadHook
, 1);
2023 hook
->func
.v1
= func
;
2024 hook
->user_data
= user_data
;
2025 hook
->next
= assembly_refonly_preload_hook
;
2026 assembly_refonly_preload_hook
= hook
;
2030 mono_install_assembly_preload_hook_v2 (MonoAssemblyPreLoadFuncV2 func
, gpointer user_data
, gboolean refonly
)
2032 AssemblyPreLoadHook
*hook
;
2034 g_return_if_fail (func
!= NULL
);
2036 AssemblyPreLoadHook
**hooks
= refonly
? &assembly_refonly_preload_hook
: &assembly_preload_hook
;
2038 hook
= g_new0 (AssemblyPreLoadHook
, 1);
2040 hook
->func
.v2
= func
;
2041 hook
->user_data
= user_data
;
2042 hook
->next
= *hooks
;
2048 free_assembly_preload_hooks (void)
2050 AssemblyPreLoadHook
*hook
, *next
;
2052 for (hook
= assembly_preload_hook
; hook
; hook
= next
) {
2057 for (hook
= assembly_refonly_preload_hook
; hook
; hook
= next
) {
2063 typedef struct AssemblyAsmCtxFromPathHook AssemblyAsmCtxFromPathHook
;
2064 struct AssemblyAsmCtxFromPathHook
{
2065 AssemblyAsmCtxFromPathHook
*next
;
2066 MonoAssemblyAsmCtxFromPathFunc func
;
2070 static AssemblyAsmCtxFromPathHook
*assembly_asmctx_from_path_hook
= NULL
;
2073 * mono_install_assembly_asmctx_from_path_hook:
2075 * \param func Hook function
2076 * \param user_data User data
2078 * Installs a hook function \p func that when called with an absolute path name
2079 * returns \c TRUE and writes to \c out_asmctx if an assembly that name would
2080 * be found by that asmctx. The hooks are called in the order from most
2081 * recently added to oldest.
2085 mono_install_assembly_asmctx_from_path_hook (MonoAssemblyAsmCtxFromPathFunc func
, gpointer user_data
)
2087 g_return_if_fail (func
!= NULL
);
2089 AssemblyAsmCtxFromPathHook
*hook
= g_new0 (AssemblyAsmCtxFromPathHook
, 1);
2091 hook
->user_data
= user_data
;
2092 hook
->next
= assembly_asmctx_from_path_hook
;
2093 assembly_asmctx_from_path_hook
= hook
;
2097 * mono_assembly_invoke_asmctx_from_path_hook:
2099 * \param absfname absolute path name
2100 * \param requesting_assembly the \c MonoAssembly that requested the load, may be \c NULL
2101 * \param out_asmctx assembly context kind, written on output
2103 * Invokes hooks to find the assembly context that would have searched for the
2104 * given assembly name. Writes to \p out_asmctx the assembly context kind from
2105 * the first hook to return \c TRUE. \returns \c TRUE if any hook wrote to \p
2106 * out_asmctx, or \c FALSE otherwise.
2109 assembly_invoke_asmctx_from_path_hook (const char *absfname
, MonoAssembly
*requesting_assembly
, MonoAssemblyContextKind
*out_asmctx
)
2111 g_assert (absfname
);
2112 g_assert (out_asmctx
);
2113 AssemblyAsmCtxFromPathHook
*hook
;
2115 for (hook
= assembly_asmctx_from_path_hook
; hook
; hook
= hook
->next
) {
2116 *out_asmctx
= MONO_ASMCTX_INDIVIDUAL
;
2117 if (hook
->func (absfname
, requesting_assembly
, hook
->user_data
, out_asmctx
))
2125 free_assembly_asmctx_from_path_hooks (void)
2127 AssemblyAsmCtxFromPathHook
*hook
, *next
;
2129 for (hook
= assembly_asmctx_from_path_hook
; hook
; hook
= next
) {
2136 absolute_dir (const gchar
*filename
)
2147 if (g_path_is_absolute (filename
)) {
2148 part
= g_path_get_dirname (filename
);
2149 res
= g_strconcat (part
, G_DIR_SEPARATOR_S
, NULL
);
2154 cwd
= g_get_current_dir ();
2155 mixed
= g_build_filename (cwd
, filename
, NULL
);
2156 parts
= g_strsplit (mixed
, G_DIR_SEPARATOR_S
, 0);
2161 for (i
= 0; (part
= parts
[i
]) != NULL
; i
++) {
2162 if (!strcmp (part
, "."))
2165 if (!strcmp (part
, "..")) {
2166 if (list
&& list
->next
) /* Don't remove root */
2167 list
= g_list_delete_link (list
, list
);
2169 list
= g_list_prepend (list
, part
);
2173 result
= g_string_new ("");
2174 list
= g_list_reverse (list
);
2176 /* Ignores last data pointer, which should be the filename */
2177 for (tmp
= list
; tmp
&& tmp
->next
!= NULL
; tmp
= tmp
->next
){
2179 g_string_append_printf (result
, "%s%c", (char *) tmp
->data
,
2184 g_string_free (result
, FALSE
);
2189 return g_strdup (".");
2196 * mono_assembly_open_from_bundle:
2197 * \param filename Filename requested
2198 * \param status return status code
2200 * This routine tries to open the assembly specified by \p filename from the
2201 * defined bundles, if found, returns the MonoImage for it, if not found
2205 mono_assembly_open_from_bundle (MonoAssemblyLoadContext
*alc
, const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
2209 gchar
*lowercase_filename
;
2210 MonoImage
*image
= NULL
;
2211 gboolean is_satellite
= FALSE
;
2213 * we do a very simple search for bundled assemblies: it's not a general
2214 * purpose assembly loading mechanism.
2220 lowercase_filename
= g_utf8_strdown (filename
, -1);
2221 is_satellite
= g_str_has_suffix (lowercase_filename
, ".resources.dll");
2222 g_free (lowercase_filename
);
2223 name
= g_path_get_basename (filename
);
2224 for (i
= 0; !image
&& bundles
[i
]; ++i
) {
2225 if (strcmp (bundles
[i
]->name
, is_satellite
? filename
: name
) == 0) {
2226 image
= mono_image_open_from_data_internal (alc
, (char*)bundles
[i
]->data
, bundles
[i
]->size
, FALSE
, status
, refonly
, FALSE
, name
);
2231 mono_image_addref (image
);
2232 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite
? filename
: name
);
2241 * mono_assembly_open_full:
2242 * \param filename the file to load
2243 * \param status return status code
2244 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2246 * This loads an assembly from the specified \p filename. The \p filename allows
2247 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2248 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2249 * is treated as a local path.
2251 * First, an attempt is made to load the assembly from the bundled executable (for those
2252 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2253 * assembly has been registered as an embedded assembly). If this is not the case, then
2254 * the assembly is loaded from disk using `api:mono_image_open_full`.
2256 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2257 * the assembly is made.
2259 * If \p refonly is set to true, then the assembly is loaded purely for inspection with
2260 * the \c System.Reflection API.
2262 * \returns NULL on error, with the \p status set to an error code, or a pointer
2266 mono_assembly_open_full (const char *filename
, MonoImageOpenStatus
*status
, gboolean refonly
)
2269 MONO_ENTER_GC_UNSAFE
;
2270 MonoAssemblyOpenRequest req
;
2271 mono_assembly_request_prepare (&req
.request
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
2272 res
= mono_assembly_request_open (filename
, &req
, status
);
2273 MONO_EXIT_GC_UNSAFE
;
2278 assembly_loadfrom_asmctx_from_path (const char *filename
, MonoAssembly
*requesting_assembly
,
2279 gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
) {
2280 if (requesting_assembly
&& mono_asmctx_get_kind (&requesting_assembly
->context
) == MONO_ASMCTX_LOADFROM
) {
2281 if (mono_path_filename_in_basedir (filename
, requesting_assembly
->basedir
)) {
2282 *out_asmctx
= MONO_ASMCTX_LOADFROM
;
2290 mono_assembly_request_open (const char *filename
, const MonoAssemblyOpenRequest
*open_req
,
2291 MonoImageOpenStatus
*status
)
2295 MonoImageOpenStatus def_status
;
2298 gboolean loaded_from_bundle
;
2300 MonoAssemblyLoadRequest load_req
;
2301 /* we will be overwriting the load request's asmctx.*/
2302 memcpy (&load_req
, &open_req
->request
, sizeof (load_req
));
2304 g_return_val_if_fail (filename
!= NULL
, NULL
);
2307 status
= &def_status
;
2308 *status
= MONO_IMAGE_OK
;
2310 if (strncmp (filename
, "file://", 7) == 0) {
2311 GError
*gerror
= NULL
;
2312 gchar
*uri
= (gchar
*) filename
;
2316 * MS allows file://c:/... and fails on file://localhost/c:/...
2317 * They also throw an IndexOutOfRangeException if "file://"
2320 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
2323 uri
= mono_escape_uri_string (tmpuri
);
2324 fname
= g_filename_from_uri (uri
, NULL
, &gerror
);
2327 if (tmpuri
!= filename
)
2330 if (gerror
!= NULL
) {
2331 g_warning ("%s\n", gerror
->message
);
2332 g_error_free (gerror
);
2333 fname
= g_strdup (filename
);
2336 fname
= g_strdup (filename
);
2339 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2340 "Assembly Loader probing location: '%s'.", fname
);
2343 if (!mono_assembly_is_in_gac (fname
)) {
2345 new_fname
= mono_make_shadow_copy (fname
, error
);
2346 if (!is_ok (error
)) {
2347 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2348 "Assembly Loader shadow copy error: %s.", mono_error_get_message (error
));
2349 mono_error_cleanup (error
);
2350 *status
= MONO_IMAGE_IMAGE_INVALID
;
2355 if (load_req
.asmctx
!= MONO_ASMCTX_REFONLY
) {
2356 MonoAssemblyContextKind out_asmctx
;
2357 /* If the path belongs to the appdomain base dir or the
2358 * base dir of the requesting assembly, load the
2359 * assembly in the corresponding asmctx.
2361 if (assembly_invoke_asmctx_from_path_hook (fname
, open_req
->requesting_assembly
, &out_asmctx
))
2362 load_req
.asmctx
= out_asmctx
;
2365 if (load_req
.asmctx
!= MONO_ASMCTX_REFONLY
) {
2366 /* GAC assemblies always in default context or refonly context. */
2367 load_req
.asmctx
= MONO_ASMCTX_DEFAULT
;
2370 if (new_fname
&& new_fname
!= fname
) {
2373 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2374 "Assembly Loader shadow-copied assembly to: '%s'.", fname
);
2379 const gboolean refonly
= load_req
.asmctx
== MONO_ASMCTX_REFONLY
;
2380 /* for LoadFrom(string), LoadFile(string) and Load(byte[]), allow them
2381 * to load problematic images. Not sure if ReflectionOnlyLoad(string)
2382 * and ReflectionOnlyLoadFrom(string) should also be allowed - let's
2385 const gboolean load_from_context
= load_req
.asmctx
== MONO_ASMCTX_LOADFROM
|| load_req
.asmctx
== MONO_ASMCTX_INDIVIDUAL
|| load_req
.asmctx
== MONO_ASMCTX_REFONLY
;
2387 // If VM built with mkbundle
2388 loaded_from_bundle
= FALSE
;
2389 if (bundles
!= NULL
) {
2390 image
= mono_assembly_open_from_bundle (load_req
.alc
, fname
, status
, refonly
);
2391 loaded_from_bundle
= image
!= NULL
;
2395 image
= mono_image_open_a_lot (load_req
.alc
, fname
, status
, refonly
, load_from_context
);
2398 if (*status
== MONO_IMAGE_OK
)
2399 *status
= MONO_IMAGE_ERROR_ERRNO
;
2404 if (load_req
.asmctx
== MONO_ASMCTX_LOADFROM
|| load_req
.asmctx
== MONO_ASMCTX_INDIVIDUAL
) {
2405 MonoAssembly
*redirected_asm
= NULL
;
2406 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2407 if ((redirected_asm
= chain_redirections_loadfrom (image
, &new_status
))) {
2408 mono_image_close (image
);
2409 image
= redirected_asm
->image
;
2410 mono_image_addref (image
); /* so that mono_image_close, below, has something to do */
2411 /* fall thru to if (image->assembly) below */
2412 } else if (new_status
!= MONO_IMAGE_OK
) {
2413 *status
= new_status
;
2414 mono_image_close (image
);
2420 if (image
->assembly
) {
2421 /* We want to return the MonoAssembly that's already loaded,
2422 * but if we're using the strict assembly loader, we also need
2423 * to check that the previously loaded assembly matches the
2424 * predicate. It could be that we previously loaded a
2425 * different version that happens to have the filename that
2426 * we're currently probing. */
2427 if (mono_loader_get_strict_strong_names () &&
2428 load_req
.predicate
&& !load_req
.predicate (image
->assembly
, load_req
.predicate_ud
)) {
2429 mono_image_close (image
);
2433 /* Already loaded by another appdomain */
2434 mono_assembly_invoke_load_hook (image
->assembly
);
2435 mono_image_close (image
);
2437 return image
->assembly
;
2441 ass
= mono_assembly_request_load_from (image
, fname
, &load_req
, status
);
2444 if (!loaded_from_bundle
)
2445 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
,
2446 "Assembly Loader loaded assembly from location: '%s'.", filename
);
2448 mono_config_for_assembly_internal (ass
->image
);
2451 /* Clear the reference added by mono_image_open */
2452 mono_image_close (image
);
2460 free_item (gpointer val
, gpointer user_data
)
2466 * mono_assembly_load_friends:
2467 * \param ass an assembly
2469 * Load the list of friend assemblies that are allowed to access
2470 * the assembly's internal types and members. They are stored as assembly
2471 * names in custom attributes.
2473 * This is an internal method, we need this because when we load mscorlib
2474 * we do not have the internals visible cattr loaded yet,
2475 * so we need to load these after we initialize the runtime.
2477 * LOCKING: Acquires the assemblies lock plus the loader lock.
2480 mono_assembly_load_friends (MonoAssembly
* ass
)
2484 MonoCustomAttrInfo
* attrs
;
2487 if (ass
->friend_assembly_names_inited
)
2490 attrs
= mono_custom_attrs_from_assembly_checked (ass
, FALSE
, error
);
2491 mono_error_assert_ok (error
);
2493 mono_assemblies_lock ();
2494 ass
->friend_assembly_names_inited
= TRUE
;
2495 mono_assemblies_unlock ();
2499 mono_assemblies_lock ();
2500 if (ass
->friend_assembly_names_inited
) {
2501 mono_assemblies_unlock ();
2504 mono_assemblies_unlock ();
2508 * We build the list outside the assemblies lock, the worse that can happen
2509 * is that we'll need to free the allocated list.
2511 for (i
= 0; i
< attrs
->num_attrs
; ++i
) {
2512 MonoCustomAttrEntry
*attr
= &attrs
->attrs
[i
];
2513 MonoAssemblyName
*aname
;
2515 uint32_t data_length
;
2516 gchar
*data_with_terminator
;
2517 /* Do some sanity checking */
2518 if (!attr
->ctor
|| attr
->ctor
->klass
!= mono_class_try_get_internals_visible_class ())
2520 if (attr
->data_size
< 4)
2522 data
= (const char*)attr
->data
;
2523 /* 0xFF means null string, see custom attr format */
2524 if (data
[0] != 1 || data
[1] != 0 || (data
[2] & 0xFF) == 0xFF)
2526 data_length
= mono_metadata_decode_value (data
+ 2, &data
);
2527 data_with_terminator
= (char *)g_memdup (data
, data_length
+ 1);
2528 data_with_terminator
[data_length
] = 0;
2529 aname
= g_new0 (MonoAssemblyName
, 1);
2530 /*g_print ("friend ass: %s\n", data);*/
2531 if (mono_assembly_name_parse_full (data_with_terminator
, aname
, TRUE
, NULL
, NULL
)) {
2532 list
= g_slist_prepend (list
, aname
);
2536 g_free (data_with_terminator
);
2538 mono_custom_attrs_free (attrs
);
2540 mono_assemblies_lock ();
2541 if (ass
->friend_assembly_names_inited
) {
2542 mono_assemblies_unlock ();
2543 g_slist_foreach (list
, free_item
, NULL
);
2544 g_slist_free (list
);
2547 ass
->friend_assembly_names
= list
;
2549 /* Because of the double checked locking pattern above */
2550 mono_memory_barrier ();
2551 ass
->friend_assembly_names_inited
= TRUE
;
2552 mono_assemblies_unlock ();
2555 struct HasReferenceAssemblyAttributeIterData
{
2560 has_reference_assembly_attribute_iterator (MonoImage
*image
, guint32 typeref_scope_token
, const char *nspace
, const char *name
, guint32 method_token
, gpointer user_data
)
2562 gboolean stop_scanning
= FALSE
;
2563 struct HasReferenceAssemblyAttributeIterData
*iter_data
= (struct HasReferenceAssemblyAttributeIterData
*)user_data
;
2565 if (!strcmp (name
, "ReferenceAssemblyAttribute") && !strcmp (nspace
, "System.Runtime.CompilerServices")) {
2566 /* Note we don't check the assembly name, same as coreCLR. */
2567 iter_data
->has_attr
= TRUE
;
2568 stop_scanning
= TRUE
;
2571 return stop_scanning
;
2575 * mono_assembly_has_reference_assembly_attribute:
2576 * \param assembly a MonoAssembly
2577 * \param error set on error.
2579 * \returns TRUE if \p assembly has the \c System.Runtime.CompilerServices.ReferenceAssemblyAttribute set.
2580 * On error returns FALSE and sets \p error.
2583 mono_assembly_has_reference_assembly_attribute (MonoAssembly
*assembly
, MonoError
*error
)
2585 g_assert (assembly
&& assembly
->image
);
2586 /* .NET Framework appears to ignore the attribute on dynamic
2587 * assemblies, so don't call this function for dynamic assemblies. */
2588 g_assert (!image_is_dynamic (assembly
->image
));
2592 * This might be called during assembly loading, so do everything using the low-level
2596 struct HasReferenceAssemblyAttributeIterData iter_data
= { FALSE
};
2598 mono_assembly_metadata_foreach_custom_attr (assembly
, &has_reference_assembly_attribute_iterator
, &iter_data
);
2600 return iter_data
.has_attr
;
2604 * chain_redirections_loadfrom:
2605 * \param image a MonoImage that we wanted to load using LoadFrom context
2606 * \param status set if there was an error opening the redirected image
2608 * Check if we need to open a different image instead of the given one for some reason.
2609 * Returns NULL and sets status to \c MONO_IMAGE_OK if the given image was good.
2611 * Otherwise returns the assembly that we opened instead or sets status if
2612 * there was a problem opening the redirected image.
2616 chain_redirections_loadfrom (MonoImage
*image
, MonoImageOpenStatus
*out_status
)
2618 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
2619 MonoAssembly
*redirected
= NULL
;
2621 redirected
= mono_assembly_binding_applies_to_image (image
, &status
);
2622 if (redirected
|| status
!= MONO_IMAGE_OK
) {
2623 *out_status
= status
;
2627 redirected
= mono_problematic_image_reprobe (image
, &status
);
2628 if (redirected
|| status
!= MONO_IMAGE_OK
) {
2629 *out_status
= status
;
2633 *out_status
= MONO_IMAGE_OK
;
2638 * mono_assembly_binding_applies_to_image:
2639 * \param image The image whose assembly name we should check
2640 * \param status sets on error;
2642 * Get the \c MonoAssemblyName from the given \p image metadata and apply binding redirects to it.
2643 * If the resulting name is different from the name in the image, load that \c MonoAssembly instead
2645 * \returns the loaded \c MonoAssembly, or NULL if no binding redirection applied.
2649 mono_assembly_binding_applies_to_image (MonoImage
* image
, MonoImageOpenStatus
*status
)
2651 g_assert (status
!= NULL
);
2653 /* This is a "fun" one now.
2654 * For LoadFrom ("/basedir/some.dll") or LoadFile("/basedir/some.dll") or Load(byte[])),
2655 * apparently what we're meant to do is:
2656 * 1. probe the assembly name from some.dll (or the byte array)
2657 * 2. apply binding redirects
2658 * 3. If we get some other different name, drop this image and use
2659 * the binding redirected name to probe.
2660 * 4. Return the new assembly.
2662 MonoAssemblyName probed_aname
, dest_name
;
2663 if (!mono_assembly_fill_assembly_name_full (image
, &probed_aname
, TRUE
)) {
2664 if (*status
== MONO_IMAGE_OK
)
2665 *status
= MONO_IMAGE_IMAGE_INVALID
;
2668 MonoAssembly
*result_ass
= NULL
;
2669 MonoAssemblyName
*result_name
= &probed_aname
;
2670 result_name
= mono_assembly_apply_binding (result_name
, &dest_name
);
2671 if (result_name
!= &probed_aname
&& !mono_assembly_names_equal (result_name
, &probed_aname
)) {
2672 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
2673 char *probed_fullname
= mono_stringify_assembly_name (&probed_aname
);
2674 char *result_fullname
= mono_stringify_assembly_name (result_name
);
2675 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Request to load from %s in (%s) remapped to %s", probed_fullname
, image
->name
, result_fullname
);
2676 g_free (probed_fullname
);
2677 g_free (result_fullname
);
2679 const char *new_basedir
= NULL
; /* FIXME: null? - do a test of this */
2680 MonoAssemblyContextKind new_asmctx
= MONO_ASMCTX_DEFAULT
; /* FIXME: default? or? */
2681 MonoAssembly
*new_requesting
= NULL
; /* this seems okay */
2682 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2684 MonoAssemblyByNameRequest new_req
;
2685 mono_assembly_request_prepare (&new_req
.request
, sizeof (new_req
), new_asmctx
);
2686 new_req
.requesting_assembly
= new_requesting
;
2687 new_req
.basedir
= new_basedir
;
2688 result_ass
= mono_assembly_request_byname (result_name
, &new_req
, &new_status
);
2690 if (result_ass
&& new_status
== MONO_IMAGE_OK
) {
2691 g_assert (result_ass
->image
->assembly
!= NULL
);
2693 *status
= new_status
;
2696 mono_assembly_name_free (&probed_aname
);
2701 * mono_problematic_image_reprobe:
2702 * \param image A MonoImage
2703 * \param status set on error
2705 * If the given image is problematic for mono (see image.c), then try to load
2706 * by assembly name in the default context (which should succeed with Mono's
2707 * own implementations of those assemblies).
2709 * Returns NULL and sets status to MONO_IMAGE_OK if no redirect is needed.
2711 * Otherwise returns the assembly we were redirected to, or NULL and sets a
2712 * non-ok status on failure.
2714 * IMPORTANT NOTE: Don't call this if \c image was found by probing the search
2715 * path, you will end up in a loop and a stack overflow.
2718 mono_problematic_image_reprobe (MonoImage
*image
, MonoImageOpenStatus
*status
)
2720 g_assert (status
!= NULL
);
2722 if (G_LIKELY (!mono_is_problematic_image (image
))) {
2723 *status
= MONO_IMAGE_OK
;
2726 MonoAssemblyName probed_aname
;
2727 if (!mono_assembly_fill_assembly_name_full (image
, &probed_aname
, TRUE
)) {
2728 *status
= MONO_IMAGE_IMAGE_INVALID
;
2731 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
2732 char *probed_fullname
= mono_stringify_assembly_name (&probed_aname
);
2733 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Requested to load from problematic image %s, probing instead for assembly with name %s", image
->name
, probed_fullname
);
2734 g_free (probed_fullname
);
2736 const char *new_basedir
= NULL
;
2737 MonoAssemblyContextKind new_asmctx
= MONO_ASMCTX_DEFAULT
;
2738 MonoAssembly
*new_requesting
= NULL
;
2739 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2740 MonoAssemblyByNameRequest new_req
;
2741 mono_assembly_request_prepare (&new_req
.request
, sizeof (new_req
), new_asmctx
);
2742 new_req
.requesting_assembly
= new_requesting
;
2743 new_req
.basedir
= new_basedir
;
2744 // Note: this interacts with mono_image_open_a_lot (). If the path from
2745 // which we tried to load the problematic image is among the probing
2746 // paths, the MonoImage will be in the hash of loaded images and we
2747 // would just get it back again here, except for the code there that
2748 // mitigates the situation. Instead
2749 MonoAssembly
*result_ass
= mono_assembly_request_byname (&probed_aname
, &new_req
, &new_status
);
2751 if (! (result_ass
&& new_status
== MONO_IMAGE_OK
)) {
2752 *status
= new_status
;
2754 mono_assembly_name_free (&probed_aname
);
2758 * mono_assembly_open:
2759 * \param filename Opens the assembly pointed out by this name
2760 * \param status return status code
2762 * This loads an assembly from the specified \p filename. The \p filename allows
2763 * a local URL (starting with a \c file:// prefix). If a file prefix is used, the
2764 * filename is interpreted as a URL, and the filename is URL-decoded. Otherwise the file
2765 * is treated as a local path.
2767 * First, an attempt is made to load the assembly from the bundled executable (for those
2768 * deployments that have been done with the \c mkbundle tool or for scenarios where the
2769 * assembly has been registered as an embedded assembly). If this is not the case, then
2770 * the assembly is loaded from disk using `api:mono_image_open_full`.
2772 * If the pointed assembly does not live in the Global Assembly Cache, a shadow copy of
2773 * the assembly is made.
2775 * \returns a pointer to the \c MonoAssembly if \p filename contains a valid
2776 * assembly or NULL on error. Details about the error are stored in the
2777 * \p status variable.
2780 mono_assembly_open (const char *filename
, MonoImageOpenStatus
*status
)
2783 MONO_ENTER_GC_UNSAFE
;
2784 MonoAssemblyOpenRequest req
;
2785 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
2786 res
= mono_assembly_request_open (filename
, &req
, status
);
2787 MONO_EXIT_GC_UNSAFE
;
2792 * mono_assembly_load_from_full:
2793 * \param image Image to load the assembly from
2794 * \param fname assembly name to associate with the assembly
2795 * \param status returns the status condition
2796 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
2798 * If the provided \p image has an assembly reference, it will process the given
2799 * image as an assembly with the given name.
2801 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2803 * Returns: A valid pointer to a \c MonoAssembly* on success and the \p status will be
2804 * set to \c MONO_IMAGE_OK; or NULL on error.
2806 * If there is an error loading the assembly the \p status will indicate the
2807 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
2808 * image did not contain an assembly reference table.
2811 mono_assembly_load_from_full (MonoImage
*image
, const char*fname
,
2812 MonoImageOpenStatus
*status
, gboolean refonly
)
2815 MONO_ENTER_GC_UNSAFE
;
2816 MonoAssemblyLoadRequest req
;
2817 MonoImageOpenStatus def_status
;
2819 status
= &def_status
;
2820 mono_assembly_request_prepare (&req
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
2821 res
= mono_assembly_request_load_from (image
, fname
, &req
, status
);
2822 MONO_EXIT_GC_UNSAFE
;
2827 mono_assembly_request_load_from (MonoImage
*image
, const char *fname
,
2828 const MonoAssemblyLoadRequest
*req
,
2829 MonoImageOpenStatus
*status
)
2831 MonoAssemblyContextKind asmctx
;
2832 MonoAssemblyCandidatePredicate predicate
;
2835 MonoAssembly
*ass
, *ass2
;
2838 g_assert (status
!= NULL
);
2840 asmctx
= req
->asmctx
;
2841 predicate
= req
->predicate
;
2842 user_data
= req
->predicate_ud
;
2844 if (!image
->tables
[MONO_TABLE_ASSEMBLY
].rows
) {
2845 /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
2846 *status
= MONO_IMAGE_IMAGE_INVALID
;
2850 #if defined (HOST_WIN32)
2855 tmp_fn
= g_strdup (fname
);
2856 for (i
= strlen (tmp_fn
) - 1; i
>= 0; i
--) {
2857 if (tmp_fn
[i
] == '/')
2861 base_dir
= absolute_dir (tmp_fn
);
2865 base_dir
= absolute_dir (fname
);
2869 * Create assembly struct, and enter it into the assembly cache
2871 ass
= g_new0 (MonoAssembly
, 1);
2872 ass
->basedir
= base_dir
;
2873 ass
->context
.kind
= asmctx
;
2876 MONO_PROFILER_RAISE (assembly_loading
, (ass
));
2878 mono_assembly_fill_assembly_name (image
, &ass
->aname
);
2880 if (mono_defaults
.corlib
&& strcmp (ass
->aname
.name
, MONO_ASSEMBLY_CORLIB_NAME
) == 0) {
2881 // MS.NET doesn't support loading other mscorlibs
2884 mono_image_addref (mono_defaults
.corlib
);
2885 *status
= MONO_IMAGE_OK
;
2886 return mono_defaults
.corlib
->assembly
;
2889 /* Add a non-temporary reference because of ass->image */
2890 mono_image_addref (image
);
2892 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Image addref %s[%p] (asmctx %s) -> %s[%p]: %d", ass
->aname
.name
, ass
, mono_asmctx_get_name (&ass
->context
), image
->name
, image
, image
->ref_count
);
2895 * The load hooks might take locks so we can't call them while holding the
2898 if (ass
->aname
.name
&& asmctx
!= MONO_ASMCTX_INDIVIDUAL
) {
2899 /* 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?) */
2900 ass2
= mono_assembly_invoke_search_hook_internal (req
->alc
, NULL
, &ass
->aname
, asmctx
== MONO_ASMCTX_REFONLY
, FALSE
);
2902 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
);
2905 mono_image_close (image
);
2906 *status
= MONO_IMAGE_OK
;
2911 /* We need to check for ReferenceAssmeblyAttribute before we
2912 * mark the assembly as loaded and before we fire the load
2913 * hook. Otherwise mono_domain_fire_assembly_load () in
2914 * appdomain.c will cache a mapping from the assembly name to
2915 * this image and we won't be able to look for a different
2918 if (asmctx
!= MONO_ASMCTX_REFONLY
) {
2919 ERROR_DECL (refasm_error
);
2920 if (mono_assembly_has_reference_assembly_attribute (ass
, refasm_error
)) {
2921 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass
->aname
.name
, image
->name
);
2924 mono_image_close (image
);
2925 *status
= MONO_IMAGE_IMAGE_INVALID
;
2928 mono_error_cleanup (refasm_error
);
2931 if (predicate
&& !predicate (ass
, user_data
)) {
2932 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate returned FALSE, skipping '%s' (%s)\n", ass
->aname
.name
, image
->name
);
2935 mono_image_close (image
);
2936 *status
= MONO_IMAGE_IMAGE_INVALID
;
2940 mono_assemblies_lock ();
2942 /* If an assembly is loaded into an individual context, always return a
2943 * new MonoAssembly, even if another assembly with the same name has
2944 * already been loaded.
2946 if (image
->assembly
&& asmctx
!= MONO_ASMCTX_INDIVIDUAL
) {
2948 * This means another thread has already loaded the assembly, but not yet
2949 * called the load hooks so the search hook can't find the assembly.
2951 mono_assemblies_unlock ();
2952 ass2
= image
->assembly
;
2955 mono_image_close (image
);
2956 *status
= MONO_IMAGE_OK
;
2960 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Prepared to set up assembly '%s' (%s)", ass
->aname
.name
, image
->name
);
2962 /* If asmctx is INDIVIDUAL, image->assembly might not be NULL, so don't
2964 if (image
->assembly
== NULL
)
2965 image
->assembly
= ass
;
2967 loaded_assemblies
= g_list_prepend (loaded_assemblies
, ass
);
2968 mono_assemblies_unlock ();
2971 if (m_image_is_module_handle (image
))
2972 mono_image_fixup_vtable (image
);
2975 mono_assembly_invoke_load_hook (ass
);
2977 MONO_PROFILER_RAISE (assembly_loaded
, (ass
));
2983 * mono_assembly_load_from:
2984 * \param image Image to load the assembly from
2985 * \param fname assembly name to associate with the assembly
2986 * \param status return status code
2988 * If the provided \p image has an assembly reference, it will process the given
2989 * image as an assembly with the given name.
2991 * Most likely you want to use the `api:mono_assembly_load_full` method instead.
2993 * This is equivalent to calling `api:mono_assembly_load_from_full` with the
2994 * \p refonly parameter set to FALSE.
2995 * \returns A valid pointer to a \c MonoAssembly* on success and then \p status will be
2996 * set to \c MONO_IMAGE_OK; or NULL on error.
2998 * If there is an error loading the assembly the \p status will indicate the
2999 * reason with \p status being set to \c MONO_IMAGE_INVALID if the
3000 * image did not contain an assembly reference table.
3004 mono_assembly_load_from (MonoImage
*image
, const char *fname
,
3005 MonoImageOpenStatus
*status
)
3008 MONO_ENTER_GC_UNSAFE
;
3009 MonoAssemblyLoadRequest req
;
3010 MonoImageOpenStatus def_status
;
3012 status
= &def_status
;
3013 mono_assembly_request_prepare (&req
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
3014 res
= mono_assembly_request_load_from (image
, fname
, &req
, status
);
3015 MONO_EXIT_GC_UNSAFE
;
3020 * mono_assembly_name_free:
3021 * \param aname assembly name to free
3023 * Frees the provided assembly name object.
3024 * (it does not frees the object itself, only the name members).
3027 mono_assembly_name_free (MonoAssemblyName
*aname
)
3029 MONO_ENTER_GC_UNSAFE
;
3030 mono_assembly_name_free_internal (aname
);
3031 MONO_EXIT_GC_UNSAFE
;
3035 mono_assembly_name_free_internal (MonoAssemblyName
*aname
)
3037 MONO_REQ_GC_UNSAFE_MODE
;
3042 g_free ((void *) aname
->name
);
3043 g_free ((void *) aname
->culture
);
3044 g_free ((void *) aname
->hash_value
);
3045 g_free ((guint8
*) aname
->public_key
);
3049 parse_public_key (const gchar
*key
, gchar
** pubkey
, gboolean
*is_ecma
)
3052 gchar header
[16], val
, *arr
, *endp
;
3053 gint i
, j
, offset
, bitlen
, keylen
, pkeylen
;
3055 //both pubkey and is_ecma are required arguments
3056 g_assert (pubkey
&& is_ecma
);
3058 keylen
= strlen (key
) >> 1;
3062 /* allow the ECMA standard key */
3063 if (strcmp (key
, "00000000000000000400000000000000") == 0) {
3069 val
= g_ascii_xdigit_value (key
[0]) << 4;
3070 val
|= g_ascii_xdigit_value (key
[1]);
3075 val
= g_ascii_xdigit_value (key
[24]);
3076 val
|= g_ascii_xdigit_value (key
[25]);
3088 /* We need the first 16 bytes
3089 * to check whether this key is valid or not */
3090 pkeylen
= strlen (pkey
) >> 1;
3094 for (i
= 0, j
= 0; i
< 16; i
++) {
3095 header
[i
] = g_ascii_xdigit_value (pkey
[j
++]) << 4;
3096 header
[i
] |= g_ascii_xdigit_value (pkey
[j
++]);
3099 if (header
[0] != 0x06 || /* PUBLICKEYBLOB (0x06) */
3100 header
[1] != 0x02 || /* Version (0x02) */
3101 header
[2] != 0x00 || /* Reserved (word) */
3102 header
[3] != 0x00 ||
3103 (guint
)(read32 (header
+ 8)) != 0x31415352) /* DWORD magic = RSA1 */
3106 /* Based on this length, we _should_ be able to know if the length is right */
3107 bitlen
= read32 (header
+ 12) >> 3;
3108 if ((bitlen
+ 16 + 4) != pkeylen
)
3111 arr
= (gchar
*)g_malloc (keylen
+ 4);
3112 /* Encode the size of the blob */
3113 mono_metadata_encode_value (keylen
, &arr
[0], &endp
);
3114 offset
= (gint
)(endp
-arr
);
3116 for (i
= offset
, j
= 0; i
< keylen
+ offset
; i
++) {
3117 arr
[i
] = g_ascii_xdigit_value (key
[j
++]) << 4;
3118 arr
[i
] |= g_ascii_xdigit_value (key
[j
++]);
3127 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
)
3131 gchar
*pkeyptr
, *encoded
, tok
[8];
3133 memset (aname
, 0, sizeof (MonoAssemblyName
));
3136 #ifdef ENABLE_NETCORE
3143 const char *s
= version
;
3145 for (i
= 0; i
< 4; ++i
) {
3146 int n
= sscanf (s
, "%u%n", &parts
[i
], &part_len
);
3149 if (parts
[i
] < 0 || parts
[i
] > 65535)
3151 if (i
< 2 && parts
[i
] == 65535)
3165 if (version_parts
< 2 || version_parts
> 4)
3167 aname
->major
= parts
[0];
3168 aname
->minor
= parts
[1];
3169 if (version_parts
>= 3)
3170 aname
->build
= parts
[2];
3173 if (version_parts
== 4)
3174 aname
->revision
= parts
[3];
3176 aname
->revision
= -1;
3178 gint major
, minor
, build
, revision
;
3180 version_parts
= sscanf (version
, "%u.%u.%u.%u", &major
, &minor
, &build
, &revision
);
3181 if (version_parts
< 2 || version_parts
> 4)
3184 /* FIXME: we should set build & revision to -1 (instead of 0)
3185 if these are not set in the version string. That way, later on,
3186 we can still determine if these were specified. */
3187 aname
->major
= major
;
3188 aname
->minor
= minor
;
3189 if (version_parts
>= 3)
3190 aname
->build
= build
;
3193 if (version_parts
== 4)
3194 aname
->revision
= revision
;
3196 aname
->revision
= 0;
3200 aname
->flags
= flags
;
3202 aname
->name
= g_strdup (name
);
3205 if (g_ascii_strcasecmp (culture
, "neutral") == 0)
3206 aname
->culture
= g_strdup ("");
3208 aname
->culture
= g_strdup (culture
);
3211 if (token
&& strncmp (token
, "null", 4) != 0) {
3214 /* the constant includes the ending NULL, hence the -1 */
3215 if (strlen (token
) != (MONO_PUBLIC_KEY_TOKEN_LENGTH
- 1)) {
3216 mono_assembly_name_free (aname
);
3219 lower
= g_ascii_strdown (token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3220 g_strlcpy ((char*)aname
->public_key_token
, lower
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3225 gboolean is_ecma
= FALSE
;
3227 if (strcmp (key
, "null") == 0 || !parse_public_key (key
, &pkey
, &is_ecma
)) {
3228 mono_assembly_name_free (aname
);
3233 g_assert (pkey
== NULL
);
3234 aname
->public_key
= NULL
;
3235 g_strlcpy ((gchar
*)aname
->public_key_token
, "b77a5c561934e089", MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3239 len
= mono_metadata_decode_blob_size ((const gchar
*) pkey
, (const gchar
**) &pkeyptr
);
3240 // We also need to generate the key token
3241 mono_digest_get_public_token ((guchar
*) tok
, (guint8
*) pkeyptr
, len
);
3242 encoded
= encode_public_tok ((guchar
*) tok
, 8);
3243 g_strlcpy ((gchar
*)aname
->public_key_token
, encoded
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
3246 if (save_public_key
)
3247 aname
->public_key
= (guint8
*) pkey
;
3256 parse_assembly_directory_name (const char *name
, const char *dirname
, MonoAssemblyName
*aname
)
3261 parts
= g_strsplit (dirname
, "_", 3);
3262 if (!parts
|| !parts
[0] || !parts
[1] || !parts
[2]) {
3267 res
= build_assembly_name (name
, parts
[0], parts
[1], parts
[2], NULL
, 0, 0, aname
, FALSE
);
3273 split_key_value (const gchar
*pair
, gchar
**key
, guint32
*keylen
, gchar
**value
)
3275 char *eqsign
= (char*)strchr (pair
, '=');
3283 *key
= (gchar
*)pair
;
3284 *keylen
= eqsign
- *key
;
3285 while (*keylen
> 0 && g_ascii_isspace ((*key
) [*keylen
- 1]))
3287 *value
= g_strstrip (eqsign
+ 1);
3292 mono_assembly_name_parse_full (const char *name
, MonoAssemblyName
*aname
, gboolean save_public_key
, gboolean
*is_version_defined
, gboolean
*is_token_defined
)
3296 gchar
*version
= NULL
;
3298 gchar
*culture
= NULL
;
3300 gchar
*token
= NULL
;
3304 gchar
*retargetable
= NULL
;
3305 gchar
*retargetable_uq
;
3309 gchar
*value
, *part_name
;
3310 guint32 part_name_len
;
3313 gboolean version_defined
;
3314 gboolean token_defined
;
3316 guint32 arch
= MONO_PROCESSOR_ARCHITECTURE_NONE
;
3318 if (!is_version_defined
)
3319 is_version_defined
= &version_defined
;
3320 *is_version_defined
= FALSE
;
3321 if (!is_token_defined
)
3322 is_token_defined
= &token_defined
;
3323 *is_token_defined
= FALSE
;
3325 parts
= tmp
= g_strsplit (name
, ",", 6);
3326 if (!tmp
|| !*tmp
) {
3331 dllname
= g_strstrip (*tmp
);
3336 if (!split_key_value (g_strstrip (*tmp
), &part_name
, &part_name_len
, &value
))
3337 goto cleanup_and_fail
;
3339 if (part_name_len
== 7 && !g_ascii_strncasecmp (part_name
, "Version", part_name_len
)) {
3340 *is_version_defined
= TRUE
;
3342 if (strlen (version
) == 0) {
3343 goto cleanup_and_fail
;
3349 if (part_name_len
== 7 && !g_ascii_strncasecmp (part_name
, "Culture", part_name_len
)) {
3351 if (strlen (culture
) == 0) {
3352 goto cleanup_and_fail
;
3358 if (part_name_len
== 14 && !g_ascii_strncasecmp (part_name
, "PublicKeyToken", part_name_len
)) {
3359 *is_token_defined
= TRUE
;
3361 if (strlen (token
) == 0) {
3362 goto cleanup_and_fail
;
3368 if (part_name_len
== 9 && !g_ascii_strncasecmp (part_name
, "PublicKey", part_name_len
)) {
3370 if (strlen (key
) == 0) {
3371 goto cleanup_and_fail
;
3377 if (part_name_len
== 12 && !g_ascii_strncasecmp (part_name
, "Retargetable", part_name_len
)) {
3378 retargetable
= value
;
3379 retargetable_uq
= unquote (retargetable
);
3380 if (retargetable_uq
!= NULL
)
3381 retargetable
= retargetable_uq
;
3383 if (!g_ascii_strcasecmp (retargetable
, "yes")) {
3384 flags
|= ASSEMBLYREF_RETARGETABLE_FLAG
;
3385 } else if (g_ascii_strcasecmp (retargetable
, "no")) {
3386 g_free (retargetable_uq
);
3387 goto cleanup_and_fail
;
3390 g_free (retargetable_uq
);
3395 if (part_name_len
== 21 && !g_ascii_strncasecmp (part_name
, "ProcessorArchitecture", part_name_len
)) {
3397 procarch_uq
= unquote (procarch
);
3398 if (procarch_uq
!= NULL
)
3399 procarch
= procarch_uq
;
3401 if (!g_ascii_strcasecmp (procarch
, "MSIL"))
3402 arch
= MONO_PROCESSOR_ARCHITECTURE_MSIL
;
3403 else if (!g_ascii_strcasecmp (procarch
, "X86"))
3404 arch
= MONO_PROCESSOR_ARCHITECTURE_X86
;
3405 else if (!g_ascii_strcasecmp (procarch
, "IA64"))
3406 arch
= MONO_PROCESSOR_ARCHITECTURE_IA64
;
3407 else if (!g_ascii_strcasecmp (procarch
, "AMD64"))
3408 arch
= MONO_PROCESSOR_ARCHITECTURE_AMD64
;
3409 else if (!g_ascii_strcasecmp (procarch
, "ARM"))
3410 arch
= MONO_PROCESSOR_ARCHITECTURE_ARM
;
3412 g_free (procarch_uq
);
3413 goto cleanup_and_fail
;
3416 g_free (procarch_uq
);
3425 /* if retargetable flag is set, then we must have a fully qualified name */
3426 if (retargetable
!= NULL
&& (version
== NULL
|| culture
== NULL
|| (key
== NULL
&& token
== NULL
))) {
3427 goto cleanup_and_fail
;
3430 dllname_uq
= unquote (dllname
);
3431 version_uq
= unquote (version
);
3432 culture_uq
= unquote (culture
);
3433 token_uq
= unquote (token
);
3434 key_uq
= unquote (key
);
3436 res
= build_assembly_name (
3437 dllname_uq
== NULL
? dllname
: dllname_uq
,
3438 version_uq
== NULL
? version
: version_uq
,
3439 culture_uq
== NULL
? culture
: culture_uq
,
3440 token_uq
== NULL
? token
: token_uq
,
3441 key_uq
== NULL
? key
: key_uq
,
3442 flags
, arch
, aname
, save_public_key
);
3444 g_free (dllname_uq
);
3445 g_free (version_uq
);
3446 g_free (culture_uq
);
3459 unquote (const char *str
)
3467 slen
= strlen (str
);
3471 if (*str
!= '\'' && *str
!= '\"')
3474 end
= str
+ slen
- 1;
3478 return g_strndup (str
+ 1, slen
- 2);
3482 * mono_assembly_name_parse:
3483 * \param name name to parse
3484 * \param aname the destination assembly name
3486 * Parses an assembly qualified type name and assigns the name,
3487 * version, culture and token to the provided assembly name object.
3489 * \returns TRUE if the name could be parsed.
3492 mono_assembly_name_parse (const char *name
, MonoAssemblyName
*aname
)
3494 return mono_assembly_name_parse_full (name
, aname
, FALSE
, NULL
, NULL
);
3498 * mono_assembly_name_new:
3499 * \param name name to parse
3501 * Allocate a new \c MonoAssemblyName and fill its values from the
3504 * \returns a newly allocated structure or NULL if there was any failure.
3507 mono_assembly_name_new (const char *name
)
3509 MonoAssemblyName
*result
= NULL
;
3510 MONO_ENTER_GC_UNSAFE
;
3511 MonoAssemblyName
*aname
= g_new0 (MonoAssemblyName
, 1);
3512 if (mono_assembly_name_parse (name
, aname
))
3516 MONO_EXIT_GC_UNSAFE
;
3521 * mono_assembly_name_get_name:
3524 mono_assembly_name_get_name (MonoAssemblyName
*aname
)
3526 const char *result
= NULL
;
3527 MONO_ENTER_GC_UNSAFE
;
3528 result
= aname
->name
;
3529 MONO_EXIT_GC_UNSAFE
;
3534 * mono_assembly_name_get_culture:
3537 mono_assembly_name_get_culture (MonoAssemblyName
*aname
)
3539 const char *result
= NULL
;
3540 MONO_ENTER_GC_UNSAFE
;
3541 result
= aname
->culture
;
3542 MONO_EXIT_GC_UNSAFE
;
3547 * mono_assembly_name_get_pubkeytoken:
3550 mono_assembly_name_get_pubkeytoken (MonoAssemblyName
*aname
)
3552 if (aname
->public_key_token
[0])
3553 return aname
->public_key_token
;
3558 * mono_assembly_name_get_version:
3561 mono_assembly_name_get_version (MonoAssemblyName
*aname
, uint16_t *minor
, uint16_t *build
, uint16_t *revision
)
3564 *minor
= aname
->minor
;
3566 *build
= aname
->build
;
3568 *revision
= aname
->revision
;
3569 return aname
->major
;
3572 static MonoAssembly
*
3573 probe_for_partial_name (const char *basepath
, const char *fullname
, MonoAssemblyName
*aname
, MonoImageOpenStatus
*status
)
3575 gchar
*fullpath
= NULL
;
3577 const char* direntry
;
3578 MonoAssemblyName gac_aname
;
3579 gint major
=-1, minor
=0, build
=0, revision
=0;
3580 gboolean exact_version
;
3582 dirhandle
= g_dir_open (basepath
, 0, NULL
);
3586 exact_version
= (aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) != 0;
3588 while ((direntry
= g_dir_read_name (dirhandle
))) {
3589 gboolean match
= TRUE
;
3591 if(!parse_assembly_directory_name (aname
->name
, direntry
, &gac_aname
))
3594 if (aname
->culture
!= NULL
&& strcmp (aname
->culture
, gac_aname
.culture
) != 0)
3597 if (match
&& strlen ((char*)aname
->public_key_token
) > 0 &&
3598 !mono_public_tokens_are_equal (aname
->public_key_token
, gac_aname
.public_key_token
))
3602 if (exact_version
) {
3603 match
= (aname
->major
== gac_aname
.major
&& aname
->minor
== gac_aname
.minor
&&
3604 aname
->build
== gac_aname
.build
&& aname
->revision
== gac_aname
.revision
);
3606 else if (gac_aname
.major
< major
)
3608 else if (gac_aname
.major
== major
) {
3609 if (gac_aname
.minor
< minor
)
3611 else if (gac_aname
.minor
== minor
) {
3612 if (gac_aname
.build
< build
)
3614 else if (gac_aname
.build
== build
&& gac_aname
.revision
<= revision
)
3621 major
= gac_aname
.major
;
3622 minor
= gac_aname
.minor
;
3623 build
= gac_aname
.build
;
3624 revision
= gac_aname
.revision
;
3626 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, basepath
, direntry
, fullname
, NULL
);
3629 mono_assembly_name_free (&gac_aname
);
3632 g_dir_close (dirhandle
);
3634 if (fullpath
== NULL
)
3637 MonoAssemblyOpenRequest req
;
3638 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
3639 MonoAssembly
*res
= mono_assembly_request_open (fullpath
, &req
, status
);
3646 * mono_assembly_load_with_partial_name:
3647 * \param name an assembly name that is then parsed by `api:mono_assembly_name_parse`.
3648 * \param status return status code
3650 * Loads a \c MonoAssembly from a name. The name is parsed using `api:mono_assembly_name_parse`,
3651 * so it might contain a qualified type name, version, culture and token.
3653 * This will load the assembly from the file whose name is derived from the assembly name
3654 * by appending the \c .dll extension.
3656 * The assembly is loaded from either one of the extra Global Assembly Caches specified
3657 * by the extra GAC paths (specified by the \c MONO_GAC_PREFIX environment variable) or
3658 * if that fails from the GAC.
3660 * \returns NULL on failure, or a pointer to a \c MonoAssembly on success.
3663 mono_assembly_load_with_partial_name (const char *name
, MonoImageOpenStatus
*status
)
3665 MonoAssembly
*result
;
3666 MONO_ENTER_GC_UNSAFE
;
3667 MonoImageOpenStatus def_status
;
3669 status
= &def_status
;
3670 result
= mono_assembly_load_with_partial_name_internal (name
, status
);
3671 MONO_EXIT_GC_UNSAFE
;
3676 mono_assembly_load_with_partial_name_internal (const char *name
, MonoImageOpenStatus
*status
)
3680 MonoAssemblyName
*aname
, base_name
;
3681 MonoAssemblyName mapped_aname
;
3683 MONO_REQ_GC_UNSAFE_MODE
;
3685 g_assert (status
!= NULL
);
3687 memset (&base_name
, 0, sizeof (MonoAssemblyName
));
3690 if (!mono_assembly_name_parse (name
, aname
))
3694 * If no specific version has been requested, make sure we load the
3695 * correct version for system assemblies.
3697 if ((aname
->major
| aname
->minor
| aname
->build
| aname
->revision
) == 0)
3698 aname
= mono_assembly_remap_version (aname
, &mapped_aname
);
3700 /* FIXME: get the ALC as an argument from the caller */
3701 MonoAssemblyLoadContext
*alc
= mono_domain_ambient_alc (mono_domain_get ());
3703 res
= mono_assembly_loaded_internal (alc
, aname
, FALSE
);
3705 mono_assembly_name_free (aname
);
3709 res
= invoke_assembly_preload_hook (alc
, aname
, assemblies_path
);
3711 res
->in_gac
= FALSE
;
3712 mono_assembly_name_free (aname
);
3717 gchar
*fullname
, *gacpath
;
3719 fullname
= g_strdup_printf ("%s.dll", aname
->name
);
3721 if (extra_gac_paths
) {
3722 paths
= extra_gac_paths
;
3723 while (!res
&& *paths
) {
3724 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", aname
->name
, NULL
);
3725 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
3734 mono_assembly_name_free (aname
);
3738 gacpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (), "mono", "gac", aname
->name
, NULL
);
3739 res
= probe_for_partial_name (gacpath
, fullname
, aname
, status
);
3747 mono_assembly_name_free (aname
);
3750 MonoDomain
*domain
= mono_domain_get ();
3752 res
= mono_try_assembly_resolve (domain
, name
, NULL
, FALSE
, error
);
3753 if (!is_ok (error
)) {
3754 mono_error_cleanup (error
);
3755 if (*status
== MONO_IMAGE_OK
)
3756 *status
= MONO_IMAGE_IMAGE_INVALID
;
3764 mono_assembly_is_in_gac (const gchar
*filename
)
3767 const gchar
*rootdir
;
3771 if (filename
== NULL
)
3774 for (paths
= extra_gac_paths
; paths
&& *paths
; paths
++) {
3775 if (strstr (*paths
, filename
) != *paths
)
3778 gp
= (gchar
*) (filename
+ strlen (*paths
));
3779 if (*gp
!= G_DIR_SEPARATOR
)
3782 if (strncmp (gp
, "lib", 3))
3785 if (*gp
!= G_DIR_SEPARATOR
)
3788 if (strncmp (gp
, "mono", 4))
3791 if (*gp
!= G_DIR_SEPARATOR
)
3794 if (strncmp (gp
, "gac", 3))
3797 if (*gp
!= G_DIR_SEPARATOR
)
3803 rootdir
= mono_assembly_getrootdir ();
3804 if (strstr (filename
, rootdir
) != filename
)
3807 gp
= (gchar
*) (filename
+ strlen (rootdir
));
3808 if (*gp
!= G_DIR_SEPARATOR
)
3811 if (strncmp (gp
, "mono", 4))
3814 if (*gp
!= G_DIR_SEPARATOR
)
3817 if (strncmp (gp
, "gac", 3))
3820 if (*gp
!= G_DIR_SEPARATOR
)
3825 #endif /* DISABLE_GAC */
3829 mono_assembly_load_publisher_policy (MonoAssemblyName
*aname
)
3831 MonoImage
*image
= NULL
;
3833 gchar
*filename
, *pname
, *name
, *culture
, *version
, *fullpath
, *subpath
;
3837 if (strstr (aname
->name
, ".dll")) {
3838 len
= strlen (aname
->name
) - 4;
3839 name
= (gchar
*)g_malloc (len
+ 1);
3840 memcpy (name
, aname
->name
, len
);
3843 name
= g_strdup (aname
->name
);
3846 culture
= g_utf8_strdown (aname
->culture
, -1);
3848 culture
= g_strdup ("");
3850 pname
= g_strdup_printf ("policy.%d.%d.%s", aname
->major
, aname
->minor
, name
);
3851 version
= g_strdup_printf ("0.0.0.0_%s_%s", culture
, aname
->public_key_token
);
3855 filename
= g_strconcat (pname
, ".dll", NULL
);
3856 subpath
= g_build_path (G_DIR_SEPARATOR_S
, pname
, version
, filename
, NULL
);
3862 if (extra_gac_paths
) {
3863 paths
= extra_gac_paths
;
3864 while (!image
&& *paths
) {
3865 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
,
3866 "lib", "mono", "gac", subpath
, NULL
);
3867 image
= mono_image_open (fullpath
, NULL
);
3878 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
3879 "mono", "gac", subpath
, NULL
);
3880 image
= mono_image_open (fullpath
, NULL
);
3888 static MonoAssemblyName
*
3889 mono_assembly_bind_version (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
3891 memcpy (dest_name
, aname
, sizeof (MonoAssemblyName
));
3892 dest_name
->major
= info
->new_version
.major
;
3893 dest_name
->minor
= info
->new_version
.minor
;
3894 dest_name
->build
= info
->new_version
.build
;
3895 dest_name
->revision
= info
->new_version
.revision
;
3900 /* LOCKING: assembly_binding lock must be held */
3901 static MonoAssemblyBindingInfo
*
3902 search_binding_loaded (MonoAssemblyName
*aname
)
3906 for (tmp
= loaded_assembly_bindings
; tmp
; tmp
= tmp
->next
) {
3907 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)tmp
->data
;
3908 if (assembly_binding_maps_name (info
, aname
))
3915 static inline gboolean
3916 info_compare_versions (AssemblyVersionSet
*left
, AssemblyVersionSet
*right
)
3918 if (left
->major
!= right
->major
|| left
->minor
!= right
->minor
||
3919 left
->build
!= right
->build
|| left
->revision
!= right
->revision
)
3925 static inline gboolean
3926 info_versions_equal (MonoAssemblyBindingInfo
*left
, MonoAssemblyBindingInfo
*right
)
3928 if (left
->has_old_version_bottom
!= right
->has_old_version_bottom
)
3931 if (left
->has_old_version_top
!= right
->has_old_version_top
)
3934 if (left
->has_new_version
!= right
->has_new_version
)
3937 if (left
->has_old_version_bottom
&& !info_compare_versions (&left
->old_version_bottom
, &right
->old_version_bottom
))
3940 if (left
->has_old_version_top
&& !info_compare_versions (&left
->old_version_top
, &right
->old_version_top
))
3943 if (left
->has_new_version
&& !info_compare_versions (&left
->new_version
, &right
->new_version
))
3949 /* LOCKING: assumes all the necessary locks are held */
3951 assembly_binding_info_parsed (MonoAssemblyBindingInfo
*info
, void *user_data
)
3953 MonoAssemblyBindingInfo
*info_copy
;
3955 MonoAssemblyBindingInfo
*info_tmp
;
3956 MonoDomain
*domain
= (MonoDomain
*)user_data
;
3961 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
)) {
3962 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
3963 info
->name
, info
->new_version
.major
, info
->new_version
.minor
, info
->new_version
.build
, info
->new_version
.revision
);
3967 for (tmp
= domain
->assembly_bindings
; tmp
; tmp
= tmp
->next
) {
3968 info_tmp
= (MonoAssemblyBindingInfo
*)tmp
->data
;
3969 if (strcmp (info
->name
, info_tmp
->name
) == 0 && info_versions_equal (info
, info_tmp
))
3973 info_copy
= (MonoAssemblyBindingInfo
*)mono_mempool_alloc0 (domain
->mp
, sizeof (MonoAssemblyBindingInfo
));
3974 memcpy (info_copy
, info
, sizeof (MonoAssemblyBindingInfo
));
3976 info_copy
->name
= mono_mempool_strdup (domain
->mp
, info
->name
);
3978 info_copy
->culture
= mono_mempool_strdup (domain
->mp
, info
->culture
);
3980 domain
->assembly_bindings
= g_slist_append_mempool (domain
->mp
, domain
->assembly_bindings
, info_copy
);
3984 get_version_number (int major
, int minor
)
3986 return major
* 256 + minor
;
3989 static inline gboolean
3990 info_major_minor_in_range (MonoAssemblyBindingInfo
*info
, MonoAssemblyName
*aname
)
3992 int aname_version_number
= get_version_number (aname
->major
, aname
->minor
);
3993 if (!info
->has_old_version_bottom
)
3996 if (get_version_number (info
->old_version_bottom
.major
, info
->old_version_bottom
.minor
) > aname_version_number
)
3999 if (info
->has_old_version_top
&& get_version_number (info
->old_version_top
.major
, info
->old_version_top
.minor
) < aname_version_number
)
4002 /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
4003 info
->major
= aname
->major
;
4004 info
->minor
= aname
->minor
;
4009 /* LOCKING: Assumes that we are already locked - both loader and domain locks */
4010 static MonoAssemblyBindingInfo
*
4011 get_per_domain_assembly_binding_info (MonoDomain
*domain
, MonoAssemblyName
*aname
)
4013 MonoAssemblyBindingInfo
*info
;
4016 if (!domain
->assembly_bindings
)
4020 for (list
= domain
->assembly_bindings
; list
; list
= list
->next
) {
4021 info
= (MonoAssemblyBindingInfo
*)list
->data
;
4022 if (info
&& !strcmp (aname
->name
, info
->name
) && info_major_minor_in_range (info
, aname
))
4028 if (info
->name
&& info
->public_key_token
[0] && info
->has_old_version_bottom
&&
4029 info
->has_new_version
&& assembly_binding_maps_name (info
, aname
))
4030 info
->is_valid
= TRUE
;
4032 info
->is_valid
= FALSE
;
4039 mono_domain_parse_assembly_bindings (MonoDomain
*domain
, int amajor
, int aminor
, gchar
*domain_config_file_name
)
4041 if (domain
->assembly_bindings_parsed
)
4043 mono_domain_lock (domain
);
4044 if (!domain
->assembly_bindings_parsed
) {
4046 gchar
*domain_config_file_path
= mono_portability_find_file (domain_config_file_name
, TRUE
);
4048 if (!domain_config_file_path
)
4049 domain_config_file_path
= domain_config_file_name
;
4051 mono_config_parse_assembly_bindings (domain_config_file_path
, amajor
, aminor
, domain
, assembly_binding_info_parsed
);
4052 domain
->assembly_bindings_parsed
= TRUE
;
4053 if (domain_config_file_name
!= domain_config_file_path
)
4054 g_free (domain_config_file_path
);
4057 mono_domain_unlock (domain
);
4060 static MonoAssemblyName
*
4061 mono_assembly_apply_binding (MonoAssemblyName
*aname
, MonoAssemblyName
*dest_name
)
4063 HANDLE_FUNCTION_ENTER ();
4066 MonoAssemblyBindingInfo
*info
, *info2
;
4070 if (aname
->public_key_token
[0] == 0)
4073 domain
= mono_domain_get ();
4075 mono_assembly_binding_lock ();
4076 info
= search_binding_loaded (aname
);
4077 mono_assembly_binding_unlock ();
4080 mono_domain_lock (domain
);
4081 info
= get_per_domain_assembly_binding_info (domain
, aname
);
4082 mono_domain_unlock (domain
);
4086 if (!check_policy_versions (info
, aname
))
4089 mono_assembly_bind_version (info
, aname
, dest_name
);
4090 goto return_dest_name
;
4093 MonoAppDomainSetupHandle setup
;
4094 MonoStringHandle configuration_file
;
4097 && !MONO_HANDLE_IS_NULL (setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, domain
->setup
))
4098 && !MONO_HANDLE_IS_NULL (configuration_file
= MONO_HANDLE_NEW_GET (MonoString
, setup
, configuration_file
))) {
4099 char *domain_config_file_name
= mono_string_handle_to_utf8 (configuration_file
, error
);
4100 /* expect this to succeed because mono_domain_set_options_from_config () did
4101 * the same thing when the domain was created. */
4102 mono_error_assert_ok (error
);
4103 mono_domain_parse_assembly_bindings (domain
, aname
->major
, aname
->minor
, domain_config_file_name
);
4104 g_free (domain_config_file_name
);
4106 mono_domain_lock (domain
);
4107 info2
= get_per_domain_assembly_binding_info (domain
, aname
);
4110 info
= (MonoAssemblyBindingInfo
*)g_memdup (info2
, sizeof (MonoAssemblyBindingInfo
));
4111 info
->name
= g_strdup (info2
->name
);
4112 info
->culture
= g_strdup (info2
->culture
);
4113 info
->domain_id
= domain
->domain_id
;
4116 mono_domain_unlock (domain
);
4120 info
= g_new0 (MonoAssemblyBindingInfo
, 1);
4121 info
->major
= aname
->major
;
4122 info
->minor
= aname
->minor
;
4125 if (!info
->is_valid
) {
4126 ppimage
= mono_assembly_load_publisher_policy (aname
);
4128 get_publisher_policy_info (ppimage
, aname
, info
);
4129 mono_image_close (ppimage
);
4133 /* Define default error value if needed */
4134 if (!info
->is_valid
) {
4135 info
->name
= g_strdup (aname
->name
);
4136 info
->culture
= g_strdup (aname
->culture
);
4137 g_strlcpy ((char *)info
->public_key_token
, (const char *)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
4140 mono_assembly_binding_lock ();
4141 info2
= search_binding_loaded (aname
);
4143 /* This binding was added by another thread
4145 mono_assembly_binding_info_free (info
);
4150 loaded_assembly_bindings
= g_slist_prepend (loaded_assembly_bindings
, info
);
4152 mono_assembly_binding_unlock ();
4154 if (!info
->is_valid
|| !check_policy_versions (info
, aname
))
4157 mono_assembly_bind_version (info
, aname
, dest_name
);
4158 goto return_dest_name
;
4160 MonoAssemblyName
* result
;
4170 HANDLE_FUNCTION_RETURN_VAL (result
);
4175 * mono_assembly_load_from_gac
4177 * \param aname The assembly name object
4179 static MonoAssembly
*
4180 mono_assembly_load_from_gac (MonoAssemblyName
*aname
, gchar
*filename
, MonoImageOpenStatus
*status
, MonoBoolean refonly
)
4182 MonoAssembly
*result
= NULL
;
4183 gchar
*name
, *version
, *culture
, *fullpath
, *subpath
;
4188 if (aname
->public_key_token
[0] == 0) {
4192 if (strstr (aname
->name
, ".dll")) {
4193 len
= strlen (filename
) - 4;
4194 name
= (gchar
*)g_malloc (len
+ 1);
4195 memcpy (name
, aname
->name
, len
);
4198 name
= g_strdup (aname
->name
);
4201 if (aname
->culture
) {
4202 culture
= g_utf8_strdown (aname
->culture
, -1);
4204 culture
= g_strdup ("");
4207 pubtok
= g_ascii_strdown ((char*)aname
->public_key_token
, MONO_PUBLIC_KEY_TOKEN_LENGTH
);
4208 version
= g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname
->major
,
4209 aname
->minor
, aname
->build
, aname
->revision
,
4213 subpath
= g_build_path (G_DIR_SEPARATOR_S
, name
, version
, filename
, NULL
);
4218 MonoAssemblyOpenRequest req
;
4219 mono_assembly_request_prepare (&req
.request
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
4221 if (extra_gac_paths
) {
4222 paths
= extra_gac_paths
;
4223 while (!result
&& *paths
) {
4224 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, *paths
, "lib", "mono", "gac", subpath
, NULL
);
4225 result
= mono_assembly_request_open (fullpath
, &req
, status
);
4232 result
->in_gac
= TRUE
;
4237 fullpath
= g_build_path (G_DIR_SEPARATOR_S
, mono_assembly_getrootdir (),
4238 "mono", "gac", subpath
, NULL
);
4239 result
= mono_assembly_request_open (fullpath
, &req
, status
);
4243 result
->in_gac
= TRUE
;
4249 #endif /* DISABLE_GAC */
4252 mono_assembly_load_corlib (const MonoRuntimeInfo
*runtime
, MonoImageOpenStatus
*status
)
4254 MonoAssemblyName
*aname
;
4255 MonoAssemblyOpenRequest req
;
4256 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
4259 /* g_print ("corlib already loaded\n"); */
4263 req
.request
.alc
= mono_domain_default_alc (mono_domain_get ());
4265 #ifdef ENABLE_NETCORE
4266 aname
= mono_assembly_name_new (MONO_ASSEMBLY_CORLIB_NAME
);
4267 corlib
= invoke_assembly_preload_hook (req
.request
.alc
, aname
, NULL
);
4268 /* MonoCore preload hook should know how to find it */
4269 /* FIXME: AOT compiler comes here without an installed hook. */
4271 if (assemblies_path
) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
4272 char *corlib_name
= g_strdup_printf ("%s.dll", MONO_ASSEMBLY_CORLIB_NAME
);
4273 corlib
= load_in_path (corlib_name
, (const char**)assemblies_path
, &req
, status
);
4278 // A nonstandard preload hook may provide a special mscorlib assembly
4279 aname
= mono_assembly_name_new ("mscorlib.dll");
4280 corlib
= invoke_assembly_preload_hook (req
.request
.alc
, aname
, assemblies_path
);
4281 mono_assembly_name_free (aname
);
4284 goto return_corlib_and_facades
;
4286 // This unusual directory layout can occur if mono is being built and run out of its own source repo
4287 if (assemblies_path
) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
4288 corlib
= load_in_path ("mscorlib.dll", (const char**)assemblies_path
, &req
, status
);
4290 goto return_corlib_and_facades
;
4293 /* Normal case: Load corlib from mono/<version> */
4295 corlib_file
= g_build_filename ("mono", runtime
->framework_version
, "mscorlib.dll", NULL
);
4296 if (assemblies_path
) { // Custom assemblies path
4297 corlib
= load_in_path (corlib_file
, (const char**)assemblies_path
, &req
, status
);
4299 g_free (corlib_file
);
4300 goto return_corlib_and_facades
;
4303 corlib
= load_in_path (corlib_file
, (const char**) default_path
, &req
, status
);
4304 g_free (corlib_file
);
4306 return_corlib_and_facades
:
4307 if (corlib
) // FIXME: stop hardcoding 4.5 here
4308 default_path
[1] = g_strdup_printf ("%s/Facades", corlib
->basedir
);
4309 #endif /*!ENABLE_NETCORE*/
4314 static MonoAssembly
*
4315 prevent_reference_assembly_from_running (MonoAssembly
* candidate
, gboolean refonly
)
4317 ERROR_DECL (refasm_error
);
4318 if (candidate
&& !refonly
) {
4319 /* .NET Framework seems to not check for ReferenceAssemblyAttribute on dynamic assemblies */
4320 if (!image_is_dynamic (candidate
->image
) &&
4321 mono_assembly_has_reference_assembly_attribute (candidate
, refasm_error
))
4324 mono_error_cleanup (refasm_error
);
4329 mono_assembly_candidate_predicate_sn_same_name (MonoAssembly
*candidate
, gpointer ud
)
4331 MonoAssemblyName
*wanted_name
= (MonoAssemblyName
*)ud
;
4332 MonoAssemblyName
*candidate_name
= &candidate
->aname
;
4334 g_assert (wanted_name
!= NULL
);
4335 g_assert (candidate_name
!= NULL
);
4337 if (mono_trace_is_traced (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
)) {
4338 char * s
= mono_stringify_assembly_name (wanted_name
);
4339 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: wanted = %s\n", s
);
4341 s
= mono_stringify_assembly_name (candidate_name
);
4342 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate = %s\n", s
);
4347 /* Wanted name has no token, not strongly named: always matches. */
4348 if (0 == wanted_name
->public_key_token
[0]) {
4349 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: wanted has no token, returning TRUE\n");
4353 /* Candidate name has no token, not strongly named: never matches */
4354 if (0 == candidate_name
->public_key_token
[0]) {
4355 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate has no token, returning FALSE\n");
4359 return exact_sn_match (wanted_name
, candidate_name
) ||
4360 framework_assembly_sn_match (wanted_name
, candidate_name
);
4364 exact_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
)
4367 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_VERSION
| MONO_ANAME_EQ_IGNORE_PUBKEY
);
4368 if (result
&& assembly_names_compare_versions (wanted_name
, candidate_name
, -1) > 0)
4371 gboolean result
= mono_assembly_names_equal (wanted_name
, candidate_name
);
4374 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s\n",
4375 result
? "match, returning TRUE" : "don't match, returning FALSE");
4381 framework_assembly_sn_match (MonoAssemblyName
*wanted_name
, MonoAssemblyName
*candidate_name
)
4383 #ifndef DISABLE_DESKTOP_LOADER
4384 g_assert (wanted_name
!= NULL
);
4385 g_assert (candidate_name
!= NULL
);
4386 const AssemblyVersionMap
*vmap
= (AssemblyVersionMap
*)g_hash_table_lookup (assembly_remapping_table
, wanted_name
->name
);
4388 if (!vmap
->framework_facade_assembly
) {
4389 /* 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. */
4390 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_PUBKEY
);
4391 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s (ignoring the public key token)", result
? "match, returning TRUE" : "don't match, returning FALSE");
4394 /* For facades, the name and public key token should
4395 * match, but the version doesn't matter as long as the
4396 * candidate is not older. */
4397 gboolean result
= mono_assembly_names_equal_flags (wanted_name
, candidate_name
, MONO_ANAME_EQ_IGNORE_VERSION
);
4398 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate and wanted names %s (ignoring version)", result
? "match" : "don't match, returning FALSE");
4400 // compare major of candidate and wanted
4401 int c
= assembly_names_compare_versions (candidate_name
, wanted_name
, 1);
4402 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Predicate: candidate major version is %s wanted major version, returning %s\n", c
== 0 ? "the same as" : (c
< 0 ? "lower than" : "greater than"),
4403 (c
>= 0) ? "TRUE" : "FALSE");
4404 return (c
>= 0); // don't accept a candidate that's older than wanted.
4414 static MonoAssembly
*
4415 mono_assembly_request_byname_nosearch (MonoAssemblyName
*aname
,
4416 const MonoAssemblyByNameRequest
*req
,
4417 MonoImageOpenStatus
*status
)
4419 MonoAssembly
*result
;
4420 MonoAssemblyName maped_aname
;
4421 MonoAssemblyName maped_name_pp
;
4423 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
4425 const gboolean refonly
= req
->request
.asmctx
== MONO_ASMCTX_REFONLY
;
4427 /* Reflection only assemblies don't get assembly binding */
4429 aname
= mono_assembly_apply_binding (aname
, &maped_name_pp
);
4431 result
= mono_assembly_loaded_internal (req
->request
.alc
, aname
, refonly
);
4435 result
= refonly
? invoke_assembly_refonly_preload_hook (req
->request
.alc
, aname
, assemblies_path
) : invoke_assembly_preload_hook (req
->request
.alc
, aname
, assemblies_path
);
4437 result
->in_gac
= FALSE
;
4441 /* TODO: for netcore can we avoid calling this method? There is no GAC and we also shouldn't need to load anything from the default path */
4442 return mono_assembly_load_full_gac_base_default (aname
, req
->basedir
, req
->request
.alc
, req
->request
.asmctx
, status
);
4445 /* Like mono_assembly_request_byname_nosearch, but don't ask the preload look (ie,
4446 * the appdomain) to run. Just looks in the gac, the specified base dir or the
4447 * default_path. Does NOT look in the appdomain application base or in the
4451 mono_assembly_load_full_gac_base_default (MonoAssemblyName
*aname
,
4452 const char *basedir
,
4453 MonoAssemblyLoadContext
*alc
,
4454 MonoAssemblyContextKind asmctx
,
4455 MonoImageOpenStatus
*status
)
4457 MonoAssembly
*result
;
4458 MonoAssemblyName maped_aname
;
4459 char *fullpath
, *filename
;
4464 /* If we remap e.g. 4.1.3.0 to 4.0.0.0, look in the 4.0.0.0
4465 * GAC directory, not 4.1.3.0 */
4466 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
4468 /* Currently we retrieve the loaded corlib for reflection
4469 * only requests, like a common reflection only assembly
4471 gboolean name_is_corlib
= strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
) == 0;
4472 /* Assembly.Load (new AssemblyName ("mscorlib.dll")) (respectively,
4473 * "System.Private.CoreLib.dll" for netcore) is treated the same as
4474 * "mscorlib" (resp "System.Private.CoreLib"). */
4475 name_is_corlib
= name_is_corlib
|| strcmp (aname
->name
, MONO_ASSEMBLY_CORLIB_NAME
".dll") == 0;
4476 if (name_is_corlib
) {
4477 return mono_assembly_load_corlib (mono_get_runtime_info (), status
);
4480 MonoAssemblyCandidatePredicate predicate
= NULL
;
4481 void* predicate_ud
= NULL
;
4482 #if !defined(DISABLE_DESKTOP_LOADER)
4483 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
4484 predicate
= &mono_assembly_candidate_predicate_sn_same_name
;
4485 predicate_ud
= aname
;
4489 MonoAssemblyOpenRequest req
;
4490 mono_assembly_request_prepare (&req
.request
, sizeof (req
), asmctx
);
4491 req
.request
.alc
= alc
;
4492 req
.request
.predicate
= predicate
;
4493 req
.request
.predicate_ud
= predicate_ud
;
4495 len
= strlen (aname
->name
);
4496 for (ext_index
= 0; ext_index
< 2; ext_index
++) {
4497 ext
= ext_index
== 0 ? ".dll" : ".exe";
4498 if (len
> 4 && (!strcmp (aname
->name
+ len
- 4, ".dll") || !strcmp (aname
->name
+ len
- 4, ".exe"))) {
4499 filename
= g_strdup (aname
->name
);
4500 /* Don't try appending .dll/.exe if it already has one of those extensions */
4503 filename
= g_strconcat (aname
->name
, ext
, NULL
);
4507 const gboolean refonly
= asmctx
== MONO_ASMCTX_REFONLY
;
4509 result
= mono_assembly_load_from_gac (aname
, filename
, status
, refonly
);
4517 fullpath
= g_build_filename (basedir
, filename
, NULL
);
4518 result
= mono_assembly_request_open (fullpath
, &req
, status
);
4521 result
->in_gac
= FALSE
;
4527 result
= load_in_path (filename
, (const char**) default_path
, &req
, status
);
4529 result
->in_gac
= FALSE
;
4539 mono_assembly_request_byname (MonoAssemblyName
*aname
, const MonoAssemblyByNameRequest
*req
, MonoImageOpenStatus
*status
)
4541 MonoDomain
*domain
= mono_domain_get ();
4542 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
);
4543 MonoAssembly
*result
= mono_assembly_request_byname_nosearch (aname
, req
, status
);
4544 const gboolean refonly
= req
->request
.asmctx
== MONO_ASMCTX_REFONLY
;
4546 if (!result
&& !req
->no_postload_search
) {
4547 /* Try a postload search hook */
4548 result
= mono_assembly_invoke_search_hook_internal (req
->request
.alc
, req
->requesting_assembly
, aname
, refonly
, TRUE
);
4549 result
= prevent_reference_assembly_from_running (result
, refonly
);
4555 * mono_assembly_load_full:
4556 * \param aname A MonoAssemblyName with the assembly name to load.
4557 * \param basedir A directory to look up the assembly at.
4558 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
4559 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
4561 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
4562 * attempts to load the assembly from that directory before probing the standard locations.
4564 * If the assembly is being opened in reflection-only mode (\p refonly set to TRUE) then no
4565 * assembly binding takes place.
4567 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
4568 * value pointed by \p status is updated with an error code.
4571 mono_assembly_load_full (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
, gboolean refonly
)
4574 MONO_ENTER_GC_UNSAFE
;
4575 MonoAssemblyByNameRequest req
;
4576 mono_assembly_request_prepare (&req
.request
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
4577 req
.requesting_assembly
= NULL
;
4578 req
.basedir
= basedir
;
4579 res
= mono_assembly_request_byname (aname
, &req
, status
);
4580 MONO_EXIT_GC_UNSAFE
;
4585 * mono_assembly_load:
4586 * \param aname A MonoAssemblyName with the assembly name to load.
4587 * \param basedir A directory to look up the assembly at.
4588 * \param status a pointer to a MonoImageOpenStatus to return the status of the load operation
4590 * Loads the assembly referenced by \p aname, if the value of \p basedir is not NULL, it
4591 * attempts to load the assembly from that directory before probing the standard locations.
4593 * \returns the assembly referenced by \p aname loaded or NULL on error. On error the
4594 * value pointed by \p status is updated with an error code.
4597 mono_assembly_load (MonoAssemblyName
*aname
, const char *basedir
, MonoImageOpenStatus
*status
)
4599 MonoAssemblyByNameRequest req
;
4600 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_DEFAULT
);
4601 req
.requesting_assembly
= NULL
;
4602 req
.request
.alc
= mono_domain_default_alc (mono_domain_get ());
4603 req
.basedir
= basedir
;
4604 return mono_assembly_request_byname (aname
, &req
, status
);
4608 * mono_assembly_loaded_full:
4609 * \param aname an assembly to look for.
4610 * \param refonly Whether this assembly is being opened in "reflection-only" mode.
4612 * This is used to determine if the specified assembly has been loaded
4613 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
4614 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
4617 mono_assembly_loaded_full (MonoAssemblyName
*aname
, gboolean refonly
)
4619 MonoAssemblyLoadContext
*alc
= mono_domain_ambient_alc (mono_domain_get ());
4620 return mono_assembly_loaded_internal (alc
, aname
, refonly
);
4624 mono_assembly_loaded_internal (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
, gboolean refonly
)
4627 MonoAssemblyName maped_aname
;
4629 aname
= mono_assembly_remap_version (aname
, &maped_aname
);
4631 res
= mono_assembly_invoke_search_hook_internal (alc
, NULL
, aname
, refonly
, FALSE
);
4637 * mono_assembly_loaded:
4638 * \param aname an assembly to look for.
4640 * This is used to determine if the specified assembly has been loaded
4642 * \returns NULL If the given \p aname assembly has not been loaded, or a pointer to
4643 * a \c MonoAssembly that matches the \c MonoAssemblyName specified.
4646 mono_assembly_loaded (MonoAssemblyName
*aname
)
4649 MONO_ENTER_GC_UNSAFE
;
4650 res
= mono_assembly_loaded_internal (mono_domain_ambient_alc (mono_domain_get ()), aname
, FALSE
);
4651 MONO_EXIT_GC_UNSAFE
;
4656 mono_assembly_release_gc_roots (MonoAssembly
*assembly
)
4658 if (assembly
== NULL
|| assembly
== REFERENCE_MISSING
)
4661 if (assembly_is_dynamic (assembly
)) {
4663 MonoDynamicImage
*dynimg
= (MonoDynamicImage
*)assembly
->image
;
4664 for (i
= 0; i
< dynimg
->image
.module_count
; ++i
)
4665 mono_dynamic_image_release_gc_roots ((MonoDynamicImage
*)dynimg
->image
.modules
[i
]);
4666 mono_dynamic_image_release_gc_roots (dynimg
);
4671 * Returns whether mono_assembly_close_finish() must be called as
4672 * well. See comment for mono_image_close_except_pools() for why we
4673 * unload in two steps.
4676 mono_assembly_close_except_image_pools (MonoAssembly
*assembly
)
4679 g_return_val_if_fail (assembly
!= NULL
, FALSE
);
4681 if (assembly
== REFERENCE_MISSING
)
4684 /* Might be 0 already */
4685 if (mono_atomic_dec_i32 (&assembly
->ref_count
) > 0)
4688 MONO_PROFILER_RAISE (assembly_unloading
, (assembly
));
4690 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Unloading assembly %s [%p].", assembly
->aname
.name
, assembly
);
4692 mono_debug_close_image (assembly
->image
);
4694 mono_assemblies_lock ();
4695 loaded_assemblies
= g_list_remove (loaded_assemblies
, assembly
);
4696 mono_assemblies_unlock ();
4698 assembly
->image
->assembly
= NULL
;
4700 if (!mono_image_close_except_pools (assembly
->image
))
4701 assembly
->image
= NULL
;
4703 for (tmp
= assembly
->friend_assembly_names
; tmp
; tmp
= tmp
->next
) {
4704 MonoAssemblyName
*fname
= (MonoAssemblyName
*)tmp
->data
;
4705 mono_assembly_name_free (fname
);
4708 g_slist_free (assembly
->friend_assembly_names
);
4709 g_free (assembly
->basedir
);
4711 MONO_PROFILER_RAISE (assembly_unloaded
, (assembly
));
4717 mono_assembly_close_finish (MonoAssembly
*assembly
)
4719 g_assert (assembly
&& assembly
!= REFERENCE_MISSING
);
4721 if (assembly
->image
)
4722 mono_image_close_finish (assembly
->image
);
4724 if (assembly_is_dynamic (assembly
)) {
4725 g_free ((char*)assembly
->aname
.culture
);
4732 * mono_assembly_close:
4733 * \param assembly the assembly to release.
4735 * This method releases a reference to the \p assembly. The assembly is
4736 * only released when all the outstanding references to it are released.
4739 mono_assembly_close (MonoAssembly
*assembly
)
4741 if (mono_assembly_close_except_image_pools (assembly
))
4742 mono_assembly_close_finish (assembly
);
4746 * mono_assembly_load_module:
4749 mono_assembly_load_module (MonoAssembly
*assembly
, guint32 idx
)
4752 MonoImage
*result
= mono_assembly_load_module_checked (assembly
, idx
, error
);
4753 mono_error_assert_ok (error
);
4758 mono_assembly_load_module_checked (MonoAssembly
*assembly
, uint32_t idx
, MonoError
*error
)
4760 return mono_image_load_file_for_image_checked (assembly
->image
, idx
, error
);
4765 * mono_assembly_foreach:
4766 * \param func function to invoke for each assembly loaded
4767 * \param user_data data passed to the callback
4769 * Invokes the provided \p func callback for each assembly loaded into
4770 * the runtime. The first parameter passed to the callback is the
4771 * \c MonoAssembly*, and the second parameter is the \p user_data.
4773 * This is done for all assemblies loaded in the runtime, not just
4774 * those loaded in the current application domain.
4777 mono_assembly_foreach (GFunc func
, gpointer user_data
)
4782 * We make a copy of the list to avoid calling the callback inside the
4783 * lock, which could lead to deadlocks.
4785 mono_assemblies_lock ();
4786 copy
= g_list_copy (loaded_assemblies
);
4787 mono_assemblies_unlock ();
4789 g_list_foreach (loaded_assemblies
, func
, user_data
);
4795 * mono_assemblies_cleanup:
4797 * Free all resources used by this module.
4800 mono_assemblies_cleanup (void)
4804 mono_os_mutex_destroy (&assemblies_mutex
);
4805 mono_os_mutex_destroy (&assembly_binding_mutex
);
4807 for (l
= loaded_assembly_bindings
; l
; l
= l
->next
) {
4808 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)l
->data
;
4810 mono_assembly_binding_info_free (info
);
4813 g_slist_free (loaded_assembly_bindings
);
4815 free_assembly_asmctx_from_path_hooks ();
4816 free_assembly_load_hooks ();
4817 free_assembly_search_hooks ();
4818 free_assembly_preload_hooks ();
4821 /*LOCKING takes the assembly_binding lock*/
4823 mono_assembly_cleanup_domain_bindings (guint32 domain_id
)
4827 mono_assembly_binding_lock ();
4828 iter
= &loaded_assembly_bindings
;
4831 MonoAssemblyBindingInfo
*info
= (MonoAssemblyBindingInfo
*)l
->data
;
4833 if (info
->domain_id
== domain_id
) {
4835 mono_assembly_binding_info_free (info
);
4842 mono_assembly_binding_unlock ();
4846 * Holds the assembly of the application, for
4847 * System.Diagnostics.Process::MainModule
4849 static MonoAssembly
*main_assembly
=NULL
;
4852 * mono_assembly_set_main:
4855 mono_assembly_set_main (MonoAssembly
*assembly
)
4857 main_assembly
= assembly
;
4861 * mono_assembly_get_main:
4863 * Returns: the assembly for the application, the first assembly that is loaded by the VM
4866 mono_assembly_get_main (void)
4868 return (main_assembly
);
4872 * mono_assembly_get_image:
4873 * \param assembly The assembly to retrieve the image from
4875 * \returns the \c MonoImage associated with this assembly.
4878 mono_assembly_get_image (MonoAssembly
*assembly
)
4881 MONO_ENTER_GC_UNSAFE
;
4882 res
= mono_assembly_get_image_internal (assembly
);
4883 MONO_EXIT_GC_UNSAFE
;
4888 mono_assembly_get_image_internal (MonoAssembly
*assembly
)
4890 MONO_REQ_GC_UNSAFE_MODE
;
4891 return assembly
->image
;
4895 * mono_assembly_get_name:
4896 * \param assembly The assembly to retrieve the name from
4898 * The returned name's lifetime is the same as \p assembly's.
4900 * \returns the \c MonoAssemblyName associated with this assembly.
4903 mono_assembly_get_name (MonoAssembly
*assembly
)
4905 MonoAssemblyName
*res
;
4906 MONO_ENTER_GC_UNSAFE
;
4907 res
= mono_assembly_get_name_internal (assembly
);
4908 MONO_EXIT_GC_UNSAFE
;
4913 mono_assembly_get_name_internal (MonoAssembly
*assembly
)
4915 MONO_REQ_GC_UNSAFE_MODE
;
4916 return &assembly
->aname
;
4920 * mono_register_bundled_assemblies:
4923 mono_register_bundled_assemblies (const MonoBundledAssembly
**assemblies
)
4925 bundles
= assemblies
;
4928 #define MONO_DECLSEC_FORMAT_10 0x3C
4929 #define MONO_DECLSEC_FORMAT_20 0x2E
4930 #define MONO_DECLSEC_FIELD 0x53
4931 #define MONO_DECLSEC_PROPERTY 0x54
4933 #define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"")
4934 #define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute")
4935 #define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1)
4936 #define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification")
4937 #define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1)
4940 mono_assembly_try_decode_skip_verification_param (const char *p
, const char **resp
, gboolean
*abort_decoding
)
4944 case MONO_DECLSEC_PROPERTY
:
4946 case MONO_DECLSEC_FIELD
:
4948 *abort_decoding
= TRUE
;
4953 if (*p
++ != MONO_TYPE_BOOLEAN
) {
4954 *abort_decoding
= TRUE
;
4958 /* property name length */
4959 len
= mono_metadata_decode_value (p
, &p
);
4961 if (len
>= SKIP_VISIBILITY_PROPERTY_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_PROPERTY_NAME
, SKIP_VISIBILITY_PROPERTY_SIZE
)) {
4972 mono_assembly_try_decode_skip_verification (const char *p
, const char *endn
)
4974 int i
, j
, num
, len
, params_len
;
4976 if (*p
== MONO_DECLSEC_FORMAT_10
) {
4977 gsize read
, written
;
4978 char *res
= g_convert (p
, endn
- p
, "UTF-8", "UTF-16LE", &read
, &written
, NULL
);
4980 gboolean found
= strstr (res
, SKIP_VISIBILITY_XML_ATTRIBUTE
) != NULL
;
4986 if (*p
++ != MONO_DECLSEC_FORMAT_20
)
4989 /* number of encoded permission attributes */
4990 num
= mono_metadata_decode_value (p
, &p
);
4991 for (i
= 0; i
< num
; ++i
) {
4992 gboolean is_valid
= FALSE
;
4993 gboolean abort_decoding
= FALSE
;
4995 /* attribute name length */
4996 len
= mono_metadata_decode_value (p
, &p
);
4998 /* We don't really need to fully decode the type. Comparing the name is enough */
4999 is_valid
= len
>= SKIP_VISIBILITY_ATTRIBUTE_SIZE
&& !memcmp (p
, SKIP_VISIBILITY_ATTRIBUTE_NAME
, SKIP_VISIBILITY_ATTRIBUTE_SIZE
);
5003 /*size of the params table*/
5004 params_len
= mono_metadata_decode_value (p
, &p
);
5006 const char *params_end
= p
+ params_len
;
5008 /* number of parameters */
5009 len
= mono_metadata_decode_value (p
, &p
);
5011 for (j
= 0; j
< len
; ++j
) {
5012 if (mono_assembly_try_decode_skip_verification_param (p
, &p
, &abort_decoding
))
5028 mono_assembly_has_skip_verification (MonoAssembly
*assembly
)
5031 guint32 cols
[MONO_DECL_SECURITY_SIZE
];
5035 if (MONO_SECMAN_FLAG_INIT (assembly
->skipverification
))
5036 return MONO_SECMAN_FLAG_GET_VALUE (assembly
->skipverification
);
5038 t
= &assembly
->image
->tables
[MONO_TABLE_DECLSECURITY
];
5040 for (i
= 0; i
< t
->rows
; ++i
) {
5041 mono_metadata_decode_row (t
, i
, cols
, MONO_DECL_SECURITY_SIZE
);
5042 if ((cols
[MONO_DECL_SECURITY_PARENT
] & MONO_HAS_DECL_SECURITY_MASK
) != MONO_HAS_DECL_SECURITY_ASSEMBLY
)
5044 if (cols
[MONO_DECL_SECURITY_ACTION
] != SECURITY_ACTION_REQMIN
)
5047 blob
= mono_metadata_blob_heap (assembly
->image
, cols
[MONO_DECL_SECURITY_PERMISSIONSET
]);
5048 len
= mono_metadata_decode_blob_size (blob
, &blob
);
5052 if (mono_assembly_try_decode_skip_verification (blob
, blob
+ len
)) {
5053 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, TRUE
);
5058 MONO_SECMAN_FLAG_SET_VALUE (assembly
->skipverification
, FALSE
);
5062 MonoAssemblyContextKind
5063 mono_asmctx_get_kind (const MonoAssemblyContext
*ctx
)
5069 mono_asmctx_get_name (const MonoAssemblyContext
*asmctx
)
5071 static const char* names
[] = {
5077 g_assert (asmctx
->kind
>= 0 && asmctx
->kind
<= MONO_ASMCTX_LAST
);
5078 return names
[asmctx
->kind
];