X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fverify.c;h=3ca8b590296fb2514529544f3ffeb260033af28b;hb=a5f3c441eef82a7e0e38bbe30e3b5577eebcaf77;hp=bf99e6f8cd72234f54caa98d030c17784de05592;hpb=2a2473d23f210a0185f0974b86d02ee2c1b57bd2;p=mono.git diff --git a/mono/metadata/verify.c b/mono/metadata/verify.c index bf99e6f8cd7..3ca8b590296 100644 --- a/mono/metadata/verify.c +++ b/mono/metadata/verify.c @@ -7,6 +7,7 @@ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) * Copyright 2004-2009 Novell, Inc (http://www.novell.com) */ +#include #include #include @@ -19,12 +20,34 @@ #include #include #include +#include +#include #include #include #include #include +static MiniVerifierMode verifier_mode = MONO_VERIFIER_MODE_OFF; +static gboolean verify_all = FALSE; + +/* + * Set the desired level of checks for the verfier. + * + */ +void +mono_verifier_set_mode (MiniVerifierMode mode) +{ + verifier_mode = mode; +} + +void +mono_verifier_enable_verify_all () +{ + verify_all = TRUE; +} + +#ifndef DISABLE_VERIFIER /* * Pull the list of opcodes */ @@ -90,6 +113,19 @@ enum { (__ctx)->valid = 0; \ } \ } while (0) + +#define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a)) +#define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a)) + +#if SIZEOF_VOID_P == 4 +#define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b) +#else +#define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b) +#endif + +#define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b)) +#define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b)) + /*Flags to be used with ILCodeDesc::flags */ enum { /*Instruction has not been processed.*/ @@ -343,9 +379,9 @@ static MonoType* mono_type_get_underlying_type_any (MonoType *type) { if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) - return type->data.klass->enum_basetype; + return mono_class_enum_basetype (type->data.klass); if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype) - return type->data.generic_class->container_class->enum_basetype; + return mono_class_enum_basetype (type->data.generic_class->container_class); return type; } @@ -373,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; @@ -384,76 +423,74 @@ 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; - 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; -} - /* - * Test if @candidate is a subtype of @target using the minimal possible information - * TODO move the code for non finished TypeBuilders to here. + * 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, */ static gboolean -mono_class_is_constraint_compatible (MonoClass *candidate, MonoClass *target) +mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context) { - 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; + int i; + MonoGenericInst *inst; - //if target is not a supertype it must be an interface - if (!MONO_CLASS_IS_INTERFACE (target)) + switch (type->type) { + case MONO_TYPE_VAR: + case MONO_TYPE_MVAR: + if (!context) + return FALSE; + inst = type->type == MONO_TYPE_VAR ? context->class_inst : context->method_inst; + if (!inst || mono_type_get_generic_param_num (type) >= inst->type_argc) return FALSE; + break; + case MONO_TYPE_SZARRAY: + return mono_type_is_valid_type_in_context (&type->data.klass->byval_arg, context); + case MONO_TYPE_ARRAY: + return mono_type_is_valid_type_in_context (&type->data.array->eklass->byval_arg, context); + case MONO_TYPE_PTR: + return mono_type_is_valid_type_in_context (type->data.type, context); + case MONO_TYPE_GENERICINST: + inst = type->data.generic_class->context.class_inst; + if (!inst->is_open) + break; + for (i = 0; i < inst->type_argc; ++i) + if (!mono_type_is_valid_type_in_context (inst->type_argv [i], context)) + return FALSE; + break; + } + return TRUE; +} - 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; +/*This function returns NULL if the type is not instantiatable*/ +static MonoType* +verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context) +{ + MonoError error; + MonoType *result; + + result = mono_class_inflate_generic_type_checked (type, context, &error); + if (!mono_error_ok (&error)) { + mono_error_cleanup (&error); + return NULL; } - return mono_class_interface_implements_interface (candidate, target); + return result; } + static gboolean is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst) { + MonoError error; int i; if (ginst->type_argc != gc->type_argc) return FALSE; for (i = 0; i < gc->type_argc; ++i) { - MonoGenericParam *param = &gc->type_params [i]; + MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i); MonoClass *paramClass; MonoClass **constraints; - if (!param->constraints && !(param->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK)) + if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK)) continue; if (mono_type_is_generic_argument (ginst->type_argv [i])) continue; //it's not our job to validate type variables @@ -469,27 +506,31 @@ is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *co return FALSE; } - if ((param->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!paramClass->valuetype || mono_class_is_nullable (paramClass))) + if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!paramClass->valuetype || mono_class_is_nullable (paramClass))) return FALSE; - if ((param->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && paramClass->valuetype) + if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && paramClass->valuetype) return FALSE; - if ((param->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !paramClass->valuetype && !mono_class_has_default_constructor (paramClass)) + if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !paramClass->valuetype && !mono_class_has_default_constructor (paramClass)) return FALSE; - if (!param->constraints) + if (!param_info->constraints) continue; - for (constraints = param->constraints; *constraints; ++constraints) { + for (constraints = param_info->constraints; *constraints; ++constraints) { MonoClass *ctr = *constraints; MonoType *inflated; - inflated = mono_class_inflate_generic_type (&ctr->byval_arg, context); + inflated = mono_class_inflate_generic_type_checked (&ctr->byval_arg, context, &error); + if (!mono_error_ok (&error)) { + mono_error_cleanup (&error); + return FALSE; + } 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; } } @@ -502,26 +543,33 @@ is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *co * This means that @candidate constraints are a super set of @target constaints */ static gboolean -mono_generic_param_is_constraint_compatible (MonoGenericParam *target, MonoGenericParam *candidate, MonoGenericContext *context) +mono_generic_param_is_constraint_compatible (VerifyContext *ctx, MonoGenericParam *target, MonoGenericParam *candidate, MonoGenericContext *context) { - int tmask = target->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK; - int cmask = candidate->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK; + MonoGenericParamInfo *tinfo = mono_generic_param_info (target); + MonoGenericParamInfo *cinfo = mono_generic_param_info (candidate); + + int tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK; + int cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK; if ((tmask & cmask) != tmask) return FALSE; - if (target->constraints) { + if (tinfo->constraints) { MonoClass **target_class, **candidate_class; - if (!candidate->constraints) + if (!cinfo->constraints) return FALSE; - for (target_class = target->constraints; *target_class; ++target_class) { - MonoType *inflated = mono_class_inflate_generic_type (&(*target_class)->byval_arg, context); - MonoClass *tc = mono_class_from_mono_type (inflated); + for (target_class = tinfo->constraints; *target_class; ++target_class) { + MonoClass *tc; + MonoType *inflated = verifier_inflate_type (ctx, &(*target_class)->byval_arg, context); + if (!inflated) + return FALSE; + tc = mono_class_from_mono_type (inflated); mono_metadata_free_type (inflated); - for (candidate_class = candidate->constraints; *candidate_class; ++candidate_class) { + for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) { MonoClass *cc; - - inflated = mono_class_inflate_generic_type (&(*candidate_class)->byval_arg, context); + inflated = verifier_inflate_type (ctx, &(*candidate_class)->byval_arg, ctx->generic_context); + if (!inflated) + return FALSE; cc = mono_class_from_mono_type (inflated); mono_metadata_free_type (inflated); @@ -542,7 +590,7 @@ verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type) MonoMethod *method = ctx->method; int num; - num = type->data.generic_param->num; + num = mono_type_get_generic_param_num (type); if (type->type == MONO_TYPE_VAR) { MonoClass *gtd = method->klass; @@ -557,7 +605,7 @@ verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type) } if (!gc) return FALSE; - return &gc->type_params [num]; + return mono_generic_container_get_param (gc, num); } @@ -570,20 +618,7 @@ verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type) static gboolean is_valid_type_in_context (VerifyContext *ctx, MonoType *type) { - if (mono_type_is_generic_argument (type) && !ctx->generic_context) - return FALSE; - if (type->type == MONO_TYPE_VAR) { - if (!ctx->generic_context->class_inst) - return FALSE; - if (type->data.generic_param->num >= ctx->generic_context->class_inst->type_argc) - return FALSE; - } else if (type->type == MONO_TYPE_MVAR) { - if (!ctx->generic_context->method_inst) - return FALSE; - if (type->data.generic_param->num >= ctx->generic_context->method_inst->type_argc) - return FALSE; - } - return TRUE; + return mono_type_is_valid_type_in_context (type, ctx->generic_context); } static gboolean @@ -604,7 +639,7 @@ generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer int i; for (i = 0; i < ginst->type_argc; ++i) { MonoType *type = ginst->type_argv [i]; - MonoGenericParam *target = &gc->type_params [i]; + MonoGenericParam *target = mono_generic_container_get_param (gc, i); MonoGenericParam *candidate; if (!mono_type_is_generic_argument (type)) @@ -615,7 +650,7 @@ generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer candidate = verifier_get_generic_param_from_type (ctx, type); - if (!mono_generic_param_is_constraint_compatible (target, candidate, context)) + if (!mono_generic_param_is_constraint_compatible (ctx, target, candidate, context)) return FALSE; } return TRUE; @@ -669,6 +704,11 @@ mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type) { MonoClass *klass; + if (type == NULL) { + ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); + return FALSE; + } + 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", @@ -691,7 +731,7 @@ mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type) return FALSE; } - if (klass->exception_type != MONO_EXCEPTION_NONE || (klass->generic_class && klass->generic_class->container_class->exception_type != MONO_EXCEPTION_NONE)) { + if (klass->generic_class && klass->generic_class->container_class->exception_type != MONO_EXCEPTION_NONE) { ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Could not load type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD); return FALSE; } @@ -735,23 +775,25 @@ mono_method_is_valid_in_context (VerifyContext *ctx, MonoMethod *method) static MonoClassField* -verifier_load_field (VerifyContext *ctx, int token, MonoClass **klass, const char *opcode) { +verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) { MonoClassField *field; - + MonoClass *klass = NULL; + if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) { - ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid field token 0x%x08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); + ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid field token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); return NULL; } - field = mono_field_from_token (ctx->image, token, klass, ctx->generic_context); - if (!field) { + field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context); + if (!field || !field->parent || !klass) { ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load field from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE); return NULL; } - if (!mono_type_is_valid_in_context (ctx, &field->parent->byval_arg)) + if (!mono_type_is_valid_in_context (ctx, &klass->byval_arg)) return NULL; + *out_klass = klass; return field; } @@ -1002,7 +1044,7 @@ is_valid_culture (const char *cname) found = *cname == 0; for (i = 0; i < G_N_ELEMENTS (valid_cultures); ++i) { - if (g_strcasecmp (valid_cultures [i], cname)) { + if (g_ascii_strcasecmp (valid_cultures [i], cname)) { found = 1; break; } @@ -1939,6 +1981,7 @@ check_unverifiable_type (VerifyContext *ctx, MonoType *type) static ILStackDesc * stack_push (VerifyContext *ctx) { + g_assert (ctx->eval.size < ctx->max_stack); return & ctx->eval.stack [ctx->eval.size++]; } @@ -1954,7 +1997,9 @@ stack_push_val (VerifyContext *ctx, int stype, MonoType *type) static ILStackDesc * stack_pop (VerifyContext *ctx) { - ILStackDesc *ret = ctx->eval.stack + --ctx->eval.size; + ILStackDesc *ret; + g_assert (ctx->eval.size > 0); + ret = ctx->eval.stack + --ctx->eval.size; if ((ret->stype & UNINIT_THIS_MASK) == UNINIT_THIS_MASK) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Found use of uninitialized 'this ptr' ref at 0x%04x", ctx->ip_offset)); return ret; @@ -1966,6 +2011,7 @@ stack_pop (VerifyContext *ctx) static ILStackDesc * stack_pop_safe (VerifyContext *ctx) { + g_assert (ctx->eval.size > 0); return ctx->eval.stack + --ctx->eval.size; } @@ -1985,7 +2031,7 @@ static MonoType* get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode) { MonoType *type; - + MonoClass *class; if (!(type = verifier_load_type (ctx, token, opcode))) return NULL; @@ -2003,6 +2049,12 @@ get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode) if (type->type == MONO_TYPE_TYPEDBYREF) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref for %s at 0x%04x", opcode, ctx->ip_offset)); + if (!(class = mono_class_from_mono_type (type))) + ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset)); + + if (class->generic_container && type->type != MONO_TYPE_GENERICINST) + CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use the generic type definition in a boxable type position for %s at 0x%04x", opcode, ctx->ip_offset)); + check_unverifiable_type (ctx, type); return type; } @@ -2168,10 +2220,10 @@ dump_stack_value (ILStackDesc *value) 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); + printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (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); + printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name); return; default: { //should be a boxed value @@ -2285,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; } } @@ -2383,12 +2433,29 @@ handle_enum: static void init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass) { - MonoType *type = mono_class_inflate_generic_type (&klass->byval_arg, ctx->generic_context); + MonoError error; + MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, ctx->generic_context, &error); + + if (!mono_error_ok (&error)) { + char *name = mono_type_get_full_name (klass); + ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid class %s used for exception", name)); + g_free (name); + mono_error_cleanup (&error); + 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); code->size = 1; code->flags |= IL_CODE_FLAG_WAS_TARGET; + if (mono_type_is_generic_argument (type)) + code->stack->stype |= BOXED_MASK; } /*Verify if type 'candidate' can be stored in type 'target'. @@ -2402,7 +2469,7 @@ verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType * #define IS_ONE_OF2(T, A, B) (T == A || T == B) MonoType *original_candidate = candidate; - VERIFIER_DEBUG ( printf ("checking type compatibility %p %p[%x][%x] %p[%x][%x]\n", ctx, target, target->type, target->byref, candidate, candidate->type, candidate->byref); ); + VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); ); /*only one is byref */ if (candidate->byref ^ target->byref) { @@ -2517,9 +2584,9 @@ handle_enum: if (candidate->type != MONO_TYPE_SZARRAY) return FALSE; - left = target->data.array->eklass; - right = candidate->data.array->eklass; - return mono_class_is_assignable_from(left, right); + left = mono_class_from_mono_type (target)->element_class; + right = mono_class_from_mono_type (candidate)->element_class; + return mono_class_is_assignable_from (left, right); } case MONO_TYPE_ARRAY: @@ -2530,24 +2597,28 @@ handle_enum: case MONO_TYPE_TYPEDBYREF: return candidate->type == MONO_TYPE_TYPEDBYREF; - case MONO_TYPE_VALUETYPE: - if (candidate->type == MONO_TYPE_VALUETYPE && target->data.klass == candidate->data.klass) + case MONO_TYPE_VALUETYPE: { + MonoClass *target_klass = mono_class_from_mono_type (target); + MonoClass *candidate_klass = mono_class_from_mono_type (candidate); + + if (target_klass == candidate_klass) return TRUE; if (mono_type_is_enum_type (target)) { target = mono_type_get_underlying_type_any (target); goto handle_enum; } return FALSE; + } case MONO_TYPE_VAR: if (candidate->type != MONO_TYPE_VAR) return FALSE; - return candidate->data.generic_param->num == target->data.generic_param->num; + return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target); case MONO_TYPE_MVAR: if (candidate->type != MONO_TYPE_MVAR) return FALSE; - return candidate->data.generic_param->num == target->data.generic_param->num; + return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target); default: VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); ); @@ -2572,7 +2643,7 @@ verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candi static MonoGenericParam* get_generic_param (VerifyContext *ctx, MonoType *param) { - guint16 param_num = param->data.generic_param->num; + guint16 param_num = mono_type_get_generic_param_num (param); if (param->type == MONO_TYPE_VAR) { if (!ctx->generic_context->class_inst || ctx->generic_context->class_inst->type_argc <= param_num) { ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic type argument %d", param_num)); @@ -2611,7 +2682,7 @@ is_compatible_boxed_valuetype (VerifyContext *ctx, MonoType *type, MonoType *can if (mono_type_is_generic_argument (candidate)) { MonoGenericParam *param = get_generic_param (ctx, candidate); MonoClass **class; - for (class = param->constraints; class && *class; ++class) { + for (class = mono_generic_param_info (param)->constraints; class && *class; ++class) { if (verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (& (*class)->byval_arg), FALSE)) return TRUE; } @@ -2700,14 +2771,12 @@ mono_delegate_type_equal (MonoType *target, MonoType *candidate) return MONO_TYPE_IS_REFERENCE (candidate); case MONO_TYPE_CLASS: - if (candidate->type != MONO_TYPE_CLASS) - return FALSE; - return mono_class_is_assignable_from(target->data.klass, candidate->data.klass); + return mono_class_is_assignable_from(target->data.klass, mono_class_from_mono_type (candidate)); case MONO_TYPE_SZARRAY: if (candidate->type != MONO_TYPE_SZARRAY) return FALSE; - return mono_class_is_assignable_from (target->data.array->eklass, candidate->data.array->eklass); + return mono_class_is_assignable_from (mono_class_from_mono_type (target)->element_class, mono_class_from_mono_type (candidate)->element_class); case MONO_TYPE_ARRAY: if (candidate->type != MONO_TYPE_ARRAY) @@ -2716,14 +2785,14 @@ mono_delegate_type_equal (MonoType *target, MonoType *candidate) case MONO_TYPE_VALUETYPE: /*FIXME handle nullables and enum*/ - return candidate->type == MONO_TYPE_VALUETYPE && target->data.klass == candidate->data.klass; + return mono_class_from_mono_type (candidate) == mono_class_from_mono_type (target); case MONO_TYPE_VAR: - return candidate->type == MONO_TYPE_VAR && target->data.generic_param->num == candidate->data.generic_param->num; + return candidate->type == MONO_TYPE_VAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate); return FALSE; case MONO_TYPE_MVAR: - return candidate->type == MONO_TYPE_MVAR && target->data.generic_param->num == candidate->data.generic_param->num; + return candidate->type == MONO_TYPE_MVAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate); return FALSE; default: @@ -2842,13 +2911,32 @@ 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) is_first_arg_bound = mono_method_signature (invoke)->param_count + 1 == mono_method_signature (method)->param_count; - if (!mono_delegate_signature_equal (mono_method_signature (invoke), mono_method_signature (method), is_first_arg_bound)) - CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Function pointer parameter for delegate constructor has diferent signature at 0x%04x", ctx->ip_offset)); + if (!mono_delegate_signature_equal (mono_method_signature (invoke), mono_method_signature (method), is_first_arg_bound)) { + char *fun_sig = mono_signature_get_desc (mono_method_signature (method), FALSE); + char *invoke_sig = mono_signature_get_desc (mono_method_signature (invoke), FALSE); + CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Function pointer signature '%s' doesn't match delegate's signature '%s' at 0x%04x", fun_sig, invoke_sig, ctx->ip_offset)); + g_free (fun_sig); + g_free (invoke_sig); + } /* * Delegate code sequences: @@ -2872,11 +2960,16 @@ verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackD //general tests if (is_first_arg_bound) { - if (!verify_stack_type_compatibility_full (ctx, mono_method_signature (method)->params [0], value, FALSE, TRUE)) + if (mono_method_signature (method)->param_count == 0 || !verify_stack_type_compatibility_full (ctx, mono_method_signature (method)->params [0], value, FALSE, TRUE)) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset)); } else { - if (!verify_stack_type_compatibility_full (ctx, &method->klass->byval_arg, value, FALSE, TRUE) && !stack_slot_is_null_literal (value)) - CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset)); + if (method->flags & METHOD_ATTRIBUTE_STATIC) { + if (!stack_slot_is_null_literal (value) && !is_first_arg_bound) + CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Non-null this args used with static function for delegate creation at 0x%04x", ctx->ip_offset)); + } else { + if (!verify_stack_type_compatibility_full (ctx, &method->klass->byval_arg, value, FALSE, TRUE) && !stack_slot_is_null_literal (value)) + CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset)); + } } if (stack_slot_get_type (value) != TYPE_COMPLEX) @@ -3252,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; @@ -3262,7 +3362,7 @@ do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual) if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) { char *stack_name = stack_slot_full_name (value); char *sig_name = mono_type_full_name (sig->params [i]); - CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with function signature: %s X %s at 0x%04x", sig_name, stack_name, ctx->ip_offset)); + CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter with function signature: Calling method with signature (%s) but for argument %d there is a (%s) on stack at 0x%04x", sig_name, i, stack_name, ctx->ip_offset)); g_free (stack_name); g_free (sig_name); } @@ -3325,11 +3425,17 @@ do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual) 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_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); + if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) { + char *name = mono_method_full_name (method, TRUE); + CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS); + g_free (name); + } - } 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); + } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) { + char *name = mono_method_full_name (method, TRUE); + CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS); + g_free (name); + } if (sig->ret->type != MONO_TYPE_VOID) { if (check_overflow (ctx)) { @@ -3356,6 +3462,8 @@ do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr) { MonoClassField *field; MonoClass *klass; + if (!check_overflow (ctx)) + return; if (!take_addr) CLEAR_PREFIX (ctx, PREFIX_VOLATILE); @@ -3787,7 +3895,12 @@ do_initobj (VerifyContext *ctx, int token) else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack)) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset)); } else if (!verify_type_compatibility (ctx, stack, type)) { - CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset)); + char *expected_name = mono_type_full_name (type); + char *stack_name = mono_type_full_name (stack); + + CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Initobj %s not compatible with value on stack %s at 0x%04x", expected_name, stack_name, ctx->ip_offset)); + g_free (expected_name); + g_free (stack_name); } } @@ -3811,11 +3924,21 @@ do_newobj (VerifyContext *ctx, int token) 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_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); + if (!mono_method_can_access_method_full (ctx->method, method, NULL)) { + char *from = mono_method_full_name (ctx->method, TRUE); + char *to = mono_method_full_name (method, TRUE); + CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Constructor %s not visible from %s at 0x%04x", to, from, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS); + g_free (from); + g_free (to); + } //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; @@ -3875,8 +3998,11 @@ do_cast (VerifyContext *ctx, int token, const char *opcode) { if (stack_slot_is_managed_pointer (value)) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset)); - else if (mono_class_from_mono_type (value->type)->valuetype && !is_boxed) - CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Value cannot be a valuetype for %s at 0x%04x", opcode, ctx->ip_offset)); + else if (!MONO_TYPE_IS_REFERENCE (value->type) && !is_boxed) { + char *name = stack_slot_full_name (value); + CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Expected a reference type on stack for %s but found %s at 0x%04x", opcode, name, ctx->ip_offset)); + g_free (name); + } switch (value->type->type) { case MONO_TYPE_FNPTR: @@ -4102,7 +4228,7 @@ do_ldelem (VerifyContext *ctx, int opcode, int token) if (!check_underflow (ctx, 2)) return; - if (opcode == CEE_LDELEM_ANY) { + if (opcode == CEE_LDELEM) { if (!(type = verifier_load_type (ctx, token, "ldelem.any"))) { ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset)); return; @@ -4155,7 +4281,7 @@ do_stelem (VerifyContext *ctx, int opcode, int token) if (!check_underflow (ctx, 3)) return; - if (opcode == CEE_STELEM_ANY) { + if (opcode == CEE_STELEM) { if (!(type = verifier_load_type (ctx, token, "stelem.any"))) { ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset)); return; @@ -4207,6 +4333,11 @@ do_throw (VerifyContext *ctx) if (!stack_slot_is_null_literal (exception) && !(stack_slot_get_type (exception) == TYPE_COMPLEX && !mono_class_from_mono_type (exception->type)->valuetype)) CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset)); + if (mono_type_is_generic_argument (exception->type) && !stack_slot_is_boxed_value (exception)) { + char *name = mono_type_full_name (exception->type); + CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type but found unboxed %s at 0x%04x ", name, ctx->ip_offset)); + g_free (name); + } /*The stack is left empty after a throw*/ ctx->eval.size = 0; } @@ -4411,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 (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; } @@ -4516,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); @@ -4582,6 +4717,12 @@ merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean sta } } + 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)) { @@ -4679,10 +4820,8 @@ static void verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test) { /*clause is nested*/ - if (is_clause_nested (to_test, clause)) { - if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER) { - ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter")); - } + if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (clause, to_test->data.filter_offset, to_test->handler_offset)) { + ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter")); return; } @@ -4709,13 +4848,13 @@ verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, Mon } /*not completelly disjoint*/ - if (is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) || - is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) + if ((is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) || + is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) && !is_clause_nested (to_test, clause)) ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap")); } #define code_bounds_check(size) \ - if (ip + size > end) {\ + if (ADDP_IS_GREATER_OR_OVF (ip, size, end)) {\ ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Code overrun starting with 0x%x at 0x%04x", *ip, ctx.ip_offset)); \ break; \ } \ @@ -4728,6 +4867,7 @@ verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, Mon GSList* mono_method_verify (MonoMethod *method, int level) { + MonoError error; const unsigned char *ip; const unsigned char *end; int i, n, need_merge = 0, start = 0; @@ -4794,24 +4934,55 @@ mono_method_verify (MonoMethod *method, int level) ctx.generic_context = generic_context = &method->klass->generic_container->context; } - for (i = 0; i < ctx.num_locals; ++i) - ctx.locals [i] = mono_class_inflate_generic_type (ctx.locals [i], ctx.generic_context); - for (i = 0; i < ctx.max_args; ++i) - ctx.params [i] = mono_class_inflate_generic_type (ctx.params [i], ctx.generic_context); + for (i = 0; i < ctx.num_locals; ++i) { + MonoType *uninflated = ctx.locals [i]; + ctx.locals [i] = mono_class_inflate_generic_type_checked (ctx.locals [i], ctx.generic_context, &error); + if (!mono_error_ok (&error)) { + char *name = mono_type_full_name (ctx.locals [i] ? ctx.locals [i] : uninflated); + ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %d of type %s", i, name)); + g_free (name); + mono_error_cleanup (&error); + /* we must not free (in cleanup) what was not yet allocated (but only copied) */ + ctx.num_locals = i; + ctx.max_args = 0; + goto cleanup; + } + } + for (i = 0; i < ctx.max_args; ++i) { + MonoType *uninflated = ctx.params [i]; + ctx.params [i] = mono_class_inflate_generic_type_checked (ctx.params [i], ctx.generic_context, &error); + if (!mono_error_ok (&error)) { + char *name = mono_type_full_name (ctx.params [i] ? ctx.params [i] : uninflated); + ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %d of type %s", i, name)); + g_free (name); + mono_error_cleanup (&error); + /* we must not free (in cleanup) what was not yet allocated (but only copied) */ + ctx.max_args = i; + goto cleanup; + } + } stack_init (&ctx, &ctx.eval); for (i = 0; i < ctx.num_locals; ++i) { - if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i])) { - /*TODO use the last error message to provide better feedback. */ - ADD_VERIFY_ERROR2 (&ctx, g_strdup_printf ("Invalid local variable %d", i), MONO_EXCEPTION_BAD_IMAGE); + 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])) { - /*TODO use the last error message to provide better feedback. */ - ADD_VERIFY_ERROR2 (&ctx, g_strdup_printf ("Invalid parameter %d", i), MONO_EXCEPTION_BAD_IMAGE); + 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; } } @@ -4823,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) + 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) - ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset)); + 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); @@ -4845,10 +5019,17 @@ mono_method_verify (MonoMethod *method, int level) break; ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET; - ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET; - ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET; + if (clause->try_offset + clause->try_len < ctx.code_size) + ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET; + if (clause->handler_offset + clause->handler_len < ctx.code_size) + 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) { @@ -4891,7 +5072,7 @@ mono_method_verify (MonoMethod *method, int level) start = 1; } - if (clause->try_offset == ip_offset && ctx.eval.size > 0) { + if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) { ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset)); start = 1; } @@ -5142,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; @@ -5223,16 +5404,22 @@ mono_method_verify (MonoMethod *method, int level) need_merge = 1; break; - case CEE_SWITCH: + case CEE_SWITCH: { + guint32 entries; code_bounds_check (5); - n = read32 (ip + 1); - code_bounds_check (5 + sizeof (guint32) * n); + entries = read32 (ip + 1); + + if (entries > 0xFFFFFFFFU / sizeof (guint32)) + ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Too many switch entries %x at 0x%04x", entries, ctx.ip_offset)); + + ip += 5; + code_bounds_check (sizeof (guint32) * entries); - do_switch (&ctx, n, (ip + 5)); + do_switch (&ctx, entries, ip); start = 1; - ip += 5 + sizeof (guint32) * n; + ip += sizeof (guint32) * entries; break; - + } case CEE_LDIND_I1: case CEE_LDIND_U1: case CEE_LDIND_I2: @@ -5328,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: @@ -5447,13 +5635,13 @@ mono_method_verify (MonoMethod *method, int level) ++ip; break; - case CEE_LDELEM_ANY: + case CEE_LDELEM: code_bounds_check (5); do_ldelem (&ctx, *ip, read32 (ip + 1)); ip += 5; break; - case CEE_STELEM_ANY: + case CEE_STELEM: code_bounds_check (5); do_stelem (&ctx, *ip, read32 (ip + 1)); ip += 5; @@ -5582,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); @@ -5605,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: @@ -5670,9 +5858,7 @@ mono_method_verify (MonoMethod *method, int level) if (!is_correct_rethrow (ctx.header, ip_offset)) ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset)); ctx.eval.size = 0; - ++ip; - break; - case CEE_UNUSED: + start = 1; ++ip; break; @@ -5744,8 +5930,16 @@ mono_method_verify (MonoMethod *method, int level) CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid call to a non-final virtual function in method with stdarg.0 or ldarga.0 at 0x%04x", i)); } - if (mono_method_is_constructor (ctx.method) && !ctx.super_ctor_called && !ctx.method->klass->valuetype && ctx.method->klass != mono_defaults.object_class) - CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor not calling super\n")); + if (mono_method_is_constructor (ctx.method) && !ctx.super_ctor_called && !ctx.method->klass->valuetype && ctx.method->klass != mono_defaults.object_class) { + char *method_name = mono_method_full_name (ctx.method, TRUE); + char *type = mono_type_get_full_name (ctx.method->klass); + if (ctx.method->klass->parent && ctx.method->klass->parent->exception_type != MONO_EXCEPTION_NONE) + CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor %s for type %s not calling base type ctor due to a TypeLoadException on base type.", method_name, type)); + else + CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor %s for type %s not calling base type ctor.", method_name, type)); + g_free (method_name); + g_free (type); + } cleanup: if (ctx.code) { @@ -5763,10 +5957,14 @@ cleanup: mono_metadata_free_type (tmp->data); g_slist_free (ctx.exception_types); - for (i = 0; i < ctx.num_locals; ++i) - mono_metadata_free_type (ctx.locals [i]); - for (i = 0; i < ctx.max_args; ++i) - mono_metadata_free_type (ctx.params [i]); + for (i = 0; i < ctx.num_locals; ++i) { + if (ctx.locals [i]) + mono_metadata_free_type (ctx.locals [i]); + } + for (i = 0; i < ctx.max_args; ++i) { + if (ctx.params [i]) + mono_metadata_free_type (ctx.params [i]); + } if (ctx.eval.stack) g_free (ctx.eval.stack); @@ -5785,25 +5983,6 @@ mono_verify_corlib () return NULL; } -static MiniVerifierMode verifier_mode = MONO_VERIFIER_MODE_OFF; -static gboolean verify_all = FALSE; - -/* - * Set the desired level of checks for the verfier. - * - */ -void -mono_verifier_set_mode (MiniVerifierMode mode) -{ - verifier_mode = mode; -} - -void -mono_verifier_enable_verify_all () -{ - verify_all = TRUE; -} - /* * Returns true if @method needs to be verified. * @@ -5824,6 +6003,12 @@ mono_verifier_is_enabled_for_class (MonoClass *klass) return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !klass->image->assembly->in_gac && klass->image != mono_defaults.corlib); } +gboolean +mono_verifier_is_enabled_for_image (MonoImage *image) +{ + return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF; +} + gboolean mono_verifier_is_method_full_trust (MonoMethod *method) { @@ -5835,18 +6020,19 @@ mono_verifier_is_method_full_trust (MonoMethod *method) * * TODO This code doesn't take CAS into account. * - * This value is only pertinent to assembly verification and has - * nothing to do with CoreClr security. - * * Under verify_all all user code must be verifiable if no security option was set * */ 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) ? + klass->image->assembly->in_gac : mono_security_core_clr_is_platform_image (klass->image); + if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF) - return klass->image->assembly->in_gac || klass->image == mono_defaults.corlib; - return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || klass->image->assembly->in_gac || klass->image == mono_defaults.corlib; + return trusted_location || klass->image == mono_defaults.corlib; + return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || klass->image == mono_defaults.corlib; } GSList* @@ -5900,6 +6086,99 @@ verify_class_for_overlapping_reference_fields (MonoClass *class) return TRUE; } +static guint +field_hash (gconstpointer key) +{ + const MonoClassField *field = key; + return g_str_hash (field->name) ^ mono_metadata_type_hash (field->type); /**/ +} + +static gboolean +field_equals (gconstpointer _a, gconstpointer _b) +{ + const MonoClassField *a = _a; + const MonoClassField *b = _b; + return !strcmp (a->name, b->name) && mono_metadata_type_equal (a->type, b->type); +} + + +static gboolean +verify_class_fields (MonoClass *class) +{ + gpointer iter = NULL; + MonoClassField *field; + MonoGenericContext *context = mono_class_get_context (class); + GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL); + if (class->generic_container) + context = &class->generic_container->context; + + while ((field = mono_class_get_fields (class, &iter)) != NULL) { + if (!mono_type_is_valid_type_in_context (field->type, context)) { + g_hash_table_destroy (unique_fields); + return FALSE; + } + if (g_hash_table_lookup (unique_fields, field)) { + g_hash_table_destroy (unique_fields); + return FALSE; + } + g_hash_table_insert (unique_fields, field, field); + } + g_hash_table_destroy (unique_fields); + return TRUE; +} + +static gboolean +verify_interfaces (MonoClass *class) +{ + int i; + for (i = 0; i < class->interface_count; ++i) { + MonoClass *iface = class->interfaces [i]; + if (!(iface->flags & TYPE_ATTRIBUTE_INTERFACE)) + return FALSE; + } + return TRUE; +} + +static gboolean +verify_valuetype_layout_with_target (MonoClass *class, MonoClass *target_class) +{ + int type; + gpointer iter = NULL; + MonoClassField *field; + MonoClass *field_class; + + if (!class->valuetype) + return TRUE; + + type = class->byval_arg.type; + /*primitive type fields are not properly decoded*/ + if ((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_R8) || (type >= MONO_TYPE_I && type <= MONO_TYPE_U)) + return TRUE; + + while ((field = mono_class_get_fields (class, &iter)) != NULL) { + if (!field->type) + return FALSE; + + if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)) + continue; + + field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type (field->type)); + + if (field_class == target_class || class == field_class || !verify_valuetype_layout_with_target (field_class, target_class)) + return FALSE; + } + + return TRUE; +} + +static gboolean +verify_valuetype_layout (MonoClass *class) +{ + gboolean res; + res = verify_valuetype_layout_with_target (class, class); + return res; +} + /* * Check if the class is verifiable. * @@ -5912,12 +6191,97 @@ verify_class_for_overlapping_reference_fields (MonoClass *class) gboolean mono_verifier_verify_class (MonoClass *class) { + /*Neither , 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)) /* 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)) return FALSE; - if (class->generic_class && !mono_class_is_valid_generic_instantiation (NULL, class)) return FALSE; + if (class->generic_class == NULL && !verify_class_fields (class)) + return FALSE; + if (class->valuetype && !verify_valuetype_layout (class)) + return FALSE; + if (!verify_interfaces (class)) + return FALSE; return TRUE; } +#else + +gboolean +mono_verifier_verify_class (MonoClass *class) +{ + /* The verifier was disabled at compile time */ + return TRUE; +} + +GSList* +mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility) +{ + /* The verifier was disabled at compile time */ + return NULL; +} + +gboolean +mono_verifier_is_class_full_trust (MonoClass *klass) +{ + /* The verifier was disabled at compile time */ + return TRUE; +} + +gboolean +mono_verifier_is_method_full_trust (MonoMethod *method) +{ + /* The verifier was disabled at compile time */ + return TRUE; +} + +gboolean +mono_verifier_is_enabled_for_image (MonoImage *image) +{ + /* The verifier was disabled at compile time */ + return FALSE; +} + +gboolean +mono_verifier_is_enabled_for_class (MonoClass *klass) +{ + /* The verifier was disabled at compile time */ + return FALSE; +} + +gboolean +mono_verifier_is_enabled_for_method (MonoMethod *method) +{ + /* The verifier was disabled at compile time */ + return FALSE; +} + +GSList* +mono_method_verify (MonoMethod *method, int level) +{ + /* The verifier was disabled at compile time */ + return NULL; +} + +void +mono_free_verify_list (GSList *list) +{ + /* The verifier was disabled at compile time */ + /* will always be null if verifier is disabled */ +} + +GSList* +mono_image_verify_tables (MonoImage *image, int level) +{ + /* The verifier was disabled at compile time */ + return NULL; +} +#endif