New tests.
[mono.git] / mono / metadata / metadata-verify.c
index 5690ff0eee4c71ed8549cd1638620c2df5affc73..78a7a533d6489a8ad12a27d8c91addc7e521e069 100644 (file)
@@ -24,7 +24,7 @@
 #include <mono/metadata/attrdefs.h>
 #include <mono/utils/strenc.h>
 #include <string.h>
-#include <signal.h>
+//#include <signal.h>
 #include <ctype.h>
 
 #ifndef DISABLE_VERIFIER
@@ -97,7 +97,7 @@ const static unsigned char coded_index_desc[] = {
 
 #define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
        5, /*bits*/
-       19, /*tables*/
+       20, /*tables*/
        MONO_TABLE_METHOD,
        MONO_TABLE_FIELD,
        MONO_TABLE_TYPEREF,
@@ -117,8 +117,9 @@ const static unsigned char coded_index_desc[] = {
        MONO_TABLE_FILE,
        MONO_TABLE_EXPORTEDTYPE,
        MONO_TABLE_MANIFESTRESOURCE,
+       MONO_TABLE_GENERICPARAM,
 
-#define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
+#define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 22)
        1, /*bits*/
        2, /*tables*/
        MONO_TABLE_FIELD,
@@ -216,12 +217,12 @@ typedef struct {
 
 typedef struct {
        const char *data;
-       guint32 size;
+       guint32 size, token;
        GSList *errors;
        int valid;
-       gboolean is_corlib;
        MonoImage *image;
        gboolean report_error;
+       gboolean report_warning;
        int stage;
 
        DataDirectory data_directories [16];
@@ -240,6 +241,21 @@ typedef struct {
                (__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 {    \
@@ -249,10 +265,40 @@ typedef struct {
                return; \
        } while (0)
 
+#define FAIL(__ctx, __msg)     \
+       do {    \
+               if ((__ctx)->report_error) \
+                       ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
+               (__ctx)->valid = 0; \
+               return FALSE; \
+       } while (0)
+
 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
 
 #define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
 
+#define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
+#define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
+
+#if SIZEOF_VOID_P == 4
+#define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
+#else
+#define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
+#endif
+
+#define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
+#define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
+
+static const char *
+dword_align (const char *ptr)
+{
+#if SIZEOF_VOID_P == 8
+       return (const char *) (((guint64) (ptr + 3)) & ~3);
+#else
+       return (const char *) (((guint32) (ptr + 3)) & ~3);
+#endif
+}
+
 static guint32
 pe_signature_offset (VerifyContext *ctx)
 {
@@ -557,34 +603,42 @@ verify_import_table (VerifyContext *ctx)
                ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
 
        ilt_rva = read32 (ptr);
-       if (!bounds_check_virtual_address (ctx, ilt_rva, 8))
+       if (ilt_rva && !bounds_check_virtual_address (ctx, ilt_rva, 8))
                ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
 
        name_rva = read32 (ptr + 12);
-       if (!bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
+       if (name_rva && !bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
                ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
 
        iat_rva = read32 (ptr + 16);
-       if (!bounds_check_virtual_address (ctx, iat_rva, 8))
-               ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
-
-       if (iat_rva != ctx->data_directories [IAT_IDX].rva)
-               ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
+       if (iat_rva) {
+               if (!bounds_check_virtual_address (ctx, iat_rva, 8))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
 
-       name_rva = translate_rva (ctx, name_rva);
-       g_assert (name_rva != INVALID_OFFSET);
-       ptr = ctx->data + name_rva;
+               if (iat_rva != ctx->data_directories [IAT_IDX].rva)
+                       ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
+       }
 
-       if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
-               char name[SIZE_OF_MSCOREE];
-               memcpy (name, ptr, SIZE_OF_MSCOREE);
-               name [SIZE_OF_MSCOREE - 1] = 0;
-               ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
+       if (name_rva) {
+               name_rva = translate_rva (ctx, name_rva);
+               g_assert (name_rva != INVALID_OFFSET);
+               ptr = ctx->data + name_rva;
+       
+               if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
+                       char name[SIZE_OF_MSCOREE];
+                       memcpy (name, ptr, SIZE_OF_MSCOREE);
+                       name [SIZE_OF_MSCOREE - 1] = 0;
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
+               }
        }
        
-       verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
-       CHECK_ERROR ();
-       verify_hint_name_table (ctx, iat_rva, "Import Address Table");
+       if (ilt_rva) {
+               verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
+               CHECK_ERROR ();
+       }
+
+       if (iat_rva)
+               verify_hint_name_table (ctx, iat_rva, "Import Address Table");
 }
 
 static void
@@ -695,7 +749,7 @@ verify_metadata_header (VerifyContext *ctx)
 {
        int i;
        DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
-       guint32 offset;
+       guint32 offset, section_count;
        const char *ptr;
 
        offset = it.translated_offset;
@@ -725,13 +779,14 @@ verify_metadata_header (VerifyContext *ctx)
 
        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;
 
@@ -767,8 +822,12 @@ verify_metadata_header (VerifyContext *ctx)
                        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));
@@ -799,11 +858,9 @@ verify_tables_schema (VerifyContext *ctx)
        guint32 count;
        int i;
 
-       //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
        if (tables_area.size < 24)
                ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
 
-       //printf ("ptr %x %x\n", ptr[4], ptr[5]);
        if (ptr [4] != 2 && ptr [4] != 1)
                ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
        if (ptr [5] != 0)
@@ -822,7 +879,7 @@ verify_tables_schema (VerifyContext *ctx)
                  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;
@@ -1014,93 +1071,22 @@ string_cmp (VerifyContext *ctx, const char *str, guint offset)
 }
 
 static gboolean
-typedef_is_system_object (VerifyContext *ctx, guint32 *data)
-{
-       return ctx->is_corlib && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAME]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAMESPACE]);
-}
-
-static gboolean
-is_valid_field_signature (VerifyContext *ctx, guint32 offset)
-{
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return blob.size >= 2 && blob.size - 2 >= offset;
-}
-
-static gboolean
-is_valid_method_signature (VerifyContext *ctx, guint32 offset)
-{
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return blob.size >= 2 && blob.size - 2 >= offset;
-}
-
-static gboolean
-is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
-{
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return blob.size >= 2 && blob.size - 2 >= offset;
-}
-
-static gboolean
-is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
-{
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return blob.size >= 1 && blob.size - 1 >= offset;
-}
-
-static gboolean
-is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
-{
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return blob.size >= 1 && blob.size - 1 >= offset;
-}
-
-static gboolean
-is_valid_permission_set (VerifyContext *ctx, guint32 offset)
-{
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return blob.size >= 1 && blob.size - 1 >= offset;
-}
-
-static gboolean
-is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
-{
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return blob.size >= 1 && blob.size - 1 >= offset;
-}
-
-static gboolean
-is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
+mono_verifier_is_corlib (MonoImage *image)
 {
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
-}
+       gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
+                       TRUE : mono_security_core_clr_is_platform_image (image);
 
-static gboolean
-is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
-{
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
+       return trusted_location && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
 }
 
 static gboolean
-is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
+typedef_is_system_object (VerifyContext *ctx, guint32 *data)
 {
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       //TODO do proper verification
-       return offset > 0 && blob.size >= 1 && blob.size - 1 >= offset;
+       return mono_verifier_is_corlib (ctx->image) && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAMESPACE]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAME]);
 }
 
 static gboolean
