#include "loader.h"
#include "marshal.h"
#include "coree.h"
-#include <mono/io-layer/io-layer.h>
+#include <mono/utils/checked-build.h>
#include <mono/utils/mono-logger-internals.h>
#include <mono/utils/mono-path.h>
#include <mono/utils/mono-mmap.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+#include <mono/metadata/w32error.h>
#define INVALID_ADDRESS 0xffffffff
image->heap_tables.size = read32 (ptr + 4);
ptr += 8 + 3;
image->uncompressed_metadata = TRUE;
- mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly '%s' has the non-standard metadata heap #-.\nRecompile it correctly (without the /incremental switch or in Release mode).\n", image->name);
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly '%s' has the non-standard metadata heap #-.\nRecompile it correctly (without the /incremental switch or in Release mode).", image->name);
} else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
image->heap_pdb.data = image->raw_metadata + read32 (ptr);
image->heap_pdb.size = read32 (ptr + 4);
/* They must be the same */
g_assert ((const void *) image->tables_base == (const void *) rows);
+ if (image->heap_pdb.size) {
+ /*
+ * Obtain token sizes from the pdb stream.
+ */
+ /* 24 = guid + entry point */
+ int pos = 24;
+ image->referenced_tables = read64 (image->heap_pdb.data + pos);
+ pos += 8;
+ image->referenced_table_rows = g_new0 (int, 64);
+ for (int i = 0; i < 64; ++i) {
+ if (image->referenced_tables & ((guint64)1 << i)) {
+ image->referenced_table_rows [i] = read32 (image->heap_pdb.data + pos);
+ pos += 4;
+ }
+ }
+ }
+
mono_metadata_compute_table_bases (image);
return TRUE;
}
GList *list_iter, *valid_modules = NULL;
MonoImageOpenStatus status;
+ error_init (error);
+
if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
return NULL;
if (image->modules_loaded [idx - 1])
if (valid) {
module_ref = g_build_filename (base_dir, name, NULL);
MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
- if (image->modules [idx - 1]) {
- g_assert(!image->modules [idx - 1]->assembly || image->modules [idx - 1]->assembly == image->assembly);
- image->modules [idx - 1]->assembly = image->assembly;
-
+ if (moduleImage) {
if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
mono_image_close (moduleImage);
g_free (module_ref);
return NULL;
}
- image->modules [idx - 1] = image;
+ image->modules [idx - 1] = moduleImage;
#ifdef HOST_WIN32
if (image->modules [idx - 1]->is_module_handle)
mono_image_load_module (MonoImage *image, int idx)
{
MonoError error;
- mono_error_init (&error);
MonoImage *result = mono_image_load_module_checked (image, idx, &error);
mono_error_assert_ok (&error);
- mono_error_cleanup (&error);
return result;
}
static gpointer*
class_next_value (gpointer value)
{
- MonoClass *klass = (MonoClass *)value;
+ MonoClassDef *klass = (MonoClassDef *)value;
return (gpointer*)&klass->next_class_cache;
}
mono_install_image_loader (&pe_loader);
}
+/*
+Ignored assemblies.
+
+There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
+Mono provides its own implementation of those assemblies so it's safe to do so.
+
+The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
+
+Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
+
+This is to be removed once a proper fix is shipped through nuget.
+
+*/
+
+typedef enum {
+ SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
+ SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
+ SYS_IO_COMPRESSION = 2, //System.IO.Compression
+ SYS_NET_HTTP = 3, //System.Net.Http
+ SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
+ SYS_REF_DISP_PROXY = 5, //System.Reflection.DispatchProxy
+ SYS_VALUE_TUPLE = 6, //System.ValueTuple
+} IgnoredAssemblyNames;
+
+typedef struct {
+ int hash;
+ int assembly_name;
+ const char guid [40];
+} IgnoredAssembly;
+
+typedef struct {
+ int assembly_name;
+ guint16 major, minor, build, revision;
+} IgnoredAssemblyVersion;
+
+const char *ignored_assemblies_file_names[] = {
+ "System.Runtime.InteropServices.RuntimeInformation.dll",
+ "System.Globalization.Extensions.dll",
+ "System.IO.Compression.dll",
+ "System.Net.Http.dll",
+ "System.Text.Encoding.CodePages.dll",
+ "System.Reflection.DispatchProxy.dll",
+ "System.ValueTuple.dll"
+};
+
+#define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
+
+static const IgnoredAssembly ignored_assemblies [] = {
+ IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
+ IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
+ IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
+ IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
+ IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
+ IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
+ IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
+ IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
+ IGNORED_ASSEMBLY (0x4A15555E, SYS_REF_DISP_PROXY, "E40AFEB4-CABE-4124-8412-B46AB79C92FD", "4.0.0 net46"),
+ IGNORED_ASSEMBLY (0xD20D9783, SYS_REF_DISP_PROXY, "2A69F0AD-B86B-40F2-8E4C-5B671E47479F", "4.0.1 netstandard1.3"),
+ IGNORED_ASSEMBLY (0xA33A7E68, SYS_REF_DISP_PROXY, "D4E8D2DB-BD65-4168-99EA-D2C1BDEBF9CC", "4.3.0 netstandard1.3"),
+ IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
+ IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
+ IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
+ IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
+ IGNORED_ASSEMBLY (0x75B4B041, SYS_VALUE_TUPLE, "F81A4140-A898-4E2B-B6E9-55CE78C273EC", "4.3.0 netstandard1.0"),
+};
+
+
+const char *ignored_assemblies_names[] = {
+ "System.Runtime.InteropServices.RuntimeInformation",
+ "System.Globalization.Extensions",
+ "System.IO.Compression",
+ "System.Net.Http",
+ "System.Text.Encoding.CodePages",
+ "System.Reflection.DispatchProxy",
+ "System.ValueTuple"
+};
+
+#define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
+
+static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
+ IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
+ IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
+ IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
+ IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
+ IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
+ IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
+ IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
+ IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
+ IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 0, 0),
+ IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 1, 0),
+ IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 2, 0),
+ IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
+ IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
+ IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
+ IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
+ IGNORED_ASM_VER (SYS_VALUE_TUPLE, 4, 0, 1, 0),
+};
+
+gboolean
+mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
+{
+ for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
+ if (ignored_assembly_versions [i].major != major ||
+ ignored_assembly_versions [i].minor != minor ||
+ ignored_assembly_versions [i].build != build ||
+ ignored_assembly_versions [i].revision != revision)
+ continue;
+ if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+Equivalent C# code:
+ static void Main () {
+ string str = "...";
+ int h = 5381;
+ for (int i = 0; i < str.Length; ++i)
+ h = ((h << 5) + h) ^ str[i];
+
+ Console.WriteLine ("{0:X}", h);
+ }
+*/
+static int
+hash_guid (const char *str)
+{
+ int h = 5381;
+ while (*str) {
+ h = ((h << 5) + h) ^ *str;
+ ++str;
+ }
+
+ return h;
+}
+
+static gboolean
+is_problematic_image (MonoImage *image)
+{
+ int h = hash_guid (image->guid);
+
+ //TODO make this more cache effiecient.
+ // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
+ for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
+ if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
+ const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
+ size_t needle_len = strlen (needle);
+ size_t asm_len = strlen (image->name);
+ if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
static MonoImage *
do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
gboolean care_about_cli, gboolean care_about_pecoff)
if (!mono_image_load_cli_data (image))
goto invalid_image;
+ if (!image->ref_only && is_problematic_image (image)) {
+ if (image->load_from_context) {
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
+ } else {
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
+ *status = MONO_IMAGE_IMAGE_INVALID;
+ goto invalid_image;
+ }
+ }
+
if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
goto invalid_image;
static MonoImage *
do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
- gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only)
+ gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
{
MonoCLIImageInfo *iinfo;
MonoImage *image;
image->name = mono_path_resolve_symlinks (fname);
image->ref_only = refonly;
image->metadata_only = metadata_only;
+ image->load_from_context = load_from_context;
image->ref_count = 1;
/* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
MonoImage *
mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
+{
+ return mono_image_open_a_lot (fname, status, refonly, FALSE);
+}
+
+MonoImage *
+mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
{
MonoImage *image;
GHashTable *loaded_images = get_loaded_images_hash (refonly);
fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
module_handle = MonoLoadImage (fname_utf16);
if (status && module_handle == NULL)
- last_error = GetLastError ();
+ last_error = mono_w32error_get_last ();
/* mono_image_open_from_module_handle is called by _CorDllMain. */
image = g_hash_table_lookup (loaded_images, absfname);
mono_images_unlock ();
// Image not loaded, load it now
- image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE);
+ image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
if (image == NULL)
return NULL;
{
g_return_val_if_fail (fname != NULL, NULL);
- return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE);
+ return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
}
/**
{
g_return_val_if_fail (fname != NULL, NULL);
- return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE);
+ return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
}
/*
MonoImage *
mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
{
- return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE);
+ return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
}
void
const char *fname;
guint32 fname_id;
+ error_init (error);
+
if (fileidx < 1 || fileidx > t->rows)
return NULL;
mono_image_load_file_for_image (MonoImage *image, int fileidx)
{
MonoError error;
- mono_error_init (&error);
MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
mono_error_assert_ok (&error);
- mono_error_cleanup (&error);
return result;
}
{
MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
MonoDotNetHeader *header = &iinfo->cli_header;
+ if (!header)
+ return FALSE;
MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
// the Authenticode "pre" (non ASN.1) header is 8 bytes long
return ((de->rva != 0) && (de->size > 8));
return res;
}
+char*
+mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
+{
+ char *buf;
+ mono_image_lock (image);
+ buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
+ mono_image_unlock (image);
+#ifndef DISABLE_PERFCOUNTERS
+ mono_perfcounters->loader_bytes += strlen (buf);
+#endif
+ return buf;
+}
+
+char*
+mono_image_strdup_printf (MonoImage *image, const char *format, ...)
+{
+ char *buf;
+ va_list args;
+
+ va_start (args, format);
+ buf = mono_image_strdup_vprintf (image, format, args);
+ va_end (args);
+ return buf;
+}
+
GList*
g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
{
void
mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
{
+ CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
mono_image_lock (image);
mono_property_hash_insert (image->property_hash, subject, property, value);
mono_image_unlock (image);