2010-01-18 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / verify.c
index 5669389bd43b27a388b6d7fbee7e55b057e9e6e0..3ca8b590296fb2514529544f3ffeb260033af28b 100644 (file)
@@ -409,10 +409,13 @@ mono_class_has_default_constructor (MonoClass *klass)
        int i;
 
        mono_class_setup_methods (klass);
+       if (klass->exception_type)
+               return FALSE;
 
        for (i = 0; i < klass->method.count; ++i) {
                method = klass->methods [i];
                if (mono_method_is_constructor (method) &&
+                       mono_method_signature (method) &&
                        mono_method_signature (method)->param_count == 0 &&
                        (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC)
                        return TRUE;
@@ -420,23 +423,6 @@ mono_class_has_default_constructor (MonoClass *klass)
        return FALSE;
 }
 
-static gboolean
-mono_class_interface_implements_interface (MonoClass *candidate, MonoClass *iface)
-{
-       int i;
-       do {
-               if (candidate == iface)
-                       return TRUE;
-               mono_class_setup_interfaces (candidate);
-               for (i = 0; i < candidate->interface_count; ++i) {
-                       if (candidate->interfaces [i] == iface || mono_class_interface_implements_interface (candidate->interfaces [i], iface))
-                               return TRUE;
-               }
-               candidate = candidate->parent;
-       } while (candidate);
-       return FALSE;
-}
-
 /*
  * Verify if @type is valid for the given @ctx verification context.
  * this function checks for VAR and MVAR types that are invalid under the current verifier,
@@ -488,45 +474,7 @@ verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *c
        }
        return result;
 }
-/*
- * Test if @candidate is a subtype of @target using the minimal possible information
- * TODO move the code for non finished TypeBuilders to here.
- */
-static gboolean
-mono_class_is_constraint_compatible (MonoClass *candidate, MonoClass *target)
-{
-       if (candidate == target)
-               return TRUE;
-       if (target == mono_defaults.object_class)
-                       return TRUE;
-
-       //setup_supertypes don't mono_class_init anything
-       mono_class_setup_supertypes (candidate);
-       mono_class_setup_supertypes (target);
-
-       if (mono_class_has_parent (candidate, target))
-               return TRUE;
 
-       //if target is not a supertype it must be an interface
-       if (!MONO_CLASS_IS_INTERFACE (target))
-                       return FALSE;
-
-       if (candidate->image->dynamic && !candidate->wastypebuilder) {
-               MonoReflectionTypeBuilder *tb = candidate->reflection_info;
-               int j;
-               if (tb->interfaces) {
-                       for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
-                               MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
-                               MonoClass *ifaceClass = mono_class_from_mono_type (iface->type);
-                               if (mono_class_is_constraint_compatible (ifaceClass, target)) {
-                                       return TRUE;
-                               }
-                       }
-               }
-               return FALSE;
-       }
-       return mono_class_interface_implements_interface (candidate, target);
-}
 
 static gboolean
 is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
@@ -582,7 +530,7 @@ is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *co
                        ctr = mono_class_from_mono_type (inflated);
                        mono_metadata_free_type (inflated);
 
-                       if (!mono_class_is_constraint_compatible (paramClass, ctr))
+                       if (!mono_class_is_assignable_from_slow (ctr, paramClass))
                                return FALSE;
                }
        }
@@ -2389,9 +2337,7 @@ handle_enum:
                }
 
        default:
-               VERIFIER_DEBUG ( printf ("unknown type %02x in eval stack type\n", type->type); );
-               g_assert_not_reached ();
-               return 0;
+               return TYPE_INV;
        }
 }
 
@@ -2498,6 +2444,11 @@ init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *cod
                return;
        }
 
+       if (!ctx->max_stack) {
+               ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack overflow at 0x%04x", ctx->ip_offset));
+               return;
+       }
+
        stack_init (ctx, code);
        set_stack_value (ctx, code->stack, type, FALSE);
        ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
@@ -2960,6 +2911,20 @@ verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackD
        invoke = mono_get_delegate_invoke (delegate);
        method = funptr->method;
 