-decode_value (const char *_ptr, guint32 available, guint32 *value, guint32 *size)
+decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *size)
 {
        unsigned char b;
        const unsigned char *ptr = (const unsigned char *)_ptr;
@@ -1133,200 +1119,1277 @@ decode_value (const char *_ptr, guint32 available, guint32 *value, guint32 *size
 }
 
 static gboolean
-is_valid_blob_object (VerifyContext *ctx, guint32 offset)
+decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
 {
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       guint32 entry_size, bytes;
+       MonoStreamHeader blob = ctx->image->heap_blob;
+       guint32 value, enc_size;
 
-       if (blob.size < offset) {
-               printf ("1\n");
+       if (offset >= blob.size)
                return FALSE;
-       }
 
-       if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
+       if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
                return FALSE;
 
-       if (offset + entry_size < offset)
+       if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
                return FALSE;
 
-       return blob.size >= offset + entry_size;
+       offset += enc_size;
+
+       if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
+               return FALSE;
+
+       *size = value;
+       *first_byte = blob.data + offset;
+       return TRUE;
 }
 
 static gboolean
-is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
+safe_read (const char **_ptr, const char *limit, unsigned *dest, int size)
 {
-       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
-       guint32 size, entry_size, bytes;
-
-       if (blob.size < offset) {
-               printf ("1\n");
+       const char *ptr = *_ptr;
+       if (ptr + size > limit)
                return FALSE;
-       }
-
-       
-       if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
-               return FALSE;
-
-       if (type == MONO_TYPE_STRING) {
-               //String is encoded as: compressed_int:len len *chars
-
-               offset += bytes;
-               if (offset > offset + entry_size * 2) //overflow
-                       return FALSE;
-               offset += offset + entry_size * 2;
-               return  offset <= blob.size;
-       }
-
-       switch (type) {
-       case MONO_TYPE_BOOLEAN:
-       case MONO_TYPE_I1:
-       case MONO_TYPE_U1:
-               size = 1;
-               break;
-       case MONO_TYPE_CHAR:
-       case MONO_TYPE_I2:
-       case MONO_TYPE_U2:
-               size = 2;
+       switch (size) {
+       case 1:
+               *dest = *((guint8*)ptr);
+               ++ptr;
                break;
-       case MONO_TYPE_I4:
-       case MONO_TYPE_U4:
-       case MONO_TYPE_R4:
-       case MONO_TYPE_CLASS:
-               size = 4;
+       case 2:
+               *dest = read16 (ptr);
+               ptr += 2;
                break;
-
-       case MONO_TYPE_I8:
-       case MONO_TYPE_U8:
-       case MONO_TYPE_R8:
-               size = 8;
+       case 4:
+               *dest = read32 (ptr);
+               ptr += 4;
                break;
-       default:
-               g_assert_not_reached ();
        }
+       *_ptr = ptr;
+       return TRUE;
+}
 
-       if (size != entry_size)
-               return FALSE;
-       offset += bytes;
+static gboolean
+safe_read_compressed_int (const char **_ptr, const char *limit, unsigned *dest)
+{
+       unsigned size = 0;
+       const char *ptr = *_ptr;
+       gboolean res = decode_value (ptr, limit - ptr, dest, &size);
+       *_ptr = ptr + size;
+       return res;
+}
 
-       if(offset > offset + size) //overflow
-               return FALSE;
+#define safe_read8(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 1)
+#define safe_read_cint(VAR, PTR, LIMIT) safe_read_compressed_int (&PTR, LIMIT, &VAR)
+#define safe_read16(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 2)
+#define safe_read32(VAR, PTR, LIMIT) safe_read (&PTR, LIMIT, &VAR, 4)
 
-       if (offset + size > blob.size)
-               return FALSE;
+static gboolean
+parse_type (VerifyContext *ctx, const char **_ptr, const char *end);
 
-       if (type == MONO_TYPE_CLASS && read32 (ctx->data + offset))
-               return FALSE;
-       return TRUE;
-}
+static gboolean
+parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged);
 
 static gboolean
-is_valid_method_header (VerifyContext *ctx, guint32 rva)
+parse_custom_mods (VerifyContext *ctx, const char **_ptr, const char *end)
 {
-       //TODO do proper method header validation
-       return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
+       const char *ptr = *_ptr;
+       unsigned type = 0;
+       unsigned token = 0;
+
+       while (TRUE) {
+               if (!safe_read8 (type, ptr, end))
+                       FAIL (ctx, g_strdup ("CustomMod: Not enough room for the type"));
+       
+               if (type != MONO_TYPE_CMOD_REQD && type != MONO_TYPE_CMOD_OPT) {
+                       --ptr;
+                       break;
+               }
+       
+               if (!safe_read_cint (token, ptr, end))
+                       FAIL (ctx, g_strdup ("CustomMod: Not enough room for the token"));
+       
+               if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, token))
+                       FAIL (ctx, g_strdup_printf ("CustomMod: invalid TypeDefOrRef token %x", token));
+       }
+
+       *_ptr = ptr;
+       return TRUE;
 }
 
-static void
-verify_module_table (VerifyContext *ctx)
+static gboolean
+parse_array_shape (VerifyContext *ctx, const char **_ptr, const char *end)
 {
-       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
-       guint32 data [MONO_MODULE_SIZE];
+       const char *ptr = *_ptr;
+       unsigned val = 0;
+       unsigned size, num, i;
 
-       if (table->rows != 1)
-               ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
+       if (!safe_read8 (val, ptr, end))
+               FAIL (ctx, g_strdup ("ArrayShape: Not enough room for Rank"));
 
-       mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
+       if (val == 0)
+               FAIL (ctx, g_strdup ("ArrayShape: Invalid shape with zero Rank"));
 
-       if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
-               ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
+       if (!safe_read_cint (size, ptr, end))
+               FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumSizes"));
 
-       if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
-               ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
+       for (i = 0; i < size; ++i) {
+               if (!safe_read_cint (num, ptr, end))
+                       FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for Size of rank %d", i + 1));
+       }
 
-       if (data [MONO_MODULE_ENC] != 0)
-               ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
+       if (!safe_read_cint (size, ptr, end))
+               FAIL (ctx, g_strdup ("ArrayShape: Not enough room for NumLoBounds"));
 
-       if (data [MONO_MODULE_ENCBASE] != 0)
-               ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
+       for (i = 0; i < size; ++i) {
+               if (!safe_read_cint (num, ptr, end))
+                       FAIL (ctx, g_strdup_printf ("ArrayShape: Not enough room for LoBound of rank %d", i + 1));
+       }
+
+       *_ptr = ptr;
+       return TRUE;
 }
 
