Merge pull request #1122 from PoppermostProductions/master
[mono.git] / mono / metadata / verify.c
index e4b48e7b26f1806df68d01a79c3e92a3a8070673..b23a830dbcba02f8f2613f96c052ac10499044f9 100644 (file)
@@ -306,8 +306,8 @@ enum {
 
 #ifdef ENABLE_VERIFIER_STATS
 
-#define MEM_ALLOC(amt) do { allocated_memory += (amt); working_set += (amt); } while (0)
-#define MEM_FREE(amt) do { working_set -= (amt); } while (0)
+#define _MEM_ALLOC(amt) do { allocated_memory += (amt); working_set += (amt); } while (0)
+#define _MEM_FREE(amt) do { working_set -= (amt); } while (0)
 
 static int allocated_memory;
 static int working_set;
@@ -338,8 +338,8 @@ init_verifier_stats (void)
 
 #else
 
-#define MEM_ALLOC(amt) do {} while (0)
-#define MEM_FREE(amt) do { } while (0)
+#define _MEM_ALLOC(amt) do {} while (0)
+#define _MEM_FREE(amt) do { } while (0)
 
 #define finish_collect_stats()
 #define init_verifier_stats()
@@ -378,7 +378,7 @@ static MonoType *
 mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
 {
        MonoType *res = g_new0 (MonoType, 1);
-       MEM_ALLOC (sizeof (MonoType));
+       _MEM_ALLOC (sizeof (MonoType));
 
        //FIXME use mono_method_get_signature_full
        res->data.method = mono_method_signature (method);
@@ -869,7 +869,7 @@ mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
        if (!is_valid_type_in_context (ctx, type)) {
                char *str = mono_type_full_name (type);
                ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
-                       type->type == MONO_TYPE_VAR ? "!" : "!!",
+                       str [0] == '!' ? "" : type->type == MONO_TYPE_VAR ? "!" : "!!",
                        str,
                        type->type == MONO_TYPE_VAR ? "class" : "method",
                        ctx->ip_offset),
@@ -1500,13 +1500,13 @@ ensure_stack_size (ILCodeDesc *stack, int required)
        g_assert (new_size >= required);
 
        tmp = g_new0 (ILStackDesc, new_size);
-       MEM_ALLOC (sizeof (ILStackDesc) * new_size);
+       _MEM_ALLOC (sizeof (ILStackDesc) * new_size);
 
        if (stack->stack) {
                if (stack->size)
                        memcpy (tmp, stack->stack, stack->size * sizeof (ILStackDesc));
                g_free (stack->stack);
-               MEM_FREE (sizeof (ILStackDesc) * stack->max_size);
+               _MEM_FREE (sizeof (ILStackDesc) * stack->max_size);
        }
 
        stack->stack = tmp;
@@ -2088,6 +2088,28 @@ get_icollection_class (void)
                return generic_icollection_class;
 }
 
+static MonoClass*
+get_ireadonlylist_class (void)
+{
+       static MonoClass* generic_ireadonlylist_class = NULL;
+
+       if (generic_ireadonlylist_class == NULL)
+               generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
+                       "System.Collections.Generic", "IReadOnlyList`1");
+       return generic_ireadonlylist_class;
+}
+
+static MonoClass*
+get_ireadonlycollection_class (void)
+{
+       static MonoClass* generic_ireadonlycollection_class = NULL;
+
+       if (generic_ireadonlycollection_class == NULL)
+               generic_ireadonlycollection_class = mono_class_from_name (mono_defaults.corlib,
+                       "System.Collections.Generic", "IReadOnlyCollection`1");
+       return generic_ireadonlycollection_class;
+}
+
 static MonoClass*
 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
 {
@@ -2118,6 +2140,9 @@ verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate)
 
        if (mono_class_has_variant_generic_params (target)) {
                if (MONO_CLASS_IS_INTERFACE (target)) {
+                       if (MONO_CLASS_IS_INTERFACE (candidate) && mono_class_is_variant_compatible (target, candidate, TRUE))
+                               return TRUE;
+
                        if (candidate->rank == 1) {
                                if (verifier_inflate_and_check_compat (target, mono_defaults.generic_ilist_class, candidate->element_class))
                                        return TRUE;
@@ -2125,6 +2150,10 @@ verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate)
                                        return TRUE;
                                if (verifier_inflate_and_check_compat (target, get_ienumerable_class (), candidate->element_class))
                                        return TRUE;
+                               if (verifier_inflate_and_check_compat (target, get_ireadonlylist_class (), candidate->element_class))
+                                       return TRUE;
+                               if (verifier_inflate_and_check_compat (target, get_ireadonlycollection_class (), candidate->element_class))
+                                       return TRUE;
                        } else {
                                MonoError error;
                                int i;
@@ -3165,14 +3194,14 @@ do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual)
                ILStackDesc copy;
 
                if (mono_method_is_constructor (method) && !method->klass->valuetype) {
-                       if (!mono_method_is_constructor (ctx->method))
+                       if (IS_STRICT_MODE (ctx) && !mono_method_is_constructor (ctx->method))
                                CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
-                       if (method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
+                       if (IS_STRICT_MODE (ctx) && method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
                                CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor of a type different from this or super at 0x%04x", ctx->ip_offset));
 
                        ctx->super_ctor_called = TRUE;
                        value = stack_pop_safe (ctx);
-                       if ((value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
+                       if (IS_STRICT_MODE (ctx) && (value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
                                CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
                } else {
                        value = stack_pop (ctx);
@@ -3190,9 +3219,10 @@ do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual)
                if (constrained && virtual) {
                        if (!stack_slot_is_managed_pointer (value))
                                CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
-                       if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), ctx->constrained_type, TRUE))
+                       if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), mono_type_get_underlying_type (ctx->constrained_type), TRUE))
                                CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
                        copy.stype |= BOXED_MASK;
+                       copy.type = ctx->constrained_type;
                } else {
                        if (stack_slot_is_managed_pointer (value) && !mono_class_from_mono_type (value->type)->valuetype)
                                CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a reference type using a managed pointer to the this arg at 0x%04x", ctx->ip_offset));
@@ -4500,7 +4530,7 @@ static void
 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external) 
 {
        MonoError error;
-       int i, j, k;
+       int i, j;
        stack_init (ctx, to);
 
        if (start) {
@@ -4544,6 +4574,14 @@ merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean sta
                        continue;
                }
 
+               /*Both slots are the same boxed valuetype. Simply copy it.*/
+               if (stack_slot_is_boxed_value (old_slot) && 
+                       stack_slot_is_boxed_value (new_slot) &&
+                       mono_metadata_type_equal (old_type, new_type)) {
+                       copy_stack_value (new_slot, old_slot);
+                       continue;
+               }
+
                if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
                        char *old_name = stack_slot_full_name (old_slot); 
                        char *new_name = stack_slot_full_name (new_slot);
@@ -4575,11 +4613,36 @@ merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean sta
                                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)) {
+                       mono_class_setup_interfaces (new_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;
+                       }
+
+                       /* if old class is an interface that new class implements */
+                       if (old_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                               if (verifier_class_is_assignable_from (old_class, new_class)) {
+                                       match_class = old_class;
+                                       goto match_found;       
+                               }
+                               for (j = 0; j < old_class->interface_count; ++j) {
+                                       if (verifier_class_is_assignable_from (old_class->interfaces [j], new_class)) {
                                                match_class = old_class->interfaces [j];
-                                               goto match_found;
+                                               goto match_found;       
+                                       }
+                               }
+                       }
+
+                       if (new_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                               if (verifier_class_is_assignable_from (new_class, old_class)) {
+                                       match_class = new_class;
+                                       goto match_found;       
+                               }
+                               for (j = 0; j < new_class->interface_count; ++j) {
+                                       if (verifier_class_is_assignable_from (new_class->interfaces [j], old_class)) {
+                                               match_class = new_class->interfaces [j];
+                                               goto match_found;       
                                        }
                                }
                        }
@@ -4788,19 +4851,19 @@ mono_method_verify (MonoMethod *method, int level)
 
        ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
        ctx.code_size = ctx.header->code_size;
-       MEM_ALLOC (sizeof (ILCodeDesc) * ctx.header->code_size);
+       _MEM_ALLOC (sizeof (ILCodeDesc) * ctx.header->code_size);
 
        memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
 
        ctx.num_locals = ctx.header->num_locals;
        ctx.locals = g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);
