typedef struct {
const char *data;
- guint32 size;
+ guint32 size, token;
GSList *errors;
int valid;
MonoImage *image;
gboolean report_error;
+ gboolean report_warning;
int stage;
DataDirectory data_directories [16];
(__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
} while (0)
+#define ADD_WARNING(__ctx, __msg) \
+ do { \
+ if ((__ctx)->report_warning) { \
+ ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_WARNING, MONO_EXCEPTION_INVALID_PROGRAM); \
+ (__ctx)->valid = 0; \
+ return; \
+ } \
+ } while (0)
+
+#define ADD_ERROR_NO_RETURN(__ctx, __msg) \
+ do { \
+ if ((__ctx)->report_error) \
+ ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
+ (__ctx)->valid = 0; \
+ } while (0)
#define ADD_ERROR(__ctx, __msg) \
do { \
{
int i;
DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
- guint32 offset;
+ guint32 offset, section_count;
const char *ptr;
offset = it.translated_offset;
ptr = ctx->data + offset; //move to streams header
- if (read16 (ptr + 2) < 3)
+ section_count = read16 (ptr + 2);
+ if (section_count < 3)
ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 3 streams (#~, #GUID and #Blob"));
ptr += 4;
offset += 4;
- for (i = 0; i < 5; ++i) {
+ for (i = 0; i < section_count; ++i) {
guint32 stream_off, stream_size;
int string_size, stream_idx;
stream_idx = GUID_STREAM;
else if (!strncmp ("#~", ptr, 3))
stream_idx = TILDE_STREAM;
- else
- ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
+ else {
+ ADD_WARNING (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
+ offset = pad4 (offset);
+ ptr = ctx->data + offset;
+ continue;
+ }
if (ctx->metadata_streams [stream_idx].offset != 0)
ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
Unused: 0x1E 0x1F 0x2D-0x3F
We don't care about the MS extensions.*/
if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
- ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
+ ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support MS specific table %x", i));
if (i == 0x1E || i == 0x1F || i >= 0x2D)
ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
++count;
}
static gboolean
-safe_read (const char **_ptr, const char *limit, void *dest, int size)
+safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
{
const char *ptr = *_ptr;
if (ptr + size > limit)
return FALSE;
switch (size) {
case 1:
- *((guint8*)dest) = *((guint8*)ptr);
+ *dest = *((guint8*)ptr);
++ptr;
break;
case 2:
- *((guint16*)dest) = read16 (ptr);
+ *dest = read16 (ptr);
ptr += 2;
break;
case 4:
- *((guint32*)dest) = read32 (ptr);
+ *dest = read32 (ptr);
ptr += 4;
break;
}
parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint type = 0;
- guint32 token = 0;
+ unsigned type = 0;
+ unsigned token = 0;
while (TRUE) {
if (!safe_read8 (type, ptr, end))
parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint8 val;
- guint32 size, num, i;
+ unsigned val = 0;
+ unsigned size, num, i;
if (!safe_read8 (val, ptr, end))
FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint8 type;
- guint32 count, token, i;
+ unsigned type;
+ unsigned count, token, i;
if (!safe_read8 (type, ptr, end))
FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
FAIL (ctx, g_strdup_printf ("GenericInst: invalid TypeDefOrRef token %x", token));
+ if (ctx->token) {
+ if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
+ mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
+ FAIL (ctx, g_strdup_printf ("Type: Recurside generic instance specification (%x). A type signature can't reference itself", ctx->token));
+ }
+
if (!safe_read_cint (count, ptr, end))
FAIL (ctx, g_strdup ("GenericInst: Not enough room for argument count"));
parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint8 type = 0;
- guint32 token = 0;
+ unsigned type;
+ unsigned token = 0;
if (!safe_read8 (type, ptr, end))
FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
FAIL (ctx, g_strdup_printf ("Type: invalid TypeDefOrRef token %x", token));
+ if (ctx->token) {
+ if (mono_metadata_token_index (ctx->token) == get_coded_index_token (TYPEDEF_OR_REF_DESC, token) &&
+ mono_metadata_token_table (ctx->token) == get_coded_index_table (TYPEDEF_OR_REF_DESC, token))
+ FAIL (ctx, g_strdup_printf ("Type: Recurside type specification (%x). A type signature can't reference itself", ctx->token));
+ }
break;
case MONO_TYPE_VAR:
parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr;
- int type = 0;
+ unsigned type = 0;
if (!parse_custom_mods (ctx, _ptr, end))
return FALSE;
parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr;
- int type = 0;
+ unsigned type = 0;
if (!parse_custom_mods (ctx, _ptr, end))
return FALSE;
static gboolean
parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
{
- int cconv = 0;
+ unsigned cconv = 0;
unsigned param_count = 0, gparam_count = 0, type = 0, i;
const char *ptr = *_ptr;
gboolean saw_sentinel = FALSE;
parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
{
const char *ptr = *_ptr;
- guint8 signature = 0;
+ unsigned signature = 0;
if (!safe_read8 (signature, ptr, end))
FAIL (ctx, g_strdup ("Field: Not enough room for field signature"));
if (signature != 0x06)
FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
- *_ptr = ptr;
- if (!parse_custom_mods (ctx, _ptr, end))
+ if (!parse_custom_mods (ctx, &ptr, end))
return FALSE;
+ if (safe_read8 (signature, ptr, end)) {
+ if (signature != MONO_TYPE_BYREF)
+ --ptr;
+ }
+ *_ptr = ptr;
+
return parse_type (ctx, _ptr, end);
}
if (!safe_read_cint (locals_count, ptr, end))
FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
+ /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
if (locals_count == 0)
FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
+ */
for (i = 0; i < locals_count; ++i) {
if (!safe_read8 (sig, ptr, end))
FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
- if (sig == MONO_TYPE_TYPEDBYREF)
- continue;
-
while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
if (!safe_read8 (sig, ptr, end))
FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
}
+
+ if (sig == MONO_TYPE_BYREF) {
+ if (!safe_read8 (sig, ptr, end))
+ FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
+ if (sig == MONO_TYPE_TYPEDBYREF)
+ FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
+ }
+
+ if (sig == MONO_TYPE_TYPEDBYREF)
+ continue;
+
--ptr;
+
if (!parse_type (ctx, &ptr, end))
FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
}
static gboolean
is_valid_field_signature (VerifyContext *ctx, guint32 offset)
{
- int size = 0, signature = 0;
+ int size = 0;
+ unsigned signature = 0;
const char *ptr = NULL, *end;
if (!decode_signature_header (ctx, offset, &size, &ptr))
is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
{
int size = 0;
- guint16 prolog = 0;
+ unsigned prolog = 0;
const char *ptr = NULL, *end;
if (!offset)
--ptr;
if (signature == 0x07)
return parse_locals_signature (ctx, &ptr, end);
+
+ /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
+ if (signature == 0x06)
+ return parse_field (ctx, &ptr, end);
+
return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
}
{
int size = 0;
const char *ptr = NULL, *end;
- guint8 type = 0;
+ unsigned type = 0;
if (!decode_signature_header (ctx, offset, &size, &ptr))
if (!safe_read8 (type, ptr, end))
FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
- --ptr;
+ if (type == MONO_TYPE_BYREF) {
+ if (!safe_read8 (type, ptr, end))
+ FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
+ if (type == MONO_TYPE_TYPEDBYREF)
+ FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
+ }
+
if (type == MONO_TYPE_TYPEDBYREF)
return TRUE;
+ --ptr;
return parse_type (ctx, &ptr, end);
}
static gboolean
-is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
+is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
{
int size = 0;
const char *ptr = NULL, *end;
- guint8 type = 0;
- guint32 count = 0, i;
+ unsigned type = 0;
+ unsigned count = 0, i;
if (!decode_signature_header (ctx, offset, &size, &ptr))
FAIL (ctx, g_strdup ("MethodSpec: Could not decode signature header"));
static gboolean
is_valid_method_header (VerifyContext *ctx, guint32 rva)
{
- guint32 local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
- guint8 header = 0;
- guint16 fat_header = 0, size = 0, max_stack;
+ unsigned local_vars_tok, code_size, offset = mono_cli_rva_image_map (ctx->image, rva);
+ unsigned header = 0;
+ unsigned fat_header = 0, size = 0, max_stack;
const char *ptr = NULL, *end;
if (offset == INVALID_ADDRESS)
ptr += code_size;
do {
- guint32 section_header = 0, section_size = 0;
+ unsigned section_header = 0, section_size = 0;
gboolean is_fat;
ptr = dword_align (ptr);
FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section content %d", section_size));
if (section_header & METHOD_HEADER_SECTION_EHTABLE) {
- guint32 i, clauses = (section_size - 4) / (is_fat ? 24 : 12);
- if (clauses * (is_fat ? 24 : 12) + 4 != section_size)
- FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the proper size", section_size));
+ guint32 i, clauses = section_size / (is_fat ? 24 : 12);
+ /*
+ LAMEIMPL: MS emits section_size without accounting for header size.
+ Mono does as the spec says. section_size is header + section
+ MS's peverify happily accepts both.
+ */
+ if ((clauses * (is_fat ? 24 : 12) != section_size) && (clauses * (is_fat ? 24 : 12) + 4 != section_size))
+ FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid EH section size %d, it's not of the expected size %d", section_size, clauses * (is_fat ? 24 : 12)));
/* only verify the class token is verified as the rest is done by the IL verifier*/
for (i = 0; i < clauses; ++i) {
- guint flags = *ptr;
- guint32 class_token = 0;
+ unsigned flags = *(unsigned char*)ptr;
+ unsigned class_token = 0;
ptr += (is_fat ? 20 : 8);
if (!safe_read32 (class_token, ptr, end))
FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for section %d", i));
{
MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
guint32 data [MONO_TYPEDEF_SIZE];
- guint32 fieldlist = 1, methodlist = 1;
+ guint32 fieldlist = 1, methodlist = 1, visibility;
int i;
if (table->rows == 0)
if (data [MONO_TYPEDEF_EXTENDS] && !is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
+ visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+ if ((visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) &&
+ search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1) == -1)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d has nested visibility but no rows in the NestedClass table", i));
+
if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
if (i == 0) {
- if (data [MONO_TYPEDEF_EXTENDS] != 0)
+ /*XXX it's ok if <module> extends object, or anything at all, actually. */
+ /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
+ */
continue;
}
}
}
-/*bits 6,8,9,10,11,13,14,15*/
-#define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
+/*bits 8,9,10,11,13,14,15*/
+#define INVALID_METHOD_IMPLFLAG_BITS ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
static void
verify_method_table (VerifyContext *ctx)
{
if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
+ if (flags & METHOD_ATTRIBUTE_FINAL)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and Final", i));
if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
}
if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
+ ADD_WARNING (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
- if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
- ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
+ if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+ if (flags & METHOD_ATTRIBUTE_VIRTUAL)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
+ if (!(flags & METHOD_ATTRIBUTE_STATIC))
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but not Static", i));
+ }
if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) &&
!(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
-
+ ctx->token = (i + 1) | MONO_TOKEN_TYPE_SPEC;
if (!is_valid_typespec_blob (ctx, data [MONO_TYPESPEC_SIGNATURE]))
ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
}
+ ctx->token = 0;
}
#define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
}
}
-#define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 8) | (1 << 14) | (1 << 15))
+#define INVALID_ASSEMBLY_FLAGS_BITS ~((1 << 0) | (1 << 4) | (1 << 8) | (1 << 14) | (1 << 15))
static void
verify_assembly_table (VerifyContext *ctx)
{
for (i = 0; i < table->rows; ++i) {
mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
- if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
+ if (!is_valid_methodspec_blob (ctx, data [MONO_METHODSPEC_SIGNATURE]))
ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid Instantiation token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
}
}
}
}
+
+typedef struct {
+ const char *name;
+ const char *name_space;
+ guint32 resolution_scope;
+} TypeDefUniqueId;
+
+static guint
+typedef_hash (gconstpointer _key)
+{
+ const TypeDefUniqueId *key = _key;
+ return g_str_hash (key->name) ^ g_str_hash (key->name_space) ^ key->resolution_scope; /*XXX better salt the int key*/
+}
+
+static gboolean
+typedef_equals (gconstpointer _a, gconstpointer _b)
+{
+ const TypeDefUniqueId *a = _a;
+ const TypeDefUniqueId *b = _b;
+ return !strcmp (a->name, b->name) && !strcmp (a->name_space, b->name_space) && a->resolution_scope == b->resolution_scope;
+}
+
+static void
+verify_typedef_table_global_constraints (VerifyContext *ctx)
+{
+ int i;
+ guint32 data [MONO_TYPEDEF_SIZE];
+ guint32 nested_data [MONO_NESTED_CLASS_SIZE];
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+ MonoTableInfo *nested_table = &ctx->image->tables [MONO_TABLE_NESTEDCLASS];
+ GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
+
+ for (i = 0; i < table->rows; ++i) {
+ guint visibility;
+ TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
+ mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
+
+ type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAME]);
+ type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEDEF_NAMESPACE]);
+ type->resolution_scope = 0;
+
+ visibility = data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+ if (visibility >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visibility <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) {
+ int res = search_sorted_table (ctx, MONO_TABLE_NESTEDCLASS, MONO_NESTED_CLASS_NESTED, i + 1);
+ g_assert (res >= 0);
+
+ mono_metadata_decode_row (nested_table, res, nested_data, MONO_NESTED_CLASS_SIZE);
+ type->resolution_scope = nested_data [MONO_NESTED_CLASS_ENCLOSING];
+ }
+
+ if (g_hash_table_lookup (unique_types, type)) {
+ ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeDef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
+ g_hash_table_destroy (unique_types);
+ g_free (type);
+ return;
+ }
+ g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
+ }
+
+ g_hash_table_destroy (unique_types);
+}
+
+static void
+verify_typeref_table_global_constraints (VerifyContext *ctx)
+{
+ int i;
+ guint32 data [MONO_TYPEREF_SIZE];
+ MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
+ GHashTable *unique_types = g_hash_table_new_full (&typedef_hash, &typedef_equals, g_free, NULL);
+
+ for (i = 0; i < table->rows; ++i) {
+ TypeDefUniqueId *type = g_new (TypeDefUniqueId, 1);
+ mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
+
+ type->resolution_scope = data [MONO_TYPEREF_SCOPE];
+ type->name = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAME]);
+ type->name_space = mono_metadata_string_heap (ctx->image, data [MONO_TYPEREF_NAMESPACE]);
+
+ if (g_hash_table_lookup (unique_types, type)) {
+ ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("TypeRef table row %d has duplicate for tuple (%s,%s,%x)", i, type->name, type->name_space, type->resolution_scope));
+ g_hash_table_destroy (unique_types);
+ g_free (type);
+ return;
+ }
+ g_hash_table_insert (unique_types, type, GUINT_TO_POINTER (1));
+ }
+
+ g_hash_table_destroy (unique_types);
+}
+
+static void
+verify_tables_data_global_constraints (VerifyContext *ctx)
+{
+ verify_typeref_table_global_constraints (ctx);
+ CHECK_ERROR ();
+ verify_typedef_table_global_constraints (ctx);
+}
+
static void
verify_tables_data (VerifyContext *ctx)
{
verify_method_spec_table (ctx);
CHECK_ERROR ();
verify_generic_param_constraint_table (ctx);
+ CHECK_ERROR ();
+ verify_tables_data_global_constraints (ctx);
}
static void
memset (ctx, 0, sizeof (VerifyContext));
ctx->image = image;
ctx->report_error = error_list != NULL;
+ ctx->report_warning = FALSE; //export this setting in the API
ctx->valid = 1;
ctx->size = image->raw_data_len;
ctx->data = image->raw_data;
}
gboolean
-mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
+mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
{
VerifyContext ctx;
init_verify_context (&ctx, image, error_list);
ctx.stage = STAGE_TABLES;
+ ctx.token = token;
is_valid_typespec_blob (&ctx, offset);
return cleanup_context (&ctx, error_list);
init_verify_context (&ctx, image, error_list);
ctx.stage = STAGE_TABLES;
- is_valid_methodspec_blog (&ctx, offset);
+ is_valid_methodspec_blob (&ctx, offset);
+ return cleanup_context (&ctx, error_list);
+}
+
+static void
+verify_user_string (VerifyContext *ctx, guint32 offset)
+{
+ OffsetAndSize heap_us = get_metadata_stream (ctx, &ctx->image->heap_us);
+ guint32 entry_size, bytes;
+
+ if (heap_us.size < offset)
+ ADD_ERROR (ctx, g_strdup ("User string offset beyond heap_us size"));
+
+ if (!decode_value (ctx->data + offset + heap_us.offset, heap_us.size - heap_us.offset, &entry_size, &bytes))
+ ADD_ERROR (ctx, g_strdup ("Could not decode user string blob size"));
+
+ if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
+ ADD_ERROR (ctx, g_strdup ("User string size overflow"));
+
+ entry_size += bytes;
+
+ if (ADD_IS_GREATER_OR_OVF (offset, entry_size, heap_us.size))
+ ADD_ERROR (ctx, g_strdup ("User string oveflow heap_us"));
+}
+
+gboolean
+mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ VerifyContext ctx;
+
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ init_verify_context (&ctx, image, error_list);
+ ctx.stage = STAGE_TABLES;
+
+ verify_user_string (&ctx, offset);
+
return cleanup_context (&ctx, error_list);
}
+gboolean
+mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
+{
+ MonoMethodSignature *original_sig;
+ if (!mono_verifier_is_enabled_for_image (image))
+ return TRUE;
+
+ original_sig = mono_method_signature (method);
+ if (original_sig->call_convention == MONO_CALL_VARARG) {
+ if (original_sig->hasthis != signature->hasthis)
+ return FALSE;
+ if (original_sig->call_convention != signature->call_convention)
+ return FALSE;
+ if (original_sig->explicit_this != signature->explicit_this)
+ return FALSE;
+ if (original_sig->call_convention != signature->call_convention)
+ return FALSE;
+ if (original_sig->pinvoke != signature->pinvoke)
+ return FALSE;
+ if (original_sig->sentinelpos != signature->sentinelpos)
+ return FALSE;
+ } else if (!mono_metadata_signature_equal (signature, original_sig)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
#else
gboolean
mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
}
gboolean
-mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, GSList **error_list)
+mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
{
return TRUE;
}
return TRUE;
}
+gboolean
+mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+ return TRUE;
+}
+
+gboolean
+mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
+{
+ return TRUE;
+}
+
+
#endif /* DISABLE_VERIFIER */