-static void
-verify_typeref_table (VerifyContext *ctx)
+static gboolean
+parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
 {
-       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
-       guint32 data [MONO_TYPEREF_SIZE];
-       int i;
+       const char *ptr = *_ptr;
+       unsigned type;
+       unsigned count, token, i;
 
-       for (i = 0; i < table->rows; ++i) {
-               mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
-               if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
-               
-               if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
-                       ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
+       if (!safe_read8 (type, ptr, end))
+               FAIL (ctx, g_strdup ("GenericInst: Not enough room for kind"));
 
-               if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
+       if (type != MONO_TYPE_CLASS && type != MONO_TYPE_VALUETYPE)
+               FAIL (ctx, g_strdup_printf ("GenericInst: Invalid GenericInst kind %x\n", type));
 
-               if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
+       if (!safe_read_cint (token, ptr, end))
+               FAIL (ctx, g_strdup ("GenericInst: Not enough room for type token"));
+
+       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"));
+
+       if (count == 0)
+               FAIL (ctx, g_strdup ("GenericInst: Zero arguments generic instance"));
+
+       for (i = 0; i < count; ++i) {
+               if (!parse_type (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup_printf ("GenericInst: invalid generic argument %d", i + 1));
        }
+       *_ptr = ptr;
+       return TRUE;
 }
 
-/*bits 9,11,14,15,19,21,24-31 */
-#define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
-static void
-verify_typedef_table (VerifyContext *ctx)
+static gboolean
+parse_type (VerifyContext *ctx, const char **_ptr, const char *end)
 {
-       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
-       guint32 data [MONO_TYPEDEF_SIZE];
-       guint32 fieldlist = 1, methodlist = 1;
-       int i;
+       const char *ptr = *_ptr;
+       unsigned type;
+       unsigned token = 0;
 
-       if (table->rows == 0)
-               ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
+       if (!safe_read8 (type, ptr, end))
+               FAIL (ctx, g_strdup ("Type: Not enough room for the type"));
 
-       for (i = 0; i < table->rows; ++i) {
-               mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
-               if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
+       if (!((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_PTR) ||
+               (type >= MONO_TYPE_VALUETYPE && type <= MONO_TYPE_GENERICINST) ||
+               (type >= MONO_TYPE_I && type <= MONO_TYPE_U) ||
+               (type >= MONO_TYPE_FNPTR && type <= MONO_TYPE_MVAR)))
+               FAIL (ctx, g_strdup_printf ("Type: Invalid type kind %x\n", type));
 
-               if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
+       switch (type) {
+       case MONO_TYPE_PTR:
+               if (!parse_custom_mods (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup ("Type: Failed to parse pointer custom attr"));
 
-               if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+               if (!safe_read8 (type, ptr, end))
+                       FAIL (ctx, g_strdup ("Type: Not enough room to parse the pointer type"));
 
-               if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+               if (type != MONO_TYPE_VOID) {
+                       --ptr;
+                       if (!parse_type (ctx, &ptr, end))
+                               FAIL (ctx, g_strdup ("Type: Could not parse pointer type"));
+               }
+               break;
 
-               if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
+       case MONO_TYPE_VALUETYPE:
+       case MONO_TYPE_CLASS:
+               if (!safe_read_cint (token, ptr, end))
+                       FAIL (ctx, g_strdup ("Type: Not enough room for the type token"));
+       
+               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;
 
-               if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR:
+               if (!safe_read_cint (token, ptr, end))
+                       FAIL (ctx, g_strdup ("Type: Not enough room for to decode generic argument number"));
+               break;
 
-               if (i == 0) {
-                       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"));
+       case MONO_TYPE_ARRAY:
+               if (!parse_type (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup ("Type: Could not parse array type"));
+               if (!parse_array_shape (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup ("Type: Could not parse array shape"));
+               break;
+
+       case MONO_TYPE_GENERICINST:
+               if (!parse_generic_inst (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup ("Type: Could not parse generic inst"));
+               break;
+
+       case MONO_TYPE_FNPTR:
+               if (!parse_method_signature (ctx, &ptr, end, TRUE, TRUE))
+                       FAIL (ctx, g_strdup ("Type: Could not parse method pointer signature"));
+               break;
+
+       case MONO_TYPE_SZARRAY:
+               if (!parse_custom_mods (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup ("Type: Failed to parse array element custom attr"));
+               if (!parse_type (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup ("Type: Could not parse array type"));
+               break;
+       }
+       *_ptr = ptr;
+       return TRUE;
+}
+
+static gboolean
+parse_return_type (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+       const char *ptr;
+       unsigned type = 0;
+
+       if (!parse_custom_mods (ctx, _ptr, end))
+               return FALSE;
+
+       ptr = *_ptr;
+       if (!safe_read8 (type, ptr, end))
+               FAIL (ctx, g_strdup ("ReturnType: Not enough room for the type"));
+
+       if (type == MONO_TYPE_VOID || type == MONO_TYPE_TYPEDBYREF) {
+               *_ptr = ptr;
+               return TRUE;
+       }
+
+       //it's a byref, update the cursor ptr
+       if (type == MONO_TYPE_BYREF)
+               *_ptr = ptr;
+
+       return parse_type (ctx, _ptr, end);
+}
+
+static gboolean
+parse_param (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+       const char *ptr;
+       unsigned type = 0;
+
+       if (!parse_custom_mods (ctx, _ptr, end))
+               return FALSE;
+
+       ptr = *_ptr;
+       if (!safe_read8 (type, ptr, end))
+               FAIL (ctx, g_strdup ("Param: Not enough room for the type"));
+
+       if (type == MONO_TYPE_TYPEDBYREF) {
+               *_ptr = ptr;
+               return TRUE;
+       }
+
+       //it's a byref, update the cursor ptr
+       if (type == MONO_TYPE_BYREF)
+               *_ptr = ptr;
+
+       return parse_type (ctx, _ptr, end);
+}
+
+static gboolean
+parse_method_signature (VerifyContext *ctx, const char **_ptr, const char *end, gboolean allow_sentinel, gboolean allow_unmanaged)
+{
+       unsigned cconv = 0;
+       unsigned param_count = 0, gparam_count = 0, type = 0, i;
+       const char *ptr = *_ptr;
+       gboolean saw_sentinel = FALSE;
+
+       if (!safe_read8 (cconv, ptr, end))
+               FAIL (ctx, g_strdup ("MethodSig: Not enough room for the call conv"));
+
+       if (cconv & 0x80)
+               FAIL (ctx, g_strdup ("MethodSig: CallConv has 0x80 set"));
+
+       if (allow_unmanaged) {
+               if ((cconv & 0x0F) > MONO_CALL_VARARG)
+                       FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not valid, it's %x", cconv & 0x0F));
+       } else if ((cconv & 0x0F) != MONO_CALL_DEFAULT && (cconv & 0x0F) != MONO_CALL_VARARG)
+               FAIL (ctx, g_strdup_printf ("MethodSig: CallConv is not Default or Vararg, it's %x", cconv & 0x0F));
+
+       if ((cconv & 0x10) && !safe_read_cint (gparam_count, ptr, end))
+               FAIL (ctx, g_strdup ("MethodSig: Not enough room for the generic param count"));
+
+       if ((cconv & 0x10) && gparam_count == 0)
+               FAIL (ctx, g_strdup ("MethodSig: Signature with generics but zero arity"));
+
+       if (allow_unmanaged && (cconv & 0x10))
+               FAIL (ctx, g_strdup ("MethodSig: Standalone signature with generic params"));
+
+       if (!safe_read_cint (param_count, ptr, end))
+               FAIL (ctx, g_strdup ("MethodSig: Not enough room for the param count"));
+
+       if (!parse_return_type (ctx, &ptr, end))
+               FAIL (ctx, g_strdup ("MethodSig: Error parsing return type"));
+
+       for (i = 0; i < param_count; ++i) {
+               if (allow_sentinel) {
+                       if (!safe_read8 (type, ptr, end))
+                               FAIL (ctx, g_strdup_printf ("MethodSig: Not enough room for param %d type", i));
+
+                       if (type == MONO_TYPE_SENTINEL) {
+                               if ((cconv & 0x0F) != MONO_CALL_VARARG)
+                                       FAIL (ctx, g_strdup ("MethodSig: Found sentinel but signature is not vararg"));
+
+                               if (saw_sentinel)
+                                       FAIL (ctx, g_strdup ("MethodSig: More than one sentinel type"));
+
+                               saw_sentinel = TRUE;
+                       } else {
+                               --ptr;
+                       }
+               }
+
+               if (!parse_param (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup_printf ("MethodSig: Error parsing arg %d", i));
+       }
+
+       *_ptr = ptr;
+       return TRUE;
+}
+
+static gboolean
+parse_property_signature (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+       unsigned sig = 0;
+       unsigned param_count = 0, i;
+       const char *ptr = *_ptr;
+
+       if (!safe_read8 (sig, ptr, end))
+               FAIL (ctx, g_strdup ("PropertySig: Not enough room for signature"));
+
+       if (sig != 0x08 && sig != 0x28)
+               FAIL (ctx, g_strdup_printf ("PropertySig: Signature is not 0x28 or 0x08: %x", sig));
+
+       if (!safe_read_cint (param_count, ptr, end))
+               FAIL (ctx, g_strdup ("PropertySig: Not enough room for the param count"));
+
+       if (!parse_custom_mods (ctx, &ptr, end))
+               return FALSE;
+
+       if (!parse_type (ctx, &ptr, end))
+               FAIL (ctx, g_strdup ("PropertySig: Could not parse property type"));
+
+       for (i = 0; i < param_count; ++i) {
+               if (!parse_type (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup_printf ("PropertySig: Error parsing arg %d", i));
+       }
+
+       *_ptr = ptr;
+       return TRUE;
+}
+
+static gboolean
+parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+       const char *ptr = *_ptr;
+       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));
+
+       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);
+}
+
+static gboolean
+parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+       unsigned sig = 0;
+       unsigned locals_count = 0, i;
+       const char *ptr = *_ptr;        
+
+       if (!safe_read8 (sig, ptr, end))
+               FAIL (ctx, g_strdup ("LocalsSig: Not enough room for signature"));
+
+       if (sig != 0x07)
+               FAIL (ctx, g_strdup_printf ("LocalsSig: Signature is not 0x28 or 0x08: %x", sig));
+
+       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"));
+
+               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));
+       }
+
+       *_ptr = ptr;
+       return TRUE;
+}
+
+static gboolean
+is_valid_field_signature (VerifyContext *ctx, guint32 offset)
+{
+       guint32 size = 0;
+       unsigned signature = 0;
+       const char *ptr = NULL, *end;
+
+       if (!decode_signature_header (ctx, offset, &size, &ptr))
+               FAIL (ctx, g_strdup ("FieldSig: Could not decode signature header"));
+       end = ptr + size;
+
+       if (!safe_read8 (signature, ptr, end))
+               FAIL (ctx, g_strdup ("FieldSig: Not enough room for the signature"));
+
+       if (signature != 6)
+               FAIL (ctx, g_strdup_printf ("FieldSig: Invalid signature %x", signature));
+       --ptr;
+
+       return parse_field (ctx, &ptr, end);
+}
+
+static gboolean
+is_valid_method_signature (VerifyContext *ctx, guint32 offset)
+{
+       guint32 size = 0;
+       const char *ptr = NULL, *end;
+
+       if (!decode_signature_header (ctx, offset, &size, &ptr))
+               FAIL (ctx, g_strdup ("MethodSig: Could not decode signature header"));
+       end = ptr + size;
+
+       return parse_method_signature (ctx, &ptr, end, FALSE, FALSE);
+}
+
+static gboolean
+is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
+{
+       guint32 size = 0;
+       unsigned signature = 0;
+       const char *ptr = NULL, *end;
+
+       if (!decode_signature_header (ctx, offset, &size, &ptr))
+               FAIL (ctx, g_strdup ("MemberRefSig: Could not decode signature header"));
+       end = ptr + size;
+
+       if (!safe_read8 (signature, ptr, end))
+               FAIL (ctx, g_strdup ("MemberRefSig: Not enough room for the call conv"));
+       --ptr;
+
+       if (signature == 0x06)
+               return parse_field (ctx, &ptr, end);
+
+       return parse_method_signature (ctx, &ptr, end, TRUE, FALSE);
+}
+
+static gboolean
+is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
+{
+       guint32 size = 0;
+       unsigned prolog = 0;
+       const char *ptr = NULL, *end;
+
+       if (!offset)
+               return TRUE;
+
+       if (!decode_signature_header (ctx, offset, &size, &ptr))
+               FAIL (ctx, g_strdup ("CustomAttribute: Could not decode signature header"));
+       end = ptr + size;
+
+       if (!safe_read16 (prolog, ptr, end))
+               FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
+
+       if (prolog != 1)
+               FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
+
+       return TRUE;
+}
+
+static gboolean
+is_valid_cattr_type (MonoType *type)
+{
+       MonoClass *klass;
+
+       if (type->type == MONO_TYPE_OBJECT || (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_STRING))
+               return TRUE;
+
+       if (type->type == MONO_TYPE_VALUETYPE) {
+               klass = mono_class_from_mono_type (type);
+               return klass && klass->enumtype;
+       }
+
+       if (type->type == MONO_TYPE_CLASS)
+               return mono_class_from_mono_type (type) == mono_defaults.systemtype_class;
+
+       return FALSE;
+}
+
+static gboolean
+is_valid_ser_string_full (VerifyContext *ctx, const char **str_start, guint32 *str_len, const char **_ptr, const char *end)
+{
+       guint32 size = 0;
+       const char *ptr = *_ptr;
+
+       *str_start = NULL;
+       *str_len = 0;
+
+       if (ptr >= end)
+               FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
+
+       /*NULL string*/
+       if (*ptr == (char)0xFF) {
+               *_ptr = ptr + 1;
+               return TRUE;
+       }
+
+       if (!safe_read_cint (size, ptr, end))
+               FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string size"));
+
+       if (ADDP_IS_GREATER_OR_OVF (ptr, size, end))
+               FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for string"));
+
+       *str_start = ptr;
+       *str_len = size;
+
+       *_ptr = ptr + size;
+       return TRUE;
+}
+
+static gboolean
+is_valid_ser_string (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+       const char *dummy_str;
+       guint32 dummy_int;
+       return is_valid_ser_string_full (ctx, &dummy_str, &dummy_int, _ptr, end);
+}
+
+static MonoClass*
+get_enum_by_encoded_name (VerifyContext *ctx, const char **_ptr, const char *end)
+{
+       MonoType *type;
+       MonoClass *klass;
+       const char *str_start = NULL;
+       const char *ptr = *_ptr;
+       char *enum_name;
+       guint32 str_len = 0;
+
+       if (!is_valid_ser_string_full (ctx, &str_start, &str_len, &ptr, end))
+               return NULL;
+
+       /*NULL or empty string*/
+       if (str_start == NULL || str_len == 0) {
+               ADD_ERROR_NO_RETURN (ctx, g_strdup ("CustomAttribute: Null or empty enum name"));
+               return NULL;
+       }
+
+       enum_name = g_memdup (str_start, str_len + 1);
+       enum_name [str_len] = 0;
+       type = mono_reflection_type_from_name (enum_name, ctx->image);
+       if (!type) {
+               ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid enum class %s", enum_name));
+               g_free (enum_name);
+               return NULL;
+       }
+       g_free (enum_name);
+
+       klass = mono_class_from_mono_type (type);
+       if (!klass || !klass->enumtype) {
+               ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute:Class %s::%s is not an enum", klass->name_space, klass->name));
+               return NULL;
+       }
+
+       *_ptr = ptr;
+       return klass;
+}
+
+static gboolean
+is_valid_fixed_param (VerifyContext *ctx, MonoType *mono_type, const char **_ptr, const char *end)
+{
+       MonoClass *klass;
+       const char *ptr = *_ptr;
+       int elem_size = 0;
+       guint32 element_count, i;
+       int type;
+
+       klass = mono_type->data.klass;
+       type = mono_type->type;
+
+handle_enum:
+       switch (type) {
+       case MONO_TYPE_BOOLEAN:
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+               elem_size = 1;
+               break;
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+       case MONO_TYPE_CHAR:
+               elem_size = 2;
+               break;
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+       case MONO_TYPE_R4:
+               elem_size = 4;
+               break;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+       case MONO_TYPE_R8:
+               elem_size = 8;
+               break;
+
+       case MONO_TYPE_STRING:
+               *_ptr = ptr;
+               return is_valid_ser_string (ctx, _ptr, end);
+
+       case MONO_TYPE_OBJECT: {
+               unsigned sub_type = 0;
+               if (!safe_read8 (sub_type, ptr, end))
+                       FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array type"));
+
+               if (sub_type >= MONO_TYPE_BOOLEAN && sub_type <= MONO_TYPE_STRING) {
+                       type = sub_type;
+                       goto handle_enum;
+               }
+               if (sub_type == MONO_TYPE_ENUM) {
+                       klass = get_enum_by_encoded_name (ctx, &ptr, end);
+                       if (!klass)
+                               return FALSE;
+
+                       klass = klass->element_class;
+                       type = klass->byval_arg.type;
+                       goto handle_enum;
+               }
+               if (sub_type == 0x50) { /*Type*/
+                       *_ptr = ptr;
+                       return is_valid_ser_string (ctx, _ptr, end);
+               }
+               if (sub_type == MONO_TYPE_SZARRAY) {
+                       MonoType simple_type = {{0}};
+                       unsigned etype = 0;
+                       if (!safe_read8 (etype, ptr, end))
+                               FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
+
+                       if (etype == MONO_TYPE_ENUM) {
+                               klass = get_enum_by_encoded_name (ctx, &ptr, end);
+                               if (!klass)
+                                       return FALSE;
+                       } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
+                               simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
+                               klass = mono_class_from_mono_type (&simple_type);
+                       } else
+                               FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
+
+                       type = MONO_TYPE_SZARRAY;
+                       goto handle_enum;
+               }
+               FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid boxed object type %x", sub_type));
+       }
+
+
+       case MONO_TYPE_CLASS:
+               if (klass != mono_defaults.systemtype_class)
+                       FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
+               *_ptr = ptr;
+               return is_valid_ser_string (ctx, _ptr, end);
+
+       case MONO_TYPE_VALUETYPE:
+               if (!klass || !klass->enumtype)
+                       FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid valuetype parameter expected enum %s:%s ",klass->name_space, klass->name));
+
+               klass = klass->element_class;
+               type = klass->byval_arg.type;
+               goto handle_enum;
+
+       case MONO_TYPE_SZARRAY:
+               mono_type = &klass->byval_arg;
+               if (!is_valid_cattr_type (mono_type))
+                       FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %s:%s ",klass->name_space, klass->name));
+               if (!safe_read32 (element_count, ptr, end))
+                       FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid class parameter type %s:%s ",klass->name_space, klass->name));
+               if (element_count == 0xFFFFFFFFu) {
+                       *_ptr = ptr;
+                       return TRUE;
+               }
+               for (i = 0; i < element_count; ++i) {
+                       if (!is_valid_fixed_param (ctx, mono_type, &ptr, end))
+                               return FALSE;
+               }
+               *_ptr = ptr;
+               return TRUE;
+       default:
+               FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid parameter type %x ", type));
+       }
+
+       if (ADDP_IS_GREATER_OR_OVF (ptr, elem_size, end))
+               FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for element"));
+       *_ptr = ptr + elem_size;
+       return TRUE;
+}
+
+static gboolean
+is_valid_cattr_content (VerifyContext *ctx, MonoMethod *ctor, const char *ptr, guint32 size)
+{
+       MonoError error;
+       unsigned prolog = 0;
+       const char *end;
+       MonoMethodSignature *sig;
+       int args, i;
+       unsigned num_named;
+
+       if (!ctor)
+               FAIL (ctx, g_strdup ("CustomAttribute: Invalid constructor"));
+
+       sig = mono_method_signature_checked (ctor, &error);
+       if (!mono_error_ok (&error)) {
+               ADD_ERROR_NO_RETURN (ctx, g_strdup_printf ("CustomAttribute: Invalid constructor signature %s", mono_error_get_message (&error)));
+               mono_error_cleanup (&error);
+               return FALSE;
+       }
+
+       if (sig->sentinelpos != -1 || sig->call_convention == MONO_CALL_VARARG)
+               FAIL (ctx, g_strdup ("CustomAttribute: Constructor cannot have VARAG signature"));
+
+       end = ptr + size;
+
+       if (!safe_read16 (prolog, ptr, end))
+               FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for prolog"));
+
+       if (prolog != 1)
+               FAIL (ctx, g_strdup_printf ("CustomAttribute: Prolog is 0x%x, expected 0x1", prolog));
+
+       args = sig->param_count;
+       for (i = 0; i < args; ++i) {
+               MonoType *arg_type = sig->params [i];
+               if (!is_valid_fixed_param (ctx, arg_type, &ptr, end))
+                       return FALSE;
+       }
+
+       if (!safe_read16 (num_named, ptr, end))
+               FAIL (ctx, g_strdup ("CustomAttribute: Not enough space for num_named field"));
+
+       for (i = 0; i < num_named; ++i) {
+               MonoType *type, simple_type = {{0}};
+               unsigned kind;
+
+               if (!safe_read8 (kind, ptr, end))
+                       FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d kind", i));
+               if (kind != 0x53 && kind != 0x54)
+                       FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter %d kind %x", i, kind));
+               if (!safe_read8 (kind, ptr, end))
+                       FAIL (ctx, g_strdup_printf ("CustomAttribute: Not enough space for named parameter %d type", i));
+
+               if (kind >= MONO_TYPE_BOOLEAN && kind <= MONO_TYPE_STRING) {
+                       simple_type.type = kind;
+                       type = &simple_type;
+               } else if (kind == MONO_TYPE_ENUM) {
+                       MonoClass *klass = get_enum_by_encoded_name (ctx, &ptr, end);
+                       if (!klass)
+                               return FALSE;
+                       type = &klass->byval_arg;
+               } else if (kind == 0x50) {
+                       type = &mono_defaults.systemtype_class->byval_arg;
+               } else if (kind == 0x51) {
+                       type = &mono_defaults.object_class->byval_arg;
+               } else if (kind == MONO_TYPE_SZARRAY) {
+                       MonoClass *klass;
+                       unsigned etype = 0;
+                       if (!safe_read8 (etype, ptr, end))
+                               FAIL (ctx, g_strdup ("CustomAttribute: Not enough room for array element type"));
+
+                       if (etype == MONO_TYPE_ENUM) {
+                               klass = get_enum_by_encoded_name (ctx, &ptr, end);
+                               if (!klass)
+                                       return FALSE;
+                       } else if ((etype >= MONO_TYPE_BOOLEAN && etype <= MONO_TYPE_STRING) || etype == 0x51) {
+                               simple_type.type = etype == 0x51 ? MONO_TYPE_OBJECT : etype;
+                               klass = mono_class_from_mono_type (&simple_type);
+                       } else
+                               FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid array element type %x", etype));
+
+                       type = &mono_array_class_get (klass, 1)->byval_arg;
                } else {
-                       if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
-                               ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
+                       FAIL (ctx, g_strdup_printf ("CustomAttribute: Invalid named parameter type %x", kind));
+               }
+
+               if (!is_valid_ser_string (ctx, &ptr, end))
+                       return FALSE;
+
+               if (!is_valid_fixed_param (ctx, type, &ptr, end))
+                       return FALSE;
+
+       }
+
+       return TRUE;
+}
+
+static gboolean
+is_valid_marshal_spec (VerifyContext *ctx, guint32 offset)
+{
+       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+       //TODO do proper verification
+       return blob.size >= 1 && blob.size - 1 >= offset;
+}
+
+static gboolean
+is_valid_permission_set (VerifyContext *ctx, guint32 offset)
+{
+       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+       //TODO do proper verification
+       return blob.size >= 1 && blob.size - 1 >= offset;
+}
+
+static gboolean
+is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
+{
+       guint32 size = 0;
+       unsigned signature = 0;
+       const char *ptr = NULL, *end;
+
+       if (!decode_signature_header (ctx, offset, &size, &ptr))
+               FAIL (ctx, g_strdup ("StandAloneSig: Could not decode signature header"));
+       end = ptr + size;
+
+       if (!safe_read8 (signature, ptr, end))
+               FAIL (ctx, g_strdup ("StandAloneSig: Not enough room for the call conv"));
+
+       --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);
+}
+
+static gboolean
+is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
+{
+       guint32 size = 0;
+       const char *ptr = NULL, *end;
+
+       if (!decode_signature_header (ctx, offset, &size, &ptr))
+               FAIL (ctx, g_strdup ("PropertySig: Could not decode signature header"));
+       end = ptr + size;
+
+       return parse_property_signature (ctx, &ptr, end);
+}
+
+static gboolean
+is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
+{
+       guint32 size = 0;
+       const char *ptr = NULL, *end;
+       unsigned type = 0;
        
-                       if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
-                               if (data [MONO_TYPEDEF_EXTENDS])
-                                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
-                               if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
-                                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
-                       } else {
-                               if (!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]));
+       if (!decode_signature_header (ctx, offset, &size, &ptr))
+               FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
+       end = ptr + size;
+
+       if (!parse_custom_mods (ctx, &ptr, end))
+               return FALSE;
+
+       if (!safe_read8 (type, ptr, end))
+               FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
+
+       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 (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS])) 
-                                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
+       if (type == MONO_TYPE_TYPEDBYREF)
+               return TRUE;
+
+       --ptr;
+       return parse_type (ctx, &ptr, end);
+}
+
+static gboolean
+is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
+{
+       guint32 size = 0;
+       const char *ptr = NULL, *end;
+       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"));
+       end = ptr + size;
+
+       if (!safe_read8 (type, ptr, end))
+               FAIL (ctx, g_strdup ("MethodSpec: Not enough room for call convention"));
+
+       if (type != 0x0A)
+               FAIL (ctx, g_strdup_printf ("MethodSpec: Invalid call convention 0x%x, expected 0x0A", type));
+
+       if (!safe_read_cint (count, ptr, end))
+               FAIL (ctx, g_strdup ("MethodSpec: Not enough room for parameter count"));
+
+       if (!count)
+               FAIL (ctx, g_strdup ("MethodSpec: Zero generic argument count"));
+
+       for (i = 0; i < count; ++i) {
+               if (!parse_type (ctx, &ptr, end))
+                       FAIL (ctx, g_strdup_printf ("MethodSpec: Could not parse parameter %d", i + 1));
+       }
+       return TRUE;
+}
+
+static gboolean
+is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
+{
+       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+       guint32 entry_size, bytes;
+
+       if (blob.size < offset)
+               return FALSE;
+
+       if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
+               return FALSE;
+
+       if (entry_size < minsize)
+               return FALSE;
+
+       if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
+               return FALSE;
+       entry_size += bytes;
+
+       return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
+}
+
+static gboolean
+is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
+{
+       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+       guint32 size, entry_size, bytes;
+
+       if (blob.size < offset)
+               FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
+       
+       if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
+               FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
+
+       if (type == MONO_TYPE_STRING) {
+               //String is encoded as: compressed_int:len len *bytes
+               offset += bytes;
+
+               if (ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size))
+                       FAIL (ctx, g_strdup_printf ("ContantValue: not enough space for string, required %d but got %d", entry_size * 2, blob.size - offset));  
+
+               return TRUE;
+       }
+
+       switch (type) {
+       case MONO_TYPE_BOOLEAN:
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+               size = 1;
+               break;
+       case MONO_TYPE_CHAR:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+               size = 2;
+               break;
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+       case MONO_TYPE_R4:
+       case MONO_TYPE_CLASS:
+               size = 4;
+               break;
+
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+       case MONO_TYPE_R8:
+               size = 8;
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+
+       if (size != entry_size)
+               FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
+
+       offset += bytes;
+
+       if (ADD_IS_GREATER_OR_OVF (offset, size, blob.size))
+               FAIL (ctx, g_strdup_printf ("ContantValue: Not enough room for constant, required %d but have %d", size, blob.size - offset));
+
+       if (type == MONO_TYPE_CLASS && read32 (ctx->data + blob.offset + offset))
+               FAIL (ctx, g_strdup_printf ("ContantValue: Type is class but value is not null"));
+       return TRUE;
+}
+
+#define FAT_HEADER_INVALID_FLAGS ~(0x3 | 0x8 | 0x10 | 0xF000)
+//only 0x01, 0x40 and 0x80 are allowed
+#define SECTION_HEADER_INVALID_FLAGS 0x3E
+
+static gboolean
+is_valid_method_header (VerifyContext *ctx, guint32 rva)
+{
+       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)
+               FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
+
+       ptr = ctx->data + offset;
+       end = ctx->data + ctx->size; /*no worries if it spawns multiple sections*/
+
+       if (!safe_read8 (header, ptr, end))
+               FAIL (ctx, g_strdup ("MethodHeader: Not enough room for header"));
+
+       switch (header & 0x3) {
+       case 0:
+       case 1:
+               FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid header type 0x%x", header & 0x3));
+       case 2:
+               header >>= 2;
+               if (ADDP_IS_GREATER_OR_OVF (ptr, header, end)) 
+                       FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for method body. Required %d, but only %d is available", header, (int)(end - ptr)));
+               return TRUE;
+       }
+       //FAT HEADER
+       --ptr;
+       if (!safe_read16 (fat_header, ptr, end))
+               FAIL (ctx, g_strdup ("MethodHeader: Not enough room for fat header"));
+
+       size = (fat_header >> 12) & 0xF;
+       if (size != 3)
+               FAIL (ctx, g_strdup ("MethodHeader: header size must be 3"));
+
+       if (!safe_read16 (max_stack, ptr, end))
+               FAIL (ctx, g_strdup ("MethodHeader: Not enough room for max stack"));
+
+       if (!safe_read32 (code_size, ptr, end))
+               FAIL (ctx, g_strdup ("MethodHeader: Not enough room for code size"));
+
+       if (!safe_read32 (local_vars_tok, ptr, end))
+               FAIL (ctx, g_strdup ("MethodHeader: Not enough room for local vars tok"));
+
+       if (local_vars_tok) {
+               if (((local_vars_tok >> 24) & 0xFF) != 0x11)
+                       FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature table 0x%x", ((local_vars_tok >> 24) & 0xFF)));
+               if ((local_vars_tok & 0xFFFFFF) > ctx->image->tables [MONO_TABLE_STANDALONESIG].rows)   
+                       FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid local vars signature points to invalid row 0x%x", local_vars_tok & 0xFFFFFF));
+       }
+
+       if (fat_header & FAT_HEADER_INVALID_FLAGS)
+               FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid fat signature flags %x", fat_header & FAT_HEADER_INVALID_FLAGS));
+
+       if (ADDP_IS_GREATER_OR_OVF (ptr, code_size, end))
+               FAIL (ctx, g_strdup_printf ("MethodHeader: Not enough room for code %d", code_size));
+
+       if (!(fat_header & 0x08))
+               return TRUE;
+
+       ptr += code_size;
+
+       do {
+               unsigned section_header = 0, section_size = 0;
+               gboolean is_fat;
+
+               ptr = dword_align (ptr);
+               if (!safe_read32 (section_header, ptr, end))
+                       FAIL (ctx, g_strdup ("MethodHeader: Not enough room for data section header"));
+
+               if (section_header & SECTION_HEADER_INVALID_FLAGS)
+                       FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section header flags 0x%x", section_header & SECTION_HEADER_INVALID_FLAGS));
+                       
+               is_fat = (section_header & METHOD_HEADER_SECTION_FAT_FORMAT) != 0;
+               section_size = (section_header >> 8) & (is_fat ? 0xFFFFFF : 0xFF);
+
+               if (section_size < 4)
+                       FAIL (ctx, g_strdup_printf ("MethodHeader: Section size too small"));
+
+               if (ADDP_IS_GREATER_OR_OVF (ptr, section_size - 4, end)) /*must be section_size -4 as ptr was incremented by safe_read32*/
+                       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 / (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) {
+                               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));
+                               if (flags == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
+                                       guint table = mono_metadata_token_table (class_token);
+                                       if (table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPESPEC)
+                                               FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token table %x", i, table));
+                                       if (mono_metadata_token_index (class_token) > ctx->image->tables [table].rows)
+                                               FAIL (ctx, g_strdup_printf ("MethodHeader: Invalid section %d class token index %x", i, mono_metadata_token_index (class_token)));
+                               }
                        }
                }
 
