} while (0)
#define UNMASK_TYPE(type) ((type) & TYPE_MASK)
+#define IS_MANAGED_POINTER(type) (((type) & POINTER_MASK) == POINTER_MASK)
enum {
IL_CODE_FLAG_NOT_PROCESSED = 0,
MonoGenericContext *generic_context;
MonoImage *image;
+ MonoMethod *method;
} VerifyContext;
//////////////////////////////////////////////////////////////////
TYPE_R8 = 4,
/* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
TYPE_PTR = 5,
- /* Method pointer, value types and classes */
+ /* value types and classes */
TYPE_COMPLEX = 6,
/* Number of types, used to define the size of the tables*/
TYPE_MAX = 8, /* FIXME: This should probably be 7, but would require all the tables to be updated */
* assemblies, though (the spec claims we didn't have to, bah).
*/
/*
- * We need to check that the parent types have the samme layout
+ * We need to check that the parent types have the same layout
* type as well.
*/
}
if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
ADD_ERROR (list, g_strdup_printf ("RTSpecialName needs also SpecialName set in Field row %d", i + 1));
/*
- * FIXME: check there is only ono owner in the respective table.
+ * FIXME: check there is only one owner in the respective table.
* if (flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
* if (flags & FIELD_ATTRIBUTE_HAS_DEFAULT)
* if (flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
for (i = 0; i < header->num_clauses; ++i) {
clause = &header->clauses [i];
- if (MONO_OFFSET_IN_CLAUSE (clause, offset) && !MONO_OFFSET_IN_CLAUSE (clause, target))
+ if (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target))
return 0;
- if (MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
+ if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
return 0;
/* need to check filter ... */
}
static gboolean
is_valid_bool_arg (ILStackDesc *arg)
{
- if (arg->stype & POINTER_MASK)
+ if (IS_MANAGED_POINTER (arg->stype))
return TRUE;
switch (arg->stype) {
case TYPE_I4:
case TYPE_I8:
case TYPE_NATIVE_INT:
+ case TYPE_PTR:
return TRUE;
case TYPE_COMPLEX:
g_assert (arg->type);
}
+/*Type manipulation helper*/
+
+/*Returns the byref version of the supplied MonoType*/
+static MonoType*
+mono_type_get_type_byref (MonoType *type)
+{
+ return &mono_class_from_mono_type (type)->this_arg;
+}
+
+
+/*Returns the byval version of the supplied MonoType*/
+static MonoType*
+mono_type_get_type_byval (MonoType *type)
+{
+ return &mono_class_from_mono_type (type)->byval_arg;
+}
/*Stack manipulation code*/
check_underflow (VerifyContext *ctx, int size)
{
if (ctx->eval.size < size) {
- ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d", size, ctx->eval.size));
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
return 0;
}
return 1;
check_overflow (VerifyContext *ctx)
{
if (ctx->eval.size >= ctx->max_stack) {
- ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d", ctx->eval.size + 1));
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
return 0;
}
return 1;
}
static gboolean
-check_unmanaged_pointer_type (VerifyContext *ctx, MonoType *type)
+check_unverifiable_type (VerifyContext *ctx, MonoType *type)
{
if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
return 0;
}
+ if (type->type == MONO_TYPE_TYPEDBYREF) {
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("TypedByRef is not a verifiable type at 0x%04x", ctx->ip_offset));
+ return 0;
+ }
return 1;
}
return ctx->eval.stack + (ctx->eval.size - distance - 1);
}
+/* Returns the MonoType associated with the token, or NULL if it is invalid.
+ *
+ * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer
+ * */
+static MonoType*
+get_boxable_mono_type (VerifyContext* ctx, int token)
+{
+ MonoType *type = mono_type_get_full (ctx->image, token, ctx->generic_context);
+
+ if (!type) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
+ return NULL;
+ }
+
+ if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
+ return NULL;
+ }
+
+ check_unverifiable_type (ctx, type);
+ return type;
+}
+
/*operation result tables */
if (value->stype & CMMP_MASK)
printf ("Controled Mutability MP: ");
- if (value->stype & POINTER_MASK)
+ if (IS_MANAGED_POINTER (value->stype))
printf ("Managed Pointer to: ");
- switch (value->stype & TYPE_MASK) {
+ switch (UNMASK_TYPE (value->stype)) {
case TYPE_INV:
printf ("invalid type]");
return;
printf ("unmanaged pointer]");
return;
case TYPE_COMPLEX:
- printf ("complex]");
- return;
+ switch (value->type->type) {
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_VALUETYPE:
+ printf ("complex] (%s)", value->type->data.klass->name);
+ return;
+ case MONO_TYPE_STRING:
+ printf ("complex] (string)");
+ return;
+ case MONO_TYPE_OBJECT:
+ printf ("complex] (object)");
+ return;
+ case MONO_TYPE_SZARRAY:
+ printf ("complex] (%s [])", value->type->data.klass->name);
+ return;
+ case MONO_TYPE_ARRAY:
+ printf ("complex] (%s [%d %d %d])",
+ value->type->data.array->eklass->name,
+ value->type->data.array->rank,
+ value->type->data.array->numsizes,
+ value->type->data.array->numlobounds);
+ return;
+ case MONO_TYPE_GENERICINST:
+ printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
+ return;
+ case MONO_TYPE_VAR:
+ printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, value->type->data.generic_param->name);
+ return;
+ case MONO_TYPE_MVAR:
+ printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, value->type->data.generic_param->name);
+ return;
+ default:
+ printf ("unknown complex %d type]\n", value->type->type);
+ g_assert_not_reached ();
+ }
default:
- printf ("unknown %d type]", value->stype);
+ printf ("unknown stack %d type]\n", value->stype);
g_assert_not_reached ();
}
}
/* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */
case MONO_TYPE_FNPTR:
case MONO_TYPE_PTR:
+ case MONO_TYPE_TYPEDBYREF:
return TYPE_PTR | mask;
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
- case MONO_TYPE_TYPEDBYREF:
case MONO_TYPE_GENERICINST:
return TYPE_COMPLEX | mask;
/*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
case MONO_TYPE_FNPTR:
case MONO_TYPE_PTR:
+ case MONO_TYPE_TYPEDBYREF:
stack->stype = TYPE_PTR | mask;
return;
case MONO_TYPE_OBJECT:
case MONO_TYPE_SZARRAY:
case MONO_TYPE_ARRAY:
- case MONO_TYPE_TYPEDBYREF:
case MONO_TYPE_GENERICINST:
+ case MONO_TYPE_VAR:
+ case MONO_TYPE_MVAR:
stack->stype = TYPE_COMPLEX | mask;
return;
case MONO_TYPE_I8:
return;
}
default:
- VERIFIER_DEBUG ( printf ("unknown type %02x in eval stack type\n", type->type); );
+ VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
g_assert_not_reached ();
}
return;
*/
static gboolean
verify_stack_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict) {
- VERIFIER_DEBUG ( printf ("checking type compatibility %p %p %p\n", ctx, target, candidate); );
+#define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
+#define IS_ONE_OF2(T, A, B) (T == A || T == B)
+
+ VERIFIER_DEBUG ( printf ("checking type compatibility %p %p[%d][%d] %p[%d][%d]\n", ctx, target, target->type, target->byref, candidate, candidate->type, candidate->byref); );
/*only one is byref */
if (candidate->byref ^ target->byref) {
case MONO_TYPE_I1:
case MONO_TYPE_U1:
case MONO_TYPE_BOOLEAN:
+ if (strict)
+ return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
case MONO_TYPE_I2:
case MONO_TYPE_U2:
case MONO_TYPE_CHAR:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
if (strict)
- return candidate->type == target->type;
+ return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
return get_stack_type (candidate) == TYPE_I4;
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4: {
+ gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
+ gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
+ if (strict)
+ return is_native_int || is_int4;
+ return is_native_int || get_stack_type (candidate) == TYPE_I4;
+ }
+
case MONO_TYPE_I8:
case MONO_TYPE_U8:
- if (strict)
- return candidate->type == target->type;
- return get_stack_type (candidate) == TYPE_I8;
+ return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
case MONO_TYPE_R4:
case MONO_TYPE_R8:
if (strict)
return candidate->type == target->type;
- return get_stack_type (target) == TYPE_R8;
+ return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
case MONO_TYPE_I:
- case MONO_TYPE_U:
- if (strict)
- return candidate->type == target->type;
- return get_stack_type (target) == TYPE_NATIVE_INT;
+ case MONO_TYPE_U: {
+ gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
+ gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
+ return is_native_int || is_int4;
+ }
case MONO_TYPE_PTR:
if (candidate->type != MONO_TYPE_PTR)
/* check the underlying type */
return verify_stack_type_compatibility (ctx, target->data.type, candidate->data.type, TRUE);
+ case MONO_TYPE_FNPTR: {
+ MonoMethodSignature *left, *right;
+ if (candidate->type != MONO_TYPE_FNPTR)
+ return FALSE;
+
+ left = mono_type_get_signature (target);
+ right = mono_type_get_signature (candidate);
+ return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
+ }
+
case MONO_TYPE_GENERICINST: {
MonoGenericClass *left;
MonoGenericClass *right;
- if (target->type != MONO_TYPE_GENERICINST)
+ if (candidate->type != MONO_TYPE_GENERICINST)
return FALSE;
left = target->data.generic_class;
right = candidate->data.generic_class;
case MONO_TYPE_SZARRAY: {
MonoClass *left;
MonoClass *right;
- if (target->type != MONO_TYPE_SZARRAY)
+ if (candidate->type != MONO_TYPE_SZARRAY)
return FALSE;
left = target->data.klass;
//TODO verify aditional checks that needs to be done
case MONO_TYPE_TYPEDBYREF:
- return candidate->type != MONO_TYPE_TYPEDBYREF;
+ return candidate->type == MONO_TYPE_TYPEDBYREF;
case MONO_TYPE_VALUETYPE:
if (target->data.klass->enumtype) {
return FALSE;
return target->data.klass == candidate->data.klass;
}
+
+ case MONO_TYPE_VAR:
+ if (candidate->type != MONO_TYPE_VAR)
+ return FALSE;
+ return candidate->data.generic_param->num == target->data.generic_param->num;
+
+ case MONO_TYPE_MVAR:
+ if (candidate->type != MONO_TYPE_MVAR)
+ return FALSE;
+ return candidate->data.generic_param->num == target->data.generic_param->num;
default:
VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
return FALSE;
}
return 1;
+#undef IS_ONE_OF3
+#undef IS_ONE_OF2
}
-/*
- TODO MONO_TYPE_PTR:
- TODO MONO_TYPE_FNPTR:
-*/
static int
verify_type_compat (VerifyContext *ctx, MonoType *type, ILStackDesc *stack) {
int stack_type = stack->stype;
- VERIFIER_DEBUG ( printf ("checking compatibility %p %p %p\n", ctx, stack, type); );
- if (type->byref) {
- if (stack_type == TYPE_NATIVE_INT) {
+ VERIFIER_DEBUG ( printf ("checking compatibility %p %p[%d] %p[%d]\n", ctx, type, type->type, stack, stack_type ); );
+
+ /*only one is byref */
+ if (type->byref ^ IS_MANAGED_POINTER (stack_type)) {
+ /* converting from native int to byref*/
+ if (type->byref && stack_type == TYPE_NATIVE_INT) {
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
return TRUE;
}
return FALSE;
}
+ if (type->byref)
+ return verify_stack_type_compatibility (ctx, type, mono_type_get_type_byref (stack->type), TRUE);
handle_enum:
switch (type->type) {
case MONO_TYPE_I:
case MONO_TYPE_U:
- return stack_type == TYPE_NATIVE_INT;
+ return stack_type == TYPE_NATIVE_INT || stack_type == TYPE_I4;
case MONO_TYPE_PTR:
- if ((stack_type & POINTER_MASK) == 0)
+ if (stack_type != TYPE_PTR || stack->type->type != MONO_TYPE_PTR)
return FALSE;
- stack_type &= ~POINTER_MASK;
- if (stack_type != TYPE_COMPLEX) {
- type = type->data.type;
- goto handle_enum;
- }
- return verify_stack_type_compatibility (ctx, type->data.type, stack->type, TRUE);
+ return verify_stack_type_compatibility (ctx, type->data.type, stack->type->data.type, TRUE);
+
+ case MONO_TYPE_FNPTR: {
+ MonoMethodSignature *left, *right;
+ if (stack_type != TYPE_PTR || stack->type->type != MONO_TYPE_FNPTR)
+ return FALSE;
+
+ left = mono_type_get_signature (type);
+ right = mono_type_get_signature (stack->type);
+ return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
+ }
case MONO_TYPE_GENERICINST: {
MonoGenericClass *left;
if (stack_type != TYPE_COMPLEX)
return FALSE;
g_assert (stack->type);
- if (stack->type->type != type->type)
+ if (stack->type->type != MONO_TYPE_ARRAY)
return FALSE;
return is_array_type_compatible (type, stack->type);
/*TODO verify aditional checks that needs to be done */
case MONO_TYPE_TYPEDBYREF:
- if (stack_type != TYPE_COMPLEX)
+ if (stack_type != TYPE_PTR)
return FALSE;
g_assert (stack->type);
- if (stack->type->type != type->type)
+ if (stack->type->type != MONO_TYPE_TYPEDBYREF)
return FALSE;
return TRUE;
if (stack_type != TYPE_COMPLEX)
return FALSE;
g_assert (stack->type);
- if (stack->type->type != type->type)
+ if (stack->type->type != MONO_TYPE_VALUETYPE)
return FALSE;
return stack->type->data.klass == type->data.klass;
}
+ case MONO_TYPE_VAR:
+ if (stack_type != TYPE_COMPLEX)
+ return FALSE;
+ g_assert (stack->type);
+ if (stack->type->type != MONO_TYPE_VAR)
+ return FALSE;
+ return stack->type->data.generic_param->num == type->data.generic_param->num;
+
+ case MONO_TYPE_MVAR:
+ if (stack_type != TYPE_COMPLEX)
+ return FALSE;
+ g_assert (stack->type);
+ if (stack->type->type != MONO_TYPE_MVAR)
+ return FALSE;
+ return stack->type->data.generic_param->num == type->data.generic_param->num;
+
default:
printf("unknown store type %d\n", type->type);
g_assert_not_reached ();
push_arg (VerifyContext *ctx, unsigned int arg, int take_addr)
{
if (arg >= ctx->max_args) {
- ADD_VERIFY_ERROR(ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
+ if (take_addr)
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
+ else {
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
+ if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
+ stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
+ }
} else if (check_overflow (ctx)) {
/*We must let the value be pushed, otherwise we would get an underflow error*/
- check_unmanaged_pointer_type (ctx, ctx->params [arg]);
- set_stack_value (stack_push (ctx), ctx->params [arg], FALSE);
+ check_unverifiable_type (ctx, ctx->params [arg]);
+ if (ctx->params [arg]->byref && take_addr)
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
+ set_stack_value (stack_push (ctx), ctx->params [arg], take_addr);
}
}
ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
} else if (check_overflow (ctx)) {
/*We must let the value be pushed, otherwise we would get an underflow error*/
- check_unmanaged_pointer_type (ctx, ctx->locals [arg]);
+ check_unverifiable_type (ctx, ctx->locals [arg]);
+ if (ctx->locals [arg]->byref && take_addr)
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
+
set_stack_value (stack_push (ctx), ctx->locals [arg], take_addr);
}
}
ILStackDesc *value;
if (arg >= ctx->max_args) {
- ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
+ check_underflow (ctx, 1);
+ stack_pop (ctx);
return;
}
if (check_underflow (ctx, 1)) {
value = stack_pop (ctx);
if (!verify_type_compat (ctx, ctx->params [arg], value)) {
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in local store at 0x%04x", type_names [value->stype & TYPE_MASK], ctx->ip_offset));
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in local store at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
}
}
}
if (check_underflow (ctx, 1)) {
value = stack_pop(ctx);
if (!verify_type_compat (ctx, ctx->locals [arg], value)) {
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in local store at 0x%04x", type_names [value->stype & TYPE_MASK], ctx->ip_offset));
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in local store at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
}
}
}
b = stack_top (ctx);
idxa = a->stype;
- if (idxa & POINTER_MASK) {
+ if (IS_MANAGED_POINTER (idxa)) {
idxa = TYPE_PTR;
complexMerge = 1;
}
idxb = b->stype;
- if (idxb & POINTER_MASK) {
+ if (IS_MANAGED_POINTER (idxb)) {
idxb = TYPE_PTR;
complexMerge = 2;
}
VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
+ ctx->eval.size--;
if (res == TYPE_INV) {
- ADD_VERIFY_ERROR(ctx, g_strdup_printf (
- "Binary instruction applyed to ill formed stack (%s x %s)",
- type_names [idxa & TYPE_MASK], type_names [idxb & TYPE_MASK]));
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Binary instruction applyed to ill formed stack (%s x %s)", type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)]));
return;
}
if (res & NON_VERIFIABLE_RESULT) {
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Binary instruction is not verifiable (%s x %s)",
- type_names [idxa & TYPE_MASK], type_names [idxb & TYPE_MASK]));
+ type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)]));
res = res & ~NON_VERIFIABLE_RESULT;
}
} else
stack_top (ctx)->stype = res;
- ctx->eval.size--;
}
top = stack_pop (ctx);
if (!is_valid_bool_arg (top))
- ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Argument type %s not valid for brtrue/brfalse at 0x%04x", type_names [stack_get (ctx, -1)->stype & TYPE_MASK], ctx->ip_offset));
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Argument type %s not valid for brtrue/brfalse at 0x%04x", type_names [UNMASK_TYPE (stack_get (ctx, -1)->stype)], ctx->ip_offset));
check_unmanaged_pointer (ctx, top);
}
a = stack_pop (ctx);
idxa = a->stype;
- if (idxa & POINTER_MASK)
+ if (IS_MANAGED_POINTER (idxa))
idxa = TYPE_PTR;
idxb = b->stype;
- if (idxb & POINTER_MASK)
+ if (IS_MANAGED_POINTER (idxb))
idxb = TYPE_PTR;
--idxa;
if (res == TYPE_INV) {
ADD_VERIFY_ERROR (ctx,
g_strdup_printf ("Compare and Branch instruction applyed to ill formed stack (%s x %s) at 0x%04x",
- type_names [idxa & TYPE_MASK], type_names [idxb & TYPE_MASK], ctx->ip_offset));
+ type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset));
} else if (res & NON_VERIFIABLE_RESULT) {
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Compare and Branch instruction is not verifiable (%s x %s) at 0x%04x",
- type_names [idxa & TYPE_MASK], type_names [idxb & TYPE_MASK], ctx->ip_offset));
+ type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset));
res = res & ~NON_VERIFIABLE_RESULT;
}
}
a = stack_pop (ctx);
idxa = a->stype;
- if (idxa & POINTER_MASK)
+ if (IS_MANAGED_POINTER (idxa))
idxa = TYPE_PTR;
idxb = b->stype;
- if (idxb & POINTER_MASK)
+ if (IS_MANAGED_POINTER (idxb))
idxb = TYPE_PTR;
--idxa;
--idxb;
res = table [idxa][idxb];
- printf("binop res %d\n", res);
- printf("idxa %d idxb %d\n", idxa, idxb);
-
if(res == TYPE_INV) {
- ADD_VERIFY_ERROR (ctx, g_strdup_printf("Compare instruction applyed to ill formed stack (%s x %s) at 0x%04x", type_names [idxa & TYPE_MASK], type_names [idxb & TYPE_MASK], ctx->ip_offset));
- return;
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf("Compare instruction applyed to ill formed stack (%s x %s) at 0x%04x", type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset));
} else if (res & NON_VERIFIABLE_RESULT) {
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Compare instruction is not verifiable (%s x %s) at 0x%04x",
- type_names [idxa & TYPE_MASK], type_names [idxb & TYPE_MASK], ctx->ip_offset));
+ type_names [UNMASK_TYPE (idxa)], type_names [UNMASK_TYPE (idxb)], ctx->ip_offset));
res = res & ~NON_VERIFIABLE_RESULT;
}
- stack_push_val (ctx, TYPE_I4, &mono_defaults.int_class->byval_arg);
+ stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
}
static void
}
if (ctx->eval.size > 0) {
- ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
- } else if (in_any_block (ctx->header, ctx->ip_offset))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
+ }
+ if (in_any_block (ctx->header, ctx->ip_offset))
ADD_VERIFY_ERROR (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
}
* TODO handle vararg calls
* TODO handle non virt calls to non-final virtual calls (from the verifiability clause in page 52 of partition 3)
* TODO handle abstract calls
+ * TODO handle calling .ctor outside one or calling the .ctor for other class but super
+ * TODO handle call invoking virtual methods (only allowed to invoke super)
*/
static void
do_invoke_method (VerifyContext *ctx, int method_token)
VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
value = stack_pop (ctx);
if (!verify_type_compat (ctx, sig->params[i], value)) {
- ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Incompatible parameter value with function signature at 0x%04x", ctx->ip_offset));
- return;
+ if (sig->params [i]->type == MONO_TYPE_TYPEDBYREF) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type for a call parameter at 0x%04x", ctx->ip_offset));
+ return;
+ }
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with function signature at 0x%04x", ctx->ip_offset));
}
}
VERIFIER_DEBUG ( printf ("verifying this argument\n"); );
value = stack_pop (ctx);
if (!verify_type_compat (ctx, type, value)) {
- ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Incompatible return value on stack with method signature ret at 0x%04x", ctx->ip_offset));
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature ret at 0x%04x", ctx->ip_offset));
return;
}
}
+ if (!mono_method_can_access_method (ctx->method, method))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method is not accessible at 0x%04x", ctx->ip_offset));
if (sig->ret->type != MONO_TYPE_VOID) {
if (check_overflow (ctx))
}
}
+static void
+do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
+{
+ MonoClassField *field;
+ MonoClass *klass;
+
+ field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
+ if (!field) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ctx->ip_offset));
+ return;
+ }
+
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
+ return;
+ }
+ /*taking the address of initonly field only works from the static constructor */
+ if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
+ !(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 (!mono_method_can_access_field (ctx->method, field))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
+
+ set_stack_value (stack_push (ctx), field->type, take_addr);
+}
+
+static void
+do_store_static_field (VerifyContext *ctx, int token) {
+ MonoClassField *field;
+ MonoClass *klass;
+ ILStackDesc *value;
+
+ if (!check_underflow (ctx, 1))
+ return;
+
+ value = stack_pop (ctx);
+
+ field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
+ if (!field) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store field from token 0x%08x at 0x%04x", token, ctx->ip_offset));
+ return;
+ }
+
+ if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
+ return;
+ }
+
+ if (field->type->type == MONO_TYPE_TYPEDBYREF) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
+ return;
+ }
+
+ if (!mono_method_can_access_field (ctx->method, field))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
+
+ if (!verify_type_compat (ctx, field->type, value))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in static field store at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
+}
+
+static gboolean
+check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field)
+{
+ MonoClassField *field;
+ MonoClass *klass;
+
+ /*must be one of: object type, managed pointer, unmanaged pointer (native int) or an instance of a value type */
+ if (!((obj->stype == TYPE_COMPLEX)
+ /* the managed reference must be to an object or value type */
+ || (( IS_MANAGED_POINTER (obj->stype)) && (UNMASK_TYPE (obj->stype) == TYPE_COMPLEX))
+ || (obj->stype == TYPE_NATIVE_INT)
+ || (obj->stype == TYPE_PTR)
+ || (obj->stype == TYPE_COMPLEX))) {
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument %s to load field at 0x%04x", type_names [UNMASK_TYPE (obj->stype)], ctx->ip_offset));
+ }
+
+ field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
+ if (!field) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ctx->ip_offset));
+ return FALSE;
+ }
+
+ *ret_field = field;
+
+ if (field->type->type == MONO_TYPE_TYPEDBYREF) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
+ return FALSE;
+ }
+ g_assert (obj->type);
+
+ /*The value on the stack must be a subclass of the defining type of the field*/
+ /* we need to check if we can load the field from the stack value*/
+ if (UNMASK_TYPE (obj->stype) == TYPE_COMPLEX) {
+ MonoType *type = obj->type->byref ? &field->parent->this_arg : &field->parent->byval_arg;
+
+ if (!verify_stack_type_compatibility (ctx, type, obj->type, FALSE)) {
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not compatible to reference the field at 0x%04x", ctx->ip_offset));
+ }
+
+ if (!mono_method_can_access_field (ctx->method, field))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
+ }
+
+ if (!mono_method_can_access_field (ctx->method, field))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset));
+
+ if (obj->stype == TYPE_NATIVE_INT)
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
+
+ check_unmanaged_pointer (ctx, obj);
+ return TRUE;
+}
+
+static void
+do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
+{
+ ILStackDesc *obj;
+ MonoClassField *field;
+
+ if (!check_underflow (ctx, 1))
+ return;
+ obj = stack_pop (ctx);
+
+ if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field))
+ return;
+
+ if (take_addr && field->parent->valuetype && !IS_MANAGED_POINTER (obj->stype))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
+
+ if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
+ !(field->parent == ctx->method->klass && (ctx->method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && !strcmp (".ctor", 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));
+
+ set_stack_value (stack_push (ctx), field->type, take_addr);
+}
+
+static void
+do_store_field (VerifyContext *ctx, int token)
+{
+ ILStackDesc *value, *obj;
+ MonoClassField *field;
+
+ if (!check_underflow (ctx, 2))
+ return;
+
+ value = stack_pop (ctx);
+ obj = stack_pop (ctx);
+
+ if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field))
+ return;
+
+ if (!verify_type_compat (ctx, field->type, value))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
+}
+
+/*TODO proper handle for Nullable<T>*/
+static void
+do_box_value (VerifyContext *ctx, int klass_token)
+{
+ ILStackDesc *value;
+ MonoType *type = get_boxable_mono_type (ctx, klass_token);
+
+ if (!type)
+ return;
+
+ if (!check_underflow (ctx, 1))
+ return;
+
+ value = stack_top (ctx);
+ /*box is a nop for reference types*/
+ if (value->stype == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type))
+ return;
+
+ value = stack_pop (ctx);
+
+ if (!verify_type_compat (ctx, type, value))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
+
+ stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (mono_defaults.object_class));
+}
+
+static void
+do_unbox_value (VerifyContext *ctx, int klass_token)
+{
+ ILStackDesc *value;
+ MonoType *type = get_boxable_mono_type (ctx, klass_token);
+
+ if (!type)
+ return;
+
+ if (!check_underflow (ctx, 1))
+ return;
+
+ value = stack_pop (ctx);
+
+ if (value->stype != TYPE_COMPLEX || value->type->type != MONO_TYPE_OBJECT)
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type %s at stack for unbox operation at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
+
+ //TODO Pushed managed pointer is haver controled mutability (CMMP)
+ set_stack_value (stack_push (ctx), mono_type_get_type_byref (type), FALSE);
+}
+
+static void
+do_unary_math_op (VerifyContext *ctx, int op)
+{
+ ILStackDesc *value;
+ if (!check_underflow (ctx, 1))
+ return;
+ value = stack_top (ctx);
+ switch(value->stype) {
+ case TYPE_I4:
+ case TYPE_I8:
+ case TYPE_NATIVE_INT:
+ break;
+ case TYPE_R8:
+ if (op == CEE_NEG)
+ break;
+ case TYPE_COMPLEX: /*only enums are ok*/
+ if (value->type->type == MONO_TYPE_VALUETYPE && value->type->data.klass->enumtype)
+ break;
+ default:
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
+ }
+}
+
+static void
+do_conversion (VerifyContext *ctx, int kind)
+{
+ ILStackDesc *value;
+ if (!check_underflow (ctx, 1))
+ return;
+ value = stack_pop (ctx);
+
+ switch(value->stype) {
+ case TYPE_I4:
+ case TYPE_I8:
+ case TYPE_NATIVE_INT:
+ case TYPE_R8:
+ break;
+ default:
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for conversion operation at 0x%04x", ctx->ip_offset));
+ }
+
+ switch (kind) {
+ case TYPE_I4:
+ stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
+ break;
+ case TYPE_I8:
+ stack_push_val (ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
+ break;
+ case TYPE_R8:
+ stack_push_val (ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
+ break;
+ case TYPE_NATIVE_INT:
+ stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
+ break;
+ default:
+ g_error ("unknown type %02x in conversion", kind);
+
+ }
+}
+
+static void
+do_load_token (VerifyContext *ctx, int token)
+{
+ gpointer handle;
+ MonoClass *handle_class;
+ if (!check_overflow (ctx))
+ return;
+ handle = mono_ldtoken (ctx->image, token, &handle_class, ctx->generic_context);
+ if (!handle) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid token 0x%x for ldtoken at 0x%04x", token, ctx->ip_offset));
+ return;
+ }
+ stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (handle_class));
+}
+
+static void
+do_ldobj_value (VerifyContext *ctx, int token)
+{
+ ILStackDesc *value;
+ MonoType *type = get_boxable_mono_type (ctx, token);
+
+ if (!type)
+ return;
+
+ if (!check_underflow (ctx, 1))
+ return;
+
+ value = stack_pop (ctx);
+ if (!IS_MANAGED_POINTER (value->stype)
+ && value->stype != TYPE_NATIVE_INT
+ && !(value->stype == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
+ ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
+ return;
+ }
+
+ if (value->stype == TYPE_NATIVE_INT)
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
+
+ /*We have a byval on the stack, we */
+ if (!verify_stack_type_compatibility (ctx, type, mono_type_get_type_byval (value->type), TRUE))
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
+
+ set_stack_value (stack_push (ctx), type, FALSE);
+}
+
+static void
+do_newarr (VerifyContext *ctx, int token)
+{
+ ILStackDesc *value;
+ MonoType *type = get_boxable_mono_type (ctx, token);
+
+ if (!type)
+ return;
+
+ if (!check_underflow (ctx, 1))
+ return;
+
+ value = stack_pop (ctx);
+ if (value->stype != TYPE_I4 && value->stype != TYPE_NATIVE_INT)
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Array size type on stack (%s) is not a verifiable type at 0x%04x", type_names [UNMASK_TYPE (value->stype)], ctx->ip_offset));
+
+ set_stack_value (stack_push (ctx), mono_class_get_type (mono_array_class_get (mono_class_from_mono_type (type), 1)), FALSE);
+}
+
/*Merge the stacks and perform compat checks*/
static void
merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, int start)
int from_stype = from_slot->stype;
int to_stype = to_slot->stype;
+#define IS_NATIVE_INT_AND_I4(val0, val1) (UNMASK_TYPE(val0) == TYPE_NATIVE_INT && \
+ UNMASK_TYPE(val1->stype) == TYPE_I4 && (val1->type->type == MONO_TYPE_I4 || val1->type->type == MONO_TYPE_U4))
+ /* This is the only case of merging between verification types.
+ * Both stack values must be either native int or int4, and both must be either byref or not.*/
+ if ((IS_NATIVE_INT_AND_I4 (from_stype, to_slot) || IS_NATIVE_INT_AND_I4 (to_stype, from_slot)) &&
+ !(IS_MANAGED_POINTER (from_stype) ^ IS_MANAGED_POINTER (to_stype))) {
+ printf ("----is native int\n");
+ to_slot->stype = TYPE_NATIVE_INT;
+ if (UNMASK_TYPE(from_stype) == TYPE_NATIVE_INT)
+ to_slot->type = from_slot->type;
+ continue;
+ }
+#undef IS_NATIVE_INT_OR_I4
+
if (from_stype != to_stype) {
VERIFIER_DEBUG ( printf ("diferent stack types %d x %d\n", from_stype, to_stype); );
CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Could not merge stacks, diferent verification types (%s x %s)",
- type_names [from_stype & TYPE_MASK], type_names [to_stype & TYPE_MASK]));
+ type_names [UNMASK_TYPE (from_stype)], type_names [UNMASK_TYPE (to_stype)]));
goto end_verify;
}
- if (from_stype & POINTER_MASK) {
- from_stype &= ~POINTER_MASK;
- to_stype &= ~POINTER_MASK;
+ if (IS_MANAGED_POINTER (from_stype)) {
+ from_stype = UNMASK_TYPE (from_stype);
+ to_stype = UNMASK_TYPE (to_stype);
if (from_slot->type && !verify_stack_type_compatibility (ctx, to_slot->type, from_slot->type, TRUE)) {
- CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Could not merge stacks, pointer types not compatible"));
+ CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Could not merge stacks, managed pointer types not compatible"));
goto end_verify;
- } else
+ } else
copy_stack_value (to_slot, from_slot);
continue;
}
const unsigned char *target = NULL; /* branch target */
int i, n, need_merge = 0, start = 0;
guint token, ip_offset = 0, prefix = 0;
- MonoClass *klass;
MonoMethod *cmethod;
- MonoClassField *field;
MonoGenericContext *generic_context = NULL;
MonoImage *image;
VerifyContext ctx;
+ VERIFIER_DEBUG ( printf ("Verify IL for method %s %s\n", method->klass->name, method->name); );
if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
(method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
memset (&ctx, 0, sizeof (VerifyContext));
ctx.signature = mono_method_signature (method);
+ if (!ctx.signature) {
+ ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
+ return ctx.list;
+ }
ctx.header = mono_method_get_header (method);
+ if (!ctx.header) {
+ ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header"));
+ return ctx.list;
+ }
+ ctx.method = method;
ip = ctx.header->code;
end = ip + ctx.header->code_size;
ctx.image = image = method->klass->image;
if (ctx.signature->hasthis) {
ctx.params = g_new0 (MonoType*, ctx.max_args);
- ctx.params [0] = &method->klass->this_arg;
+ ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
memcpy (ctx.params + 1, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
} else {
ctx.params = ctx.signature->params;
if (ctx.signature->is_inflated)
ctx.generic_context = generic_context = mono_method_get_context (method);
- stack_init(&ctx, &ctx.eval);
+ stack_init (&ctx, &ctx.eval);
- /* TODO implement exception entry
- for (i = 0; i < header->num_clauses; ++i) {
- MonoExceptionClause *clause = &header->clauses [i];
- // catch blocks have the exception on the stack.
+ for (i = 0; i < ctx.header->num_clauses; ++i) {
+ MonoExceptionClause *clause = ctx.header->clauses + i;
+ /* catch blocks and filter have the exception on the stack. */
+ /* must check boundaries for handler_offset and handler_start < handler_start*/
if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
- code [clause->handler_offset].size = 1;
- code [clause->handler_offset].flags |= IL_CODE_FLAG_SEEN;
+ ILCodeDesc *code = ctx.code + clause->handler_offset;
+ stack_init (&ctx, code);
+ code->stack [0].stype = TYPE_COMPLEX;
+ code->stack [0].type = &clause->data.catch_class->byval_arg;
+ code->size = 1;
+ code->flags = IL_CODE_FLAG_SEEN;
}
- }*/
+ else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+ ILCodeDesc *code = ctx.code + clause->data.filter_offset;
+ stack_init (&ctx, code);
+ code->stack [0].stype = TYPE_COMPLEX;
+ code->stack [0].type = &mono_defaults.exception_class->byval_arg;
+ code->size = 1;
+ code->flags = IL_CODE_FLAG_SEEN;
+ }
+ }
while (ip < end && ctx.valid) {
ctx.ip_offset = ip_offset = ip - ctx.header->code;
case CEE_LDC_I4_7:
case CEE_LDC_I4_8:
if (check_overflow (&ctx))
- stack_push_val (&ctx, TYPE_I4, &mono_defaults.int_class->byval_arg);
+ stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
++ip;
break;
case CEE_LDC_I4_S:
if (check_overflow (&ctx))
- stack_push_val (&ctx, TYPE_I4, &mono_defaults.int_class->byval_arg);
+ stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
ip += 2;
break;
case CEE_LDC_I4:
if (check_overflow (&ctx))
- stack_push_val (&ctx,TYPE_I4, &mono_defaults.int_class->byval_arg);
+ stack_push_val (&ctx,TYPE_I4, &mono_defaults.int32_class->byval_arg);
ip += 5;
break;
++ip;
break;
- case CEE_DUP:
+ case CEE_DUP: {
+ ILStackDesc * top;
if (!check_underflow (&ctx, 1))
break;
if (!check_overflow (&ctx))
break;
- copy_stack_value (stack_push (&ctx), stack_get (&ctx, 1));
+ top = stack_push (&ctx);
+ copy_stack_value (top, stack_get (&ctx, 1));
++ip;
break;
+ }
case CEE_JMP:
if (ctx.eval.size)
++ip;
break;
- case CEE_NEG:
case CEE_NOT:
+ case CEE_NEG:
+ do_unary_math_op (&ctx, *ip);
+ ++ip;
+ break;
+
+ //TODO: implement proper typecheck
case CEE_CONV_I1:
case CEE_CONV_I2:
case CEE_CONV_I4:
+ case CEE_CONV_U1:
+ case CEE_CONV_U2:
+ case CEE_CONV_U4:
+ do_conversion (&ctx, TYPE_I4);
+ ++ip;
+ break;
+
case CEE_CONV_I8:
+ case CEE_CONV_U8:
+ do_conversion (&ctx, TYPE_I8);
+ ++ip;
+ break;
+
case CEE_CONV_R4:
case CEE_CONV_R8:
- case CEE_CONV_U4:
- case CEE_CONV_U8:
- if (!check_underflow (&ctx, 1))
- break;
- if (type_from_op (*ip, stack_top (&ctx)) == TYPE_INV)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
+ case CEE_CONV_R_UN:
+ do_conversion (&ctx, TYPE_R8);
+ ++ip;
+ break;
+
+ case CEE_CONV_I:
+ case CEE_CONV_U:
+ do_conversion (&ctx, TYPE_NATIVE_INT);
++ip;
break;
+
case CEE_CPOBJ:
token = read32 (ip + 1);
if (!check_underflow (&ctx, 2))
ctx.eval.size -= 2;
ip += 5;
break;
+
case CEE_LDOBJ:
- token = read32 (ip + 1);
- if (!check_underflow (&ctx, 1))
- break;
- if (stack_top (&ctx)->stype != TYPE_COMPLEX)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument to ldobj at 0x%04x", ip_offset));
- klass = mono_class_get_full (image, token, generic_context);
- if (!klass)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot load class from token 0x%08x at 0x%04x", token, ip_offset));
- if (!klass->valuetype)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Class is not a valuetype at 0x%04x", ip_offset));
- stack_top (&ctx)->stype = TYPE_COMPLEX;
- stack_top (&ctx)->type = &klass->byval_arg;
+ do_ldobj_value (&ctx, read32 (ip + 1));
ip += 5;
break;
+
case CEE_LDSTR:
/*TODO verify if token is a valid string literal*/
token = read32 (ip + 1);
break;
ip += 5;
break;
- case CEE_CONV_R_UN:
- if (!check_underflow (&ctx, 1))
- break;
- ++ip;
- break;
case CEE_UNUSED58:
case CEE_UNUSED1:
++ip; /* warn, error ? */
break;
case CEE_UNBOX:
- token = read32 (ip + 1);
- if (!check_underflow (&ctx, 1))
- break;
- if (stack_top (&ctx)->stype != TYPE_COMPLEX)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument %s to unbox at 0x%04x", type_names [stack_top (&ctx)->stype], ip_offset));
-
- stack_top (&ctx)->stype = TYPE_COMPLEX;
- stack_top (&ctx)->type = NULL;
+ do_unbox_value (&ctx, read32 (ip + 1));
ip += 5;
break;
case CEE_THROW:
++ip;
start = 1;
break;
+
case CEE_LDFLD:
- if (!check_underflow (&ctx, 1))
- break;
- if (stack_top (&ctx)->stype != TYPE_COMPLEX && stack_top (&ctx)->stype != TYPE_COMPLEX)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument %s to ldfld at 0x%04x", type_names [stack_top (&ctx)->stype], ip_offset));
- token = read32 (ip + 1);
- field = mono_field_from_token (image, token, &klass, generic_context);
- if (!field)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
- type_to_eval_stack_type (field->type, stack_top (&ctx), FALSE);
- ip += 5;
- break;
case CEE_LDFLDA:
- if (!check_underflow (&ctx, 1))
- break;
- if (stack_top (&ctx)->stype != TYPE_COMPLEX && stack_top (&ctx)->stype != TYPE_COMPLEX)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument to ldflda at 0x%04x", ip_offset));
- token = read32 (ip + 1);
- field = mono_field_from_token (image, token, &klass, generic_context);
- if (!field)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
- type_to_eval_stack_type (field->type, stack_top (&ctx), TRUE);
- ip += 5;
- break;
- case CEE_STFLD:
- if (!check_underflow (&ctx, 2))
- break;
- ctx.eval.size -= 2;
- if (stack_top (&ctx)->stype != TYPE_COMPLEX && stack_top (&ctx)->stype != TYPE_COMPLEX)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument to stfld at 0x%04x", ip_offset));
- token = read32 (ip + 1);
- field = mono_field_from_token (image, token, &klass, generic_context);
- if (!field)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
- /* can_store */
+ do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
ip += 5;
break;
+
case CEE_LDSFLD:
- if (!check_overflow (&ctx))
- break;
- token = read32 (ip + 1);
- field = mono_field_from_token (image, token, &klass, generic_context);
- if (!field)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
- type_to_eval_stack_type (field->type, stack_top (&ctx), FALSE);
- ++ctx.eval.size;
+ case CEE_LDSFLDA:
+ do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
ip += 5;
break;
- case CEE_LDSFLDA:
- if (!check_overflow (&ctx))
- break;
- token = read32 (ip + 1);
- field = mono_field_from_token (image, token, &klass, generic_context);
- if (!field)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
- type_to_eval_stack_type (field->type, stack_top (&ctx), TRUE);
- ++ctx.eval.size;
+
+ case CEE_STFLD:
+ do_store_field (&ctx, read32 (ip + 1));
ip += 5;
break;
+
case CEE_STSFLD:
- if (!check_underflow (&ctx, 1))
- break;
- stack_pop (&ctx);
- token = read32 (ip + 1);
- field = mono_field_from_token (image, token, &klass, generic_context);
- if (!field)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
- /* can store */
+ do_store_static_field (&ctx, read32 (ip + 1));
ip += 5;
break;
case CEE_STOBJ:
token = read32 (ip + 1);
ip += 5;
break;
+
case CEE_CONV_OVF_I1_UN:
case CEE_CONV_OVF_I2_UN:
case CEE_CONV_OVF_I4_UN:
- case CEE_CONV_OVF_I8_UN:
case CEE_CONV_OVF_U1_UN:
case CEE_CONV_OVF_U2_UN:
case CEE_CONV_OVF_U4_UN:
+ do_conversion (&ctx, TYPE_I4);
+ ++ip;
+ break;
+
+ case CEE_CONV_OVF_I8_UN:
case CEE_CONV_OVF_U8_UN:
+ do_conversion (&ctx, TYPE_I8);
+ ++ip;
+ break;
+
case CEE_CONV_OVF_I_UN:
case CEE_CONV_OVF_U_UN:
- if (!check_underflow (&ctx, 1))
- break;
- if (type_from_op (*ip, stack_top (&ctx)) == TYPE_INV)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
+ do_conversion (&ctx, TYPE_NATIVE_INT);
++ip;
break;
+
case CEE_BOX:
- if (!check_underflow (&ctx, 1))
- break;
- token = read32 (ip + 1);
- if ( stack_top (&ctx)->stype == TYPE_COMPLEX)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument %s to box at 0x%04x", type_names [stack_top (&ctx)->stype], ip_offset));
- stack_top (&ctx)->stype = TYPE_COMPLEX;
+ do_box_value (&ctx, read32 (ip + 1));
ip += 5;
break;
+
case CEE_NEWARR:
- if (!check_underflow (&ctx, 1))
- break;
- token = read32 (ip + 1);
- stack_top (&ctx)->stype = TYPE_COMPLEX;
+ do_newarr (&ctx, read32 (ip + 1));
ip += 5;
break;
+
case CEE_LDLEN:
if (!check_underflow (&ctx, 1))
break;
if (stack_top (&ctx)->stype != TYPE_COMPLEX)
ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid argument to ldlen at 0x%04x", ip_offset));
- stack_top (&ctx)->type = &mono_defaults.int_class->byval_arg; /* FIXME: use a native int type */
+ stack_top (&ctx)->type = &mono_defaults.int32_class->byval_arg; /* FIXME: use a native int type */
stack_top (&ctx)->stype = TYPE_PTR;
++ip;
break;
case CEE_UNUSED17:
++ip; /* warn, error ? */
break;
+
case CEE_CONV_OVF_I1:
case CEE_CONV_OVF_U1:
case CEE_CONV_OVF_I2:
case CEE_CONV_OVF_U2:
case CEE_CONV_OVF_I4:
case CEE_CONV_OVF_U4:
+ do_conversion (&ctx, TYPE_I4);
+ ++ip;
+ break;
+
case CEE_CONV_OVF_I8:
case CEE_CONV_OVF_U8:
- if (!check_underflow (&ctx, 1))
- break;
- if (type_from_op (*ip, stack_top (&ctx)) == TYPE_INV)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
+ do_conversion (&ctx, TYPE_I8);
++ip;
break;
+
+ case CEE_CONV_OVF_I:
+ case CEE_CONV_OVF_U:
+ do_conversion (&ctx, TYPE_NATIVE_INT);
+ ++ip;
+ break;
+
case CEE_UNUSED50:
case CEE_UNUSED18:
case CEE_UNUSED19:
++ip; /* warn, error ? */
break;
case CEE_LDTOKEN:
- if (!check_overflow (&ctx))
- break;
- token = read32 (ip + 1);
- ++ctx.eval.size;
+ do_load_token (&ctx, read32 (ip + 1));
ip += 5;
break;
- case CEE_CONV_U2:
- case CEE_CONV_U1:
- case CEE_CONV_I:
- case CEE_CONV_OVF_I:
- case CEE_CONV_OVF_U:
- if (!check_underflow (&ctx, 1))
- break;
- if (type_from_op (*ip, stack_top (&ctx)) == TYPE_INV)
- ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
- ++ip;
- break;
+
case CEE_ADD_OVF:
case CEE_ADD_OVF_UN:
case CEE_MUL_OVF:
ctx.eval.size -= 2;
++ip;
break;
- case CEE_CONV_U:
- if (!check_underflow (&ctx, 1))
- break;
- ++ip;
- break;
case CEE_UNUSED26:
case CEE_UNUSED27:
case CEE_UNUSED28:
break;
token = read32 (ip + 1);
ip += 5;
- stack_top (&ctx)->type = &mono_defaults.uint_class->byval_arg;
+ stack_top (&ctx)->type = &mono_defaults.uint32_class->byval_arg;
stack_top (&ctx)->stype = TYPE_I4;
ctx.eval.size++;
break;
}
}
- g_free (ctx.eval.stack);
- g_free (ctx.code);
+ if (ctx.eval.stack)
+ g_free (ctx.eval.stack);
+ if (ctx.code)
+ g_free (ctx.code);
if (ctx.signature->hasthis)
g_free (ctx.params);