2009-07-22 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / metadata / metadata-verify.c
index 3db7074879e9c8817765e7c5c1b0076f364686a7..f3b588cb13dc66ca969d2fbc597b0bfb6d5ba31b 100644 (file)
@@ -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,
@@ -219,7 +220,6 @@ typedef struct {
        guint32 size;
        GSList *errors;
        int valid;
-       gboolean is_corlib;
        MonoImage *image;
        gboolean report_error;
        int stage;
@@ -271,6 +271,7 @@ typedef struct {
 #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)
@@ -1050,10 +1051,19 @@ string_cmp (VerifyContext *ctx, const char *str, guint offset)
        return strcmp (str, get_string_ptr (ctx, offset));
 }
 
+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 && image->module_name && !strcmp ("mscorlib.dll", image->module_name);
+}
+
 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]);
+       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
@@ -1477,11 +1487,16 @@ parse_field (VerifyContext *ctx, const char **_ptr, const char *end)
 
        if (signature != 0x06)
                FAIL (ctx, g_strdup_printf ("Field: Invalid signature 0x%x, must be 6", signature));
-       *_ptr = ptr; 
 
-       if (!parse_custom_mods (ctx, _ptr, end))
+       if (!parse_custom_mods (ctx, &ptr, end))
                return FALSE;
 
+       if (safe_read8 (signature, ptr, end)) {
+               if (signature != MONO_TYPE_BYREF)
+                       --ptr;
+       }
+       *_ptr = ptr;
+
        return parse_type (ctx, _ptr, end);
 }
 
@@ -1501,23 +1516,34 @@ parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
        if (!safe_read_cint (locals_count, ptr, end))
                FAIL (ctx, g_strdup ("LocalsSig: Not enough room for the param count"));
 
+       /* LAMEIMPL: MS sometimes generates empty local signatures and its verifier is ok with.
        if (locals_count == 0)
                FAIL (ctx, g_strdup ("LocalsSig: Signature with zero locals"));
+       */
 
        for (i = 0; i < locals_count; ++i) {
                if (!safe_read8 (sig, ptr, end))
                        FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
 
-               if (sig == MONO_TYPE_TYPEDBYREF)
-                       continue;
-
                while (sig == MONO_TYPE_CMOD_REQD || sig == MONO_TYPE_CMOD_OPT || sig == MONO_TYPE_PINNED) {
                        if (sig != MONO_TYPE_PINNED && !parse_custom_mods (ctx, &ptr, end))
                                FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
                        if (!safe_read8 (sig, ptr, end))
                                FAIL (ctx, g_strdup ("LocalsSig: Not enough room for type"));
                }
+
+               if (sig == MONO_TYPE_BYREF) {
+                       if (!safe_read8 (sig, ptr, end))
+                               FAIL (ctx, g_strdup_printf ("Type: Not enough room for byref type for local %d", i));
+                       if (sig == MONO_TYPE_TYPEDBYREF)
+                               FAIL (ctx, g_strdup_printf ("Type: Invalid type typedref& for local %d", i));
+               }
+
+               if (sig == MONO_TYPE_TYPEDBYREF)
+                       continue;
+
                --ptr;
+
                if (!parse_type (ctx, &ptr, end))
                        FAIL (ctx, g_strdup_printf ("LocalsSig: Error parsing local %d", i));
        }
@@ -1669,11 +1695,18 @@ is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
 
        if (!safe_read8 (type, ptr, end))
                FAIL (ctx, g_strdup ("TypeSpec: Not enough room for type"));
-       --ptr;
 
+       if (type == MONO_TYPE_BYREF) {
+               if (!safe_read8 (type, ptr, end)) 
+                       FAIL (ctx, g_strdup ("TypeSpec: Not enough room for byref type"));
+               if (type == MONO_TYPE_TYPEDBYREF)
+                       FAIL (ctx, g_strdup ("TypeSpec: Invalid type typedref&"));
+       }
+       
        if (type == MONO_TYPE_TYPEDBYREF)
                return TRUE;
 
+       --ptr;
        return parse_type (ctx, &ptr, end);
 }
 
@@ -1709,7 +1742,7 @@ is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
 }
 
 static gboolean
-is_valid_blob_object (VerifyContext *ctx, guint32 offset)
+is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
 {
        OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
        guint32 entry_size, bytes;
@@ -1720,10 +1753,14 @@ is_valid_blob_object (VerifyContext *ctx, guint32 offset)
        if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
                return FALSE;
 
-       if (offset + entry_size + bytes < offset)
+       if (entry_size < minsize)
+               return FALSE;
+
+       if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
                return FALSE;
+       entry_size += bytes;
 
-       return blob.size >= offset + entry_size + bytes;
+       return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
 }
 
 static gboolean