+               if (!(section_header & METHOD_HEADER_SECTION_MORE_SECTS))
+                       break;
+       } while (1);
+       return TRUE;
+}
+
+static void
+verify_module_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
+       guint32 data [MONO_MODULE_SIZE];
+
+       if (table->rows != 1)
+               ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
+
+       mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
+
+       if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
+               ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
+
+       if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
+               ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
+
+       if (data [MONO_MODULE_ENC] != 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
+
+       if (data [MONO_MODULE_ENCBASE] != 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
+}
+
+static void
+verify_typeref_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
+       guint32 data [MONO_TYPEREF_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
+               if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
+               
+               if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
+
+               if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
+
+               if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
+       }
+}
+
+/*bits 9,11,14,15,19,21,24-31 */
+#define INVALID_TYPEDEF_FLAG_BITS ((1 << 6) | (1 << 9) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
+static void
+verify_typedef_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+       guint32 data [MONO_TYPEDEF_SIZE];
+       guint32 fieldlist = 1, methodlist = 1, visibility;
+       int i;
+
+       if (table->rows == 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
+               if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
+
+               if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
+
+               if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+
+               if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+
+               if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) && (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
+
+               if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
+
+               if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
+
+               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));
 
@@ -1345,12 +2408,51 @@ verify_typedef_table (VerifyContext *ctx)
                if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_TYPEDEF_METHOD_LIST], methodlist));
 