-       MEM_ALLOC (sizeof (MonoType*) * ctx.header->num_locals);
+       _MEM_ALLOC (sizeof (MonoType*) * ctx.header->num_locals);
 
        if (ctx.num_locals > 0 && !ctx.header->init_locals)
                CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));
 
        ctx.params = g_new (MonoType*, ctx.max_args);
-       MEM_ALLOC (sizeof (MonoType*) * ctx.max_args);
+       _MEM_ALLOC (sizeof (MonoType*) * ctx.max_args);
 
        if (ctx.signature->hasthis)
                ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
@@ -4916,7 +4979,9 @@ mono_method_verify (MonoMethod *method, int level)
                                ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
                                break;
                        }
-               
+                       if (!mono_type_is_valid_in_context (&ctx, &clause->data.catch_class->byval_arg))
+                               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) {
@@ -4925,6 +4990,9 @@ mono_method_verify (MonoMethod *method, int level)
                }
        }
 
+       if (!ctx.valid)
+               goto cleanup;
+
        original_bb = bb = mono_basic_block_split (method, &error);
        if (!mono_error_ok (&error)) {
                ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (&error)));
@@ -4935,7 +5003,7 @@ mono_method_verify (MonoMethod *method, int level)
 
        while (ip < end && ctx.valid) {
                int op_size;
-               ip_offset = ip - code_start;
+               ip_offset = (guint) (ip - code_start);
                {
                        const unsigned char *ip_copy = ip;
                        int op;
@@ -4966,7 +5034,7 @@ mono_method_verify (MonoMethod *method, int level)
                        }
                }
 
-               ctx.ip_offset = ip_offset = ip - code_start;
+               ctx.ip_offset = ip_offset =  (guint) (ip - code_start);
 
                /*We need to check against fallthrou in and out of protected blocks.
                 * For fallout we check the once a protected block ends, if the start flag is not set.
@@ -5970,7 +6038,7 @@ gboolean
 mono_verifier_is_class_full_trust (MonoClass *klass)
 {
        /* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
-       gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
+       gboolean trusted_location = !mono_security_core_clr_enabled () ?
                (klass->image->assembly && klass->image->assembly->in_gac) : mono_security_core_clr_is_platform_image (klass->image);
 
        if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
@@ -6179,6 +6247,9 @@ verify_generic_parameters (MonoClass *class)
                        MonoClass *ctr = *constraints;
                        MonoType *constraint_type = &ctr->byval_arg;
 
+                       if (!mono_class_can_access_class (class, ctr))
+                               goto fail;
+
                        if (!mono_type_is_valid_type_in_context (constraint_type, &gc->context))
                                goto fail;