+       if (!method || !mono_method_signature (method)) {
+               char *name = mono_type_get_full_name (delegate);
+               ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid method on stack to create delegate %s construction at 0x%04x", name, ctx->ip_offset));
+               g_free (name);
+               return;
+       }
+
+       if (!invoke || !mono_method_signature (invoke)) {
+               char *name = mono_type_get_full_name (delegate);
+               ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Delegate type %s with bad Invoke method at 0x%04x", name, ctx->ip_offset));
+               g_free (name);
+               return;
+       }
+
        is_static_ldftn = (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) && method->flags & METHOD_ATTRIBUTE_STATIC;
 
        if (is_static_ldftn)
@@ -3380,6 +3345,13 @@ do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual)
        if (!(sig = mono_method_get_signature_full (method, ctx->image, method_token, ctx->generic_context)))
                sig = mono_method_get_signature (method, ctx->image, method_token);
 
+       if (!sig) {
+               char *name = mono_type_get_full_name (method->klass);
+               ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve signature of %s:%s at 0x%04x", name, method->name, ctx->ip_offset));
+               g_free (name);
+               return;
+       }
+
        param_count = sig->param_count + sig->hasthis;
        if (!check_underflow (ctx, param_count))
                return;
@@ -3962,6 +3934,11 @@ do_newobj (VerifyContext *ctx, int token)
 
        //FIXME use mono_method_get_signature_full
        sig = mono_method_signature (method);
+       if (!sig) {
+               ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature to newobj at 0x%04x", ctx->ip_offset));
+               return;
+       }
+
        if (!check_underflow (ctx, sig->param_count))
                return;
 
@@ -4565,12 +4542,15 @@ do_localloc (VerifyContext *ctx)
 static void
 do_ldstr (VerifyContext *ctx, guint32 token)
 {
+       GSList *error = NULL;
        if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
                ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
                return;
        }
 
-       if (!ctx->image->dynamic && mono_metadata_token_index (token) >= ctx->image->heap_us.size) {
+       if (!ctx->image->dynamic && !mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), &error)) {
+               if (error)
+                       ctx->list = g_slist_concat (ctx->list, error);
                ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
                return;
        }
@@ -4670,6 +4650,7 @@ do_ckfinite (VerifyContext *ctx)
 static void
 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external) 
 {
+       MonoError error;
        int i, j, k;
        stack_init (ctx, to);
 
@@ -4736,7 +4717,12 @@ merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean sta
                                }
                        }
 
-                       mono_class_setup_interfaces (old_class);
+                       mono_class_setup_interfaces (old_class, &error);
+                       if (!mono_error_ok (&error)) {
+                               CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot merge stacks due to a TypeLoadException %s at 0x%04x", mono_error_get_message (&error), ctx->ip_offset));
+                               mono_error_cleanup (&error);
+                               goto end_verify;
+                       }
                        for (j = 0; j < old_class->interface_count; ++j) {
                                for (k = 0; k < new_class->interface_count; ++k) {
                                        if (mono_metadata_type_equal (&old_class->interfaces [j]->byval_arg, &new_class->interfaces [k]->byval_arg)) {
@@ -4980,11 +4966,25 @@ mono_method_verify (MonoMethod *method, int level)
        for (i = 0; i < ctx.num_locals; ++i) {
                if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
                        break;
+               if (get_stack_type (ctx.locals [i]) == TYPE_INV) {
+                       char *name = mono_type_full_name (ctx.locals [i]);
+                       ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %i of type %s", i, name));
+                       g_free (name);
+                       break;
+               }
+               
        }
 
        for (i = 0; i < ctx.max_args; ++i) {
                if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
                        break;
+
+               if (get_stack_type (ctx.params [i]) == TYPE_INV) {
+                       char *name = mono_type_full_name (ctx.params [i]);
+                       ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %i of type %s", i, name));
+                       g_free (name);
+                       break;
+               }
        }
 
        if (!ctx.valid)
@@ -4994,21 +4994,24 @@ mono_method_verify (MonoMethod *method, int level)
                MonoExceptionClause *clause = ctx.header->clauses + i;
                VERIFIER_DEBUG (printf ("clause try %x len %x filter at %x handler at %x len %x\n", clause->try_offset, clause->try_len, clause->data.filter_offset, clause->handler_offset, clause->handler_len); );
 
-               if (clause->try_offset > ctx.code_size || clause->try_offset + clause->try_len > ctx.code_size)
+               if (clause->try_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, ctx.code_size))
                        ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
 
                if (clause->try_len <= 0)
                        ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
 
-               if (clause->handler_offset > ctx.code_size || clause->handler_offset + clause->handler_len > ctx.code_size)
+               if (clause->handler_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->handler_offset, clause->handler_len, ctx.code_size))
                        ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));
 
                if (clause->handler_len <= 0)
