/*This flag helps solving a corner case of delegate verification in that you cannot have a "starg 0"
*on a method that creates a delegate for a non-final virtual method using ldftn*/
gboolean has_this_store;
+
+ guint32 prefix_set;
+ MonoType *constrained_type;
} VerifyContext;
static void
PREFIX_UNALIGNED = 1,
PREFIX_VOLATILE = 2,
PREFIX_TAIL = 4,
- PREFIX_ADDR_MASK = 3,
- PREFIX_FUNC_MASK = 4
+ PREFIX_CONSTRAINED = 8,
+ PREFIX_READONLY = 16
};
//////////////////////////////////////////////////////////////////
*
* Returns TRUE is @value is a managed mutability pointer.
*/
-static gboolean
+static G_GNUC_UNUSED gboolean
stack_slot_is_managed_mutability_pointer (ILStackDesc *value)
{
return (value->stype & CMMP_MASK) == CMMP_MASK;
code->flags |= IL_CODE_FLAG_WAS_TARGET;
}
-/* Generics validation stuff, should be moved to another metadata/? file */
-static gboolean
-mono_is_generic_type_compatible (MonoType *target, MonoType *candidate)
-{
- if (target->byref != candidate->byref)
- return FALSE;
-
-handle_enum:
- switch (target->type) {
- case MONO_TYPE_STRING:
- if (candidate->type == MONO_TYPE_STRING)
- return TRUE;
- return FALSE;
-
- case MONO_TYPE_CLASS:
- if (candidate->type != MONO_TYPE_CLASS)
- return FALSE;
-
- VERIFIER_DEBUG ( printf ("verifying type class %p %p\n", target->data.klass, candidate->data.klass); );
- return mono_class_is_assignable_from (target->data.klass, candidate->data.klass);
-
- case MONO_TYPE_OBJECT:
- return MONO_TYPE_IS_REFERENCE (candidate);
-
- case MONO_TYPE_SZARRAY:
- if (candidate->type != MONO_TYPE_SZARRAY)
- return FALSE;
- return mono_class_is_assignable_from (target->data.klass, candidate->data.klass);
-
- case MONO_TYPE_VALUETYPE:
- if (mono_type_is_enum_type (target)) {
- target = mono_type_get_underlying_type_any (target);
- goto handle_enum;
- } else {
- if (candidate->type != MONO_TYPE_VALUETYPE)
- return FALSE;
- return candidate->data.klass == target->data.klass;
- }
-
- case MONO_TYPE_ARRAY:
- if (candidate->type != MONO_TYPE_ARRAY)
- return FALSE;
- return is_array_type_compatible (target, candidate);
-
- default:
- VERIFIER_DEBUG ( printf ("unknown target type %d\n", target->type); );
- g_assert_not_reached ();
- }
-
- return FALSE;
-}
-
-
-static gboolean
-mono_is_generic_instance_compatible (MonoGenericClass *target, MonoGenericClass *candidate, MonoGenericClass *root_candidate) {
- MonoGenericContainer *container;
- int i;
-
- VERIFIER_DEBUG ( printf ("candidate container %p\n", candidate->container_class->generic_container); );
- if (target->container_class != candidate->container_class) {
- MonoType *param_class;
- MonoClass *cand_class;
- VERIFIER_DEBUG ( printf ("generic class != target\n"); );
- param_class = candidate->context.class_inst->type_argv [0];
- VERIFIER_DEBUG ( printf ("param 0 %d\n", param_class->type); );
- cand_class = candidate->container_class;
-
- /* We must check if it's an interface type*/
- if (MONO_CLASS_IS_INTERFACE (target->container_class)) {
- VERIFIER_DEBUG ( printf ("generic type is an interface\n"); );
-
- do {
- int iface_count = cand_class->interface_count;
- MonoClass **ifaces = cand_class->interfaces;
- int i;
- VERIFIER_DEBUG ( printf ("type has %d interfaces\n", iface_count); );
- for (i = 0; i< iface_count; ++i) {
- MonoClass *ifc = ifaces[i];
- VERIFIER_DEBUG ( printf ("analysing %s\n", ifc->name); );
- if (ifc->generic_class) {
- VERIFIER_DEBUG ( printf ("interface has generic info\n"); );
- }
- if (mono_is_generic_instance_compatible (target, ifc->generic_class, root_candidate)) {
- VERIFIER_DEBUG ( printf ("we got compatible stuff!\n"); );
- return TRUE;
- }
- }
-
- cand_class = cand_class->parent;
- } while (cand_class);
-
- VERIFIER_DEBUG ( printf ("don't implements an interface\n"); );
-
- } else {
- VERIFIER_DEBUG ( printf ("verifying upper classes\n"); );
-
- cand_class = cand_class->parent;
-
- while (cand_class) {
- VERIFIER_DEBUG ( printf ("verifying parent class name %s\n", cand_class->name); );
- if (cand_class->generic_class) {
- VERIFIER_DEBUG ( printf ("super type has generic context\n"); );
-
- /* TODO break loop if target->container_class == cand_class->generic_class->container_class */
- return mono_is_generic_instance_compatible (target, cand_class->generic_class, root_candidate);
- } else
- VERIFIER_DEBUG ( printf ("super class has no generic context\n"); );
- cand_class = cand_class->parent;
- }
- }
- return FALSE;
- }
-
- /* now we verify if the instantiations are compatible*/
- if (target->context.class_inst == candidate->context.class_inst) {
- VERIFIER_DEBUG ( printf ("generic types are compatible, both have the same instantiation\n"); );
- return TRUE;
- }
-
- if (target->context.class_inst->type_argc != candidate->context.class_inst->type_argc) {
- VERIFIER_DEBUG ( printf ("generic instantiations with different arg counts\n"); );
- return FALSE;
- }
-
- //verify if open instance -- none should be
-
- container = target->container_class->generic_container;
-
- for (i = 0; i < container->type_argc; ++i) {
- MonoGenericParam *param = container->type_params + i;
- MonoType *target_type = target->context.class_inst->type_argv [i];
- MonoType *candidate_type = candidate->context.class_inst->type_argv [i];
- /* We resolve TYPE_VAR types before proceeding */
-
- if (candidate_type->type == MONO_TYPE_VAR) {
- MonoGenericParam *var_param = candidate_type->data.generic_param;
- candidate_type = root_candidate->context.class_inst->type_argv [var_param->num];
- }
-
- if ((param->flags & GENERIC_PARAMETER_ATTRIBUTE_VARIANCE_MASK) == 0) {
- VERIFIER_DEBUG ( printf ("generic type have no variance flag, checking each type %d %d \n",target_type->type, candidate_type->type); );
-
- if (!mono_metadata_type_equal (target_type, candidate_type))
- return FALSE;
- } else {
- VERIFIER_DEBUG ( printf ("generic type has variance flag, need to perform deeper check\n"); );
- /* first we check if they are the same kind */
- /* byref generic params are forbiden, but better safe than sorry.*/
-
- if ((param->flags & GENERIC_PARAMETER_ATTRIBUTE_COVARIANT) == GENERIC_PARAMETER_ATTRIBUTE_COVARIANT) {
- if (!mono_is_generic_type_compatible (target_type, candidate_type))
- return FALSE;
- /* the attribute must be contravariant */
- } else if (!mono_is_generic_type_compatible (candidate_type, target_type))
- return FALSE;
- }
- }
- return TRUE;
-}
-
-
-
/*Verify if type 'candidate' can be stored in type 'target'.
*
* If strict, check for the underlying type and not the verification stack types
}
case MONO_TYPE_PTR:
+ if (!IS_STRICT_MODE (ctx) && IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U))
+ return TRUE;
if (candidate->type != MONO_TYPE_PTR)
return FALSE;
/* check the underlying type */
}
case MONO_TYPE_GENERICINST: {
- MonoGenericClass *left;
- MonoGenericClass *right;
if (mono_type_is_enum_type (target)) {
target = mono_type_get_underlying_type_any (target);
goto handle_enum;
}
-
- if (candidate->type != MONO_TYPE_GENERICINST)
- return mono_class_is_assignable_from (mono_class_from_mono_type (target), mono_class_from_mono_type (candidate));
- left = target->data.generic_class;
- right = candidate->data.generic_class;
-
- return mono_is_generic_instance_compatible (left, right, right);
+ return mono_class_is_assignable_from (mono_class_from_mono_type (target), mono_class_from_mono_type (candidate));
}
case MONO_TYPE_STRING:
return FALSE;
if (!type_must_be_object && !MONO_TYPE_IS_REFERENCE (type))
return FALSE;
- return !type->byref && mono_class_from_mono_type (candidate)->valuetype && !candidate->byref && stack_slot_is_boxed_value (stack);
+ return !type->byref && !candidate->byref && stack_slot_is_boxed_value (stack);
}
static int
ILStackDesc *value;
MonoMethod *method;
gboolean virt_check_this = FALSE;
+ gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;
if (!(method = verifier_load_method (ctx, method_token, virtual ? "callvirt" : "call")))
return;
- if (!virtual && (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
+ if (virtual) {
+ ctx->prefix_set &= ~PREFIX_CONSTRAINED;
+
+ if (method->klass->valuetype) // && !constrained ???
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
- if (virtual && method->klass->valuetype)
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
+ if ((method->flags & METHOD_ATTRIBUTE_STATIC))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
- if (virtual && (method->flags & METHOD_ATTRIBUTE_STATIC))
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
+ } else {
+ if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
- if (!virtual && (method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL)) {
- virt_check_this = TRUE;
- ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
+ if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL)) {
+ virt_check_this = TRUE;
+ ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
+ }
}
if (!(sig = mono_method_get_signature_full (method, ctx->image, method_token, ctx->generic_context)))
value = stack_pop (ctx);
if (!verify_stack_type_compatibility (ctx, sig->params[i], value))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with function signature at 0x%04x", ctx->ip_offset));
+
+ if (stack_slot_is_managed_mutability_pointer (value))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of %s at 0x%04x", virtual ? "callvirt" : "call", ctx->ip_offset));
}
if (sig->hasthis) {
if (virt_check_this && !stack_slot_is_this_pointer (value) && !(method->klass->valuetype || stack_slot_is_boxed_value (value)))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a non-final virtual method from an objet diferent thant the this pointer at 0x%04x", ctx->ip_offset));
-
- 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));
-
- if (!virtual && mono_class_from_mono_type (value->type)->valuetype && !method->klass->valuetype && !stack_slot_is_boxed_value (value))
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
-
- if (virtual && mono_class_from_mono_type (value->type)->valuetype && !stack_slot_is_boxed_value (value))
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
-
- if (method->klass->valuetype && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a boxed or literal valuetype to call a valuetype method at 0x%04x", ctx->ip_offset));
+ 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))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
+ copy.stype |= BOXED_MASK;
+ } 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));
+
+ if (!virtual && mono_class_from_mono_type (value->type)->valuetype && !method->klass->valuetype && !stack_slot_is_boxed_value (value))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
+
+ if (virtual && mono_class_from_mono_type (value->type)->valuetype && !stack_slot_is_boxed_value (value))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
+
+ if (method->klass->valuetype && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a boxed or literal valuetype to call a valuetype method at 0x%04x", ctx->ip_offset));
+ }
if (!verify_stack_type_compatibility (ctx, type, ©))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature at 0x%04x", ctx->ip_offset));
- }
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method (ctx->method, method))
+ if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, value->type->data.klass))
+ CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
+
+ } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
if (sig->ret->type != MONO_TYPE_VOID) {
- if (check_overflow (ctx))
- set_stack_value (ctx, stack_push (ctx), sig->ret, FALSE);
+ if (check_overflow (ctx)) {
+ value = stack_push (ctx);
+ set_stack_value (ctx, value, sig->ret, FALSE);
+ if ((ctx->prefix_set & PREFIX_READONLY) && method->klass->rank && !strcmp (method->name, "Address")) {
+ ctx->prefix_set &= ~PREFIX_READONLY;
+ value->stype |= CMMP_MASK;
+ }
+ }
}
}
!(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+ if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
return;
}
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+ if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
if (!verify_stack_type_compatibility (ctx, field->type, value))
MonoClass *klass;
/*must be one of: complex type, managed pointer (to complex type), unmanaged pointer (native int) or an instance of a value type */
- if (!( stack_slot_get_underlying_type (obj) == TYPE_COMPLEX
+ if (!(stack_slot_get_underlying_type (obj) == TYPE_COMPLEX
|| stack_slot_get_type (obj) == TYPE_NATIVE_INT
|| stack_slot_get_type (obj) == TYPE_PTR)) {
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument %s to load field at 0x%04x", stack_slot_get_name (obj), ctx->ip_offset));
if (!stack_slot_is_null_literal (obj) && !verify_type_compatibility (ctx, &field->parent->byval_arg, mono_type_get_type_byval (obj->type)))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not compatible to reference the field at 0x%04x", ctx->ip_offset));
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+ if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, obj->type->data.klass))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
- }
-
- if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field (ctx->method, field))
+ } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
src = stack_pop (ctx);
dest = stack_pop (ctx);
+ if (stack_slot_is_managed_mutability_pointer (dest))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));
+
if (!stack_slot_is_managed_pointer (dest))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));
if (!stack_slot_is_managed_pointer (dest))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of cpobj operation at 0x%04x", ctx->ip_offset));
+ if (stack_slot_is_managed_mutability_pointer (dest))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with cpobj at 0x%04x", ctx->ip_offset));
+
if (!verify_type_compatibility (ctx, type, mono_type_get_type_byval (src->type)))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of cpobj don't match at 0x%04x", ctx->ip_offset));
if (!stack_slot_is_managed_pointer (obj))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));
+ if (stack_slot_is_managed_mutability_pointer (obj))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));
+
stack = mono_type_get_type_byval (obj->type);
if (MONO_TYPE_IS_REFERENCE (stack)) {
if (!verify_type_compatibility (ctx, stack, type))
if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
- if (!mono_method_can_access_method (ctx->method, method))
+ if (!mono_method_can_access_method_full (ctx->method, method, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Constructor not visible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
//FIXME use mono_method_get_signature_full
value = stack_pop (ctx);
if (!verify_stack_type_compatibility (ctx, sig->params [i], value))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with function signature at 0x%04x", ctx->ip_offset));
+
+ if (stack_slot_is_managed_mutability_pointer (value))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of newobj at 0x%04x", ctx->ip_offset));
}
}
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
}
- stack_push_val (ctx, TYPE_COMPLEX | (mono_class_from_mono_type (type)->valuetype ? BOXED_MASK : 0), type);
+ stack_push_val (ctx, TYPE_COMPLEX | (mono_class_from_mono_type (type)->valuetype || is_boxed ? BOXED_MASK : 0), type);
}
static MonoType *
return;
}
+ if (stack_slot_is_managed_mutability_pointer (addr)) {
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stind at 0x%04x", ctx->ip_offset));
+ return;
+ }
+
if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
static void
do_ldelema (VerifyContext *ctx, int klass_token)
{
- ILStackDesc *index, *array;
+ ILStackDesc *index, *array, *res;
MonoType *type = get_boxable_mono_type (ctx, klass_token, "ldelema");
gboolean valid;
}
}
- set_stack_value (ctx, stack_push (ctx), type, TRUE);
+ res = stack_push (ctx);
+ set_stack_value (ctx, res, type, TRUE);
+ if (ctx->prefix_set & PREFIX_READONLY) {
+ ctx->prefix_set &= ~PREFIX_READONLY;
+ res->stype |= CMMP_MASK;
+ }
}
/*
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
}
- if (!mono_method_can_access_method (ctx->method, method))
+ if (!mono_method_can_access_method_full (ctx->method, method, NULL))
CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Loaded method is not visible for ldftn/ldvirtftn at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
top = stack_pop (ctx);
+ if (stack_slot_is_managed_mutability_pointer (top))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with mkrefany at 0x%04x", ctx->ip_offset));
+
if (!stack_slot_is_managed_pointer (top)) {
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Expected a managed pointer for mkrefany, but found %s at 0x%04x", stack_slot_get_name (top), ctx->ip_offset));
}else {
const unsigned char *ip;
const unsigned char *end;
int i, n, need_merge = 0, start = 0;
- guint token, ip_offset = 0, prefix = 0, prefix_list = 0;
+ guint token, ip_offset = 0, prefix = 0;
MonoGenericContext *generic_context = NULL;
MonoImage *image;
VerifyContext ctx;
if (ctx.signature->is_inflated)
ctx.generic_context = generic_context = mono_method_get_context (method);
+ if (!generic_context && (method->klass->generic_container || method->generic_container)) {
+ if (method->generic_container)
+ ctx.generic_context = generic_context = &method->generic_container->context;
+ else
+ ctx.generic_context = generic_context = &method->klass->generic_container->context;
+ }
+
stack_init (&ctx, &ctx.eval);
for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
start = 0;
/*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
- if (prefix) {
- prefix_list |= prefix;
- } else {
- prefix_list = 0;
- ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
- }
- prefix = 0;
-
#ifdef MONO_VERIFIER_DEBUG
{
char *discode;
break;
case CEE_CONSTRAINED_:
- token = read32 (ip + 1);
+ ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
+ prefix |= PREFIX_CONSTRAINED;
ip += 5;
break;
+
+ case CEE_READONLY_:
+ prefix |= PREFIX_READONLY;
+ ip++;
+ break;
+
case CEE_CPBLK:
if (!check_underflow (&ctx, 3))
break;
break;
}
}
+
+ /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
+ if (prefix) {
+ if (!ctx.prefix_set) //first prefix
+ ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
+ ctx.prefix_set |= prefix;
+ prefix = 0;
+ } else {
+ ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
+ if (ctx.prefix_set & PREFIX_CONSTRAINED)
+ ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
+ if (ctx.prefix_set & PREFIX_READONLY)
+ ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
+ ctx.prefix_set = prefix = 0;
+ }
}
/*
* if ip != end we overflowed: mark as error.