-
                fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
                methodlist = data [MONO_TYPEDEF_METHOD_LIST];
        }
 }
 
+static void
+verify_typedef_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+       guint32 data [MONO_TYPEDEF_SIZE];
+       int i;
+
+       if (table->rows == 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
+
+               if (i == 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;
+               }
+
+               if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
+                       if (data [MONO_TYPEDEF_EXTENDS])
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
+               } else {
+                       gboolean is_sys_obj = typedef_is_system_object (ctx, data);
+                       gboolean has_parent = get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]) != 0;
+
+                       if (is_sys_obj) {
+                               if (has_parent)
+                                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
+                       } else {
+                               if (!has_parent) {
+                                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
+                               }
+                       }
+               }
+       }
+}
+
 /*bits 3,11,14 */
 #define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
 static void
@@ -1404,9 +2506,10 @@ verify_field_table (VerifyContext *ctx)
                if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
 
+               if (data [MONO_FIELD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_FIELD_SIGNATURE], 1))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature blob token 0x%x", i, data [MONO_FIELD_SIGNATURE]));
+
                //TODO verify contant flag
-               if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
 
                if (i + 1 < module_field_list) {
                        guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
@@ -1418,8 +2521,23 @@ verify_field_table (VerifyContext *ctx)
        }
 }
 
