2009-07-22 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / metadata / metadata-verify.c
index 6d7362e6c88f3c2b7cc0cdb541dff47ac3588436..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,
@@ -1486,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);
 }
 
@@ -1510,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));
        }
@@ -1678,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);
 }
 
@@ -1718,7 +1742,7 @@ is_valid_methodspec_blog (VerifyContext *ctx, guint32 offset)
 }
 
 static gboolean
-is_valid_blob_object (VerifyContext *ctx, guint32 offset, int minsize)
+is_valid_blob_object (VerifyContext *ctx, guint32 offset, guint32 minsize)
 {
        OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
        guint32 entry_size, bytes;
@@ -1729,13 +1753,12 @@ is_valid_blob_object (VerifyContext *ctx, guint32 offset, int minsize)
        if (!decode_value (ctx->data + offset + blob.offset, blob.size - blob.offset, &entry_size, &bytes))
                return FALSE;
 
-       if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
+       if (entry_size < minsize)
                return FALSE;
-       entry_size += bytes;
 
-       if (CHECK_ADD4_OVERFLOW_UN (entry_size, minsize))
+       if (CHECK_ADD4_OVERFLOW_UN (entry_size, bytes))
                return FALSE;
-       entry_size += minsize;
+       entry_size += bytes;
 
        return !ADD_IS_GREATER_OR_OVF (offset, entry_size, blob.size);
 }
@@ -1896,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));
@@ -3463,6 +3487,51 @@ mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSLi
        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)
@@ -3512,4 +3581,22 @@ mono_verifier_verify_memberref_signature (MonoImage *image, guint32 offset, GSLi
        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 */