Merge branch 'master' of github.com:mono/mono
[mono.git] / mono / metadata / metadata-verify.c
index 0f99fbca38a60cf4d9fbab63818e54e51cb7a077..dffab37255929bbc90acd6d027641fef6bc0e84e 100644 (file)
@@ -23,6 +23,7 @@
 #include <mono/metadata/cil-coff.h>
 #include <mono/metadata/attrdefs.h>
 #include <mono/utils/strenc.h>
+#include <mono/utils/mono-error-internals.h>
 #include <string.h>
 //#include <signal.h>
 #include <ctype.h>
@@ -780,8 +781,8 @@ verify_metadata_header (VerifyContext *ctx)
        ptr = ctx->data + offset; //move to streams header 
 
        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"));
+       if (section_count < 2)
+               ADD_ERROR (ctx, g_strdup_printf ("Metadata root section must have at least 2 streams (#~ and #GUID)"));
 
        ptr += 4;
        offset += 4;
@@ -843,9 +844,6 @@ verify_metadata_header (VerifyContext *ctx)
                ADD_ERROR (ctx, g_strdup_printf ("Metadata #~ stream missing"));
        if (!ctx->metadata_streams [GUID_STREAM].size)
                ADD_ERROR (ctx, g_strdup_printf ("Metadata guid stream missing"));
-       if (!ctx->metadata_streams [BLOB_STREAM].size)
-               ADD_ERROR (ctx, g_strdup_printf ("Metadata blob stream missing"));
-               
 }
 
 static void
@@ -858,11 +856,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)
@@ -1121,7 +1117,7 @@ decode_value (const char *_ptr, unsigned available, unsigned *value, unsigned *s
 }
 
 static gboolean
-decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const char **first_byte)
+decode_signature_header (VerifyContext *ctx, guint32 offset, guint32 *size, const char **first_byte)
 {
        MonoStreamHeader blob = ctx->image->heap_blob;
        guint32 value, enc_size;
@@ -1132,14 +1128,16 @@ decode_signature_header (VerifyContext *ctx, guint32 offset, int *size, const ch
        if (!decode_value (blob.data + offset, blob.size - offset, &value, &enc_size))
                return FALSE;
 
-       if (offset + enc_size + value < offset)
+       if (CHECK_ADD4_OVERFLOW_UN (offset, enc_size))
                return FALSE;
 
-       if (offset + enc_size + value > blob.size)
+       offset += enc_size;
+
+       if (ADD_IS_GREATER_OR_OVF (offset, value, blob.size))
                return FALSE;
 
        *size = value;
-       *first_byte = blob.data + offset + enc_size;
+       *first_byte = blob.data + offset;
        return TRUE;
 }
 
@@ -1267,6 +1265,12 @@ parse_generic_inst (VerifyContext *ctx, const char **_ptr, const char *end)
        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"));
 
@@ -1581,7 +1585,7 @@ parse_locals_signature (VerifyContext *ctx, const char **_ptr, const char *end)
 static gboolean
 is_valid_field_signature (VerifyContext *ctx, guint32 offset)
 {
-       int size = 0;
+       guint32 size = 0;
        unsigned signature = 0;
        const char *ptr = NULL, *end;
 
@@ -1602,7 +1606,7 @@ is_valid_field_signature (VerifyContext *ctx, guint32 offset)
 static gboolean
 is_valid_method_signature (VerifyContext *ctx, guint32 offset)
 {
-       int size = 0;
+       guint32 size = 0;
        const char *ptr = NULL, *end;
 
        if (!decode_signature_header (ctx, offset, &size, &ptr))
@@ -1615,7 +1619,7 @@ is_valid_method_signature (VerifyContext *ctx, guint32 offset)
 static gboolean
 is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
 {
-       int size = 0;
+       guint32 size = 0;
        unsigned signature = 0;
        const char *ptr = NULL, *end;
 
@@ -1634,9 +1638,9 @@ is_valid_method_or_field_signature (VerifyContext *ctx, guint32 offset)
 }
 
 static gboolean
-is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
+is_valid_cattr_blob (VerifyContext *ctx, guint32 offset)
 {
-       int size = 0;
+       guint32 size = 0;
        unsigned prolog = 0;
        const char *ptr = NULL, *end;
 
@@ -1652,7 +1656,324 @@ is_vald_cattr_blob (VerifyContext *ctx, guint32 offset)
 
        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 {
+                       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;
 }
 
@@ -1675,7 +1996,7 @@ is_valid_permission_set (VerifyContext *ctx, guint32 offset)
 static gboolean
 is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
 {
-       int size = 0;
+       guint32 size = 0;
        unsigned signature = 0;
        const char *ptr = NULL, *end;
 
@@ -1689,13 +2010,18 @@ is_valid_standalonesig_blob (VerifyContext *ctx, guint32 offset)
        --ptr;
        if (signature == 0x07)
                return parse_locals_signature (ctx, &ptr, end);
+
+       /*F# and managed C++ produce standalonesig for fields even thou the spec doesn't mention it.*/
+       if (signature == 0x06)
+               return parse_field (ctx, &ptr, end);
+
        return parse_method_signature (ctx, &ptr, end, TRUE, TRUE);
 }
 
 static gboolean
 is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
 {
-       int size = 0;
+       guint32 size = 0;
        const char *ptr = NULL, *end;
 
        if (!decode_signature_header (ctx, offset, &size, &ptr))
@@ -1708,11 +2034,10 @@ is_valid_property_sig_blob (VerifyContext *ctx, guint32 offset)
 static gboolean
 is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
 {
-       int size = 0;
+       guint32 size = 0;
        const char *ptr = NULL, *end;
        unsigned type = 0;
        
-
        if (!decode_signature_header (ctx, offset, &size, &ptr))
                FAIL (ctx, g_strdup ("TypeSpec: Could not decode signature header"));
        end = ptr + size;
@@ -1740,7 +2065,7 @@ is_valid_typespec_blob (VerifyContext *ctx, guint32 offset)
 static gboolean
 is_valid_methodspec_blob (VerifyContext *ctx, guint32 offset)
 {
-       int size = 0;
+       guint32 size = 0;
        const char *ptr = NULL, *end;
        unsigned type = 0;
        unsigned count = 0, i;
@@ -1857,13 +2182,15 @@ is_valid_constant (VerifyContext *ctx, guint32 type, guint32 offset)
 #define SECTION_HEADER_INVALID_FLAGS 0x3E
 
 static gboolean
-is_valid_method_header (VerifyContext *ctx, guint32 rva)
+is_valid_method_header (VerifyContext *ctx, guint32 rva, guint32 *locals_token)
 {
        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;
 
+       *locals_token = 0;
+
        if (offset == INVALID_ADDRESS)
                FAIL (ctx, g_strdup ("MethodHeader: Invalid RVA"));
 
@@ -1906,6 +2233,7 @@ is_valid_method_header (VerifyContext *ctx, guint32 rva)
                        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));
+               *locals_token = local_vars_tok & 0xFFFFFF;
        }
 
        if (fat_header & FAT_HEADER_INVALID_FLAGS)
@@ -2100,8 +2428,10 @@ verify_typedef_table_full (VerifyContext *ctx)
                mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
 
                if (i == 0) {
-                       if (data [MONO_TYPEDEF_EXTENDS] != 0)
+                       /*XXX it's ok if <module> extends object, or anything at all, actually. */
+                       /*if (data [MONO_TYPEDEF_EXTENDS] != 0)
                                ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
+                       */
                        continue;
                }
 
@@ -2207,8 +2537,8 @@ verify_field_table_full (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))
+/*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)
 {
@@ -2346,7 +2676,7 @@ static void
 verify_method_table_full (VerifyContext *ctx)
 {
        MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
-       guint32 data [MONO_METHOD_SIZE], rva;
+       guint32 data [MONO_METHOD_SIZE], rva, locals_token;
        int i;
 
        for (i = 0; i < table->rows; ++i) {
@@ -2356,7 +2686,7 @@ verify_method_table_full (VerifyContext *ctx)
                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))
+               if (rva && !is_valid_method_header (ctx, rva, &locals_token))
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
        }
 }
@@ -2545,14 +2875,36 @@ static void
 verify_cattr_table_full (VerifyContext *ctx)
 {
        MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
-       guint32 data [MONO_CUSTOM_ATTR_SIZE];
+       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_vald_cattr_blob (ctx, data [MONO_CUSTOM_ATTR_VALUE]))
+               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]));
        }
 }
 
@@ -2913,7 +3265,7 @@ verify_typespec_table_full (VerifyContext *ctx)
        ctx->token = 0;
 }
 
-#define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10))
+#define INVALID_IMPLMAP_FLAGS_BITS ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13))
 static void
 verify_implmap_table (VerifyContext *ctx)
 {
@@ -3330,11 +3682,15 @@ verify_typeref_table_global_constraints (VerifyContext *ctx)
 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_global_constraints_full (VerifyContext *ctx)
+{
+       verify_typeref_table_global_constraints (ctx);
+}
+
 static void
 verify_tables_data (VerifyContext *ctx)
 {
@@ -3430,11 +3786,11 @@ verify_tables_data (VerifyContext *ctx)
 }
 
 static void
-init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
+init_verify_context (VerifyContext *ctx, MonoImage *image, gboolean report_error)
 {
        memset (ctx, 0, sizeof (VerifyContext));
        ctx->image = image;
-       ctx->report_error = error_list != NULL;
+       ctx->report_error = report_error;
        ctx->report_warning = FALSE; //export this setting in the API
        ctx->valid = 1;
        ctx->size = image->raw_data_len;
@@ -3452,6 +3808,18 @@ cleanup_context (VerifyContext *ctx, GSList **error_list)
        return ctx->valid;      
 }
 
+static gboolean
+cleanup_context_checked (VerifyContext *ctx, MonoError *error)
+{
+       g_free (ctx->sections);
+       if (ctx->errors) {
+               MonoVerifyInfo *info = ctx->errors->data;
+               mono_error_set_bad_image (error, ctx->image, "%s", info->message);
+               mono_free_verify_list (ctx->errors);
+       }
+       return ctx->valid;
+}
+
 gboolean
 mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
 {
@@ -3460,7 +3828,7 @@ mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_PE;
 
        verify_msdos_header (&ctx);
@@ -3490,7 +3858,7 @@ mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_CLI;
 
        verify_cli_header (&ctx);
@@ -3523,7 +3891,7 @@ mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_TABLES;
 
        verify_tables_data (&ctx);
@@ -3543,7 +3911,7 @@ mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_TABLES;
 
        verify_typedef_table_full (&ctx);
@@ -3567,6 +3935,8 @@ mono_verifier_verify_full_table_data (MonoImage *image, GSList **error_list)
        verify_typespec_table_full (&ctx);
        CHECK_STATE ();
        verify_method_spec_table_full (&ctx);
+       CHECK_STATE ();
+       verify_tables_data_global_constraints_full (&ctx);
 
 cleanup:
        return cleanup_context (&ctx, error_list);
@@ -3580,7 +3950,7 @@ mono_verifier_verify_field_signature (MonoImage *image, guint32 offset, GSList *
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_TABLES;
 
        is_valid_field_signature (&ctx, offset);
@@ -3591,30 +3961,39 @@ gboolean
 mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **error_list)
 {
        VerifyContext ctx;
+       guint32 locals_token;
 
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_TABLES;
 
-       is_valid_method_header (&ctx, offset);
+       is_valid_method_header (&ctx, offset, &locals_token);
+       if (locals_token) {
+               guint32 sig_offset = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_STANDALONESIG], locals_token - 1, MONO_STAND_ALONE_SIGNATURE);
+               is_valid_standalonesig_blob (&ctx, sig_offset);
+       }
+
        return cleanup_context (&ctx, error_list);
 }
 
 gboolean
-mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
+mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
 {
        VerifyContext ctx;
 
+       mono_error_init (error);
+
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, TRUE);
        ctx.stage = STAGE_TABLES;
 
        is_valid_method_signature (&ctx, offset);
-       return cleanup_context (&ctx, error_list);
+       /*XXX This returns a bad image exception, it might be the case that the right exception is method load.*/
+       return cleanup_context_checked (&ctx, error);
 }
 
 gboolean
@@ -3625,7 +4004,7 @@ mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSLi
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_TABLES;
 
        is_valid_method_or_field_signature (&ctx, offset);
@@ -3640,7 +4019,7 @@ mono_verifier_verify_standalone_signature (MonoImage *image, guint32 offset, GSL
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_TABLES;
 
        is_valid_standalonesig_blob (&ctx, offset);
@@ -3655,7 +4034,7 @@ mono_verifier_verify_typespec_signature (MonoImage *image, guint32 offset, guint
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_TABLES;
        ctx.token = token;
 
@@ -3671,7 +4050,7 @@ mono_verifier_verify_methodspec_signature (MonoImage *image, guint32 offset, GSL
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_TABLES;
 
        is_valid_methodspec_blob (&ctx, offset);
@@ -3707,7 +4086,7 @@ mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList
        if (!mono_verifier_is_enabled_for_image (image))
                return TRUE;
 
-       init_verify_context (&ctx, image, error_list);
+       init_verify_context (&ctx, image, error_list != NULL);
        ctx.stage = STAGE_TABLES;
 
        verify_user_string (&ctx, offset);
@@ -3715,6 +4094,38 @@ mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList
        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 != NULL);
+       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 != NULL);
+       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)
 {
@@ -3781,8 +4192,9 @@ mono_verifier_verify_method_header (MonoImage *image, guint32 offset, GSList **e
 }
 
 gboolean
-mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, GSList **error_list)
+mono_verifier_verify_method_signature (MonoImage *image, guint32 offset, MonoError *error)
 {
+       mono_error_init (error);
        return TRUE;
 }
 
@@ -3816,6 +4228,18 @@ mono_verifier_verify_string_signature (MonoImage *image, guint32 offset, GSList
        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)
 {