-/*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))
+static void
+verify_field_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
+       guint32 data [MONO_FIELD_SIZE];
+       int i;
+       
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
+
+               if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
+       }
+}
+
+/*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)
 {
@@ -1468,12 +2586,14 @@ 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));
@@ -1482,9 +2602,6 @@ verify_method_table (VerifyContext *ctx)
 
                //TODO check iface with .ctor (15,16)
 
-               if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
-                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token %08x", i, data [MONO_METHOD_SIGNATURE]));
-
                if (i + 1 < module_method_list) {
                        if (!(flags & METHOD_ATTRIBUTE_STATIC))
                                ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
@@ -1499,8 +2616,12 @@ verify_method_table (VerifyContext *ctx)
                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)
@@ -1516,8 +2637,6 @@ verify_method_table (VerifyContext *ctx)
                                ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
                        if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
                                ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
-                       if (!is_valid_method_header (ctx, rva))
-                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
                } else {
                        if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
                                ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
@@ -1535,6 +2654,9 @@ verify_method_table (VerifyContext *ctx)
                if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
 
+               if (data [MONO_METHOD_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHOD_SIGNATURE], 1))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature blob token 0x%x", i, data [MONO_METHOD_SIGNATURE]));
+
                if (data [MONO_METHOD_PARAMLIST] == 0)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
 
@@ -1549,6 +2671,25 @@ verify_method_table (VerifyContext *ctx)
        }
 }
 
+static void
+verify_method_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
+       guint32 data [MONO_METHOD_SIZE], rva;
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
+               rva = data [MONO_METHOD_RVA];
+
+               if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token 0x%08x", i, data [MONO_METHOD_SIGNATURE]));
+
+               if (rva && !is_valid_method_header (ctx, rva))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
+       }
+}
+
 static guint32
 get_next_param_count (VerifyContext *ctx, guint32 *current_method)
 {
@@ -1582,6 +2723,12 @@ verify_param_table (VerifyContext *ctx)
        gboolean first_param = TRUE;
        int i;
 
+       if (ctx->image->tables [MONO_TABLE_METHOD].rows == 0) {
+               if (table->rows > 0)
+                       ADD_ERROR (ctx, g_strdup ("Param table has rows while the method table has zero"));
+               return;
+       }
+       
        remaining_params = get_next_param_count (ctx, &current_method);
 
        for (i = 0; i < table->rows; ++i) {
@@ -1656,6 +2803,22 @@ verify_memberref_table (VerifyContext *ctx)
                if (!is_valid_non_empty_string (ctx, data [MONO_MEMBERREF_NAME]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Name field coded is invalid or empty 0x%08x", i, data [MONO_MEMBERREF_NAME]));
 
+               if (data [MONO_MEMBERREF_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_MEMBERREF_SIGNATURE], 1))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d invalid signature blob token 0x%x", i, data [MONO_MEMBERREF_SIGNATURE]));
+       }
+}
+
+
+static void
+verify_memberref_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MEMBERREF];
+       guint32 data [MONO_MEMBERREF_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_MEMBERREF_SIZE);
+
                if (!is_valid_method_or_field_signature (ctx, data [MONO_MEMBERREF_SIGNATURE]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid MemberRef row %d Signature field  0x%08x", i, data [MONO_MEMBERREF_SIGNATURE]));
        }
@@ -1702,9 +2865,45 @@ verify_cattr_table (VerifyContext *ctx)
                if (!is_valid_coded_index (ctx, CATTR_TYPE_DESC, data [MONO_CUSTOM_ATTR_TYPE]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Parent field 0x%08x", i, data [MONO_CUSTOM_ATTR_PARENT]));
 
-               if (!is_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
+               if (data [MONO_CUSTOM_ATTR_VALUE] && !is_valid_blob_object (ctx, data [MONO_CUSTOM_ATTR_VALUE], 0))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d invalid value blob 0x%x", i, data [MONO_CUSTOM_ATTR_VALUE]));
+       }
+}
+
+static void
+verify_cattr_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
+       MonoMethod *ctor;
+       const char *ptr;
+       guint32 data [MONO_CUSTOM_ATTR_SIZE], mtoken, size;
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
+
+               if (!is_valid_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
-                       
+
+               mtoken = data [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
+               switch (data [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
+               case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
+                       mtoken |= MONO_TOKEN_METHOD_DEF;
+                       break;
+               case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
+                       mtoken |= MONO_TOKEN_MEMBER_REF;
+                       break;
+               default:
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute constructor row %d Token 0x%08x", i, data [MONO_CUSTOM_ATTR_TYPE]));
+               }
+
+               ctor = mono_get_method (ctx->image, mtoken, NULL);
+
+               /*This can't fail since this is checked in is_valid_cattr_blob*/
+               g_assert (decode_signature_header (ctx, data [MONO_CUSTOM_ATTR_VALUE], &size, &ptr));
+
+               if (!is_valid_cattr_content (ctx, ctor, ptr, size))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid CustomAttribute content row %d Value field 0x%08x", i, data [MONO_CUSTOM_ATTR_VALUE]));
        }
 }
 