@@ -1733,19 +1770,19 @@ is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
        guint32 size, entry_size, bytes;
 
        if (blob.size < offset)
-               return FALSE;
+               FAIL (ctx, g_strdup ("ContantValue: invalid offset"));
        
        if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
-               return FALSE;
+               FAIL (ctx, g_strdup ("ContantValue: not enough space to decode size"));
 
        if (type == MONO_TYPE_STRING) {
-               //String is encoded as: compressed_int:len len *chars
-
+               //String is encoded as: compressed_int:len len *bytes
                offset += bytes;
-               if (offset > offset + entry_size * 2) //overflow
-                       return FALSE;
-               offset += offset + entry_size * 2;
-               return  offset <= blob.size;
+
+               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) {
@@ -1776,17 +1813,15 @@ is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
        }
 
        if (size != entry_size)
-               return FALSE;
-       offset += bytes;
+               FAIL (ctx, g_strdup_printf ("ContantValue: Expected size %d but got %d", size, entry_size));
 
-       if(offset > offset + size) //overflow
-               return FALSE;
+       offset += bytes;
 
-       if (offset + size > blob.size)
-               return FALSE;
+       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 + offset))
-               return FALSE;
+       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;
 }
 
@@ -1818,7 +1853,7 @@ is_valid_method_header (VerifyContext *ctx, guint32 rva)
        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, end - ptr));
+                       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
@@ -1884,11 +1919,12 @@ is_valid_method_header (VerifyContext *ctx, guint32 rva)
 
                        /* only verify the class token is verified as the rest is done by the IL verifier*/
                        for (i = 0; i < clauses; ++i) {
+                               guint flags = *ptr;
                                guint32 class_token = 0;
                                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 (!*ptr == MONO_EXCEPTION_CLAUSE_NONE && class_token) {
+                               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));
@@ -1978,32 +2014,17 @@ verify_typedef_table (VerifyContext *ctx)
                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 (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"));
-               } 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));
-       
-                       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 (!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 (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]));
 
                if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
@@ -2023,12 +2044,49 @@ 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) {
+                       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
@@ -2082,9 +2140,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;
@@ -2096,6 +2155,21 @@ verify_field_table (VerifyContext *ctx)
        }
 }
 
+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 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
@@ -2160,9 +2234,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 0x%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));
@@ -2194,8 +2265,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));
@@ -2213,6 +2282,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));
 
@@ -2227,6 +2299,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)
 {
@@ -2260,6 +2351,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) {
@@ -2334,6 +2431,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]));
        }
@@ -2380,9 +2493,23 @@ 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 (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];
+       guint32 data [MONO_CUSTOM_ATTR_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_CUSTOM_ATTR_SIZE);
+
                if (!is_vald_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]));
-                       
        }
 }
 
@@ -2405,9 +2532,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]));
-                       
        }
 }
 
@@ -2429,10 +2570,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]));
-
        }
 }
 
@@ -2488,6 +2640,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);
 
@@ -2521,10 +2688,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);
@@ -2537,8 +2702,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)
@@ -2668,6 +2846,21 @@ verify_typespec_table (VerifyContext *ctx)
        guint32 data [MONO_TYPESPEC_SIZE];
        int i;
 
+       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);
 
@@ -2676,7 +2869,7 @@ verify_typespec_table (VerifyContext *ctx)
        }
 }
 
-#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)
 {
@@ -2706,7 +2899,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]));
        }
 }
@@ -2750,7 +2943,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]))
@@ -2775,7 +2968,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]))
@@ -2784,7 +2977,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]));
        }
 }
@@ -2806,7 +2999,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]));
        }
 }
@@ -2959,6 +3152,21 @@ 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 (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_blog (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]));
        }
@@ -3077,15 +3285,6 @@ verify_tables_data (VerifyContext *ctx)
        verify_generic_param_constraint_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);
-}
-
 static void
 init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
 {
@@ -3095,7 +3294,6 @@ init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
        ctx->valid = 1;
        ctx->size = image->raw_data_len;
        ctx->data = image->raw_data;
-       ctx->is_corlib = mono_verifier_is_corlib (image);       
 }
 
 static gboolean
@@ -3160,6 +3358,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)
 {
@@ -3175,6 +3385,153 @@ 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, 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_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_blog (&ctx, offset);
+       return cleanup_context (&ctx, error_list);
+}
+
 #else
 gboolean
 mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
@@ -3193,4 +3550,53 @@ 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, GSList **error_list)
+{
+       return TRUE;
+}
+
+gboolean
+mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSList **error_list)
+{
+       return TRUE;
+}
+
 #endif /* DISABLE_VERIFIER */