-                       ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
+                       ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause len <= 0 at 0x%04x", clause->try_offset));
 
-               if (clause->try_offset < clause->handler_offset && clause->try_offset + clause->try_len > HANDLER_START (clause))
+               if (clause->try_offset < clause->handler_offset && ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, HANDLER_START (clause)))
                        ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
 
+               if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->data.filter_offset > ctx.code_size)
+                       ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause out of bounds at 0x%04x", clause->try_offset));
+
                for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
                        verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
 
@@ -5022,6 +5025,11 @@ mono_method_verify (MonoMethod *method, int level)
                        ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
 
                if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
+                       if (!clause->data.catch_class) {
+                               ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
+                               break;
+                       }
+               
                        init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
                }
                else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
@@ -5315,8 +5323,8 @@ mono_method_verify (MonoMethod *method, int level)
                        ip += 2;
                        break;
 
-               /* FIXME: warn/error instead? */
                case CEE_UNUSED99:
+                       ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
                        ++ip;
                        break; 
 
@@ -5507,7 +5515,8 @@ mono_method_verify (MonoMethod *method, int level)
 
                case CEE_UNUSED58:
                case CEE_UNUSED1:
-                       ++ip; /* warn, error ? */
+                       ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
+                       ++ip;
                        break;
 
                case CEE_UNBOX:
@@ -5761,10 +5770,6 @@ mono_method_verify (MonoMethod *method, int level)
                                ip += 5;
                                break;
 
-                       case CEE_UNUSED56:
-                               ++ip;
-                               break;
-
                        case CEE_LDARG:
                        case CEE_LDARGA:
                                code_bounds_check (3);
@@ -5784,7 +5789,11 @@ mono_method_verify (MonoMethod *method, int level)
                                ++ip;
                                break;
 
+                       case CEE_UNUSED56:
                        case CEE_UNUSED57:
+                       case CEE_UNUSED70:
+                       case CEE_UNUSED:
+                               ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
                                ++ip;
                                break;
                        case CEE_ENDFILTER:
@@ -5852,9 +5861,6 @@ mono_method_verify (MonoMethod *method, int level)
                                start = 1;
                                ++ip;
                                break;
-                       case CEE_UNUSED:
-                               ++ip;
-                               break;
 
                        case CEE_SIZEOF:
                                code_bounds_check (5);
@@ -6158,7 +6164,7 @@ verify_valuetype_layout_with_target (MonoClass *class, MonoClass *target_class)
 
                field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type (field->type));
 
-               if (field_class == target_class || !verify_valuetype_layout_with_target (field_class, target_class))
+               if (field_class == target_class || class == field_class || !verify_valuetype_layout_with_target (field_class, target_class))
                        return FALSE;
        }
 
@@ -6185,6 +6191,14 @@ verify_valuetype_layout (MonoClass *class)
 gboolean
 mono_verifier_verify_class (MonoClass *class)
 {
+       /*Neither <Module>, object or ifaces have parent.*/
+       if (!class->parent &&
+               class != mono_defaults.object_class && 
+               !MONO_CLASS_IS_INTERFACE (class) &&
+               (!class->image->dynamic && class->type_token != 0x2000001)) /*<Module> is the first type in the assembly*/
+               return FALSE;
+       if (class->parent && MONO_CLASS_IS_INTERFACE (class->parent))
+               return FALSE;
        if (class->generic_container && (class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT)
                return FALSE;
        if (!verify_class_for_overlapping_reference_fields (class))