@@ -1727,9 +2926,23 @@ verify_field_marshal_table (VerifyContext *ctx)
                if (!data [MONO_FIELD_MARSHAL_NATIVE_TYPE])
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field is null", i));
 
+               if (!is_valid_blob_object (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE], 1))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d invalid NativeType blob 0x%x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
+       }
+}
+
+static void
+verify_field_marshal_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELDMARSHAL];
+       guint32 data [MONO_FIELD_MARSHAL_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_FIELD_MARSHAL_SIZE);
+
                if (!is_valid_marshal_spec (ctx, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid FieldMarshal row %d NativeType field 0x%08x", i, data [MONO_FIELD_MARSHAL_NATIVE_TYPE]));
-                       
        }
 }
 
@@ -1751,10 +2964,21 @@ verify_decl_security_table (VerifyContext *ctx)
 
                if (!data [MONO_DECL_SECURITY_PERMISSIONSET])
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field is null", i));
+       }
+}
+
+static void
+verify_decl_security_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_DECLSECURITY];
+       guint32 data [MONO_DECL_SECURITY_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_DECL_SECURITY_SIZE);
 
                if (!is_valid_permission_set (ctx, data [MONO_DECL_SECURITY_PERMISSIONSET]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid DeclSecurity row %d PermissionSet field 0x%08x", i, data [MONO_DECL_SECURITY_PERMISSIONSET]));
-
        }
 }
 
@@ -1810,6 +3034,21 @@ verify_standalonesig_table (VerifyContext *ctx)
        guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
        int i;
 
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
+
+               if (data [MONO_STAND_ALONE_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_STAND_ALONE_SIGNATURE], 1))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid StandAloneSig row %d invalid signature 0x%x", i, data [MONO_STAND_ALONE_SIGNATURE]));
+       }
+}
+
+static void
+verify_standalonesig_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_STANDALONESIG];
+       guint32 data [MONO_STAND_ALONE_SIGNATURE_SIZE];
+       int i;
+
        for (i = 0; i < table->rows; ++i) {
                mono_metadata_decode_row (table, i, data, MONO_STAND_ALONE_SIGNATURE_SIZE);
 
@@ -1843,10 +3082,8 @@ static void
 verify_event_table (VerifyContext *ctx)
 {
        MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
-       MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
-       guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
-       gboolean found_add, found_remove;
-       int i, idx;
+       guint32 data [MONO_EVENT_SIZE];
+       int i;
 
        for (i = 0; i < table->rows; ++i) {
                mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
@@ -1859,8 +3096,21 @@ verify_event_table (VerifyContext *ctx)
 
                if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_EVENT_TYPE]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid Event row %d EventType field %08x", i, data [MONO_EVENT_TYPE]));
+       }
+}
+
+static void
+verify_event_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_EVENT];
+       MonoTableInfo *sema_table = &ctx->image->tables [MONO_TABLE_METHODSEMANTICS];
+       guint32 data [MONO_EVENT_SIZE], sema_data [MONO_METHOD_SEMA_SIZE], token;
+       gboolean found_add, found_remove;
+       int i, idx;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_EVENT_SIZE);
 
-               //check for Add and Remove
                token = make_coded_token (HAS_SEMANTICS_DESC, MONO_TABLE_EVENT, i);
                idx = search_sorted_table (ctx, MONO_TABLE_METHODSEMANTICS, MONO_METHOD_SEMA_ASSOCIATION, token);
                if (idx == -1)
@@ -1993,12 +3243,28 @@ verify_typespec_table (VerifyContext *ctx)
        for (i = 0; i < table->rows; ++i) {
                mono_metadata_decode_row (table, i, data, MONO_TYPESPEC_SIZE);
 
+               if (data [MONO_TYPESPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_TYPESPEC_SIGNATURE], 1))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid TypeSpec row %d Signature field %08x", i, data [MONO_TYPESPEC_SIGNATURE]));
+       }
+}
+
+static void
+verify_typespec_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPESPEC];
+       guint32 data [MONO_TYPESPEC_SIZE];
+       int i;
+
+       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 << 7) | (1 << 8) | (1 << 9) | (1 << 10))
+#define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
 static void
 verify_implmap_table (VerifyContext *ctx)
 {
@@ -2028,7 +3294,7 @@ verify_implmap_table (VerifyContext *ctx)
                if (!is_valid_non_empty_string (ctx, data [MONO_IMPLMAP_NAME]))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d ImportName Token %x", i, data [MONO_IMPLMAP_NAME]));
 
-               if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULE].rows + 1)
+               if (!data [MONO_IMPLMAP_SCOPE] || data [MONO_IMPLMAP_SCOPE] > ctx->image->tables [MONO_TABLE_MODULEREF].rows + 1)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid ImplMap row %d Invalid ImportScope token %x", i, data [MONO_IMPLMAP_SCOPE]));
        }
 }
@@ -2051,7 +3317,7 @@ verify_fieldrva_table (VerifyContext *ctx)
        }
 }
 
-#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)
 {
@@ -2072,7 +3338,7 @@ verify_assembly_table (VerifyContext *ctx)
                if (data [MONO_ASSEMBLY_FLAGS] & INVALID_ASSEMBLY_FLAGS_BITS)
                        ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLY_FLAGS]));
 
-               if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY]))
+               if (data [MONO_ASSEMBLY_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLY_PUBLIC_KEY], 1))
                        ADD_ERROR (ctx, g_strdup_printf ("Assembly table row %d has invalid PublicKey %08x", i, data [MONO_ASSEMBLY_FLAGS]));
 
                if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLY_NAME]))
@@ -2097,7 +3363,7 @@ verify_assemblyref_table (VerifyContext *ctx)
                if (data [MONO_ASSEMBLYREF_FLAGS] & INVALID_ASSEMBLYREF_FLAGS_BITS)
                        ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Flags %08x", i, data [MONO_ASSEMBLYREF_FLAGS]));
 
-               if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY]))
+               if (data [MONO_ASSEMBLYREF_PUBLIC_KEY] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_PUBLIC_KEY], 1))
                        ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid PublicKeyOrToken %08x", i, data [MONO_ASSEMBLYREF_PUBLIC_KEY]));
 
                if (!is_valid_non_empty_string (ctx, data [MONO_ASSEMBLYREF_NAME]))
@@ -2106,7 +3372,7 @@ verify_assemblyref_table (VerifyContext *ctx)
                if (data [MONO_ASSEMBLYREF_CULTURE] && !is_valid_string (ctx, data [MONO_ASSEMBLYREF_CULTURE]))
                        ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid Culture %08x", i, data [MONO_ASSEMBLYREF_CULTURE]));
 
-               if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE]))
+               if (data [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob_object (ctx, data [MONO_ASSEMBLYREF_HASH_VALUE], 1))
                        ADD_ERROR (ctx, g_strdup_printf ("AssemblyRef table row %d has invalid HashValue %08x", i, data [MONO_ASSEMBLYREF_HASH_VALUE]));
        }
 }
@@ -2128,7 +3394,7 @@ verify_file_table (VerifyContext *ctx)
                if (!is_valid_non_empty_string (ctx, data [MONO_FILE_NAME]))
                        ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid Name %08x", i, data [MONO_FILE_NAME]));
 
-               if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE]))
+               if (!data [MONO_FILE_HASH_VALUE] || !is_valid_blob_object (ctx, data [MONO_FILE_HASH_VALUE], 1))
                        ADD_ERROR (ctx, g_strdup_printf ("File table row %d has invalid HashValue %08x", i, data [MONO_FILE_HASH_VALUE]));
        }
 }
@@ -2225,7 +3491,7 @@ verify_nested_class_table (VerifyContext *ctx)
        }
 }
 
-#define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2))
+#define INVALID_GENERIC_PARAM_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4))
 static void
 verify_generic_param_table (VerifyContext *ctx)
 {
@@ -2281,11 +3547,145 @@ verify_method_spec_table (VerifyContext *ctx)
                if (!get_coded_index_token (METHODDEF_OR_REF_DESC, data [MONO_METHODSPEC_METHOD]))
                        ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has null Method token", i));
 
-               if (!is_valid_methodspec_blog (ctx, data [MONO_METHODSPEC_SIGNATURE]))
+               if (data [MONO_METHODSPEC_SIGNATURE] && !is_valid_blob_object (ctx, data [MONO_METHODSPEC_SIGNATURE], 1))
+                       ADD_ERROR (ctx, g_strdup_printf ("MethodSpec table row %d has invalid signature token %08x", i, data [MONO_METHODSPEC_SIGNATURE]));
+       }
+}
+
+static void
+verify_method_spec_table_full (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHODSPEC];
+       guint32 data [MONO_METHODSPEC_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_METHODSPEC_SIZE);
+
+               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]));
        }
 }
-
+
+static void
+verify_generic_param_constraint_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
+       guint32 data [MONO_GENPARCONSTRAINT_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_GENPARCONSTRAINT_SIZE);
+
+               if (!data [MONO_GENPARCONSTRAINT_GENERICPAR] || data [MONO_GENPARCONSTRAINT_GENERICPAR] > ctx->image->tables [MONO_TABLE_GENERICPARAM].rows)
+                       ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Owner token %08x", i, data [MONO_TABLE_GENERICPARAM]));
+
+               if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
+                       ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has invalid Constraint token %08x", i, data [MONO_GENPARCONSTRAINT_CONSTRAINT]));
+
+               if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_GENPARCONSTRAINT_CONSTRAINT]))
+                       ADD_ERROR (ctx, g_strdup_printf ("GenericParamConstraint table row %d has null Constraint token", i));
+       }
+}
+
+
+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)
 {
@@ -2374,15 +3774,10 @@ verify_tables_data (VerifyContext *ctx)
        verify_generic_param_table (ctx);
        CHECK_ERROR ();
        verify_method_spec_table (ctx);
-}
-
-static gboolean
-mono_verifier_is_corlib (MonoImage *image)
-{
-       gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
-                       TRUE : mono_security_core_clr_is_platform_image (image);
-
-       return trusted_location && !strcmp ("mscorlib.dll", image->name);
+       CHECK_ERROR ();
+       verify_generic_param_constraint_table (ctx);
+       CHECK_ERROR ();
+       verify_tables_data_global_constraints (ctx);
 }
 
 static void
@@ -2391,10 +3786,10 @@ init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
        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;
-       ctx->is_corlib = mono_verifier_is_corlib (image);       
 }
 
 static gboolean
@@ -2459,6 +3854,18 @@ cleanup:
        return cleanup_context (&ctx, error_list);
 }
 
+
+/*
+ * Verifies basic table constraints such as global table invariants (sorting, field monotonicity, etc).
+ * Other verification checks are meant to be done lazily by the runtime. Those include:
+ *     blob items (signatures, method headers, custom attributes, etc)
+ *  type semantics related
+ *  vtable related
+ *  stuff that should not block other pieces from running such as bad types/methods/fields/etc.
+ * 
+ * The whole idea is that if this succeed the runtime is free to play around safely but any complex
+ * operation still need more checking.
+ */
 gboolean
 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
 {
@@ -2474,6 +3881,251 @@ mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
 
        return cleanup_context (&ctx, error_list);
 }
+
+
+/*
+ * Verifies all other constraints.
+ */
+gboolean
+mono_verifier_verify_full_table_data (MonoImage *image, 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_typedef_table_full (&ctx);
+       CHECK_STATE ();
+       verify_field_table_full (&ctx);
+       CHECK_STATE ();
+       verify_method_table_full (&ctx);
+       CHECK_STATE ();
+       verify_memberref_table_full (&ctx);
+       CHECK_STATE ();
+       verify_cattr_table_full (&ctx);
+       CHECK_STATE ();
+       verify_field_marshal_table_full (&ctx);
+       CHECK_STATE ();
+       verify_decl_security_table_full (&ctx);
+       CHECK_STATE ();
+       verify_standalonesig_table_full (&ctx);
+       CHECK_STATE ();
+       verify_event_table_full (&ctx);
+       CHECK_STATE ();
+       verify_typespec_table_full (&ctx);
+       CHECK_STATE ();
+       verify_method_spec_table_full (&ctx);
+
+cleanup:
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_field_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;
+
+       is_valid_field_signature (&ctx, offset);
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_method_header (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;
+
+       is_valid_method_header (&ctx, offset);
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_method_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;
+
+       is_valid_method_signature (&ctx, offset);
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_memberref_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;
+
+       is_valid_method_or_field_signature (&ctx, offset);
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_standalone_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;
+
+       is_valid_standalonesig_blob (&ctx, offset);
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, 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;
+       ctx.token = token;
+
+       is_valid_typespec_blob (&ctx, offset);
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_methodspec_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;
+
+       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_verify_cattr_blob (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;
+
+       is_valid_cattr_blob (&ctx, offset);
+
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, 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;
+
+       is_valid_cattr_content (&ctx, ctor, (const char*)data, size);
+
+       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)
@@ -2492,4 +4144,78 @@ mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
 {
        return TRUE;
 }
+
+gboolean
+mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint32 token, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_cattr_blob (MonoImage *image, guint32 offset, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_cattr_content (MonoImage *image, MonoMethod *ctor, const guchar *data, guint32 size, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_is_sig_compatible (MonoImage *image, MonoMethod *method, MonoMethodSignature *signature)
+{
+       return TRUE;
+}
+
+
 #endif /* DISABLE_VERIFIER */