[runtime] Change mono_type_get_full to use MonoError properly.
[mono-project.git] / mono / metadata / verify.c
blob95bde8efbc5433a93c092b52b3d363ee63b859b5
1 /*
2 * verify.c:
4 * Author:
5 * Mono Project (http://www.mono-project.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Rodrigo Kumpera
11 #include <config.h>
13 #include <mono/metadata/object-internals.h>
14 #include <mono/metadata/verify.h>
15 #include <mono/metadata/verify-internals.h>
16 #include <mono/metadata/opcodes.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/reflection.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/metadata.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/security-manager.h>
25 #include <mono/metadata/security-core-clr.h>
26 #include <mono/metadata/tokentype.h>
27 #include <mono/metadata/mono-basic-block.h>
28 #include <mono/metadata/attrdefs.h>
29 #include <mono/utils/mono-counters.h>
30 #include <mono/utils/monobitset.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <ctype.h>
35 static MiniVerifierMode verifier_mode = MONO_VERIFIER_MODE_OFF;
36 static gboolean verify_all = FALSE;
39 * Set the desired level of checks for the verfier.
42 void
43 mono_verifier_set_mode (MiniVerifierMode mode)
45 verifier_mode = mode;
48 void
49 mono_verifier_enable_verify_all ()
51 verify_all = TRUE;
54 #ifndef DISABLE_VERIFIER
56 * Pull the list of opcodes
58 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
59 a = i,
61 enum {
62 #include "mono/cil/opcode.def"
63 LAST = 0xff
65 #undef OPDEF
67 #ifdef MONO_VERIFIER_DEBUG
68 #define VERIFIER_DEBUG(code) do { code } while (0)
69 #else
70 #define VERIFIER_DEBUG(code)
71 #endif
73 //////////////////////////////////////////////////////////////////
74 #define IS_STRICT_MODE(ctx) (((ctx)->level & MONO_VERIFY_NON_STRICT) == 0)
75 #define IS_FAIL_FAST_MODE(ctx) (((ctx)->level & MONO_VERIFY_FAIL_FAST) == MONO_VERIFY_FAIL_FAST)
76 #define IS_SKIP_VISIBILITY(ctx) (((ctx)->level & MONO_VERIFY_SKIP_VISIBILITY) == MONO_VERIFY_SKIP_VISIBILITY)
77 #define IS_REPORT_ALL_ERRORS(ctx) (((ctx)->level & MONO_VERIFY_REPORT_ALL_ERRORS) == MONO_VERIFY_REPORT_ALL_ERRORS)
78 #define CLEAR_PREFIX(ctx, prefix) do { (ctx)->prefix_set &= ~(prefix); } while (0)
79 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
80 do { \
81 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
82 vinfo->info.status = __status; \
83 vinfo->info.message = ( __msg ); \
84 vinfo->exception_type = (__exception); \
85 (__ctx)->list = g_slist_prepend ((__ctx)->list, vinfo); \
86 } while (0)
88 //TODO support MONO_VERIFY_REPORT_ALL_ERRORS
89 #define ADD_VERIFY_ERROR(__ctx, __msg) \
90 do { \
91 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
92 (__ctx)->valid = 0; \
93 } while (0)
95 #define CODE_NOT_VERIFIABLE(__ctx, __msg) \
96 do { \
97 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
98 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, MONO_EXCEPTION_UNVERIFIABLE_IL); \
99 (__ctx)->verifiable = 0; \
100 if (IS_FAIL_FAST_MODE (__ctx)) \
101 (__ctx)->valid = 0; \
103 } while (0)
105 #define ADD_VERIFY_ERROR2(__ctx, __msg, __exception) \
106 do { \
107 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, __exception); \
108 (__ctx)->valid = 0; \
109 } while (0)
111 #define CODE_NOT_VERIFIABLE2(__ctx, __msg, __exception) \
112 do { \
113 if ((__ctx)->verifiable || IS_REPORT_ALL_ERRORS (__ctx)) { \
114 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_NOT_VERIFIABLE, __exception); \
115 (__ctx)->verifiable = 0; \
116 if (IS_FAIL_FAST_MODE (__ctx)) \
117 (__ctx)->valid = 0; \
119 } while (0)
121 #define CHECK_ADD4_OVERFLOW_UN(a, b) ((guint32)(0xFFFFFFFFU) - (guint32)(b) < (guint32)(a))
122 #define CHECK_ADD8_OVERFLOW_UN(a, b) ((guint64)(0xFFFFFFFFFFFFFFFFUL) - (guint64)(b) < (guint64)(a))
124 #if SIZEOF_VOID_P == 4
125 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD4_OVERFLOW_UN(a, b)
126 #else
127 #define CHECK_ADDP_OVERFLOW_UN(a,b) CHECK_ADD8_OVERFLOW_UN(a, b)
128 #endif
130 #define ADDP_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADDP_OVERFLOW_UN (a, b))
131 #define ADD_IS_GREATER_OR_OVF(a, b, c) (((a) + (b) > (c)) || CHECK_ADD4_OVERFLOW_UN (a, b))
133 /*Flags to be used with ILCodeDesc::flags */
134 enum {
135 /*Instruction has not been processed.*/
136 IL_CODE_FLAG_NOT_PROCESSED = 0,
137 /*Instruction was decoded by mono_method_verify loop.*/
138 IL_CODE_FLAG_SEEN = 1,
139 /*Instruction was target of a branch or is at a protected block boundary.*/
140 IL_CODE_FLAG_WAS_TARGET = 2,
141 /*Used by stack_init to avoid double initialize each entry.*/
142 IL_CODE_FLAG_STACK_INITED = 4,
143 /*Used by merge_stacks to decide if it should just copy the eval stack.*/
144 IL_CODE_STACK_MERGED = 8,
145 /*This instruction is part of the delegate construction sequence, it cannot be target of a branch.*/
146 IL_CODE_DELEGATE_SEQUENCE = 0x10,
147 /*This is a delegate created from a ldftn to a non final virtual method*/
148 IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL = 0x20,
149 /*This is a call to a non final virtual method*/
150 IL_CODE_CALL_NONFINAL_VIRTUAL = 0x40,
153 typedef enum {
154 RESULT_VALID,
155 RESULT_UNVERIFIABLE,
156 RESULT_INVALID
157 } verify_result_t;
159 typedef struct {
160 MonoType *type;
161 int stype;
162 MonoMethod *method;
163 } ILStackDesc;
166 typedef struct {
167 ILStackDesc *stack;
168 guint16 size, max_size;
169 guint16 flags;
170 } ILCodeDesc;
172 typedef struct {
173 int max_args;
174 int max_stack;
175 int verifiable;
176 int valid;
177 int level;
179 int code_size;
180 ILCodeDesc *code;
181 ILCodeDesc eval;
183 MonoType **params;
184 GSList *list;
185 /*Allocated fnptr MonoType that should be freed by us.*/
186 GSList *funptrs;
187 /*Type dup'ed exception types from catch blocks.*/
188 GSList *exception_types;
190 int num_locals;
191 MonoType **locals;
193 /*TODO get rid of target here, need_merge in mono_method_verify and hoist the merging code in the branching code*/
194 int target;
196 guint32 ip_offset;
197 MonoMethodSignature *signature;
198 MonoMethodHeader *header;
200 MonoGenericContext *generic_context;
201 MonoImage *image;
202 MonoMethod *method;
204 /*This flag helps solving a corner case of delegate verification in that you cannot have a "starg 0"
205 *on a method that creates a delegate for a non-final virtual method using ldftn*/
206 gboolean has_this_store;
208 /*This flag is used to control if the contructor of the parent class has been called.
209 *If the this pointer is pushed on the eval stack and it's a reference type constructor and
210 * super_ctor_called is false, the uninitialized flag is set on the pushed value.
212 * Poping an uninitialized this ptr from the eval stack is an unverifiable operation unless
213 * the safe variant is used. Only a few opcodes can use it : dup, pop, ldfld, stfld and call to a constructor.
215 gboolean super_ctor_called;
217 guint32 prefix_set;
218 gboolean has_flags;
219 MonoType *constrained_type;
220 } VerifyContext;
222 static void
223 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external);
225 static int
226 get_stack_type (MonoType *type);
228 static gboolean
229 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn);
231 static gboolean
232 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass);
234 static gboolean
235 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method);
237 static MonoGenericParam*
238 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type);
240 static gboolean
241 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate);
242 //////////////////////////////////////////////////////////////////
246 enum {
247 TYPE_INV = 0, /* leave at 0. */
248 TYPE_I4 = 1,
249 TYPE_I8 = 2,
250 TYPE_NATIVE_INT = 3,
251 TYPE_R8 = 4,
252 /* Used by operator tables to resolve pointer types (managed & unmanaged) and by unmanaged pointer types*/
253 TYPE_PTR = 5,
254 /* value types and classes */
255 TYPE_COMPLEX = 6,
256 /* Number of types, used to define the size of the tables*/
257 TYPE_MAX = 6,
259 /* Used by tables to signal that a result is not verifiable*/
260 NON_VERIFIABLE_RESULT = 0x80,
262 /*Mask used to extract just the type, excluding flags */
263 TYPE_MASK = 0x0F,
265 /* The stack type is a managed pointer, unmask the value to res */
266 POINTER_MASK = 0x100,
268 /*Stack type with the pointer mask*/
269 RAW_TYPE_MASK = 0x10F,
271 /* Controlled Mutability Manager Pointer */
272 CMMP_MASK = 0x200,
274 /* The stack type is a null literal*/
275 NULL_LITERAL_MASK = 0x400,
277 /**Used by ldarg.0 and family to let delegate verification happens.*/
278 THIS_POINTER_MASK = 0x800,
280 /**Signals that this is a boxed value type*/
281 BOXED_MASK = 0x1000,
283 /*This is an unitialized this ref*/
284 UNINIT_THIS_MASK = 0x2000,
287 static const char* const
288 type_names [TYPE_MAX + 1] = {
289 "Invalid",
290 "Int32",
291 "Int64",
292 "Native Int",
293 "Float64",
294 "Native Pointer",
295 "Complex"
298 enum {
299 PREFIX_UNALIGNED = 1,
300 PREFIX_VOLATILE = 2,
301 PREFIX_TAIL = 4,
302 PREFIX_CONSTRAINED = 8,
303 PREFIX_READONLY = 16
305 //////////////////////////////////////////////////////////////////
307 #ifdef ENABLE_VERIFIER_STATS
309 #define _MEM_ALLOC(amt) do { allocated_memory += (amt); working_set += (amt); } while (0)
310 #define _MEM_FREE(amt) do { working_set -= (amt); } while (0)
312 static int allocated_memory;
313 static int working_set;
314 static int max_allocated_memory;
315 static int max_working_set;
316 static int total_allocated_memory;
318 static void
319 finish_collect_stats (void)
321 max_allocated_memory = MAX (max_allocated_memory, allocated_memory);
322 max_working_set = MAX (max_working_set, working_set);
323 total_allocated_memory += allocated_memory;
324 allocated_memory = working_set = 0;
327 static void
328 init_verifier_stats (void)
330 static gboolean inited;
331 if (!inited) {
332 inited = TRUE;
333 mono_counters_register ("Maximum memory allocated during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_allocated_memory);
334 mono_counters_register ("Maximum memory used during verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &max_working_set);
335 mono_counters_register ("Total memory allocated for verification", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &total_allocated_memory);
339 #else
341 #define _MEM_ALLOC(amt) do {} while (0)
342 #define _MEM_FREE(amt) do { } while (0)
344 #define finish_collect_stats()
345 #define init_verifier_stats()
347 #endif
350 //////////////////////////////////////////////////////////////////
353 /*Token validation macros and functions */
354 #define IS_MEMBER_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_MEMBERREF)
355 #define IS_METHOD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
356 #define IS_METHOD_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_METHODSPEC)
357 #define IS_FIELD_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_FIELD)
359 #define IS_TYPE_REF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEREF)
360 #define IS_TYPE_DEF(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
361 #define IS_TYPE_SPEC(token) (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC)
362 #define IS_METHOD_DEF_OR_REF_OR_SPEC(token) (IS_METHOD_DEF (token) || IS_MEMBER_REF (token) || IS_METHOD_SPEC (token))
363 #define IS_TYPE_DEF_OR_REF_OR_SPEC(token) (IS_TYPE_DEF (token) || IS_TYPE_REF (token) || IS_TYPE_SPEC (token))
364 #define IS_FIELD_DEF_OR_REF(token) (IS_FIELD_DEF (token) || IS_MEMBER_REF (token))
367 * Verify if @token refers to a valid row on int's table.
369 static gboolean
370 token_bounds_check (MonoImage *image, guint32 token)
372 if (image_is_dynamic (image))
373 return mono_reflection_is_valid_dynamic_token ((MonoDynamicImage*)image, token);
374 return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token) && mono_metadata_token_index (token) > 0;
377 static MonoType *
378 mono_type_create_fnptr_from_mono_method (VerifyContext *ctx, MonoMethod *method)
380 MonoType *res = g_new0 (MonoType, 1);
381 _MEM_ALLOC (sizeof (MonoType));
383 //FIXME use mono_method_get_signature_full
384 res->data.method = mono_method_signature (method);
385 res->type = MONO_TYPE_FNPTR;
386 ctx->funptrs = g_slist_prepend (ctx->funptrs, res);
387 return res;
391 * mono_type_is_enum_type:
393 * Returns TRUE if @type is an enum type.
395 static gboolean
396 mono_type_is_enum_type (MonoType *type)
398 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
399 return TRUE;
400 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
401 return TRUE;
402 return FALSE;
406 * mono_type_is_value_type:
408 * Returns TRUE if @type is named after @namespace.@name.
411 static gboolean
412 mono_type_is_value_type (MonoType *type, const char *namespace, const char *name)
414 return type->type == MONO_TYPE_VALUETYPE &&
415 !strcmp (namespace, type->data.klass->name_space) &&
416 !strcmp (name, type->data.klass->name);
420 * Returns TURE if @type is VAR or MVAR
422 static gboolean
423 mono_type_is_generic_argument (MonoType *type)
425 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
429 * mono_type_get_underlying_type_any:
431 * This functions is just like mono_type_get_underlying_type but it doesn't care if the type is byref.
433 * Returns the underlying type of @type regardless if it is byref or not.
435 static MonoType*
436 mono_type_get_underlying_type_any (MonoType *type)
438 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype)
439 return mono_class_enum_basetype (type->data.klass);
440 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype)
441 return mono_class_enum_basetype (type->data.generic_class->container_class);
442 return type;
445 static G_GNUC_UNUSED const char*
446 mono_type_get_stack_name (MonoType *type)
448 return type_names [get_stack_type (type) & TYPE_MASK];
451 #define CTOR_REQUIRED_FLAGS (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
452 #define CTOR_INVALID_FLAGS (METHOD_ATTRIBUTE_STATIC)
454 static gboolean
455 mono_method_is_constructor (MonoMethod *method)
457 return ((method->flags & CTOR_REQUIRED_FLAGS) == CTOR_REQUIRED_FLAGS &&
458 !(method->flags & CTOR_INVALID_FLAGS) &&
459 !strcmp (".ctor", method->name));
462 static gboolean
463 mono_class_has_default_constructor (MonoClass *klass)
465 MonoMethod *method;
466 int i;
468 mono_class_setup_methods (klass);
469 if (klass->exception_type)
470 return FALSE;
472 for (i = 0; i < klass->method.count; ++i) {
473 method = klass->methods [i];
474 if (mono_method_is_constructor (method) &&
475 mono_method_signature (method) &&
476 mono_method_signature (method)->param_count == 0 &&
477 (method->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC)
478 return TRUE;
480 return FALSE;
484 * Verify if @type is valid for the given @ctx verification context.
485 * this function checks for VAR and MVAR types that are invalid under the current verifier,
487 static gboolean
488 mono_type_is_valid_type_in_context_full (MonoType *type, MonoGenericContext *context, gboolean check_gtd)
490 int i;
491 MonoGenericInst *inst;
493 switch (type->type) {
494 case MONO_TYPE_VAR:
495 case MONO_TYPE_MVAR:
496 if (!context)
497 return FALSE;
498 inst = type->type == MONO_TYPE_VAR ? context->class_inst : context->method_inst;
499 if (!inst || mono_type_get_generic_param_num (type) >= inst->type_argc)
500 return FALSE;
501 break;
502 case MONO_TYPE_SZARRAY:
503 return mono_type_is_valid_type_in_context_full (&type->data.klass->byval_arg, context, check_gtd);
504 case MONO_TYPE_ARRAY:
505 return mono_type_is_valid_type_in_context_full (&type->data.array->eklass->byval_arg, context, check_gtd);
506 case MONO_TYPE_PTR:
507 return mono_type_is_valid_type_in_context_full (type->data.type, context, check_gtd);
508 case MONO_TYPE_GENERICINST:
509 inst = type->data.generic_class->context.class_inst;
510 if (!inst->is_open)
511 break;
512 for (i = 0; i < inst->type_argc; ++i)
513 if (!mono_type_is_valid_type_in_context_full (inst->type_argv [i], context, check_gtd))
514 return FALSE;
515 break;
516 case MONO_TYPE_CLASS:
517 case MONO_TYPE_VALUETYPE: {
518 MonoClass *klass = type->data.klass;
520 * It's possible to encode generic'sh types in such a way that they disguise themselves as class or valuetype.
521 * Fixing the type decoding is really tricky since under some cases this behavior is needed, for example, to
522 * have a 'class' type pointing to a 'genericinst' class.
524 * For the runtime these non canonical (weird) encodings work fine, the worst they can cause is some
525 * reflection oddities which are harmless - to security at least.
527 if (klass->byval_arg.type != type->type)
528 return mono_type_is_valid_type_in_context_full (&klass->byval_arg, context, check_gtd);
530 if (check_gtd && klass->generic_container)
531 return FALSE;
532 break;
535 return TRUE;
538 static gboolean
539 mono_type_is_valid_type_in_context (MonoType *type, MonoGenericContext *context)
541 return mono_type_is_valid_type_in_context_full (type, context, FALSE);
544 /*This function returns NULL if the type is not instantiatable*/
545 static MonoType*
546 verifier_inflate_type (VerifyContext *ctx, MonoType *type, MonoGenericContext *context)
548 MonoError error;
549 MonoType *result;
551 result = mono_class_inflate_generic_type_checked (type, context, &error);
552 if (!mono_error_ok (&error)) {
553 mono_error_cleanup (&error);
554 return NULL;
556 return result;
559 /*A side note here. We don't need to check if arguments are broken since this
560 is only need to be done by the runtime before realizing the type.
562 static gboolean
563 is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
565 MonoError error;
566 int i;
568 if (ginst->type_argc != gc->type_argc)
569 return FALSE;
571 for (i = 0; i < gc->type_argc; ++i) {
572 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
573 MonoClass *paramClass;
574 MonoClass **constraints;
575 MonoType *param_type = ginst->type_argv [i];
577 /*it's not our job to validate type variables*/
578 if (mono_type_is_generic_argument (param_type))
579 continue;
581 paramClass = mono_class_from_mono_type (param_type);
584 /* A GTD can't be a generic argument.
586 * Due to how types are encoded we must check for the case of a genericinst MonoType and GTD MonoClass.
587 * This happens in cases such as: class Foo<T> { void X() { new Bar<T> (); } }
589 * Open instantiations can have GTDs as this happens when one type is instantiated with others params
590 * and the former has an expansion into the later. For example:
591 * class B<K> {}
592 * class A<T>: B<K> {}
593 * The type A <K> has a parent B<K>, that is inflated into the GTD B<>.
594 * Since A<K> is open, thus not instantiatable, this is valid.
596 if (paramClass->generic_container && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open)
597 return FALSE;
599 /*it's not safe to call mono_class_init from here*/
600 if (paramClass->generic_class && !paramClass->inited) {
601 if (!mono_class_is_valid_generic_instantiation (NULL, paramClass))
602 return FALSE;
605 if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
606 continue;
608 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!paramClass->valuetype || mono_class_is_nullable (paramClass)))
609 return FALSE;
611 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && paramClass->valuetype)
612 return FALSE;
614 if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !paramClass->valuetype && !mono_class_has_default_constructor (paramClass))
615 return FALSE;
617 if (!param_info->constraints)
618 continue;
620 for (constraints = param_info->constraints; *constraints; ++constraints) {
621 MonoClass *ctr = *constraints;
622 MonoType *inflated;
624 inflated = mono_class_inflate_generic_type_checked (&ctr->byval_arg, context, &error);
625 if (!mono_error_ok (&error)) {
626 mono_error_cleanup (&error);
627 return FALSE;
629 ctr = mono_class_from_mono_type (inflated);
630 mono_metadata_free_type (inflated);
632 /*FIXME maybe we need the same this as verifier_class_is_assignable_from*/
633 if (!mono_class_is_assignable_from_slow (ctr, paramClass))
634 return FALSE;
637 return TRUE;
641 * Return true if @candidate is constraint compatible with @target.
643 * This means that @candidate constraints are a super set of @target constaints
645 static gboolean
646 mono_generic_param_is_constraint_compatible (VerifyContext *ctx, MonoGenericParam *target, MonoGenericParam *candidate, MonoClass *candidate_param_class, MonoGenericContext *context)
648 MonoGenericParamInfo *tinfo = mono_generic_param_info (target);
649 MonoGenericParamInfo *cinfo = mono_generic_param_info (candidate);
650 MonoClass **candidate_class;
651 gboolean class_constraint_satisfied = FALSE;
652 gboolean valuetype_constraint_satisfied = FALSE;
654 int tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
655 int cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
657 if (cinfo->constraints) {
658 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
659 MonoClass *cc;
660 MonoType *inflated = verifier_inflate_type (ctx, &(*candidate_class)->byval_arg, ctx->generic_context);
661 if (!inflated)
662 return FALSE;
663 cc = mono_class_from_mono_type (inflated);
664 mono_metadata_free_type (inflated);
666 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
667 class_constraint_satisfied = TRUE;
668 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
669 valuetype_constraint_satisfied = TRUE;
672 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
673 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
675 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
676 return FALSE;
677 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
678 return FALSE;
679 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
680 valuetype_constraint_satisfied)) {
681 return FALSE;
685 if (tinfo->constraints) {
686 MonoClass **target_class;
687 for (target_class = tinfo->constraints; *target_class; ++target_class) {
688 MonoClass *tc;
689 MonoType *inflated = verifier_inflate_type (ctx, &(*target_class)->byval_arg, context);
690 if (!inflated)
691 return FALSE;
692 tc = mono_class_from_mono_type (inflated);
693 mono_metadata_free_type (inflated);
696 * A constraint from @target might inflate into @candidate itself and in that case we don't need
697 * check it's constraints since it satisfy the constraint by itself.
699 if (mono_metadata_type_equal (&tc->byval_arg, &candidate_param_class->byval_arg))
700 continue;
702 if (!cinfo->constraints)
703 return FALSE;
705 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
706 MonoClass *cc;
707 inflated = verifier_inflate_type (ctx, &(*candidate_class)->byval_arg, ctx->generic_context);
708 if (!inflated)
709 return FALSE;
710 cc = mono_class_from_mono_type (inflated);
711 mono_metadata_free_type (inflated);
713 if (verifier_class_is_assignable_from (tc, cc))
714 break;
717 * This happens when we have the following:
719 * Bar<K> where K : IFace
720 * Foo<T, U> where T : U where U : IFace
721 * ...
722 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
725 if (mono_type_is_generic_argument (&cc->byval_arg)) {
726 MonoGenericParam *other_candidate = verifier_get_generic_param_from_type (ctx, &cc->byval_arg);
728 if (mono_generic_param_is_constraint_compatible (ctx, target, other_candidate, cc, context)) {
729 break;
733 if (!*candidate_class)
734 return FALSE;
737 return TRUE;
740 static MonoGenericParam*
741 verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type)
743 MonoGenericContainer *gc;
744 MonoMethod *method = ctx->method;
745 int num;
747 num = mono_type_get_generic_param_num (type);
749 if (type->type == MONO_TYPE_VAR) {
750 MonoClass *gtd = method->klass;
751 if (gtd->generic_class)
752 gtd = gtd->generic_class->container_class;
753 gc = gtd->generic_container;
754 } else { //MVAR
755 MonoMethod *gmd = method;
756 if (method->is_inflated)
757 gmd = ((MonoMethodInflated*)method)->declaring;
758 gc = mono_method_get_generic_container (gmd);
760 if (!gc)
761 return NULL;
762 return mono_generic_container_get_param (gc, num);
768 * Verify if @type is valid for the given @ctx verification context.
769 * this function checks for VAR and MVAR types that are invalid under the current verifier,
770 * This means that it either
772 static gboolean
773 is_valid_type_in_context (VerifyContext *ctx, MonoType *type)
775 return mono_type_is_valid_type_in_context (type, ctx->generic_context);
778 static gboolean
779 is_valid_generic_instantiation_in_context (VerifyContext *ctx, MonoGenericInst *ginst, gboolean check_gtd)
781 int i;
782 for (i = 0; i < ginst->type_argc; ++i) {
783 MonoType *type = ginst->type_argv [i];
785 if (!mono_type_is_valid_type_in_context_full (type, ctx->generic_context, TRUE))
786 return FALSE;
788 return TRUE;
791 static gboolean
792 generic_arguments_respect_constraints (VerifyContext *ctx, MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
794 int i;
795 for (i = 0; i < ginst->type_argc; ++i) {
796 MonoType *type = ginst->type_argv [i];
797 MonoGenericParam *target = mono_generic_container_get_param (gc, i);
798 MonoGenericParam *candidate;
799 MonoClass *candidate_class;
801 if (!mono_type_is_generic_argument (type))
802 continue;
804 if (!is_valid_type_in_context (ctx, type))
805 return FALSE;
807 candidate = verifier_get_generic_param_from_type (ctx, type);
808 candidate_class = mono_class_from_mono_type (type);
810 if (!mono_generic_param_is_constraint_compatible (ctx, target, candidate, candidate_class, context))
811 return FALSE;
813 return TRUE;
816 static gboolean
817 mono_method_repect_method_constraints (VerifyContext *ctx, MonoMethod *method)
819 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
820 MonoGenericInst *ginst = gmethod->context.method_inst;
821 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
822 return !gc || generic_arguments_respect_constraints (ctx, gc, &gmethod->context, ginst);
825 static gboolean
826 mono_class_repect_method_constraints (VerifyContext *ctx, MonoClass *klass)
828 MonoGenericClass *gklass = klass->generic_class;
829 MonoGenericInst *ginst = gklass->context.class_inst;
830 MonoGenericContainer *gc = gklass->container_class->generic_container;
831 return !gc || generic_arguments_respect_constraints (ctx, gc, &gklass->context, ginst);
834 static gboolean
835 mono_method_is_valid_generic_instantiation (VerifyContext *ctx, MonoMethod *method)
837 MonoMethodInflated *gmethod = (MonoMethodInflated *)method;
838 MonoGenericInst *ginst = gmethod->context.method_inst;
839 MonoGenericContainer *gc = mono_method_get_generic_container (gmethod->declaring);
840 if (!gc) /*non-generic inflated method - it's part of a generic type */
841 return TRUE;
842 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
843 return FALSE;
844 return is_valid_generic_instantiation (gc, &gmethod->context, ginst);
848 static gboolean
849 mono_class_is_valid_generic_instantiation (VerifyContext *ctx, MonoClass *klass)
851 MonoGenericClass *gklass = klass->generic_class;
852 MonoGenericInst *ginst = gklass->context.class_inst;
853 MonoGenericContainer *gc = gklass->container_class->generic_container;
854 if (ctx && !is_valid_generic_instantiation_in_context (ctx, ginst, TRUE))
855 return FALSE;
856 return is_valid_generic_instantiation (gc, &gklass->context, ginst);
859 static gboolean
860 mono_type_is_valid_in_context (VerifyContext *ctx, MonoType *type)
862 MonoClass *klass;
864 if (type == NULL) {
865 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid null type at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
866 return FALSE;
869 if (!is_valid_type_in_context (ctx, type)) {
870 char *str = mono_type_full_name (type);
871 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type (%s%s) (argument out of range or %s is not generic) at 0x%04x",
872 str [0] == '!' ? "" : type->type == MONO_TYPE_VAR ? "!" : "!!",
873 str,
874 type->type == MONO_TYPE_VAR ? "class" : "method",
875 ctx->ip_offset),
876 MONO_EXCEPTION_BAD_IMAGE);
877 g_free (str);
878 return FALSE;
881 klass = mono_class_from_mono_type (type);
882 mono_class_init (klass);
883 if (mono_loader_get_last_error () || klass->exception_type != MONO_EXCEPTION_NONE) {
884 if (klass->generic_class && !mono_class_is_valid_generic_instantiation (NULL, klass))
885 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic instantiation of type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
886 else
887 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);
888 mono_loader_clear_error ();
889 return FALSE;
892 if (klass->generic_class && klass->generic_class->container_class->exception_type != MONO_EXCEPTION_NONE) {
893 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);
894 return FALSE;
897 if (!klass->generic_class)
898 return TRUE;
900 if (!mono_class_is_valid_generic_instantiation (ctx, klass)) {
901 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type instantiation of type %s.%s at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
902 return FALSE;
905 if (!mono_class_repect_method_constraints (ctx, klass)) {
906 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic type instantiation of type %s.%s (generic args don't respect target's constraints) at 0x%04x", klass->name_space, klass->name, ctx->ip_offset), MONO_EXCEPTION_TYPE_LOAD);
907 return FALSE;
910 return TRUE;
913 static verify_result_t
914 mono_method_is_valid_in_context (VerifyContext *ctx, MonoMethod *method)
916 if (!mono_type_is_valid_in_context (ctx, &method->klass->byval_arg))
917 return RESULT_INVALID;
919 if (!method->is_inflated)
920 return RESULT_VALID;
922 if (!mono_method_is_valid_generic_instantiation (ctx, method)) {
923 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid generic method instantiation of method %s.%s::%s at 0x%04x", method->klass->name_space, method->klass->name, method->name, ctx->ip_offset), MONO_EXCEPTION_UNVERIFIABLE_IL);
924 return RESULT_INVALID;
927 if (!mono_method_repect_method_constraints (ctx, method)) {
928 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid generic method instantiation of method %s.%s::%s (generic args don't respect target's constraints) at 0x%04x", method->klass->name_space, method->klass->name, method->name, ctx->ip_offset));
929 return RESULT_UNVERIFIABLE;
931 return RESULT_VALID;
935 static MonoClassField*
936 verifier_load_field (VerifyContext *ctx, int token, MonoClass **out_klass, const char *opcode) {
937 MonoClassField *field;
938 MonoClass *klass = NULL;
940 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
941 field = mono_method_get_wrapper_data (ctx->method, (guint32)token);
942 klass = field ? field->parent : NULL;
943 } else {
944 if (!IS_FIELD_DEF_OR_REF (token) || !token_bounds_check (ctx->image, token)) {
945 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);
946 return NULL;
949 field = mono_field_from_token (ctx->image, token, &klass, ctx->generic_context);
952 if (!field || !field->parent || !klass || mono_loader_get_last_error ()) {
953 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);
954 mono_loader_clear_error ();
955 return NULL;
958 if (!mono_type_is_valid_in_context (ctx, &klass->byval_arg))
959 return NULL;
961 if (mono_field_get_flags (field) & FIELD_ATTRIBUTE_LITERAL) {
962 char *type_name = mono_type_get_full_name (field->parent);
963 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot reference literal field %s::%s at 0x%04x", type_name, field->name, ctx->ip_offset));
964 g_free (type_name);
965 return NULL;
968 *out_klass = klass;
969 return field;
972 static MonoMethod*
973 verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
974 MonoMethod* method;
976 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
977 method = mono_method_get_wrapper_data (ctx->method, (guint32)token);
978 } else {
979 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
980 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid method token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
981 return NULL;
984 method = mono_get_method_full (ctx->image, token, NULL, ctx->generic_context);
987 if (!method || mono_loader_get_last_error ()) {
988 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load method from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
989 mono_loader_clear_error ();
990 return NULL;
993 if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
994 return NULL;
996 return method;
999 static MonoType*
1000 verifier_load_type (VerifyContext *ctx, int token, const char *opcode) {
1001 MonoType* type;
1003 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
1004 MonoClass *class = mono_method_get_wrapper_data (ctx->method, (guint32)token);
1005 type = class ? &class->byval_arg : NULL;
1006 } else {
1007 MonoError error;
1008 if (!IS_TYPE_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
1009 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid type token 0x%08x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
1010 return NULL;
1012 type = mono_type_get_checked (ctx->image, token, ctx->generic_context, &error);
1013 mono_error_cleanup (&error); /*FIXME don't swallow the error */
1016 if (!type || mono_loader_get_last_error ()) {
1017 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load type from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
1018 mono_loader_clear_error ();
1019 return NULL;
1022 if (!mono_type_is_valid_in_context (ctx, type))
1023 return NULL;
1025 return type;
1029 /* stack_slot_get_type:
1031 * Returns the stack type of @value. This value includes POINTER_MASK.
1033 * Use this function to checks that account for a managed pointer.
1035 static gint32
1036 stack_slot_get_type (ILStackDesc *value)
1038 return value->stype & RAW_TYPE_MASK;
1041 /* stack_slot_get_underlying_type:
1043 * Returns the stack type of @value. This value does not include POINTER_MASK.
1045 * Use this function is cases where the fact that the value could be a managed pointer is
1046 * irrelevant. For example, field load doesn't care about this fact of type on stack.
1048 static gint32
1049 stack_slot_get_underlying_type (ILStackDesc *value)
1051 return value->stype & TYPE_MASK;
1054 /* stack_slot_is_managed_pointer:
1056 * Returns TRUE is @value is a managed pointer.
1058 static gboolean
1059 stack_slot_is_managed_pointer (ILStackDesc *value)
1061 return (value->stype & POINTER_MASK) == POINTER_MASK;
1064 /* stack_slot_is_managed_mutability_pointer:
1066 * Returns TRUE is @value is a managed mutability pointer.
1068 static G_GNUC_UNUSED gboolean
1069 stack_slot_is_managed_mutability_pointer (ILStackDesc *value)
1071 return (value->stype & CMMP_MASK) == CMMP_MASK;
1074 /* stack_slot_is_null_literal:
1076 * Returns TRUE is @value is the null literal.
1078 static gboolean
1079 stack_slot_is_null_literal (ILStackDesc *value)
1081 return (value->stype & NULL_LITERAL_MASK) == NULL_LITERAL_MASK;
1085 /* stack_slot_is_this_pointer:
1087 * Returns TRUE is @value is the this literal
1089 static gboolean
1090 stack_slot_is_this_pointer (ILStackDesc *value)
1092 return (value->stype & THIS_POINTER_MASK) == THIS_POINTER_MASK;
1095 /* stack_slot_is_boxed_value:
1097 * Returns TRUE is @value is a boxed value
1099 static gboolean
1100 stack_slot_is_boxed_value (ILStackDesc *value)
1102 return (value->stype & BOXED_MASK) == BOXED_MASK;
1105 static const char *
1106 stack_slot_get_name (ILStackDesc *value)
1108 return type_names [value->stype & TYPE_MASK];
1111 #define APPEND_WITH_PREDICATE(PRED,NAME) do {\
1112 if (PRED (value)) { \
1113 if (!first) \
1114 g_string_append (str, ", "); \
1115 g_string_append (str, NAME); \
1116 first = FALSE; \
1117 } } while (0)
1119 static char*
1120 stack_slot_stack_type_full_name (ILStackDesc *value)
1122 GString *str = g_string_new ("");
1123 char *result;
1124 gboolean has_pred = FALSE, first = TRUE;
1126 if ((value->stype & TYPE_MASK) != value->stype) {
1127 g_string_append(str, "[");
1128 APPEND_WITH_PREDICATE (stack_slot_is_this_pointer, "this");
1129 APPEND_WITH_PREDICATE (stack_slot_is_boxed_value, "boxed");
1130 APPEND_WITH_PREDICATE (stack_slot_is_null_literal, "null");
1131 APPEND_WITH_PREDICATE (stack_slot_is_managed_mutability_pointer, "cmmp");
1132 APPEND_WITH_PREDICATE (stack_slot_is_managed_pointer, "mp");
1133 has_pred = TRUE;
1136 if (mono_type_is_generic_argument (value->type) && !stack_slot_is_boxed_value (value)) {
1137 if (!has_pred)
1138 g_string_append(str, "[");
1139 if (!first)
1140 g_string_append (str, ", ");
1141 g_string_append (str, "unboxed");
1142 has_pred = TRUE;
1145 if (has_pred)
1146 g_string_append(str, "] ");
1148 g_string_append (str, stack_slot_get_name (value));
1149 result = str->str;
1150 g_string_free (str, FALSE);
1151 return result;
1154 static char*
1155 stack_slot_full_name (ILStackDesc *value)
1157 char *type_name = mono_type_full_name (value->type);
1158 char *stack_name = stack_slot_stack_type_full_name (value);
1159 char *res = g_strdup_printf ("%s (%s)", type_name, stack_name);
1160 g_free (type_name);
1161 g_free (stack_name);
1162 return res;
1165 //////////////////////////////////////////////////////////////////
1166 void
1167 mono_free_verify_list (GSList *list)
1169 MonoVerifyInfoExtended *info;
1170 GSList *tmp;
1172 for (tmp = list; tmp; tmp = tmp->next) {
1173 info = tmp->data;
1174 g_free (info->info.message);
1175 g_free (info);
1177 g_slist_free (list);
1180 #define ADD_ERROR(list,msg) \
1181 do { \
1182 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1183 vinfo->info.status = MONO_VERIFY_ERROR; \
1184 vinfo->info.message = (msg); \
1185 (list) = g_slist_prepend ((list), vinfo); \
1186 } while (0)
1188 #define ADD_WARN(list,code,msg) \
1189 do { \
1190 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1191 vinfo->info.status = (code); \
1192 vinfo->info.message = (msg); \
1193 (list) = g_slist_prepend ((list), vinfo); \
1194 } while (0)
1196 #define ADD_INVALID(list,msg) \
1197 do { \
1198 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
1199 vinfo->status = MONO_VERIFY_ERROR; \
1200 vinfo->message = (msg); \
1201 (list) = g_slist_prepend ((list), vinfo); \
1202 /*G_BREAKPOINT ();*/ \
1203 goto invalid_cil; \
1204 } while (0)
1206 #define CHECK_STACK_UNDERFLOW(num) \
1207 do { \
1208 if (cur_stack < (num)) \
1209 ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num))); \
1210 } while (0)
1212 #define CHECK_STACK_OVERFLOW() \
1213 do { \
1214 if (cur_stack >= max_stack) \
1215 ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
1216 } while (0)
1219 static int
1220 in_any_block (MonoMethodHeader *header, guint offset)
1222 int i;
1223 MonoExceptionClause *clause;
1225 for (i = 0; i < header->num_clauses; ++i) {
1226 clause = &header->clauses [i];
1227 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1228 return 1;
1229 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1230 return 1;
1231 if (MONO_OFFSET_IN_FILTER (clause, offset))
1232 return 1;
1234 return 0;
1238 * in_any_exception_block:
1240 * Returns TRUE is @offset is part of any exception clause (filter, handler, catch, finally or fault).
1242 static gboolean
1243 in_any_exception_block (MonoMethodHeader *header, guint offset)
1245 int i;
1246 MonoExceptionClause *clause;
1248 for (i = 0; i < header->num_clauses; ++i) {
1249 clause = &header->clauses [i];
1250 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1251 return TRUE;
1252 if (MONO_OFFSET_IN_FILTER (clause, offset))
1253 return TRUE;
1255 return FALSE;
1259 * is_valid_branch_instruction:
1261 * Verify if it's valid to perform a branch from @offset to @target.
1262 * This should be used with br and brtrue/false.
1263 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1264 * The major difference from other similiar functions is that branching into a
1265 * finally/fault block is invalid instead of just unverifiable.
1267 static int
1268 is_valid_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1270 int i;
1271 MonoExceptionClause *clause;
1273 for (i = 0; i < header->num_clauses; ++i) {
1274 clause = &header->clauses [i];
1275 /*branching into a finally block is invalid*/
1276 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) &&
1277 !MONO_OFFSET_IN_HANDLER (clause, offset) &&
1278 MONO_OFFSET_IN_HANDLER (clause, target))
1279 return 2;
1281 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1282 return 1;
1283 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1284 return 1;
1285 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1286 return 1;
1288 return 0;
1292 * is_valid_cmp_branch_instruction:
1294 * Verify if it's valid to perform a branch from @offset to @target.
1295 * This should be used with binary comparison branching instruction, like beq, bge and similars.
1296 * It returns 0 if valid, 1 for unverifiable and 2 for invalid.
1298 * The major differences from other similar functions are that most errors lead to invalid
1299 * code and only branching out of finally, filter or fault clauses is unverifiable.
1301 static int
1302 is_valid_cmp_branch_instruction (MonoMethodHeader *header, guint offset, guint target)
1304 int i;
1305 MonoExceptionClause *clause;
1307 for (i = 0; i < header->num_clauses; ++i) {
1308 clause = &header->clauses [i];
1309 /*branching out of a handler or finally*/
1310 if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE &&
1311 MONO_OFFSET_IN_HANDLER (clause, offset) &&
1312 !MONO_OFFSET_IN_HANDLER (clause, target))
1313 return 1;
1315 if (clause->try_offset != target && (MONO_OFFSET_IN_CLAUSE (clause, offset) ^ MONO_OFFSET_IN_CLAUSE (clause, target)))
1316 return 2;
1317 if (MONO_OFFSET_IN_HANDLER (clause, offset) ^ MONO_OFFSET_IN_HANDLER (clause, target))
1318 return 2;
1319 if (MONO_OFFSET_IN_FILTER (clause, offset) ^ MONO_OFFSET_IN_FILTER (clause, target))
1320 return 2;
1322 return 0;
1326 * A leave can't escape a finally block
1328 static int
1329 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1331 int i;
1332 MonoExceptionClause *clause;
1334 for (i = 0; i < header->num_clauses; ++i) {
1335 clause = &header->clauses [i];
1336 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1337 return 0;
1338 if (MONO_OFFSET_IN_FILTER (clause, offset))
1339 return 0;
1341 return 1;
1345 * A rethrow can't happen outside of a catch handler.
1347 static int
1348 is_correct_rethrow (MonoMethodHeader *header, guint offset)
1350 int i;
1351 MonoExceptionClause *clause;
1353 for (i = 0; i < header->num_clauses; ++i) {
1354 clause = &header->clauses [i];
1355 if (MONO_OFFSET_IN_HANDLER (clause, offset))
1356 return 1;
1358 return 0;
1362 * An endfinally can't happen outside of a finally/fault handler.
1364 static int
1365 is_correct_endfinally (MonoMethodHeader *header, guint offset)
1367 int i;
1368 MonoExceptionClause *clause;
1370 for (i = 0; i < header->num_clauses; ++i) {
1371 clause = &header->clauses [i];
1372 if (MONO_OFFSET_IN_HANDLER (clause, offset) && (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY))
1373 return 1;
1375 return 0;
1380 * An endfilter can only happens inside a filter clause.
1381 * In non-strict mode filter is allowed inside the handler clause too
1383 static MonoExceptionClause *
1384 is_correct_endfilter (VerifyContext *ctx, guint offset)
1386 int i;
1387 MonoExceptionClause *clause;
1389 for (i = 0; i < ctx->header->num_clauses; ++i) {
1390 clause = &ctx->header->clauses [i];
1391 if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
1392 continue;
1393 if (MONO_OFFSET_IN_FILTER (clause, offset))
1394 return clause;
1395 if (!IS_STRICT_MODE (ctx) && MONO_OFFSET_IN_HANDLER (clause, offset))
1396 return clause;
1398 return NULL;
1403 * Non-strict endfilter can happens inside a try block or any handler block
1405 static int
1406 is_unverifiable_endfilter (VerifyContext *ctx, guint offset)
1408 int i;
1409 MonoExceptionClause *clause;
1411 for (i = 0; i < ctx->header->num_clauses; ++i) {
1412 clause = &ctx->header->clauses [i];
1413 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
1414 return 1;
1416 return 0;
1419 static gboolean
1420 is_valid_bool_arg (ILStackDesc *arg)
1422 if (stack_slot_is_managed_pointer (arg) || stack_slot_is_boxed_value (arg) || stack_slot_is_null_literal (arg))
1423 return TRUE;
1426 switch (stack_slot_get_underlying_type (arg)) {
1427 case TYPE_I4:
1428 case TYPE_I8:
1429 case TYPE_NATIVE_INT:
1430 case TYPE_PTR:
1431 return TRUE;
1432 case TYPE_COMPLEX:
1433 g_assert (arg->type);
1434 switch (arg->type->type) {
1435 case MONO_TYPE_CLASS:
1436 case MONO_TYPE_STRING:
1437 case MONO_TYPE_OBJECT:
1438 case MONO_TYPE_SZARRAY:
1439 case MONO_TYPE_ARRAY:
1440 case MONO_TYPE_FNPTR:
1441 case MONO_TYPE_PTR:
1442 return TRUE;
1443 case MONO_TYPE_GENERICINST:
1444 /*We need to check if the container class
1445 * of the generic type is a valuetype, iow:
1446 * is it a "class Foo<T>" or a "struct Foo<T>"?
1448 return !arg->type->data.generic_class->container_class->valuetype;
1450 default:
1451 return FALSE;
1456 /*Type manipulation helper*/
1458 /*Returns the byref version of the supplied MonoType*/
1459 static MonoType*
1460 mono_type_get_type_byref (MonoType *type)
1462 if (type->byref)
1463 return type;
1464 return &mono_class_from_mono_type (type)->this_arg;
1468 /*Returns the byval version of the supplied MonoType*/
1469 static MonoType*
1470 mono_type_get_type_byval (MonoType *type)
1472 if (!type->byref)
1473 return type;
1474 return &mono_class_from_mono_type (type)->byval_arg;
1477 static MonoType*
1478 mono_type_from_stack_slot (ILStackDesc *slot)
1480 if (stack_slot_is_managed_pointer (slot))
1481 return mono_type_get_type_byref (slot->type);
1482 return slot->type;
1485 /*Stack manipulation code*/
1487 static void
1488 ensure_stack_size (ILCodeDesc *stack, int required)
1490 int new_size = 8;
1491 ILStackDesc *tmp;
1493 if (required < stack->max_size)
1494 return;
1496 /* We don't have to worry about the exponential growth since stack_copy prune unused space */
1497 new_size = MAX (8, MAX (required, stack->max_size * 2));
1499 g_assert (new_size >= stack->size);
1500 g_assert (new_size >= required);
1502 tmp = g_new0 (ILStackDesc, new_size);
1503 _MEM_ALLOC (sizeof (ILStackDesc) * new_size);
1505 if (stack->stack) {
1506 if (stack->size)
1507 memcpy (tmp, stack->stack, stack->size * sizeof (ILStackDesc));
1508 g_free (stack->stack);
1509 _MEM_FREE (sizeof (ILStackDesc) * stack->max_size);
1512 stack->stack = tmp;
1513 stack->max_size = new_size;
1516 static void
1517 stack_init (VerifyContext *ctx, ILCodeDesc *state)
1519 if (state->flags & IL_CODE_FLAG_STACK_INITED)
1520 return;
1521 state->size = state->max_size = 0;
1522 state->flags |= IL_CODE_FLAG_STACK_INITED;
1525 static void
1526 stack_copy (ILCodeDesc *to, ILCodeDesc *from)
1528 ensure_stack_size (to, from->size);
1529 to->size = from->size;
1531 /*stack copy happens at merge points, which have small stacks*/
1532 if (from->size)
1533 memcpy (to->stack, from->stack, sizeof (ILStackDesc) * from->size);
1536 static void
1537 copy_stack_value (ILStackDesc *to, ILStackDesc *from)
1539 to->stype = from->stype;
1540 to->type = from->type;
1541 to->method = from->method;
1544 static int
1545 check_underflow (VerifyContext *ctx, int size)
1547 if (ctx->eval.size < size) {
1548 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack underflow, required %d, but have %d at 0x%04x", size, ctx->eval.size, ctx->ip_offset));
1549 return 0;
1551 return 1;
1554 static int
1555 check_overflow (VerifyContext *ctx)
1557 if (ctx->eval.size >= ctx->max_stack) {
1558 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have stack-depth %d at 0x%04x", ctx->eval.size + 1, ctx->ip_offset));
1559 return 0;
1561 return 1;
1564 /*This reject out PTR, FNPTR and TYPEDBYREF*/
1565 static gboolean
1566 check_unmanaged_pointer (VerifyContext *ctx, ILStackDesc *value)
1568 if (stack_slot_get_type (value) == TYPE_PTR) {
1569 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1570 return 0;
1572 return 1;
1575 /*TODO verify if MONO_TYPE_TYPEDBYREF is not allowed here as well.*/
1576 static gboolean
1577 check_unverifiable_type (VerifyContext *ctx, MonoType *type)
1579 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
1580 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
1581 return 0;
1583 return 1;
1586 static ILStackDesc *
1587 stack_push (VerifyContext *ctx)
1589 g_assert (ctx->eval.size < ctx->max_stack);
1590 g_assert (ctx->eval.size <= ctx->eval.max_size);
1592 ensure_stack_size (&ctx->eval, ctx->eval.size + 1);
1594 return & ctx->eval.stack [ctx->eval.size++];
1597 static ILStackDesc *
1598 stack_push_val (VerifyContext *ctx, int stype, MonoType *type)
1600 ILStackDesc *top = stack_push (ctx);
1601 top->stype = stype;
1602 top->type = type;
1603 return top;
1606 static ILStackDesc *
1607 stack_pop (VerifyContext *ctx)
1609 ILStackDesc *ret;
1610 g_assert (ctx->eval.size > 0);
1611 ret = ctx->eval.stack + --ctx->eval.size;
1612 if ((ret->stype & UNINIT_THIS_MASK) == UNINIT_THIS_MASK)
1613 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Found use of uninitialized 'this ptr' ref at 0x%04x", ctx->ip_offset));
1614 return ret;
1617 /* This function allows to safely pop an unititialized this ptr from
1618 * the eval stack without marking the method as unverifiable.
1620 static ILStackDesc *
1621 stack_pop_safe (VerifyContext *ctx)
1623 g_assert (ctx->eval.size > 0);
1624 return ctx->eval.stack + --ctx->eval.size;
1627 /*Positive number distance from stack top. [0] is stack top, [1] is the one below*/
1628 static ILStackDesc*
1629 stack_peek (VerifyContext *ctx, int distance)
1631 g_assert (ctx->eval.size - distance > 0);
1632 return ctx->eval.stack + (ctx->eval.size - 1 - distance);
1635 static ILStackDesc *
1636 stack_push_stack_val (VerifyContext *ctx, ILStackDesc *value)
1638 ILStackDesc *top = stack_push (ctx);
1639 copy_stack_value (top, value);
1640 return top;
1643 /* Returns the MonoType associated with the token, or NULL if it is invalid.
1645 * A boxable type can be either a reference or value type, but cannot be a byref type or an unmanaged pointer
1646 * */
1647 static MonoType*
1648 get_boxable_mono_type (VerifyContext* ctx, int token, const char *opcode)
1650 MonoType *type;
1651 MonoClass *class;
1653 if (!(type = verifier_load_type (ctx, token, opcode)))
1654 return NULL;
1656 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
1657 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type for %s at 0x%04x", opcode, ctx->ip_offset));
1658 return NULL;
1661 if (type->type == MONO_TYPE_VOID) {
1662 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type for %s at 0x%04x", opcode, ctx->ip_offset));
1663 return NULL;
1666 if (type->type == MONO_TYPE_TYPEDBYREF)
1667 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid use of typedbyref for %s at 0x%04x", opcode, ctx->ip_offset));
1669 if (!(class = mono_class_from_mono_type (type)))
1670 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not retrieve type token for %s at 0x%04x", opcode, ctx->ip_offset));
1672 if (class->generic_container && type->type != MONO_TYPE_GENERICINST)
1673 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));
1675 check_unverifiable_type (ctx, type);
1676 return type;
1680 /*operation result tables */
1682 static const unsigned char bin_op_table [TYPE_MAX][TYPE_MAX] = {
1683 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1684 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1685 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1686 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1687 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1688 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1691 static const unsigned char add_table [TYPE_MAX][TYPE_MAX] = {
1692 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1693 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1694 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1695 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1696 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1697 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1700 static const unsigned char sub_table [TYPE_MAX][TYPE_MAX] = {
1701 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1702 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1703 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1704 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8, TYPE_INV, TYPE_INV},
1705 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1706 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1709 static const unsigned char int_bin_op_table [TYPE_MAX][TYPE_MAX] = {
1710 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1711 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1712 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1713 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1714 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1715 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1718 static const unsigned char shift_op_table [TYPE_MAX][TYPE_MAX] = {
1719 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1720 {TYPE_I8, TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV},
1721 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1722 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1723 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1724 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1727 static const unsigned char cmp_br_op [TYPE_MAX][TYPE_MAX] = {
1728 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1729 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1730 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1731 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1732 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV},
1733 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1736 static const unsigned char cmp_br_eq_op [TYPE_MAX][TYPE_MAX] = {
1737 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV},
1738 {TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1739 {TYPE_I4, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV},
1740 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4, TYPE_INV, TYPE_INV},
1741 {TYPE_INV, TYPE_INV, TYPE_I4 | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_I4, TYPE_INV},
1742 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_I4},
1745 static const unsigned char add_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1746 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1747 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1748 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV},
1749 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1750 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_INV, TYPE_INV},
1751 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1754 static const unsigned char sub_ovf_un_table [TYPE_MAX][TYPE_MAX] = {
1755 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1756 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1757 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1758 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1759 {TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_PTR | NON_VERIFIABLE_RESULT, TYPE_INV, TYPE_NATIVE_INT | NON_VERIFIABLE_RESULT, TYPE_INV},
1760 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1763 static const unsigned char bin_ovf_table [TYPE_MAX][TYPE_MAX] = {
1764 {TYPE_I4, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1765 {TYPE_INV, TYPE_I8, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1766 {TYPE_NATIVE_INT, TYPE_INV, TYPE_NATIVE_INT, TYPE_INV, TYPE_INV, TYPE_INV},
1767 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1768 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1769 {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
1772 #ifdef MONO_VERIFIER_DEBUG
1774 /*debug helpers */
1775 static void
1776 dump_stack_value (ILStackDesc *value)
1778 printf ("[(%x)(%x)", value->type->type, value->stype);
1780 if (stack_slot_is_this_pointer (value))
1781 printf ("[this] ");
1783 if (stack_slot_is_boxed_value (value))
1784 printf ("[boxed] ");
1786 if (stack_slot_is_null_literal (value))
1787 printf ("[null] ");
1789 if (stack_slot_is_managed_mutability_pointer (value))
1790 printf ("Controled Mutability MP: ");
1792 if (stack_slot_is_managed_pointer (value))
1793 printf ("Managed Pointer to: ");
1795 switch (stack_slot_get_underlying_type (value)) {
1796 case TYPE_INV:
1797 printf ("invalid type]");
1798 return;
1799 case TYPE_I4:
1800 printf ("int32]");
1801 return;
1802 case TYPE_I8:
1803 printf ("int64]");
1804 return;
1805 case TYPE_NATIVE_INT:
1806 printf ("native int]");
1807 return;
1808 case TYPE_R8:
1809 printf ("float64]");
1810 return;
1811 case TYPE_PTR:
1812 printf ("unmanaged pointer]");
1813 return;
1814 case TYPE_COMPLEX:
1815 switch (value->type->type) {
1816 case MONO_TYPE_CLASS:
1817 case MONO_TYPE_VALUETYPE:
1818 printf ("complex] (%s)", value->type->data.klass->name);
1819 return;
1820 case MONO_TYPE_STRING:
1821 printf ("complex] (string)");
1822 return;
1823 case MONO_TYPE_OBJECT:
1824 printf ("complex] (object)");
1825 return;
1826 case MONO_TYPE_SZARRAY:
1827 printf ("complex] (%s [])", value->type->data.klass->name);
1828 return;
1829 case MONO_TYPE_ARRAY:
1830 printf ("complex] (%s [%d %d %d])",
1831 value->type->data.array->eklass->name,
1832 value->type->data.array->rank,
1833 value->type->data.array->numsizes,
1834 value->type->data.array->numlobounds);
1835 return;
1836 case MONO_TYPE_GENERICINST:
1837 printf ("complex] (inst of %s )", value->type->data.generic_class->container_class->name);
1838 return;
1839 case MONO_TYPE_VAR:
1840 printf ("complex] (type generic param !%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
1841 return;
1842 case MONO_TYPE_MVAR:
1843 printf ("complex] (method generic param !!%d - %s) ", value->type->data.generic_param->num, mono_generic_param_info (value->type->data.generic_param)->name);
1844 return;
1845 default: {
1846 //should be a boxed value
1847 char * name = mono_type_full_name (value->type);
1848 printf ("complex] %s", name);
1849 g_free (name);
1850 return;
1853 default:
1854 printf ("unknown stack %x type]\n", value->stype);
1855 g_assert_not_reached ();
1859 static void
1860 dump_stack_state (ILCodeDesc *state)
1862 int i;
1864 printf ("(%d) ", state->size);
1865 for (i = 0; i < state->size; ++i)
1866 dump_stack_value (state->stack + i);
1867 printf ("\n");
1869 #endif
1871 /*Returns TRUE if candidate array type can be assigned to target.
1872 *Both parameters MUST be of type MONO_TYPE_ARRAY (target->type == MONO_TYPE_ARRAY)
1874 static gboolean
1875 is_array_type_compatible (MonoType *target, MonoType *candidate)
1877 MonoArrayType *left = target->data.array;
1878 MonoArrayType *right = candidate->data.array;
1880 g_assert (target->type == MONO_TYPE_ARRAY);
1881 g_assert (candidate->type == MONO_TYPE_ARRAY);
1883 if (left->rank != right->rank)
1884 return FALSE;
1886 return verifier_class_is_assignable_from (left->eklass, right->eklass);
1889 static int
1890 get_stack_type (MonoType *type)
1892 int mask = 0;
1893 int type_kind = type->type;
1894 if (type->byref)
1895 mask = POINTER_MASK;
1896 /*TODO handle CMMP_MASK */
1898 handle_enum:
1899 switch (type_kind) {
1900 case MONO_TYPE_I1:
1901 case MONO_TYPE_U1:
1902 case MONO_TYPE_BOOLEAN:
1903 case MONO_TYPE_I2:
1904 case MONO_TYPE_U2:
1905 case MONO_TYPE_CHAR:
1906 case MONO_TYPE_I4:
1907 case MONO_TYPE_U4:
1908 return TYPE_I4 | mask;
1910 case MONO_TYPE_I:
1911 case MONO_TYPE_U:
1912 return TYPE_NATIVE_INT | mask;
1914 /* FIXME: the spec says that you cannot have a pointer to method pointer, do we need to check this here? */
1915 case MONO_TYPE_FNPTR:
1916 case MONO_TYPE_PTR:
1917 case MONO_TYPE_TYPEDBYREF:
1918 return TYPE_PTR | mask;
1920 case MONO_TYPE_VAR:
1921 case MONO_TYPE_MVAR:
1923 case MONO_TYPE_CLASS:
1924 case MONO_TYPE_STRING:
1925 case MONO_TYPE_OBJECT:
1926 case MONO_TYPE_SZARRAY:
1927 case MONO_TYPE_ARRAY:
1928 return TYPE_COMPLEX | mask;
1930 case MONO_TYPE_I8:
1931 case MONO_TYPE_U8:
1932 return TYPE_I8 | mask;
1934 case MONO_TYPE_R4:
1935 case MONO_TYPE_R8:
1936 return TYPE_R8 | mask;
1938 case MONO_TYPE_GENERICINST:
1939 case MONO_TYPE_VALUETYPE:
1940 if (mono_type_is_enum_type (type)) {
1941 type = mono_type_get_underlying_type_any (type);
1942 if (!type)
1943 return FALSE;
1944 type_kind = type->type;
1945 goto handle_enum;
1946 } else {
1947 return TYPE_COMPLEX | mask;
1950 default:
1951 return TYPE_INV;
1955 /* convert MonoType to ILStackDesc format (stype) */
1956 static gboolean
1957 set_stack_value (VerifyContext *ctx, ILStackDesc *stack, MonoType *type, int take_addr)
1959 int mask = 0;
1960 int type_kind = type->type;
1962 if (type->byref || take_addr)
1963 mask = POINTER_MASK;
1964 /* TODO handle CMMP_MASK */
1966 handle_enum:
1967 stack->type = type;
1969 switch (type_kind) {
1970 case MONO_TYPE_I1:
1971 case MONO_TYPE_U1:
1972 case MONO_TYPE_BOOLEAN:
1973 case MONO_TYPE_I2:
1974 case MONO_TYPE_U2:
1975 case MONO_TYPE_CHAR:
1976 case MONO_TYPE_I4:
1977 case MONO_TYPE_U4:
1978 stack->stype = TYPE_I4 | mask;
1979 break;
1980 case MONO_TYPE_I:
1981 case MONO_TYPE_U:
1982 stack->stype = TYPE_NATIVE_INT | mask;
1983 break;
1985 /*FIXME: Do we need to check if it's a pointer to the method pointer? The spec says it' illegal to have that.*/
1986 case MONO_TYPE_FNPTR:
1987 case MONO_TYPE_PTR:
1988 case MONO_TYPE_TYPEDBYREF:
1989 stack->stype = TYPE_PTR | mask;
1990 break;
1992 case MONO_TYPE_CLASS:
1993 case MONO_TYPE_STRING:
1994 case MONO_TYPE_OBJECT:
1995 case MONO_TYPE_SZARRAY:
1996 case MONO_TYPE_ARRAY:
1998 case MONO_TYPE_VAR:
1999 case MONO_TYPE_MVAR:
2000 stack->stype = TYPE_COMPLEX | mask;
2001 break;
2003 case MONO_TYPE_I8:
2004 case MONO_TYPE_U8:
2005 stack->stype = TYPE_I8 | mask;
2006 break;
2007 case MONO_TYPE_R4:
2008 case MONO_TYPE_R8:
2009 stack->stype = TYPE_R8 | mask;
2010 break;
2011 case MONO_TYPE_GENERICINST:
2012 case MONO_TYPE_VALUETYPE:
2013 if (mono_type_is_enum_type (type)) {
2014 MonoType *utype = mono_type_get_underlying_type_any (type);
2015 if (!utype) {
2016 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve underlying type of %x at %d", type->type, ctx->ip_offset));
2017 return FALSE;
2019 type = utype;
2020 type_kind = type->type;
2021 goto handle_enum;
2022 } else {
2023 stack->stype = TYPE_COMPLEX | mask;
2024 break;
2026 default:
2027 VERIFIER_DEBUG ( printf ("unknown type 0x%02x in eval stack type\n", type->type); );
2028 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Illegal value set on stack 0x%02x at %d", type->type, ctx->ip_offset));
2029 return FALSE;
2031 return TRUE;
2035 * init_stack_with_value_at_exception_boundary:
2037 * Initialize the stack and push a given type.
2038 * The instruction is marked as been on the exception boundary.
2040 static void
2041 init_stack_with_value_at_exception_boundary (VerifyContext *ctx, ILCodeDesc *code, MonoClass *klass)
2043 MonoError error;
2044 MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, ctx->generic_context, &error);
2046 if (!mono_error_ok (&error)) {
2047 char *name = mono_type_get_full_name (klass);
2048 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid class %s used for exception", name));
2049 g_free (name);
2050 mono_error_cleanup (&error);
2051 return;
2054 if (!ctx->max_stack) {
2055 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack overflow at 0x%04x", ctx->ip_offset));
2056 return;
2059 stack_init (ctx, code);
2060 ensure_stack_size (code, 1);
2061 set_stack_value (ctx, code->stack, type, FALSE);
2062 ctx->exception_types = g_slist_prepend (ctx->exception_types, type);
2063 code->size = 1;
2064 code->flags |= IL_CODE_FLAG_WAS_TARGET;
2065 if (mono_type_is_generic_argument (type))
2066 code->stack->stype |= BOXED_MASK;
2069 static MonoClass*
2070 get_ienumerable_class (void)
2072 static MonoClass* generic_ienumerable_class = NULL;
2074 if (generic_ienumerable_class == NULL)
2075 generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
2076 "System.Collections.Generic", "IEnumerable`1");
2077 return generic_ienumerable_class;
2080 static MonoClass*
2081 get_icollection_class (void)
2083 static MonoClass* generic_icollection_class = NULL;
2085 if (generic_icollection_class == NULL)
2086 generic_icollection_class = mono_class_from_name (mono_defaults.corlib,
2087 "System.Collections.Generic", "ICollection`1");
2088 return generic_icollection_class;
2091 static MonoClass*
2092 get_ireadonlylist_class (void)
2094 static MonoClass* generic_ireadonlylist_class = NULL;
2096 if (generic_ireadonlylist_class == NULL)
2097 generic_ireadonlylist_class = mono_class_from_name (mono_defaults.corlib,
2098 "System.Collections.Generic", "IReadOnlyList`1");
2099 return generic_ireadonlylist_class;
2102 static MonoClass*
2103 get_ireadonlycollection_class (void)
2105 static MonoClass* generic_ireadonlycollection_class = NULL;
2107 if (generic_ireadonlycollection_class == NULL)
2108 generic_ireadonlycollection_class = mono_class_from_name (mono_defaults.corlib,
2109 "System.Collections.Generic", "IReadOnlyCollection`1");
2110 return generic_ireadonlycollection_class;
2113 static MonoClass*
2114 inflate_class_one_arg (MonoClass *gtype, MonoClass *arg0)
2116 MonoType *args [1];
2117 args [0] = &arg0->byval_arg;
2119 return mono_class_bind_generic_parameters (gtype, 1, args, FALSE);
2122 static gboolean
2123 verifier_inflate_and_check_compat (MonoClass *target, MonoClass *gtd, MonoClass *arg)
2125 MonoClass *tmp;
2126 if (!(tmp = inflate_class_one_arg (gtd, arg)))
2127 return FALSE;
2128 if (mono_class_is_variant_compatible (target, tmp, TRUE))
2129 return TRUE;
2130 return FALSE;
2133 static gboolean
2134 verifier_class_is_assignable_from (MonoClass *target, MonoClass *candidate)
2136 MonoClass *iface_gtd;
2138 if (target == candidate)
2139 return TRUE;
2141 if (mono_class_has_variant_generic_params (target)) {
2142 if (MONO_CLASS_IS_INTERFACE (target)) {
2143 if (MONO_CLASS_IS_INTERFACE (candidate) && mono_class_is_variant_compatible (target, candidate, TRUE))
2144 return TRUE;
2146 if (candidate->rank == 1) {
2147 if (verifier_inflate_and_check_compat (target, mono_defaults.generic_ilist_class, candidate->element_class))
2148 return TRUE;
2149 if (verifier_inflate_and_check_compat (target, get_icollection_class (), candidate->element_class))
2150 return TRUE;
2151 if (verifier_inflate_and_check_compat (target, get_ienumerable_class (), candidate->element_class))
2152 return TRUE;
2153 if (verifier_inflate_and_check_compat (target, get_ireadonlylist_class (), candidate->element_class))
2154 return TRUE;
2155 if (verifier_inflate_and_check_compat (target, get_ireadonlycollection_class (), candidate->element_class))
2156 return TRUE;
2157 } else {
2158 MonoError error;
2159 int i;
2160 while (candidate && candidate != mono_defaults.object_class) {
2161 mono_class_setup_interfaces (candidate, &error);
2162 if (!mono_error_ok (&error)) {
2163 mono_error_cleanup (&error);
2164 return FALSE;
2167 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
2168 for (i = 0; i < candidate->interface_offsets_count; ++i) {
2169 MonoClass *iface = candidate->interfaces_packed [i];
2170 if (mono_class_is_variant_compatible (target, iface, TRUE))
2171 return TRUE;
2174 for (i = 0; i < candidate->interface_count; ++i) {
2175 MonoClass *iface = candidate->interfaces [i];
2176 if (mono_class_is_variant_compatible (target, iface, TRUE))
2177 return TRUE;
2179 candidate = candidate->parent;
2182 } else if (target->delegate) {
2183 if (mono_class_is_variant_compatible (target, candidate, TRUE))
2184 return TRUE;
2186 return FALSE;
2189 if (mono_class_is_assignable_from (target, candidate))
2190 return TRUE;
2192 if (!MONO_CLASS_IS_INTERFACE (target) || !target->generic_class || candidate->rank != 1)
2193 return FALSE;
2195 iface_gtd = target->generic_class->container_class;
2196 if (iface_gtd != mono_defaults.generic_ilist_class && iface_gtd != get_icollection_class () && iface_gtd != get_ienumerable_class ())
2197 return FALSE;
2199 target = mono_class_from_mono_type (target->generic_class->context.class_inst->type_argv [0]);
2200 candidate = candidate->element_class;
2202 return TRUE;
2205 /*Verify if type 'candidate' can be stored in type 'target'.
2207 * If strict, check for the underlying type and not the verification stack types
2209 static gboolean
2210 verify_type_compatibility_full (VerifyContext *ctx, MonoType *target, MonoType *candidate, gboolean strict)
2212 #define IS_ONE_OF3(T, A, B, C) (T == A || T == B || T == C)
2213 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
2215 MonoType *original_candidate = candidate;
2216 VERIFIER_DEBUG ( printf ("checking type compatibility %s x %s strict %d\n", mono_type_full_name (target), mono_type_full_name (candidate), strict); );
2218 /*only one is byref */
2219 if (candidate->byref ^ target->byref) {
2220 /* converting from native int to byref*/
2221 if (get_stack_type (candidate) == TYPE_NATIVE_INT && target->byref) {
2222 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("using byref native int at 0x%04x", ctx->ip_offset));
2223 return TRUE;
2225 return FALSE;
2227 strict |= target->byref;
2228 /*From now on we don't care about byref anymore, so it's ok to discard it here*/
2229 candidate = mono_type_get_underlying_type_any (candidate);
2231 handle_enum:
2232 switch (target->type) {
2233 case MONO_TYPE_VOID:
2234 return candidate->type == MONO_TYPE_VOID;
2235 case MONO_TYPE_I1:
2236 case MONO_TYPE_U1:
2237 case MONO_TYPE_BOOLEAN:
2238 if (strict)
2239 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I1, MONO_TYPE_U1, MONO_TYPE_BOOLEAN);
2240 case MONO_TYPE_I2:
2241 case MONO_TYPE_U2:
2242 case MONO_TYPE_CHAR:
2243 if (strict)
2244 return IS_ONE_OF3 (candidate->type, MONO_TYPE_I2, MONO_TYPE_U2, MONO_TYPE_CHAR);
2245 case MONO_TYPE_I4:
2246 case MONO_TYPE_U4: {
2247 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2248 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2249 if (strict)
2250 return is_native_int || is_int4;
2251 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2254 case MONO_TYPE_I8:
2255 case MONO_TYPE_U8:
2256 return IS_ONE_OF2 (candidate->type, MONO_TYPE_I8, MONO_TYPE_U8);
2258 case MONO_TYPE_R4:
2259 case MONO_TYPE_R8:
2260 if (strict)
2261 return candidate->type == target->type;
2262 return IS_ONE_OF2 (candidate->type, MONO_TYPE_R4, MONO_TYPE_R8);
2264 case MONO_TYPE_I:
2265 case MONO_TYPE_U: {
2266 gboolean is_native_int = IS_ONE_OF2 (candidate->type, MONO_TYPE_I, MONO_TYPE_U);
2267 gboolean is_int4 = IS_ONE_OF2 (candidate->type, MONO_TYPE_I4, MONO_TYPE_U4);
2268 if (strict)
2269 return is_native_int || is_int4;
2270 return is_native_int || get_stack_type (candidate) == TYPE_I4;
2273 case MONO_TYPE_PTR:
2274 if (candidate->type != MONO_TYPE_PTR)
2275 return FALSE;
2276 /* check the underlying type */
2277 return verify_type_compatibility_full (ctx, target->data.type, candidate->data.type, TRUE);
2279 case MONO_TYPE_FNPTR: {
2280 MonoMethodSignature *left, *right;
2281 if (candidate->type != MONO_TYPE_FNPTR)
2282 return FALSE;
2284 left = mono_type_get_signature (target);
2285 right = mono_type_get_signature (candidate);
2286 return mono_metadata_signature_equal (left, right) && left->call_convention == right->call_convention;
2289 case MONO_TYPE_GENERICINST: {
2290 MonoClass *target_klass;
2291 MonoClass *candidate_klass;
2292 if (mono_type_is_enum_type (target)) {
2293 target = mono_type_get_underlying_type_any (target);
2294 if (!target)
2295 return FALSE;
2296 goto handle_enum;
2299 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2300 * to take boxing status into account.
2302 if (mono_type_is_generic_argument (original_candidate))
2303 return FALSE;
2305 target_klass = mono_class_from_mono_type (target);
2306 candidate_klass = mono_class_from_mono_type (candidate);
2307 if (mono_class_is_nullable (target_klass)) {
2308 if (!mono_class_is_nullable (candidate_klass))
2309 return FALSE;
2310 return target_klass == candidate_klass;
2312 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2315 case MONO_TYPE_STRING:
2316 return candidate->type == MONO_TYPE_STRING;
2318 case MONO_TYPE_CLASS:
2320 * VAR / MVAR compatibility must be checked by verify_stack_type_compatibility
2321 * to take boxing status into account.
2323 if (mono_type_is_generic_argument (original_candidate))
2324 return FALSE;
2326 if (candidate->type == MONO_TYPE_VALUETYPE)
2327 return FALSE;
2329 /* If candidate is an enum it should return true for System.Enum and supertypes.
2330 * That's why here we use the original type and not the underlying type.
2332 return verifier_class_is_assignable_from (target->data.klass, mono_class_from_mono_type (original_candidate));
2334 case MONO_TYPE_OBJECT:
2335 return MONO_TYPE_IS_REFERENCE (candidate);
2337 case MONO_TYPE_SZARRAY: {
2338 MonoClass *left;
2339 MonoClass *right;
2340 if (candidate->type != MONO_TYPE_SZARRAY)
2341 return FALSE;
2343 left = mono_class_from_mono_type (target);
2344 right = mono_class_from_mono_type (candidate);
2346 return verifier_class_is_assignable_from (left, right);
2349 case MONO_TYPE_ARRAY:
2350 if (candidate->type != MONO_TYPE_ARRAY)
2351 return FALSE;
2352 return is_array_type_compatible (target, candidate);
2354 case MONO_TYPE_TYPEDBYREF:
2355 return candidate->type == MONO_TYPE_TYPEDBYREF;
2357 case MONO_TYPE_VALUETYPE: {
2358 MonoClass *target_klass;
2359 MonoClass *candidate_klass;
2361 if (candidate->type == MONO_TYPE_CLASS)
2362 return FALSE;
2364 target_klass = mono_class_from_mono_type (target);
2365 candidate_klass = mono_class_from_mono_type (candidate);
2366 if (target_klass == candidate_klass)
2367 return TRUE;
2368 if (mono_type_is_enum_type (target)) {
2369 target = mono_type_get_underlying_type_any (target);
2370 if (!target)
2371 return FALSE;
2372 goto handle_enum;
2374 return FALSE;
2377 case MONO_TYPE_VAR:
2378 if (candidate->type != MONO_TYPE_VAR)
2379 return FALSE;
2380 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2382 case MONO_TYPE_MVAR:
2383 if (candidate->type != MONO_TYPE_MVAR)
2384 return FALSE;
2385 return mono_type_get_generic_param_num (candidate) == mono_type_get_generic_param_num (target);
2387 default:
2388 VERIFIER_DEBUG ( printf ("unknown store type %d\n", target->type); );
2389 g_assert_not_reached ();
2390 return FALSE;
2392 return 1;
2393 #undef IS_ONE_OF3
2394 #undef IS_ONE_OF2
2397 static gboolean
2398 verify_type_compatibility (VerifyContext *ctx, MonoType *target, MonoType *candidate)
2400 return verify_type_compatibility_full (ctx, target, candidate, FALSE);
2404 * Returns the generic param bound to the context been verified.
2407 static MonoGenericParam*
2408 get_generic_param (VerifyContext *ctx, MonoType *param)
2410 guint16 param_num = mono_type_get_generic_param_num (param);
2411 if (param->type == MONO_TYPE_VAR) {
2412 if (!ctx->generic_context->class_inst || ctx->generic_context->class_inst->type_argc <= param_num) {
2413 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic type argument %d", param_num));
2414 return NULL;
2416 return ctx->generic_context->class_inst->type_argv [param_num]->data.generic_param;
2419 /*param must be a MVAR */
2420 if (!ctx->generic_context->method_inst || ctx->generic_context->method_inst->type_argc <= param_num) {
2421 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid generic method argument %d", param_num));
2422 return NULL;
2424 return ctx->generic_context->method_inst->type_argv [param_num]->data.generic_param;
2428 static gboolean
2429 recursive_boxed_constraint_type_check (VerifyContext *ctx, MonoType *type, MonoClass *constraint_class, int recursion_level)
2431 MonoType *constraint_type = &constraint_class->byval_arg;
2432 if (recursion_level <= 0)
2433 return FALSE;
2435 if (verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (constraint_type), FALSE))
2436 return TRUE;
2438 if (mono_type_is_generic_argument (constraint_type)) {
2439 MonoGenericParam *param = get_generic_param (ctx, constraint_type);
2440 MonoClass **class;
2441 if (!param)
2442 return FALSE;
2443 for (class = mono_generic_param_info (param)->constraints; class && *class; ++class) {
2444 if (recursive_boxed_constraint_type_check (ctx, type, *class, recursion_level - 1))
2445 return TRUE;
2448 return FALSE;
2452 * is_compatible_boxed_valuetype:
2454 * Returns TRUE if @candidate / @stack is a valid boxed valuetype.
2456 * @type The source type. It it tested to be of the proper type.
2457 * @candidate type of the boxed valuetype.
2458 * @stack stack slot of the boxed valuetype, separate from @candidade since one could be changed before calling this function
2459 * @strict if TRUE candidate must be boxed compatible to the target type
2462 static gboolean
2463 is_compatible_boxed_valuetype (VerifyContext *ctx, MonoType *type, MonoType *candidate, ILStackDesc *stack, gboolean strict)
2465 if (!stack_slot_is_boxed_value (stack))
2466 return FALSE;
2467 if (type->byref || candidate->byref)
2468 return FALSE;
2470 if (mono_type_is_generic_argument (candidate)) {
2471 MonoGenericParam *param = get_generic_param (ctx, candidate);
2472 MonoClass **class;
2473 if (!param)
2474 return FALSE;
2476 for (class = mono_generic_param_info (param)->constraints; class && *class; ++class) {
2477 /*256 should be enough since there can't be more than 255 generic arguments.*/
2478 if (recursive_boxed_constraint_type_check (ctx, type, *class, 256))
2479 return TRUE;
2483 if (mono_type_is_generic_argument (type))
2484 return FALSE;
2486 if (!strict)
2487 return TRUE;
2489 return MONO_TYPE_IS_REFERENCE (type) && verifier_class_is_assignable_from (mono_class_from_mono_type (type), mono_class_from_mono_type (candidate));
2492 static int
2493 verify_stack_type_compatibility_full (VerifyContext *ctx, MonoType *type, ILStackDesc *stack, gboolean drop_byref, gboolean valuetype_must_be_boxed)
2495 MonoType *candidate = mono_type_from_stack_slot (stack);
2496 if (MONO_TYPE_IS_REFERENCE (type) && !type->byref && stack_slot_is_null_literal (stack))
2497 return TRUE;
2499 if (is_compatible_boxed_valuetype (ctx, type, candidate, stack, TRUE))
2500 return TRUE;
2502 if (valuetype_must_be_boxed && !stack_slot_is_boxed_value (stack) && !MONO_TYPE_IS_REFERENCE (candidate))
2503 return FALSE;
2505 if (!valuetype_must_be_boxed && stack_slot_is_boxed_value (stack))
2506 return FALSE;
2508 if (drop_byref)
2509 return verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (candidate), FALSE);
2511 return verify_type_compatibility_full (ctx, type, candidate, FALSE);
2514 static int
2515 verify_stack_type_compatibility (VerifyContext *ctx, MonoType *type, ILStackDesc *stack)
2517 return verify_stack_type_compatibility_full (ctx, type, stack, FALSE, FALSE);
2520 static gboolean
2521 mono_delegate_type_equal (MonoType *target, MonoType *candidate)
2523 if (candidate->byref ^ target->byref)
2524 return FALSE;
2526 switch (target->type) {
2527 case MONO_TYPE_VOID:
2528 case MONO_TYPE_I1:
2529 case MONO_TYPE_U1:
2530 case MONO_TYPE_BOOLEAN:
2531 case MONO_TYPE_I2:
2532 case MONO_TYPE_U2:
2533 case MONO_TYPE_CHAR:
2534 case MONO_TYPE_I4:
2535 case MONO_TYPE_U4:
2536 case MONO_TYPE_I8:
2537 case MONO_TYPE_U8:
2538 case MONO_TYPE_R4:
2539 case MONO_TYPE_R8:
2540 case MONO_TYPE_I:
2541 case MONO_TYPE_U:
2542 case MONO_TYPE_STRING:
2543 case MONO_TYPE_TYPEDBYREF:
2544 return candidate->type == target->type;
2546 case MONO_TYPE_PTR:
2547 if (candidate->type != MONO_TYPE_PTR)
2548 return FALSE;
2549 return mono_delegate_type_equal (target->data.type, candidate->data.type);
2551 case MONO_TYPE_FNPTR:
2552 if (candidate->type != MONO_TYPE_FNPTR)
2553 return FALSE;
2554 return mono_delegate_signature_equal (mono_type_get_signature (target), mono_type_get_signature (candidate), FALSE);
2556 case MONO_TYPE_GENERICINST: {
2557 MonoClass *target_klass;
2558 MonoClass *candidate_klass;
2559 target_klass = mono_class_from_mono_type (target);
2560 candidate_klass = mono_class_from_mono_type (candidate);
2561 /*FIXME handle nullables and enum*/
2562 return verifier_class_is_assignable_from (target_klass, candidate_klass);
2564 case MONO_TYPE_OBJECT:
2565 return MONO_TYPE_IS_REFERENCE (candidate);
2567 case MONO_TYPE_CLASS:
2568 return verifier_class_is_assignable_from(target->data.klass, mono_class_from_mono_type (candidate));
2570 case MONO_TYPE_SZARRAY:
2571 if (candidate->type != MONO_TYPE_SZARRAY)
2572 return FALSE;
2573 return verifier_class_is_assignable_from (mono_class_from_mono_type (target)->element_class, mono_class_from_mono_type (candidate)->element_class);
2575 case MONO_TYPE_ARRAY:
2576 if (candidate->type != MONO_TYPE_ARRAY)
2577 return FALSE;
2578 return is_array_type_compatible (target, candidate);
2580 case MONO_TYPE_VALUETYPE:
2581 /*FIXME handle nullables and enum*/
2582 return mono_class_from_mono_type (candidate) == mono_class_from_mono_type (target);
2584 case MONO_TYPE_VAR:
2585 return candidate->type == MONO_TYPE_VAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2586 return FALSE;
2588 case MONO_TYPE_MVAR:
2589 return candidate->type == MONO_TYPE_MVAR && mono_type_get_generic_param_num (target) == mono_type_get_generic_param_num (candidate);
2590 return FALSE;
2592 default:
2593 VERIFIER_DEBUG ( printf ("Unknown type %d. Implement me!\n", target->type); );
2594 g_assert_not_reached ();
2595 return FALSE;
2599 static gboolean
2600 mono_delegate_param_equal (MonoType *delegate, MonoType *method)
2602 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2603 return TRUE;
2605 return mono_delegate_type_equal (method, delegate);
2608 static gboolean
2609 mono_delegate_ret_equal (MonoType *delegate, MonoType *method)
2611 if (mono_metadata_type_equal_full (delegate, method, TRUE))
2612 return TRUE;
2614 return mono_delegate_type_equal (delegate, method);
2618 * mono_delegate_signature_equal:
2620 * Compare two signatures in the way expected by delegates.
2622 * This function only exists due to the fact that it should ignore the 'has_this' part of the signature.
2624 * FIXME can this function be eliminated and proper metadata functionality be used?
2626 static gboolean
2627 mono_delegate_signature_equal (MonoMethodSignature *delegate_sig, MonoMethodSignature *method_sig, gboolean is_static_ldftn)
2629 int i;
2630 int method_offset = is_static_ldftn ? 1 : 0;
2632 if (delegate_sig->param_count + method_offset != method_sig->param_count)
2633 return FALSE;
2635 if (delegate_sig->call_convention != method_sig->call_convention)
2636 return FALSE;
2638 for (i = 0; i < delegate_sig->param_count; i++) {
2639 MonoType *p1 = delegate_sig->params [i];
2640 MonoType *p2 = method_sig->params [i + method_offset];
2642 if (!mono_delegate_param_equal (p1, p2))
2643 return FALSE;
2646 if (!mono_delegate_ret_equal (delegate_sig->ret, method_sig->ret))
2647 return FALSE;
2649 return TRUE;
2652 gboolean
2653 mono_verifier_is_signature_compatible (MonoMethodSignature *target, MonoMethodSignature *candidate)
2655 return mono_delegate_signature_equal (target, candidate, FALSE);
2659 * verify_ldftn_delegate:
2661 * Verify properties of ldftn based delegates.
2663 static void
2664 verify_ldftn_delegate (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2666 MonoMethod *method = funptr->method;
2668 /*ldftn non-final virtuals only allowed if method is not static,
2669 * the object is a this arg (comes from a ldarg.0), and there is no starg.0.
2670 * This rules doesn't apply if the object on stack is a boxed valuetype.
2672 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !(method->klass->flags & TYPE_ATTRIBUTE_SEALED) && !stack_slot_is_boxed_value (value)) {
2673 /*A stdarg 0 must not happen, we fail here only in fail fast mode to avoid double error reports*/
2674 if (IS_FAIL_FAST_MODE (ctx) && ctx->has_this_store)
2675 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", ctx->ip_offset));
2677 /*current method must not be static*/
2678 if (ctx->method->flags & METHOD_ATTRIBUTE_STATIC)
2679 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid ldftn with virtual function at 0x%04x", ctx->ip_offset));
2681 /*value is the this pointer, loaded using ldarg.0 */
2682 if (!stack_slot_is_this_pointer (value))
2683 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object argument, it is not the this pointer, to ldftn with virtual method at 0x%04x", ctx->ip_offset));
2685 ctx->code [ctx->ip_offset].flags |= IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL;
2690 * verify_delegate_compatibility:
2692 * Verify delegate creation sequence.
2695 static void
2696 verify_delegate_compatibility (VerifyContext *ctx, MonoClass *delegate, ILStackDesc *value, ILStackDesc *funptr)
2698 #define IS_VALID_OPCODE(offset, opcode) (ip [ip_offset - offset] == opcode && (ctx->code [ip_offset - offset].flags & IL_CODE_FLAG_SEEN))
2699 #define IS_LOAD_FUN_PTR(kind) (IS_VALID_OPCODE (6, CEE_PREFIX1) && ip [ip_offset - 5] == kind)
2701 MonoMethod *invoke, *method;
2702 const guint8 *ip = ctx->header->code;
2703 guint32 ip_offset = ctx->ip_offset;
2704 gboolean is_static_ldftn = FALSE, is_first_arg_bound = FALSE;
2706 if (stack_slot_get_type (funptr) != TYPE_PTR || !funptr->method) {
2707 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid function pointer parameter for delegate constructor at 0x%04x", ctx->ip_offset));
2708 return;
2711 invoke = mono_get_delegate_invoke (delegate);
2712 method = funptr->method;
2714 if (!method || !mono_method_signature (method)) {
2715 char *name = mono_type_get_full_name (delegate);
2716 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid method on stack to create delegate %s construction at 0x%04x", name, ctx->ip_offset));
2717 g_free (name);
2718 return;
2721 if (!invoke || !mono_method_signature (invoke)) {
2722 char *name = mono_type_get_full_name (delegate);
2723 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Delegate type %s with bad Invoke method at 0x%04x", name, ctx->ip_offset));
2724 g_free (name);
2725 return;
2728 is_static_ldftn = (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) && method->flags & METHOD_ATTRIBUTE_STATIC;
2730 if (is_static_ldftn)
2731 is_first_arg_bound = mono_method_signature (invoke)->param_count + 1 == mono_method_signature (method)->param_count;
2733 if (!mono_delegate_signature_equal (mono_method_signature (invoke), mono_method_signature (method), is_first_arg_bound)) {
2734 char *fun_sig = mono_signature_get_desc (mono_method_signature (method), FALSE);
2735 char *invoke_sig = mono_signature_get_desc (mono_method_signature (invoke), FALSE);
2736 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));
2737 g_free (fun_sig);
2738 g_free (invoke_sig);
2742 * Delegate code sequences:
2743 * [-6] ldftn token
2744 * newobj ...
2747 * [-7] dup
2748 * [-6] ldvirtftn token
2749 * newobj ...
2751 * ldftn sequence:*/
2752 if (ip_offset > 5 && IS_LOAD_FUN_PTR (CEE_LDFTN)) {
2753 verify_ldftn_delegate (ctx, delegate, value, funptr);
2754 } else if (ip_offset > 6 && IS_VALID_OPCODE (7, CEE_DUP) && IS_LOAD_FUN_PTR (CEE_LDVIRTFTN)) {
2755 ctx->code [ip_offset - 6].flags |= IL_CODE_DELEGATE_SEQUENCE;
2756 }else {
2757 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid code sequence for delegate creation at 0x%04x", ctx->ip_offset));
2759 ctx->code [ip_offset].flags |= IL_CODE_DELEGATE_SEQUENCE;
2761 //general tests
2762 if (is_first_arg_bound) {
2763 if (mono_method_signature (method)->param_count == 0 || !verify_stack_type_compatibility_full (ctx, mono_method_signature (method)->params [0], value, FALSE, TRUE))
2764 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2765 } else {
2766 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
2767 if (!stack_slot_is_null_literal (value) && !is_first_arg_bound)
2768 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Non-null this args used with static function for delegate creation at 0x%04x", ctx->ip_offset));
2769 } else {
2770 if (!verify_stack_type_compatibility_full (ctx, &method->klass->byval_arg, value, FALSE, TRUE) && !stack_slot_is_null_literal (value))
2771 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("This object not compatible with function pointer for delegate creation at 0x%04x", ctx->ip_offset));
2775 if (stack_slot_get_type (value) != TYPE_COMPLEX)
2776 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid first parameter for delegate creation at 0x%04x", ctx->ip_offset));
2778 #undef IS_VALID_OPCODE
2779 #undef IS_LOAD_FUN_PTR
2782 /* implement the opcode checks*/
2783 static void
2784 push_arg (VerifyContext *ctx, unsigned int arg, int take_addr)
2786 ILStackDesc *top;
2788 if (arg >= ctx->max_args) {
2789 if (take_addr)
2790 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2791 else {
2792 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d", arg + 1));
2793 if (check_overflow (ctx)) //FIXME: what sane value could we ever push?
2794 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
2796 } else if (check_overflow (ctx)) {
2797 /*We must let the value be pushed, otherwise we would get an underflow error*/
2798 check_unverifiable_type (ctx, ctx->params [arg]);
2799 if (ctx->params [arg]->byref && take_addr)
2800 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2801 top = stack_push (ctx);
2802 if (!set_stack_value (ctx, top, ctx->params [arg], take_addr))
2803 return;
2805 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC)) {
2806 if (take_addr)
2807 ctx->has_this_store = TRUE;
2808 else
2809 top->stype |= THIS_POINTER_MASK;
2810 if (mono_method_is_constructor (ctx->method) && !ctx->super_ctor_called && !ctx->method->klass->valuetype)
2811 top->stype |= UNINIT_THIS_MASK;
2816 static void
2817 push_local (VerifyContext *ctx, guint32 arg, int take_addr)
2819 if (arg >= ctx->num_locals) {
2820 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local %d", arg + 1));
2821 } else if (check_overflow (ctx)) {
2822 /*We must let the value be pushed, otherwise we would get an underflow error*/
2823 check_unverifiable_type (ctx, ctx->locals [arg]);
2824 if (ctx->locals [arg]->byref && take_addr)
2825 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ByRef of ByRef at 0x%04x", ctx->ip_offset));
2827 set_stack_value (ctx, stack_push (ctx), ctx->locals [arg], take_addr);
2831 static void
2832 store_arg (VerifyContext *ctx, guint32 arg)
2834 ILStackDesc *value;
2836 if (arg >= ctx->max_args) {
2837 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", arg + 1, ctx->ip_offset));
2838 if (check_underflow (ctx, 1))
2839 stack_pop (ctx);
2840 return;
2843 if (check_underflow (ctx, 1)) {
2844 value = stack_pop (ctx);
2845 if (!verify_stack_type_compatibility (ctx, ctx->params [arg], value)) {
2846 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in argument store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
2849 if (arg == 0 && !(ctx->method->flags & METHOD_ATTRIBUTE_STATIC))
2850 ctx->has_this_store = 1;
2853 static void
2854 store_local (VerifyContext *ctx, guint32 arg)
2856 ILStackDesc *value;
2857 if (arg >= ctx->num_locals) {
2858 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", arg + 1, ctx->ip_offset));
2859 return;
2862 /*TODO verify definite assigment */
2863 if (!check_underflow (ctx, 1))
2864 return;
2866 value = stack_pop (ctx);
2867 if (ctx->locals [arg]->byref && stack_slot_is_managed_mutability_pointer (value))
2868 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly managed reference when storing on a local variable at 0x%04x", ctx->ip_offset));
2870 if (!verify_stack_type_compatibility (ctx, ctx->locals [arg], value)) {
2871 char *expected = mono_type_full_name (ctx->locals [arg]);
2872 char *found = stack_slot_full_name (value);
2873 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type '%s' on stack cannot be stored to local %d with type '%s' at 0x%04x",
2874 found,
2875 arg,
2876 expected,
2877 ctx->ip_offset));
2878 g_free (expected);
2879 g_free (found);
2883 /*FIXME add and sub needs special care here*/
2884 static void
2885 do_binop (VerifyContext *ctx, unsigned int opcode, const unsigned char table [TYPE_MAX][TYPE_MAX])
2887 ILStackDesc *a, *b, *top;
2888 int idxa, idxb, complexMerge = 0;
2889 unsigned char res;
2891 if (!check_underflow (ctx, 2))
2892 return;
2893 b = stack_pop (ctx);
2894 a = stack_pop (ctx);
2896 idxa = stack_slot_get_underlying_type (a);
2897 if (stack_slot_is_managed_pointer (a)) {
2898 idxa = TYPE_PTR;
2899 complexMerge = 1;
2902 idxb = stack_slot_get_underlying_type (b);
2903 if (stack_slot_is_managed_pointer (b)) {
2904 idxb = TYPE_PTR;
2905 complexMerge = 2;
2908 --idxa;
2909 --idxb;
2910 res = table [idxa][idxb];
2912 VERIFIER_DEBUG ( printf ("binop res %d\n", res); );
2913 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
2915 top = stack_push (ctx);
2916 if (res == TYPE_INV) {
2917 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Binary instruction applyed to ill formed stack (%s x %s)", stack_slot_get_name (a), stack_slot_get_name (b)));
2918 copy_stack_value (top, a);
2919 return;
2922 if (res & NON_VERIFIABLE_RESULT) {
2923 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Binary instruction is not verifiable (%s x %s)", stack_slot_get_name (a), stack_slot_get_name (b)));
2925 res = res & ~NON_VERIFIABLE_RESULT;
2928 if (complexMerge && res == TYPE_PTR) {
2929 if (complexMerge == 1)
2930 copy_stack_value (top, a);
2931 else if (complexMerge == 2)
2932 copy_stack_value (top, b);
2934 * There is no need to merge the type of two pointers.
2935 * The only valid operation is subtraction, that returns a native
2936 * int as result and can be used with any 2 pointer kinds.
2937 * This is valid acording to Patition III 1.1.4
2939 } else
2940 top->stype = res;
2945 static void
2946 do_boolean_branch_op (VerifyContext *ctx, int delta)
2948 int target = ctx->ip_offset + delta;
2949 ILStackDesc *top;
2951 VERIFIER_DEBUG ( printf ("boolean branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2953 if (target < 0 || target >= ctx->code_size) {
2954 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Boolean branch target out of code at 0x%04x", ctx->ip_offset));
2955 return;
2958 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
2959 case 1:
2960 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2961 break;
2962 case 2:
2963 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
2964 return;
2967 ctx->target = target;
2969 if (!check_underflow (ctx, 1))
2970 return;
2972 top = stack_pop (ctx);
2973 if (!is_valid_bool_arg (top))
2974 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Argument type %s not valid for brtrue/brfalse at 0x%04x", stack_slot_get_name (top), ctx->ip_offset));
2976 check_unmanaged_pointer (ctx, top);
2979 static gboolean
2980 stack_slot_is_complex_type_not_reference_type (ILStackDesc *slot)
2982 return stack_slot_get_type (slot) == TYPE_COMPLEX && !MONO_TYPE_IS_REFERENCE (slot->type) && !stack_slot_is_boxed_value (slot);
2985 static void
2986 do_branch_op (VerifyContext *ctx, signed int delta, const unsigned char table [TYPE_MAX][TYPE_MAX])
2988 ILStackDesc *a, *b;
2989 int idxa, idxb;
2990 unsigned char res;
2991 int target = ctx->ip_offset + delta;
2993 VERIFIER_DEBUG ( printf ("branch offset %d delta %d target %d\n", ctx->ip_offset, delta, target); );
2995 if (target < 0 || target >= ctx->code_size) {
2996 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
2997 return;
3000 switch (is_valid_cmp_branch_instruction (ctx->header, ctx->ip_offset, target)) {
3001 case 1: /*FIXME use constants and not magic numbers.*/
3002 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3003 break;
3004 case 2:
3005 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
3006 return;
3009 ctx->target = target;
3011 if (!check_underflow (ctx, 2))
3012 return;
3014 b = stack_pop (ctx);
3015 a = stack_pop (ctx);
3017 idxa = stack_slot_get_underlying_type (a);
3018 if (stack_slot_is_managed_pointer (a))
3019 idxa = TYPE_PTR;
3021 idxb = stack_slot_get_underlying_type (b);
3022 if (stack_slot_is_managed_pointer (b))
3023 idxb = TYPE_PTR;
3025 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3026 res = TYPE_INV;
3027 } else {
3028 --idxa;
3029 --idxb;
3030 res = table [idxa][idxb];
3033 VERIFIER_DEBUG ( printf ("branch res %d\n", res); );
3034 VERIFIER_DEBUG ( printf ("idxa %d idxb %d\n", idxa, idxb); );
3036 if (res == TYPE_INV) {
3037 CODE_NOT_VERIFIABLE (ctx,
3038 g_strdup_printf ("Compare and Branch instruction applyed to ill formed stack (%s x %s) at 0x%04x", stack_slot_get_name (a), stack_slot_get_name (b), ctx->ip_offset));
3039 } else if (res & NON_VERIFIABLE_RESULT) {
3040 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Compare and Branch instruction is not verifiable (%s x %s) at 0x%04x", stack_slot_get_name (a), stack_slot_get_name (b), ctx->ip_offset));
3041 res = res & ~NON_VERIFIABLE_RESULT;
3045 static void
3046 do_cmp_op (VerifyContext *ctx, const unsigned char table [TYPE_MAX][TYPE_MAX], guint32 opcode)
3048 ILStackDesc *a, *b;
3049 int idxa, idxb;
3050 unsigned char res;
3052 if (!check_underflow (ctx, 2))
3053 return;
3054 b = stack_pop (ctx);
3055 a = stack_pop (ctx);
3057 if (opcode == CEE_CGT_UN) {
3058 if (stack_slot_get_type (a) == TYPE_COMPLEX && stack_slot_get_type (b) == TYPE_COMPLEX) {
3059 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3060 return;
3064 idxa = stack_slot_get_underlying_type (a);
3065 if (stack_slot_is_managed_pointer (a))
3066 idxa = TYPE_PTR;
3068 idxb = stack_slot_get_underlying_type (b);
3069 if (stack_slot_is_managed_pointer (b))
3070 idxb = TYPE_PTR;
3072 if (stack_slot_is_complex_type_not_reference_type (a) || stack_slot_is_complex_type_not_reference_type (b)) {
3073 res = TYPE_INV;
3074 } else {
3075 --idxa;
3076 --idxb;
3077 res = table [idxa][idxb];
3080 if(res == TYPE_INV) {
3081 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf("Compare instruction applyed to ill formed stack (%s x %s) at 0x%04x", stack_slot_get_name (a), stack_slot_get_name (b), ctx->ip_offset));
3082 } else if (res & NON_VERIFIABLE_RESULT) {
3083 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Compare instruction is not verifiable (%s x %s) at 0x%04x", stack_slot_get_name (a), stack_slot_get_name (b), ctx->ip_offset));
3084 res = res & ~NON_VERIFIABLE_RESULT;
3086 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3089 static void
3090 do_ret (VerifyContext *ctx)
3092 MonoType *ret = ctx->signature->ret;
3093 VERIFIER_DEBUG ( printf ("checking ret\n"); );
3094 if (ret->type != MONO_TYPE_VOID) {
3095 ILStackDesc *top;
3096 if (!check_underflow (ctx, 1))
3097 return;
3099 top = stack_pop(ctx);
3101 if (!verify_stack_type_compatibility (ctx, ctx->signature->ret, top)) {
3102 char *ret_type = mono_type_full_name (ctx->signature->ret);
3103 char *stack_type = stack_slot_full_name (top);
3104 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible return value on stack with method signature, expected '%s' but got '%s' at 0x%04x", ret_type, stack_type, ctx->ip_offset));
3105 g_free (stack_type);
3106 g_free (ret_type);
3107 return;
3110 if (ret->byref || ret->type == MONO_TYPE_TYPEDBYREF || mono_type_is_value_type (ret, "System", "ArgIterator") || mono_type_is_value_type (ret, "System", "RuntimeArgumentHandle"))
3111 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Method returns byref, TypedReference, ArgIterator or RuntimeArgumentHandle at 0x%04x", ctx->ip_offset));
3114 if (ctx->eval.size > 0) {
3115 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", ctx->eval.size, ctx->ip_offset));
3117 if (in_any_block (ctx->header, ctx->ip_offset))
3118 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ctx->ip_offset));
3122 * FIXME we need to fix the case of a non-virtual instance method defined in the parent but call using a token pointing to a subclass.
3123 * This is illegal but mono_get_method_full decoded it.
3124 * TODO handle calling .ctor outside one or calling the .ctor for other class but super
3126 static void
3127 do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual)
3129 int param_count, i;
3130 MonoMethodSignature *sig;
3131 ILStackDesc *value;
3132 MonoMethod *method;
3133 gboolean virt_check_this = FALSE;
3134 gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;
3136 if (!(method = verifier_load_method (ctx, method_token, virtual ? "callvirt" : "call")))
3137 return;
3139 if (virtual) {
3140 CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);
3142 if (method->klass->valuetype) // && !constrained ???
3143 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));
3145 if ((method->flags & METHOD_ATTRIBUTE_STATIC))
3146 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));
3148 } else {
3149 if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
3150 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));
3152 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !(method->klass->flags & TYPE_ATTRIBUTE_SEALED)) {
3153 virt_check_this = TRUE;
3154 ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
3158 if (!(sig = mono_method_get_signature_full (method, ctx->image, method_token, ctx->generic_context)))
3159 sig = mono_method_get_signature (method, ctx->image, method_token);
3161 if (!sig) {
3162 char *name = mono_type_get_full_name (method->klass);
3163 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve signature of %s:%s at 0x%04x", name, method->name, ctx->ip_offset));
3164 g_free (name);
3165 return;
3168 param_count = sig->param_count + sig->hasthis;
3169 if (!check_underflow (ctx, param_count))
3170 return;
3172 for (i = sig->param_count - 1; i >= 0; --i) {
3173 VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
3174 value = stack_pop (ctx);
3175 if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
3176 char *stack_name = stack_slot_full_name (value);
3177 char *sig_name = mono_type_full_name (sig->params [i]);
3178 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));
3179 g_free (stack_name);
3180 g_free (sig_name);
3183 if (stack_slot_is_managed_mutability_pointer (value))
3184 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of %s at 0x%04x", virtual ? "callvirt" : "call", ctx->ip_offset));
3186 if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
3187 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot pass a byref argument to a tail %s at 0x%04x", virtual ? "callvirt" : "call", ctx->ip_offset));
3188 return;
3192 if (sig->hasthis) {
3193 MonoType *type = &method->klass->byval_arg;
3194 ILStackDesc copy;
3196 if (mono_method_is_constructor (method) && !method->klass->valuetype) {
3197 if (IS_STRICT_MODE (ctx) && !mono_method_is_constructor (ctx->method))
3198 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
3199 if (IS_STRICT_MODE (ctx) && method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
3200 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor of a type different from this or super at 0x%04x", ctx->ip_offset));
3202 ctx->super_ctor_called = TRUE;
3203 value = stack_pop_safe (ctx);
3204 if (IS_STRICT_MODE (ctx) && (value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
3205 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
3206 } else {
3207 value = stack_pop (ctx);
3210 copy_stack_value (&copy, value);
3211 //TODO we should extract this to a 'drop_byref_argument' and use everywhere
3212 //Other parts of the code suffer from the same issue of
3213 copy.type = mono_type_get_type_byval (copy.type);
3214 copy.stype &= ~POINTER_MASK;
3216 if (virt_check_this && !stack_slot_is_this_pointer (value) && !(method->klass->valuetype || stack_slot_is_boxed_value (value)))
3217 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use the call opcode with a non-final virtual method on an object different than the 'this' pointer at 0x%04x", ctx->ip_offset));
3219 if (constrained && virtual) {
3220 if (!stack_slot_is_managed_pointer (value))
3221 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
3222 if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), mono_type_get_underlying_type (ctx->constrained_type), TRUE))
3223 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
3224 copy.stype |= BOXED_MASK;
3225 copy.type = ctx->constrained_type;
3226 } else {
3227 if (stack_slot_is_managed_pointer (value) && !mono_class_from_mono_type (value->type)->valuetype)
3228 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a reference type using a managed pointer to the this arg at 0x%04x", ctx->ip_offset));
3230 if (!virtual && mono_class_from_mono_type (value->type)->valuetype && !method->klass->valuetype && !stack_slot_is_boxed_value (value))
3231 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));
3233 if (virtual && mono_class_from_mono_type (value->type)->valuetype && !stack_slot_is_boxed_value (value))
3234 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));
3236 if (method->klass->valuetype && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
3237 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a boxed or literal valuetype to call a valuetype method at 0x%04x", ctx->ip_offset));
3239 if (!verify_stack_type_compatibility (ctx, type, &copy)) {
3240 char *expected = mono_type_full_name (type);
3241 char *effective = stack_slot_full_name (&copy);
3242 char *method_name = mono_method_full_name (method, TRUE);
3243 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature expected '%s' but got '%s' for a call to '%s' at 0x%04x",
3244 expected, effective, method_name, ctx->ip_offset));
3245 g_free (method_name);
3246 g_free (effective);
3247 g_free (expected);
3250 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) {
3251 char *name = mono_method_full_name (method, TRUE);
3252 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3253 g_free (name);
3256 } else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3257 char *name = mono_method_full_name (method, TRUE);
3258 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
3259 g_free (name);
3262 if (sig->ret->type != MONO_TYPE_VOID) {
3263 if (!mono_type_is_valid_in_context (ctx, sig->ret))
3264 return;
3266 if (check_overflow (ctx)) {
3267 value = stack_push (ctx);
3268 set_stack_value (ctx, value, sig->ret, FALSE);
3269 if ((ctx->prefix_set & PREFIX_READONLY) && method->klass->rank && !strcmp (method->name, "Address")) {
3270 ctx->prefix_set &= ~PREFIX_READONLY;
3271 value->stype |= CMMP_MASK;
3276 if ((ctx->prefix_set & PREFIX_TAIL)) {
3277 if (!mono_delegate_ret_equal (mono_method_signature (ctx->method)->ret, sig->ret))
3278 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
3279 if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
3280 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
3285 static void
3286 do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
3288 MonoClassField *field;
3289 MonoClass *klass;
3290 if (!check_overflow (ctx))
3291 return;
3292 if (!take_addr)
3293 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3295 if (!(field = verifier_load_field (ctx, token, &klass, take_addr ? "ldsflda" : "ldsfld")))
3296 return;
3298 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3299 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
3300 return;
3302 /*taking the address of initonly field only works from the static constructor */
3303 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3304 !(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
3305 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3307 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3308 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3310 set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3313 static void
3314 do_store_static_field (VerifyContext *ctx, int token) {
3315 MonoClassField *field;
3316 MonoClass *klass;
3317 ILStackDesc *value;
3318 CLEAR_PREFIX (ctx, PREFIX_VOLATILE);
3320 if (!check_underflow (ctx, 1))
3321 return;
3323 value = stack_pop (ctx);
3325 if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
3326 return;
3328 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3329 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
3330 return;
3333 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3334 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
3335 return;
3338 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3339 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3341 if (!verify_stack_type_compatibility (ctx, field->type, value)) {
3342 char *stack_name = stack_slot_full_name (value);
3343 char *field_name = mono_type_full_name (field->type);
3344 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type in static field store expected '%s' but found '%s' at 0x%04x",
3345 field_name, stack_name, ctx->ip_offset));
3346 g_free (field_name);
3347 g_free (stack_name);
3351 static gboolean
3352 check_is_valid_type_for_field_ops (VerifyContext *ctx, int token, ILStackDesc *obj, MonoClassField **ret_field, const char *opcode)
3354 MonoClassField *field;
3355 MonoClass *klass;
3356 gboolean is_pointer;
3358 /*must be a reference type, a managed pointer, an unamanaged pointer, or a valuetype*/
3359 if (!(field = verifier_load_field (ctx, token, &klass, opcode)))
3360 return FALSE;
3362 *ret_field = field;
3363 //the value on stack is going to be used as a pointer
3364 is_pointer = stack_slot_get_type (obj) == TYPE_PTR || (stack_slot_get_type (obj) == TYPE_NATIVE_INT && !get_stack_type (&field->parent->byval_arg));
3366 if (field->type->type == MONO_TYPE_TYPEDBYREF) {
3367 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type at 0x%04x", ctx->ip_offset));
3368 return FALSE;
3370 g_assert (obj->type);
3372 /*The value on the stack must be a subclass of the defining type of the field*/
3373 /* we need to check if we can load the field from the stack value*/
3374 if (is_pointer) {
3375 if (stack_slot_get_underlying_type (obj) == TYPE_NATIVE_INT)
3376 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Native int is not a verifiable type to reference a field at 0x%04x", ctx->ip_offset));
3378 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
3379 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3380 } else {
3381 if (!field->parent->valuetype && stack_slot_is_managed_pointer (obj))
3382 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is a managed pointer to a reference type and is not compatible to reference the field at 0x%04x", ctx->ip_offset));
3384 /*a value type can be loaded from a value or a managed pointer, but not a boxed object*/
3385 if (field->parent->valuetype && stack_slot_is_boxed_value (obj))
3386 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type at stack is a boxed valuetype and is not compatible to reference the field at 0x%04x", ctx->ip_offset));
3388 if (!stack_slot_is_null_literal (obj) && !verify_stack_type_compatibility_full (ctx, &field->parent->byval_arg, obj, TRUE, FALSE)) {
3389 char *found = stack_slot_full_name (obj);
3390 char *expected = mono_type_full_name (&field->parent->byval_arg);
3391 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Expected type '%s' but found '%s' referencing the 'this' argument at 0x%04x", expected, found, ctx->ip_offset));
3392 g_free (found);
3393 g_free (expected);
3396 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, mono_class_from_mono_type (obj->type)))
3397 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);
3400 check_unmanaged_pointer (ctx, obj);
3401 return TRUE;
3404 static void
3405 do_push_field (VerifyContext *ctx, int token, gboolean take_addr)
3407 ILStackDesc *obj;
3408 MonoClassField *field;
3410 if (!take_addr)
3411 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3413 if (!check_underflow (ctx, 1))
3414 return;
3415 obj = stack_pop_safe (ctx);
3417 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, take_addr ? "ldflda" : "ldfld"))
3418 return;
3420 if (take_addr && field->parent->valuetype && !stack_slot_is_managed_pointer (obj))
3421 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a temporary value-type at 0x%04x", ctx->ip_offset));
3423 if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
3424 !(field->parent == ctx->method->klass && mono_method_is_constructor (ctx->method)))
3425 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));
3427 set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
3430 static void
3431 do_store_field (VerifyContext *ctx, int token)
3433 ILStackDesc *value, *obj;
3434 MonoClassField *field;
3435 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3437 if (!check_underflow (ctx, 2))
3438 return;
3440 value = stack_pop (ctx);
3441 obj = stack_pop_safe (ctx);
3443 if (!check_is_valid_type_for_field_ops (ctx, token, obj, &field, "stfld"))
3444 return;
3446 if (!verify_stack_type_compatibility (ctx, field->type, value))
3447 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type %s in field store at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3450 /*TODO proper handle for Nullable<T>*/
3451 static void
3452 do_box_value (VerifyContext *ctx, int klass_token)
3454 ILStackDesc *value;
3455 MonoType *type = get_boxable_mono_type (ctx, klass_token, "box");
3456 MonoClass *klass;
3458 if (!type)
3459 return;
3461 if (!check_underflow (ctx, 1))
3462 return;
3464 value = stack_pop (ctx);
3465 /*box is a nop for reference types*/
3467 if (stack_slot_get_underlying_type (value) == TYPE_COMPLEX && MONO_TYPE_IS_REFERENCE (value->type) && MONO_TYPE_IS_REFERENCE (type)) {
3468 stack_push_stack_val (ctx, value)->stype |= BOXED_MASK;
3469 return;
3473 if (!verify_stack_type_compatibility (ctx, type, value))
3474 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for boxing operation at 0x%04x", ctx->ip_offset));
3476 klass = mono_class_from_mono_type (type);
3477 if (mono_class_is_nullable (klass))
3478 type = &mono_class_get_nullable_param (klass)->byval_arg;
3479 stack_push_val (ctx, TYPE_COMPLEX | BOXED_MASK, type);
3482 static void
3483 do_unbox_value (VerifyContext *ctx, int klass_token)
3485 ILStackDesc *value;
3486 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox");
3488 if (!type)
3489 return;
3491 if (!check_underflow (ctx, 1))
3492 return;
3494 if (!mono_class_from_mono_type (type)->valuetype)
3495 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid reference type for unbox at 0x%04x", ctx->ip_offset));
3497 value = stack_pop (ctx);
3499 /*Value should be: a boxed valuetype or a reference type*/
3500 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3501 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3502 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type %s at stack for unbox operation at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3504 set_stack_value (ctx, value = stack_push (ctx), mono_type_get_type_byref (type), FALSE);
3505 value->stype |= CMMP_MASK;
3508 static void
3509 do_unbox_any (VerifyContext *ctx, int klass_token)
3511 ILStackDesc *value;
3512 MonoType *type = get_boxable_mono_type (ctx, klass_token, "unbox.any");
3514 if (!type)
3515 return;
3517 if (!check_underflow (ctx, 1))
3518 return;
3520 value = stack_pop (ctx);
3522 /*Value should be: a boxed valuetype or a reference type*/
3523 if (!(stack_slot_get_type (value) == TYPE_COMPLEX &&
3524 (stack_slot_is_boxed_value (value) || !mono_class_from_mono_type (value->type)->valuetype)))
3525 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type %s at stack for unbox.any operation at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3527 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3530 static void
3531 do_unary_math_op (VerifyContext *ctx, int op)
3533 ILStackDesc *value;
3534 if (!check_underflow (ctx, 1))
3535 return;
3536 value = stack_pop (ctx);
3537 switch (stack_slot_get_type (value)) {
3538 case TYPE_I4:
3539 case TYPE_I8:
3540 case TYPE_NATIVE_INT:
3541 break;
3542 case TYPE_R8:
3543 if (op == CEE_NEG)
3544 break;
3545 case TYPE_COMPLEX: /*only enums are ok*/
3546 if (mono_type_is_enum_type (value->type))
3547 break;
3548 default:
3549 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for unary not at 0x%04x", ctx->ip_offset));
3551 stack_push_stack_val (ctx, value);
3554 static void
3555 do_conversion (VerifyContext *ctx, int kind)
3557 ILStackDesc *value;
3558 if (!check_underflow (ctx, 1))
3559 return;
3560 value = stack_pop (ctx);
3562 switch (stack_slot_get_type (value)) {
3563 case TYPE_I4:
3564 case TYPE_I8:
3565 case TYPE_NATIVE_INT:
3566 case TYPE_R8:
3567 break;
3568 default:
3569 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type (%s) at stack for conversion operation. Numeric type expected at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3572 switch (kind) {
3573 case TYPE_I4:
3574 stack_push_val (ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
3575 break;
3576 case TYPE_I8:
3577 stack_push_val (ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
3578 break;
3579 case TYPE_R8:
3580 stack_push_val (ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
3581 break;
3582 case TYPE_NATIVE_INT:
3583 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
3584 break;
3585 default:
3586 g_error ("unknown type %02x in conversion", kind);
3591 static void
3592 do_load_token (VerifyContext *ctx, int token)
3594 gpointer handle;
3595 MonoClass *handle_class;
3596 if (!check_overflow (ctx))
3597 return;
3599 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
3600 handle = mono_method_get_wrapper_data (ctx->method, token);
3601 handle_class = mono_method_get_wrapper_data (ctx->method, token + 1);
3602 if (handle_class == mono_defaults.typehandle_class)
3603 handle = &((MonoClass*)handle)->byval_arg;
3604 } else {
3605 switch (token & 0xff000000) {
3606 case MONO_TOKEN_TYPE_DEF:
3607 case MONO_TOKEN_TYPE_REF:
3608 case MONO_TOKEN_TYPE_SPEC:
3609 case MONO_TOKEN_FIELD_DEF:
3610 case MONO_TOKEN_METHOD_DEF:
3611 case MONO_TOKEN_METHOD_SPEC:
3612 case MONO_TOKEN_MEMBER_REF:
3613 if (!token_bounds_check (ctx->image, token)) {
3614 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Table index out of range 0x%x for token %x for ldtoken at 0x%04x", mono_metadata_token_index (token), token, ctx->ip_offset));
3615 return;
3617 break;
3618 default:
3619 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid table 0x%x for token 0x%x for ldtoken at 0x%04x", mono_metadata_token_table (token), token, ctx->ip_offset));
3620 return;
3623 handle = mono_ldtoken (ctx->image, token, &handle_class, ctx->generic_context);
3626 if (!handle) {
3627 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid token 0x%x for ldtoken at 0x%04x", token, ctx->ip_offset));
3628 return;
3630 if (handle_class == mono_defaults.typehandle_class) {
3631 mono_type_is_valid_in_context (ctx, (MonoType*)handle);
3632 } else if (handle_class == mono_defaults.methodhandle_class) {
3633 mono_method_is_valid_in_context (ctx, (MonoMethod*)handle);
3634 } else if (handle_class == mono_defaults.fieldhandle_class) {
3635 mono_type_is_valid_in_context (ctx, &((MonoClassField*)handle)->parent->byval_arg);
3636 } else {
3637 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid ldtoken type %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
3639 stack_push_val (ctx, TYPE_COMPLEX, mono_class_get_type (handle_class));
3642 static void
3643 do_ldobj_value (VerifyContext *ctx, int token)
3645 ILStackDesc *value;
3646 MonoType *type = get_boxable_mono_type (ctx, token, "ldobj");
3647 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3649 if (!type)
3650 return;
3652 if (!check_underflow (ctx, 1))
3653 return;
3655 value = stack_pop (ctx);
3656 if (!stack_slot_is_managed_pointer (value)
3657 && stack_slot_get_type (value) != TYPE_NATIVE_INT
3658 && !(stack_slot_get_type (value) == TYPE_PTR && value->type->type != MONO_TYPE_FNPTR)) {
3659 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid argument %s to ldobj at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
3660 return;
3663 if (stack_slot_get_type (value) == TYPE_NATIVE_INT)
3664 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Using native pointer to ldobj at 0x%04x", ctx->ip_offset));
3666 /*We have a byval on the stack, but the comparison must be strict. */
3667 if (!verify_type_compatibility_full (ctx, type, mono_type_get_type_byval (value->type), TRUE))
3668 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldojb operation at 0x%04x", ctx->ip_offset));
3670 set_stack_value (ctx, stack_push (ctx), type, FALSE);
3673 static void
3674 do_stobj (VerifyContext *ctx, int token)
3676 ILStackDesc *dest, *src;
3677 MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
3678 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3680 if (!type)
3681 return;
3683 if (!check_underflow (ctx, 2))
3684 return;
3686 src = stack_pop (ctx);
3687 dest = stack_pop (ctx);
3689 if (stack_slot_is_managed_mutability_pointer (dest))
3690 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));
3692 if (!stack_slot_is_managed_pointer (dest))
3693 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));
3695 if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
3696 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use stobj with a boxed source value that is not a reference type at 0x%04x", ctx->ip_offset));
3698 if (!verify_stack_type_compatibility (ctx, type, src)) {
3699 char *type_name = mono_type_full_name (type);
3700 char *src_name = stack_slot_full_name (src);
3701 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token '%s' and source '%s' of stobj don't match ' at 0x%04x", type_name, src_name, ctx->ip_offset));
3702 g_free (type_name);
3703 g_free (src_name);
3706 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3707 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
3710 static void
3711 do_cpobj (VerifyContext *ctx, int token)
3713 ILStackDesc *dest, *src;
3714 MonoType *type = get_boxable_mono_type (ctx, token, "cpobj");
3715 if (!type)
3716 return;
3718 if (!check_underflow (ctx, 2))
3719 return;
3721 src = stack_pop (ctx);
3722 dest = stack_pop (ctx);
3724 if (!stack_slot_is_managed_pointer (src))
3725 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid source of cpobj operation at 0x%04x", ctx->ip_offset));
3727 if (!stack_slot_is_managed_pointer (dest))
3728 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of cpobj operation at 0x%04x", ctx->ip_offset));
3730 if (stack_slot_is_managed_mutability_pointer (dest))
3731 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with cpobj at 0x%04x", ctx->ip_offset));
3733 if (!verify_type_compatibility (ctx, type, mono_type_get_type_byval (src->type)))
3734 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token and source types of cpobj don't match at 0x%04x", ctx->ip_offset));
3736 if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
3737 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of cpobj don't match at 0x%04x", ctx->ip_offset));
3740 static void
3741 do_initobj (VerifyContext *ctx, int token)
3743 ILStackDesc *obj;
3744 MonoType *stack, *type = get_boxable_mono_type (ctx, token, "initobj");
3745 if (!type)
3746 return;
3748 if (!check_underflow (ctx, 1))
3749 return;
3751 obj = stack_pop (ctx);
3753 if (!stack_slot_is_managed_pointer (obj))
3754 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));
3756 if (stack_slot_is_managed_mutability_pointer (obj))
3757 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));
3759 stack = mono_type_get_type_byval (obj->type);
3760 if (MONO_TYPE_IS_REFERENCE (stack)) {
3761 if (!verify_type_compatibility (ctx, stack, type))
3762 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3763 else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack))
3764 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
3765 } else if (!verify_type_compatibility (ctx, stack, type)) {
3766 char *expected_name = mono_type_full_name (type);
3767 char *stack_name = mono_type_full_name (stack);
3769 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));
3770 g_free (expected_name);
3771 g_free (stack_name);
3775 static void
3776 do_newobj (VerifyContext *ctx, int token)
3778 ILStackDesc *value;
3779 int i;
3780 MonoMethodSignature *sig;
3781 MonoMethod *method;
3782 gboolean is_delegate = FALSE;
3784 if (!(method = verifier_load_method (ctx, token, "newobj")))
3785 return;
3787 if (!mono_method_is_constructor (method)) {
3788 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Method from token 0x%08x not a constructor at 0x%04x", token, ctx->ip_offset));
3789 return;
3792 if (method->klass->flags & (TYPE_ATTRIBUTE_ABSTRACT | TYPE_ATTRIBUTE_INTERFACE))
3793 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Trying to instantiate an abstract or interface type at 0x%04x", ctx->ip_offset));
3795 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
3796 char *from = mono_method_full_name (ctx->method, TRUE);
3797 char *to = mono_method_full_name (method, TRUE);
3798 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);
3799 g_free (from);
3800 g_free (to);
3803 //FIXME use mono_method_get_signature_full
3804 sig = mono_method_signature (method);
3805 if (!sig) {
3806 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature to newobj at 0x%04x", ctx->ip_offset));
3807 return;
3810 if (!sig->hasthis) {
3811 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid constructor signature missing hasthis at 0x%04x", ctx->ip_offset));
3812 return;
3815 if (!check_underflow (ctx, sig->param_count))
3816 return;
3818 is_delegate = method->klass->parent == mono_defaults.multicastdelegate_class;
3820 if (is_delegate) {
3821 ILStackDesc *funptr;
3822 //first arg is object, second arg is fun ptr
3823 if (sig->param_count != 2) {
3824 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid delegate constructor at 0x%04x", ctx->ip_offset));
3825 return;
3827 funptr = stack_pop (ctx);
3828 value = stack_pop (ctx);
3829 verify_delegate_compatibility (ctx, method->klass, value, funptr);
3830 } else {
3831 for (i = sig->param_count - 1; i >= 0; --i) {
3832 VERIFIER_DEBUG ( printf ("verifying constructor argument %d\n", i); );
3833 value = stack_pop (ctx);
3834 if (!verify_stack_type_compatibility (ctx, sig->params [i], value)) {
3835 char *stack_name = stack_slot_full_name (value);
3836 char *sig_name = mono_type_full_name (sig->params [i]);
3837 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter value with constructor signature: %s X %s at 0x%04x", sig_name, stack_name, ctx->ip_offset));
3838 g_free (stack_name);
3839 g_free (sig_name);
3842 if (stack_slot_is_managed_mutability_pointer (value))
3843 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of newobj at 0x%04x", ctx->ip_offset));
3847 if (check_overflow (ctx))
3848 set_stack_value (ctx, stack_push (ctx), &method->klass->byval_arg, FALSE);
3851 static void
3852 do_cast (VerifyContext *ctx, int token, const char *opcode) {
3853 ILStackDesc *value;
3854 MonoType *type;
3855 gboolean is_boxed;
3856 gboolean do_box;
3858 if (!check_underflow (ctx, 1))
3859 return;
3861 if (!(type = get_boxable_mono_type (ctx, token, opcode)))
3862 return;
3864 if (type->byref) {
3865 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid %s type at 0x%04x", opcode, ctx->ip_offset));
3866 return;
3869 value = stack_pop (ctx);
3870 is_boxed = stack_slot_is_boxed_value (value);
3872 if (stack_slot_is_managed_pointer (value))
3873 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3874 else if (!MONO_TYPE_IS_REFERENCE (value->type) && !is_boxed) {
3875 char *name = stack_slot_full_name (value);
3876 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));
3877 g_free (name);
3880 switch (value->type->type) {
3881 case MONO_TYPE_FNPTR:
3882 case MONO_TYPE_PTR:
3883 case MONO_TYPE_TYPEDBYREF:
3884 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value for %s at 0x%04x", opcode, ctx->ip_offset));
3887 do_box = is_boxed || mono_type_is_generic_argument(type) || mono_class_from_mono_type (type)->valuetype;
3888 stack_push_val (ctx, TYPE_COMPLEX | (do_box ? BOXED_MASK : 0), type);
3891 static MonoType *
3892 mono_type_from_opcode (int opcode) {
3893 switch (opcode) {
3894 case CEE_LDIND_I1:
3895 case CEE_LDIND_U1:
3896 case CEE_STIND_I1:
3897 case CEE_LDELEM_I1:
3898 case CEE_LDELEM_U1:
3899 case CEE_STELEM_I1:
3900 return &mono_defaults.sbyte_class->byval_arg;
3902 case CEE_LDIND_I2:
3903 case CEE_LDIND_U2:
3904 case CEE_STIND_I2:
3905 case CEE_LDELEM_I2:
3906 case CEE_LDELEM_U2:
3907 case CEE_STELEM_I2:
3908 return &mono_defaults.int16_class->byval_arg;
3910 case CEE_LDIND_I4:
3911 case CEE_LDIND_U4:
3912 case CEE_STIND_I4:
3913 case CEE_LDELEM_I4:
3914 case CEE_LDELEM_U4:
3915 case CEE_STELEM_I4:
3916 return &mono_defaults.int32_class->byval_arg;
3918 case CEE_LDIND_I8:
3919 case CEE_STIND_I8:
3920 case CEE_LDELEM_I8:
3921 case CEE_STELEM_I8:
3922 return &mono_defaults.int64_class->byval_arg;
3924 case CEE_LDIND_R4:
3925 case CEE_STIND_R4:
3926 case CEE_LDELEM_R4:
3927 case CEE_STELEM_R4:
3928 return &mono_defaults.single_class->byval_arg;
3930 case CEE_LDIND_R8:
3931 case CEE_STIND_R8:
3932 case CEE_LDELEM_R8:
3933 case CEE_STELEM_R8:
3934 return &mono_defaults.double_class->byval_arg;
3936 case CEE_LDIND_I:
3937 case CEE_STIND_I:
3938 case CEE_LDELEM_I:
3939 case CEE_STELEM_I:
3940 return &mono_defaults.int_class->byval_arg;
3942 case CEE_LDIND_REF:
3943 case CEE_STIND_REF:
3944 case CEE_LDELEM_REF:
3945 case CEE_STELEM_REF:
3946 return &mono_defaults.object_class->byval_arg;
3948 default:
3949 g_error ("unknown opcode %02x in mono_type_from_opcode ", opcode);
3950 return NULL;
3954 static void
3955 do_load_indirect (VerifyContext *ctx, int opcode)
3957 ILStackDesc *value;
3958 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3960 if (!check_underflow (ctx, 1))
3961 return;
3963 value = stack_pop (ctx);
3964 if (!stack_slot_is_managed_pointer (value)) {
3965 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
3966 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
3967 return;
3970 if (opcode == CEE_LDIND_REF) {
3971 if (stack_slot_get_underlying_type (value) != TYPE_COMPLEX || mono_class_from_mono_type (value->type)->valuetype)
3972 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
3973 set_stack_value (ctx, stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
3974 } else {
3975 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
3976 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
3977 set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
3981 static void
3982 do_store_indirect (VerifyContext *ctx, int opcode)
3984 ILStackDesc *addr, *val;
3985 CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
3987 if (!check_underflow (ctx, 2))
3988 return;
3990 val = stack_pop (ctx);
3991 addr = stack_pop (ctx);
3993 check_unmanaged_pointer (ctx, addr);
3995 if (!stack_slot_is_managed_pointer (addr) && stack_slot_get_type (addr) != TYPE_PTR) {
3996 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid non-pointer argument to stind at 0x%04x", ctx->ip_offset));
3997 return;
4000 if (stack_slot_is_managed_mutability_pointer (addr)) {
4001 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stind at 0x%04x", ctx->ip_offset));
4002 return;
4005 if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (addr->type), TRUE))
4006 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid addr type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4008 if (!verify_stack_type_compatibility (ctx, mono_type_from_opcode (opcode), val))
4009 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value type at stack for stind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
4012 static void
4013 do_newarr (VerifyContext *ctx, int token)
4015 ILStackDesc *value;
4016 MonoType *type = get_boxable_mono_type (ctx, token, "newarr");
4018 if (!type)
4019 return;
4021 if (!check_underflow (ctx, 1))
4022 return;
4024 value = stack_pop (ctx);
4025 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4026 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Array size type on stack (%s) is not a verifiable type at 0x%04x", stack_slot_get_name (value), ctx->ip_offset));
4028 set_stack_value (ctx, stack_push (ctx), mono_class_get_type (mono_array_class_get (mono_class_from_mono_type (type), 1)), FALSE);
4031 /*FIXME handle arrays that are not 0-indexed*/
4032 static void
4033 do_ldlen (VerifyContext *ctx)
4035 ILStackDesc *value;
4037 if (!check_underflow (ctx, 1))
4038 return;
4040 value = stack_pop (ctx);
4042 if (stack_slot_get_type (value) != TYPE_COMPLEX || value->type->type != MONO_TYPE_SZARRAY)
4043 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type for ldlen at 0x%04x", ctx->ip_offset));
4045 stack_push_val (ctx, TYPE_NATIVE_INT, &mono_defaults.int_class->byval_arg);
4048 /*FIXME handle arrays that are not 0-indexed*/
4049 /*FIXME handle readonly prefix and CMMP*/
4050 static void
4051 do_ldelema (VerifyContext *ctx, int klass_token)
4053 ILStackDesc *index, *array, *res;
4054 MonoType *type = get_boxable_mono_type (ctx, klass_token, "ldelema");
4055 gboolean valid;
4057 if (!type)
4058 return;
4060 if (!check_underflow (ctx, 2))
4061 return;
4063 index = stack_pop (ctx);
4064 array = stack_pop (ctx);
4066 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4067 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Index type(%s) for ldelema is not an int or a native int at 0x%04x", stack_slot_get_name (index), ctx->ip_offset));
4069 if (!stack_slot_is_null_literal (array)) {
4070 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4071 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelema at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
4072 else {
4073 if (get_stack_type (type) == TYPE_I4 || get_stack_type (type) == TYPE_NATIVE_INT) {
4074 valid = verify_type_compatibility_full (ctx, type, &array->type->data.klass->byval_arg, TRUE);
4075 } else {
4076 valid = mono_metadata_type_equal (type, &array->type->data.klass->byval_arg);
4078 if (!valid)
4079 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelema at 0x%04x", ctx->ip_offset));
4083 res = stack_push (ctx);
4084 set_stack_value (ctx, res, type, TRUE);
4085 if (ctx->prefix_set & PREFIX_READONLY) {
4086 ctx->prefix_set &= ~PREFIX_READONLY;
4087 res->stype |= CMMP_MASK;
4092 * FIXME handle arrays that are not 0-indexed
4093 * FIXME handle readonly prefix and CMMP
4095 static void
4096 do_ldelem (VerifyContext *ctx, int opcode, int token)
4098 #define IS_ONE_OF2(T, A, B) (T == A || T == B)
4099 ILStackDesc *index, *array;
4100 MonoType *type;
4101 if (!check_underflow (ctx, 2))
4102 return;
4104 if (opcode == CEE_LDELEM) {
4105 if (!(type = verifier_load_type (ctx, token, "ldelem.any"))) {
4106 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4107 return;
4109 } else {
4110 type = mono_type_from_opcode (opcode);
4113 index = stack_pop (ctx);
4114 array = stack_pop (ctx);
4116 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4117 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Index type(%s) for ldelem.X is not an int or a native int at 0x%04x", stack_slot_get_name (index), ctx->ip_offset));
4119 if (!stack_slot_is_null_literal (array)) {
4120 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY)
4121 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for ldelem.X at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
4122 else {
4123 if (opcode == CEE_LDELEM_REF) {
4124 if (array->type->data.klass->valuetype)
4125 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for ldelem.ref 0x%04x", ctx->ip_offset));
4126 type = &array->type->data.klass->byval_arg;
4127 } else {
4128 MonoType *candidate = &array->type->data.klass->byval_arg;
4129 if (IS_STRICT_MODE (ctx)) {
4130 MonoType *underlying_type = mono_type_get_underlying_type_any (type);
4131 MonoType *underlying_candidate = mono_type_get_underlying_type_any (candidate);
4132 if ((IS_ONE_OF2 (underlying_type->type, MONO_TYPE_I4, MONO_TYPE_U4) && IS_ONE_OF2 (underlying_candidate->type, MONO_TYPE_I, MONO_TYPE_U)) ||
4133 (IS_ONE_OF2 (underlying_candidate->type, MONO_TYPE_I4, MONO_TYPE_U4) && IS_ONE_OF2 (underlying_type->type, MONO_TYPE_I, MONO_TYPE_U)))
4134 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4136 if (!verify_type_compatibility_full (ctx, type, candidate, TRUE))
4137 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for ldelem.X at 0x%04x", ctx->ip_offset));
4142 set_stack_value (ctx, stack_push (ctx), type, FALSE);
4143 #undef IS_ONE_OF2
4147 * FIXME handle arrays that are not 0-indexed
4149 static void
4150 do_stelem (VerifyContext *ctx, int opcode, int token)
4152 ILStackDesc *index, *array, *value;
4153 MonoType *type;
4154 if (!check_underflow (ctx, 3))
4155 return;
4157 if (opcode == CEE_STELEM) {
4158 if (!(type = verifier_load_type (ctx, token, "stelem.any"))) {
4159 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Type (0x%08x) not found at 0x%04x", token, ctx->ip_offset));
4160 return;
4162 } else {
4163 type = mono_type_from_opcode (opcode);
4166 value = stack_pop (ctx);
4167 index = stack_pop (ctx);
4168 array = stack_pop (ctx);
4170 if (stack_slot_get_type (index) != TYPE_I4 && stack_slot_get_type (index) != TYPE_NATIVE_INT)
4171 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Index type(%s) for stdelem.X is not an int or a native int at 0x%04x", stack_slot_get_name (index), ctx->ip_offset));
4173 if (!stack_slot_is_null_literal (array)) {
4174 if (stack_slot_get_type (array) != TYPE_COMPLEX || array->type->type != MONO_TYPE_SZARRAY) {
4175 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type(%s) for stelem.X at 0x%04x", stack_slot_get_name (array), ctx->ip_offset));
4176 } else {
4177 if (opcode == CEE_STELEM_REF) {
4178 if (array->type->data.klass->valuetype)
4179 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4180 } else if (!verify_type_compatibility_full (ctx, &array->type->data.klass->byval_arg, type, TRUE)) {
4181 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid array type on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4185 if (opcode == CEE_STELEM_REF) {
4186 if (!stack_slot_is_boxed_value (value) && mono_class_from_mono_type (value->type)->valuetype)
4187 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value is not a reference type for stelem.ref 0x%04x", ctx->ip_offset));
4188 } else if (opcode != CEE_STELEM_REF) {
4189 if (!verify_stack_type_compatibility (ctx, type, value))
4190 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid value on stack for stdelem.X at 0x%04x", ctx->ip_offset));
4192 if (stack_slot_is_boxed_value (value) && !MONO_TYPE_IS_REFERENCE (value->type) && !MONO_TYPE_IS_REFERENCE (type))
4193 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use stobj with a boxed source value that is not a reference type at 0x%04x", ctx->ip_offset));
4198 static void
4199 do_throw (VerifyContext *ctx)
4201 ILStackDesc *exception;
4202 if (!check_underflow (ctx, 1))
4203 return;
4204 exception = stack_pop (ctx);
4206 if (!stack_slot_is_null_literal (exception) && !(stack_slot_get_type (exception) == TYPE_COMPLEX && !mono_class_from_mono_type (exception->type)->valuetype))
4207 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type on stack for throw, expected reference type at 0x%04x", ctx->ip_offset));
4209 if (mono_type_is_generic_argument (exception->type) && !stack_slot_is_boxed_value (exception)) {
4210 char *name = mono_type_full_name (exception->type);
4211 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));
4212 g_free (name);
4214 /*The stack is left empty after a throw*/
4215 ctx->eval.size = 0;
4219 static void
4220 do_endfilter (VerifyContext *ctx)
4222 MonoExceptionClause *clause;
4224 if (IS_STRICT_MODE (ctx)) {
4225 if (ctx->eval.size != 1)
4226 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack size must have one item for endfilter at 0x%04x", ctx->ip_offset));
4228 if (ctx->eval.size >= 1 && stack_slot_get_type (stack_pop (ctx)) != TYPE_I4)
4229 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Stack item type is not an int32 for endfilter at 0x%04x", ctx->ip_offset));
4232 if ((clause = is_correct_endfilter (ctx, ctx->ip_offset))) {
4233 if (IS_STRICT_MODE (ctx)) {
4234 if (ctx->ip_offset != clause->handler_offset - 2)
4235 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4236 } else {
4237 if ((ctx->ip_offset != clause->handler_offset - 2) && !MONO_OFFSET_IN_HANDLER (clause, ctx->ip_offset))
4238 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter is not the last instruction of the filter clause at 0x%04x", ctx->ip_offset));
4240 } else {
4241 if (IS_STRICT_MODE (ctx) && !is_unverifiable_endfilter (ctx, ctx->ip_offset))
4242 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4243 else
4244 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("endfilter outside filter clause at 0x%04x", ctx->ip_offset));
4247 ctx->eval.size = 0;
4250 static void
4251 do_leave (VerifyContext *ctx, int delta)
4253 int target = ((gint32)ctx->ip_offset) + delta;
4254 if (target >= ctx->code_size || target < 0)
4255 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));
4257 if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
4258 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
4259 ctx->eval.size = 0;
4260 ctx->target = target;
4264 * do_static_branch:
4266 * Verify br and br.s opcodes.
4268 static void
4269 do_static_branch (VerifyContext *ctx, int delta)
4271 int target = ctx->ip_offset + delta;
4272 if (target < 0 || target >= ctx->code_size) {
4273 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("branch target out of code at 0x%04x", ctx->ip_offset));
4274 return;
4277 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4278 case 1:
4279 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4280 break;
4281 case 2:
4282 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ctx->ip_offset));
4283 break;
4286 ctx->target = target;
4289 static void
4290 do_switch (VerifyContext *ctx, int count, const unsigned char *data)
4292 int i, base = ctx->ip_offset + 5 + count * 4;
4293 ILStackDesc *value;
4295 if (!check_underflow (ctx, 1))
4296 return;
4298 value = stack_pop (ctx);
4300 if (stack_slot_get_type (value) != TYPE_I4 && stack_slot_get_type (value) != TYPE_NATIVE_INT)
4301 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to switch at 0x%04x", ctx->ip_offset));
4303 for (i = 0; i < count; ++i) {
4304 int target = base + read32 (data + i * 4);
4306 if (target < 0 || target >= ctx->code_size) {
4307 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x out of code at 0x%04x", i, ctx->ip_offset));
4308 return;
4311 switch (is_valid_branch_instruction (ctx->header, ctx->ip_offset, target)) {
4312 case 1:
4313 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4314 break;
4315 case 2:
4316 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Switch target %x escapes out of exception block at 0x%04x", i, ctx->ip_offset));
4317 return;
4319 merge_stacks (ctx, &ctx->eval, &ctx->code [target], FALSE, TRUE);
4323 static void
4324 do_load_function_ptr (VerifyContext *ctx, guint32 token, gboolean virtual)
4326 ILStackDesc *top;
4327 MonoMethod *method;
4329 if (virtual && !check_underflow (ctx, 1))
4330 return;
4332 if (!virtual && !check_overflow (ctx))
4333 return;
4335 if (ctx->method->wrapper_type != MONO_WRAPPER_NONE) {
4336 method = mono_method_get_wrapper_data (ctx->method, (guint32)token);
4337 if (!method) {
4338 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4339 return;
4341 } else {
4342 if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
4343 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid token %x for ldftn at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4344 return;
4347 if (!(method = verifier_load_method (ctx, token, virtual ? "ldvirtfrn" : "ldftn")))
4348 return;
4351 if (mono_method_is_constructor (method))
4352 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldftn with a constructor at 0x%04x", ctx->ip_offset));
4354 if (virtual) {
4355 ILStackDesc *top = stack_pop (ctx);
4357 if (stack_slot_get_type (top) != TYPE_COMPLEX || top->type->type == MONO_TYPE_VALUETYPE)
4358 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ctx->ip_offset));
4360 if (method->flags & METHOD_ATTRIBUTE_STATIC)
4361 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use ldvirtftn with a constructor at 0x%04x", ctx->ip_offset));
4363 if (!verify_stack_type_compatibility (ctx, &method->klass->byval_arg, top))
4364 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unexpected object for ldvirtftn at 0x%04x", ctx->ip_offset));
4367 if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL))
4368 CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Loaded method is not visible for ldftn/ldvirtftn at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
4370 top = stack_push_val(ctx, TYPE_PTR, mono_type_create_fnptr_from_mono_method (ctx, method));
4371 top->method = method;
4374 static void
4375 do_sizeof (VerifyContext *ctx, int token)
4377 MonoType *type;
4379 if (!(type = verifier_load_type (ctx, token, "sizeof")))
4380 return;
4382 if (type->byref && type->type != MONO_TYPE_TYPEDBYREF) {
4383 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of byref type at 0x%04x", ctx->ip_offset));
4384 return;
4387 if (type->type == MONO_TYPE_VOID) {
4388 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Invalid use of void type at 0x%04x", ctx->ip_offset));
4389 return;
4392 if (check_overflow (ctx))
4393 set_stack_value (ctx, stack_push (ctx), &mono_defaults.uint32_class->byval_arg, FALSE);
4396 /* Stack top can be of any type, the runtime doesn't care and treat everything as an int. */
4397 static void
4398 do_localloc (VerifyContext *ctx)
4400 ILStackDesc *top;
4402 if (ctx->eval.size != 1) {
4403 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4404 return;
4407 if (in_any_exception_block (ctx->header, ctx->ip_offset)) {
4408 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ctx->ip_offset));
4409 return;
4412 /*TODO verify top type*/
4413 top = stack_pop (ctx);
4415 set_stack_value (ctx, stack_push (ctx), &mono_defaults.int_class->byval_arg, FALSE);
4416 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Instruction localloc in never verifiable at 0x%04x", ctx->ip_offset));
4419 static void
4420 do_ldstr (VerifyContext *ctx, guint32 token)
4422 GSList *error = NULL;
4423 if (ctx->method->wrapper_type == MONO_WRAPPER_NONE && !image_is_dynamic (ctx->image)) {
4424 if (mono_metadata_token_code (token) != MONO_TOKEN_STRING) {
4425 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string token %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4426 return;
4429 if (!mono_verifier_verify_string_signature (ctx->image, mono_metadata_token_index (token), &error)) {
4430 if (error)
4431 ctx->list = g_slist_concat (ctx->list, error);
4432 ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid string index %x at 0x%04x", token, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
4433 return;
4437 if (check_overflow (ctx))
4438 stack_push_val (ctx, TYPE_COMPLEX, &mono_defaults.string_class->byval_arg);
4441 static void
4442 do_refanyval (VerifyContext *ctx, int token)
4444 ILStackDesc *top;
4445 MonoType *type;
4446 if (!check_underflow (ctx, 1))
4447 return;
4449 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4450 return;
4452 top = stack_pop (ctx);
4454 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4455 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Expected a typedref as argument for refanyval, but found %s at 0x%04x", stack_slot_get_name (top), ctx->ip_offset));
4457 set_stack_value (ctx, stack_push (ctx), type, TRUE);
4460 static void
4461 do_refanytype (VerifyContext *ctx)
4463 ILStackDesc *top;
4465 if (!check_underflow (ctx, 1))
4466 return;
4468 top = stack_pop (ctx);
4470 if (top->stype != TYPE_PTR || top->type->type != MONO_TYPE_TYPEDBYREF)
4471 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Expected a typedref as argument for refanytype, but found %s at 0x%04x", stack_slot_get_name (top), ctx->ip_offset));
4473 set_stack_value (ctx, stack_push (ctx), &mono_defaults.typehandle_class->byval_arg, FALSE);
4477 static void
4478 do_mkrefany (VerifyContext *ctx, int token)
4480 ILStackDesc *top;
4481 MonoType *type;
4482 if (!check_underflow (ctx, 1))
4483 return;
4485 if (!(type = get_boxable_mono_type (ctx, token, "refanyval")))
4486 return;
4488 top = stack_pop (ctx);
4490 if (stack_slot_is_managed_mutability_pointer (top))
4491 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with mkrefany at 0x%04x", ctx->ip_offset));
4493 if (!stack_slot_is_managed_pointer (top)) {
4494 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Expected a managed pointer for mkrefany, but found %s at 0x%04x", stack_slot_get_name (top), ctx->ip_offset));
4495 }else {
4496 MonoType *stack_type = mono_type_get_type_byval (top->type);
4497 if (MONO_TYPE_IS_REFERENCE (type) && !mono_metadata_type_equal (type, stack_type))
4498 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4500 if (!MONO_TYPE_IS_REFERENCE (type) && !verify_type_compatibility_full (ctx, type, stack_type, TRUE))
4501 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type not compatible for mkrefany at 0x%04x", ctx->ip_offset));
4504 set_stack_value (ctx, stack_push (ctx), &mono_defaults.typed_reference_class->byval_arg, FALSE);
4507 static void
4508 do_ckfinite (VerifyContext *ctx)
4510 ILStackDesc *top;
4511 if (!check_underflow (ctx, 1))
4512 return;
4514 top = stack_pop (ctx);
4516 if (stack_slot_get_underlying_type (top) != TYPE_R8)
4517 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Expected float32 or float64 on stack for ckfinit but found %s at 0x%04x", stack_slot_get_name (top), ctx->ip_offset));
4518 stack_push_stack_val (ctx, top);
4521 * merge_stacks:
4522 * Merge the stacks and perform compat checks. The merge check if types of @from are mergeable with type of @to
4524 * @from holds new values for a given control path
4525 * @to holds the current values of a given control path
4527 * TODO we can eliminate the from argument as all callers pass &ctx->eval
4529 static void
4530 merge_stacks (VerifyContext *ctx, ILCodeDesc *from, ILCodeDesc *to, gboolean start, gboolean external)
4532 MonoError error;
4533 int i, j;
4534 stack_init (ctx, to);
4536 if (start) {
4537 if (to->flags == IL_CODE_FLAG_NOT_PROCESSED)
4538 from->size = 0;
4539 else
4540 stack_copy (&ctx->eval, to);
4541 goto end_verify;
4542 } else if (!(to->flags & IL_CODE_STACK_MERGED)) {
4543 stack_copy (to, &ctx->eval);
4544 goto end_verify;
4546 VERIFIER_DEBUG ( printf ("performing stack merge %d x %d\n", from->size, to->size); );
4548 if (from->size != to->size) {
4549 VERIFIER_DEBUG ( printf ("different stack sizes %d x %d at 0x%04x\n", from->size, to->size, ctx->ip_offset); );
4550 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not merge stacks, different sizes (%d x %d) at 0x%04x", from->size, to->size, ctx->ip_offset));
4551 goto end_verify;
4554 //FIXME we need to preserve CMMP attributes
4555 //FIXME we must take null literals into consideration.
4556 for (i = 0; i < from->size; ++i) {
4557 ILStackDesc *new_slot = from->stack + i;
4558 ILStackDesc *old_slot = to->stack + i;
4559 MonoType *new_type = mono_type_from_stack_slot (new_slot);
4560 MonoType *old_type = mono_type_from_stack_slot (old_slot);
4561 MonoClass *old_class = mono_class_from_mono_type (old_type);
4562 MonoClass *new_class = mono_class_from_mono_type (new_type);
4563 MonoClass *match_class = NULL;
4565 // S := T then U = S (new value is compatible with current value, keep current)
4566 if (verify_stack_type_compatibility (ctx, old_type, new_slot)) {
4567 copy_stack_value (new_slot, old_slot);
4568 continue;
4571 // T := S then U = T (old value is compatible with current value, use new)
4572 if (verify_stack_type_compatibility (ctx, new_type, old_slot)) {
4573 copy_stack_value (old_slot, new_slot);
4574 continue;
4577 /*Both slots are the same boxed valuetype. Simply copy it.*/
4578 if (stack_slot_is_boxed_value (old_slot) &&
4579 stack_slot_is_boxed_value (new_slot) &&
4580 mono_metadata_type_equal (old_type, new_type)) {
4581 copy_stack_value (new_slot, old_slot);
4582 continue;
4585 if (mono_type_is_generic_argument (old_type) || mono_type_is_generic_argument (new_type)) {
4586 char *old_name = stack_slot_full_name (old_slot);
4587 char *new_name = stack_slot_full_name (new_slot);
4588 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Could not merge stack at depth %d, types not compatible: %s X %s at 0x%04x", i, old_name, new_name, ctx->ip_offset));
4589 g_free (old_name);
4590 g_free (new_name);
4591 goto end_verify;
4594 //both are reference types, use closest common super type
4595 if (!mono_class_from_mono_type (old_type)->valuetype
4596 && !mono_class_from_mono_type (new_type)->valuetype
4597 && !stack_slot_is_managed_pointer (old_slot)
4598 && !stack_slot_is_managed_pointer (new_slot)) {
4600 mono_class_setup_supertypes (old_class);
4601 mono_class_setup_supertypes (new_class);
4603 for (j = MIN (old_class->idepth, new_class->idepth) - 1; j > 0; --j) {
4604 if (mono_metadata_type_equal (&old_class->supertypes [j]->byval_arg, &new_class->supertypes [j]->byval_arg)) {
4605 match_class = old_class->supertypes [j];
4606 goto match_found;
4610 mono_class_setup_interfaces (old_class, &error);
4611 if (!mono_error_ok (&error)) {
4612 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));
4613 mono_error_cleanup (&error);
4614 goto end_verify;
4616 mono_class_setup_interfaces (new_class, &error);
4617 if (!mono_error_ok (&error)) {
4618 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));
4619 mono_error_cleanup (&error);
4620 goto end_verify;
4623 /* if old class is an interface that new class implements */
4624 if (old_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4625 if (verifier_class_is_assignable_from (old_class, new_class)) {
4626 match_class = old_class;
4627 goto match_found;
4629 for (j = 0; j < old_class->interface_count; ++j) {
4630 if (verifier_class_is_assignable_from (old_class->interfaces [j], new_class)) {
4631 match_class = old_class->interfaces [j];
4632 goto match_found;
4637 if (new_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4638 if (verifier_class_is_assignable_from (new_class, old_class)) {
4639 match_class = new_class;
4640 goto match_found;
4642 for (j = 0; j < new_class->interface_count; ++j) {
4643 if (verifier_class_is_assignable_from (new_class->interfaces [j], old_class)) {
4644 match_class = new_class->interfaces [j];
4645 goto match_found;
4650 //No decent super type found, use object
4651 match_class = mono_defaults.object_class;
4652 goto match_found;
4653 } else if (is_compatible_boxed_valuetype (ctx,old_type, new_type, new_slot, FALSE) || is_compatible_boxed_valuetype (ctx, new_type, old_type, old_slot, FALSE)) {
4654 match_class = mono_defaults.object_class;
4655 goto match_found;
4659 char *old_name = stack_slot_full_name (old_slot);
4660 char *new_name = stack_slot_full_name (new_slot);
4661 CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Could not merge stack at depth %d, types not compatible: %s X %s at 0x%04x", i, old_name, new_name, ctx->ip_offset));
4662 g_free (old_name);
4663 g_free (new_name);
4665 set_stack_value (ctx, old_slot, &new_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4666 goto end_verify;
4668 match_found:
4669 g_assert (match_class);
4670 set_stack_value (ctx, old_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4671 set_stack_value (ctx, new_slot, &match_class->byval_arg, stack_slot_is_managed_pointer (old_slot));
4672 continue;
4675 end_verify:
4676 if (external)
4677 to->flags |= IL_CODE_FLAG_WAS_TARGET;
4678 to->flags |= IL_CODE_STACK_MERGED;
4681 #define HANDLER_START(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER ? (clause)->data.filter_offset : clause->handler_offset)
4682 #define IS_CATCH_OR_FILTER(clause) ((clause)->flags == MONO_EXCEPTION_CLAUSE_FILTER || (clause)->flags == MONO_EXCEPTION_CLAUSE_NONE)
4685 * is_clause_in_range :
4687 * Returns TRUE if either the protected block or the handler of @clause is in the @start - @end range.
4689 static gboolean
4690 is_clause_in_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4692 if (clause->try_offset >= start && clause->try_offset < end)
4693 return TRUE;
4694 if (HANDLER_START (clause) >= start && HANDLER_START (clause) < end)
4695 return TRUE;
4696 return FALSE;
4700 * is_clause_inside_range :
4702 * Returns TRUE if @clause lies completely inside the @start - @end range.
4704 static gboolean
4705 is_clause_inside_range (MonoExceptionClause *clause, guint32 start, guint32 end)
4707 if (clause->try_offset < start || (clause->try_offset + clause->try_len) > end)
4708 return FALSE;
4709 if (HANDLER_START (clause) < start || (clause->handler_offset + clause->handler_len) > end)
4710 return FALSE;
4711 return TRUE;
4715 * is_clause_nested :
4717 * Returns TRUE if @nested is nested in @clause.
4719 static gboolean
4720 is_clause_nested (MonoExceptionClause *clause, MonoExceptionClause *nested)
4722 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (nested, clause->data.filter_offset, clause->handler_offset))
4723 return TRUE;
4724 return is_clause_inside_range (nested, clause->try_offset, clause->try_offset + clause->try_len) ||
4725 is_clause_inside_range (nested, clause->handler_offset, clause->handler_offset + clause->handler_len);
4728 /* Test the relationship between 2 exception clauses. Follow P.1 12.4.2.7 of ECMA
4729 * the each pair of exception must have the following properties:
4730 * - one is fully nested on another (the outer must not be a filter clause) (the nested one must come earlier)
4731 * - completely disjoin (none of the 3 regions of each entry overlap with the other 3)
4732 * - mutual protection (protected block is EXACT the same, handlers are disjoin and all handler are catch or all handler are filter)
4734 static void
4735 verify_clause_relationship (VerifyContext *ctx, MonoExceptionClause *clause, MonoExceptionClause *to_test)
4737 /*clause is nested*/
4738 if (to_test->flags == MONO_EXCEPTION_CLAUSE_FILTER && is_clause_inside_range (clause, to_test->data.filter_offset, to_test->handler_offset)) {
4739 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clause inside filter"));
4740 return;
4743 /*wrong nesting order.*/
4744 if (is_clause_nested (clause, to_test)) {
4745 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Nested exception clause appears after enclosing clause"));
4746 return;
4749 /*mutual protection*/
4750 if (clause->try_offset == to_test->try_offset && clause->try_len == to_test->try_len) {
4751 /*handlers are not disjoint*/
4752 if (is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) {
4753 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception handlers overlap"));
4754 return;
4756 /* handlers are not catch or filter */
4757 if (!IS_CATCH_OR_FILTER (clause) || !IS_CATCH_OR_FILTER (to_test)) {
4758 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses with shared protected block are neither catch or filter"));
4759 return;
4761 /*OK*/
4762 return;
4765 /*not completelly disjoint*/
4766 if ((is_clause_in_range (to_test, clause->try_offset, clause->try_offset + clause->try_len) ||
4767 is_clause_in_range (to_test, HANDLER_START (clause), clause->handler_offset + clause->handler_len)) && !is_clause_nested (to_test, clause))
4768 ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Exception clauses overlap"));
4771 #define code_bounds_check(size) \
4772 if (ADDP_IS_GREATER_OR_OVF (ip, size, end)) {\
4773 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Code overrun starting with 0x%x at 0x%04x", *ip, ctx.ip_offset)); \
4774 break; \
4777 static gboolean
4778 mono_opcode_is_prefix (int op)
4780 switch (op) {
4781 case MONO_CEE_UNALIGNED_:
4782 case MONO_CEE_VOLATILE_:
4783 case MONO_CEE_TAIL_:
4784 case MONO_CEE_CONSTRAINED_:
4785 case MONO_CEE_READONLY_:
4786 return TRUE;
4788 return FALSE;
4792 * FIXME: need to distinguish between valid and verifiable.
4793 * Need to keep track of types on the stack.
4794 * Verify types for opcodes.
4796 GSList*
4797 mono_method_verify (MonoMethod *method, int level)
4799 MonoError error;
4800 const unsigned char *ip, *code_start;
4801 const unsigned char *end;
4802 MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
4804 int i, n, need_merge = 0, start = 0;
4805 guint token, ip_offset = 0, prefix = 0;
4806 MonoGenericContext *generic_context = NULL;
4807 MonoImage *image;
4808 VerifyContext ctx;
4809 GSList *tmp;
4810 VERIFIER_DEBUG ( printf ("Verify IL for method %s %s %s\n", method->klass->name_space, method->klass->name, method->name); );
4812 init_verifier_stats ();
4814 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
4815 (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
4816 return NULL;
4819 memset (&ctx, 0, sizeof (VerifyContext));
4821 //FIXME use mono_method_get_signature_full
4822 ctx.signature = mono_method_signature (method);
4823 if (!ctx.signature) {
4824 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method signature"));
4826 finish_collect_stats ();
4827 return ctx.list;
4829 if (!method->is_generic && !method->klass->is_generic && ctx.signature->has_type_parameters) {
4830 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Method and signature don't match in terms of genericity"));
4831 finish_collect_stats ();
4832 return ctx.list;
4835 ctx.header = mono_method_get_header (method);
4836 if (!ctx.header) {
4837 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Could not decode method header"));
4838 finish_collect_stats ();
4839 return ctx.list;
4841 ctx.method = method;
4842 code_start = ip = ctx.header->code;
4843 end = ip + ctx.header->code_size;
4844 ctx.image = image = method->klass->image;
4847 ctx.max_args = ctx.signature->param_count + ctx.signature->hasthis;
4848 ctx.max_stack = ctx.header->max_stack;
4849 ctx.verifiable = ctx.valid = 1;
4850 ctx.level = level;
4852 ctx.code = g_new (ILCodeDesc, ctx.header->code_size);
4853 ctx.code_size = ctx.header->code_size;
4854 _MEM_ALLOC (sizeof (ILCodeDesc) * ctx.header->code_size);
4856 memset(ctx.code, 0, sizeof (ILCodeDesc) * ctx.header->code_size);
4858 ctx.num_locals = ctx.header->num_locals;
4859 ctx.locals = g_memdup (ctx.header->locals, sizeof (MonoType*) * ctx.header->num_locals);
4860 _MEM_ALLOC (sizeof (MonoType*) * ctx.header->num_locals);
4862 if (ctx.num_locals > 0 && !ctx.header->init_locals)
4863 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Method with locals variable but without init locals set"));
4865 ctx.params = g_new (MonoType*, ctx.max_args);
4866 _MEM_ALLOC (sizeof (MonoType*) * ctx.max_args);
4868 if (ctx.signature->hasthis)
4869 ctx.params [0] = method->klass->valuetype ? &method->klass->this_arg : &method->klass->byval_arg;
4870 memcpy (ctx.params + ctx.signature->hasthis, ctx.signature->params, sizeof (MonoType *) * ctx.signature->param_count);
4872 if (ctx.signature->is_inflated)
4873 ctx.generic_context = generic_context = mono_method_get_context (method);
4875 if (!generic_context && (method->klass->generic_container || method->is_generic)) {
4876 if (method->is_generic)
4877 ctx.generic_context = generic_context = &(mono_method_get_generic_container (method)->context);
4878 else
4879 ctx.generic_context = generic_context = &method->klass->generic_container->context;
4882 for (i = 0; i < ctx.num_locals; ++i) {
4883 MonoType *uninflated = ctx.locals [i];
4884 ctx.locals [i] = mono_class_inflate_generic_type_checked (ctx.locals [i], ctx.generic_context, &error);
4885 if (!mono_error_ok (&error)) {
4886 char *name = mono_type_full_name (ctx.locals [i] ? ctx.locals [i] : uninflated);
4887 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %d of type %s", i, name));
4888 g_free (name);
4889 mono_error_cleanup (&error);
4890 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
4891 ctx.num_locals = i;
4892 ctx.max_args = 0;
4893 goto cleanup;
4896 for (i = 0; i < ctx.max_args; ++i) {
4897 MonoType *uninflated = ctx.params [i];
4898 ctx.params [i] = mono_class_inflate_generic_type_checked (ctx.params [i], ctx.generic_context, &error);
4899 if (!mono_error_ok (&error)) {
4900 char *name = mono_type_full_name (ctx.params [i] ? ctx.params [i] : uninflated);
4901 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %d of type %s", i, name));
4902 g_free (name);
4903 mono_error_cleanup (&error);
4904 /* we must not free (in cleanup) what was not yet allocated (but only copied) */
4905 ctx.max_args = i;
4906 goto cleanup;
4909 stack_init (&ctx, &ctx.eval);
4911 for (i = 0; i < ctx.num_locals; ++i) {
4912 if (!mono_type_is_valid_in_context (&ctx, ctx.locals [i]))
4913 break;
4914 if (get_stack_type (ctx.locals [i]) == TYPE_INV) {
4915 char *name = mono_type_full_name (ctx.locals [i]);
4916 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid local %i of type %s", i, name));
4917 g_free (name);
4918 break;
4923 for (i = 0; i < ctx.max_args; ++i) {
4924 if (!mono_type_is_valid_in_context (&ctx, ctx.params [i]))
4925 break;
4927 if (get_stack_type (ctx.params [i]) == TYPE_INV) {
4928 char *name = mono_type_full_name (ctx.params [i]);
4929 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid parameter %i of type %s", i, name));
4930 g_free (name);
4931 break;
4935 if (!ctx.valid)
4936 goto cleanup;
4938 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
4939 MonoExceptionClause *clause = ctx.header->clauses + i;
4940 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); );
4942 if (clause->try_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, ctx.code_size))
4943 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause out of bounds at 0x%04x", clause->try_offset));
4945 if (clause->try_len <= 0)
4946 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try clause len <= 0 at 0x%04x", clause->try_offset));
4948 if (clause->handler_offset > ctx.code_size || ADD_IS_GREATER_OR_OVF (clause->handler_offset, clause->handler_len, ctx.code_size))
4949 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause out of bounds at 0x%04x", clause->try_offset));
4951 if (clause->handler_len <= 0)
4952 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("handler clause len <= 0 at 0x%04x", clause->try_offset));
4954 if (clause->try_offset < clause->handler_offset && ADD_IS_GREATER_OR_OVF (clause->try_offset, clause->try_len, HANDLER_START (clause)))
4955 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("try block (at 0x%04x) includes handler block (at 0x%04x)", clause->try_offset, clause->handler_offset));
4957 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4958 if (clause->data.filter_offset > ctx.code_size)
4959 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause out of bounds at 0x%04x", clause->try_offset));
4961 if (clause->data.filter_offset >= clause->handler_offset)
4962 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("filter clause must come before the handler clause at 0x%04x", clause->data.filter_offset));
4965 for (n = i + 1; n < ctx.header->num_clauses && ctx.valid; ++n)
4966 verify_clause_relationship (&ctx, clause, ctx.header->clauses + n);
4968 if (!ctx.valid)
4969 break;
4971 ctx.code [clause->try_offset].flags |= IL_CODE_FLAG_WAS_TARGET;
4972 if (clause->try_offset + clause->try_len < ctx.code_size)
4973 ctx.code [clause->try_offset + clause->try_len].flags |= IL_CODE_FLAG_WAS_TARGET;
4974 if (clause->handler_offset + clause->handler_len < ctx.code_size)
4975 ctx.code [clause->handler_offset + clause->handler_len].flags |= IL_CODE_FLAG_WAS_TARGET;
4977 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
4978 if (!clause->data.catch_class) {
4979 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Catch clause %d with invalid type", i));
4980 break;
4982 if (!mono_type_is_valid_in_context (&ctx, &clause->data.catch_class->byval_arg))
4983 break;
4985 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, clause->data.catch_class);
4987 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4988 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->data.filter_offset, mono_defaults.exception_class);
4989 init_stack_with_value_at_exception_boundary (&ctx, ctx.code + clause->handler_offset, mono_defaults.exception_class);
4993 if (!ctx.valid)
4994 goto cleanup;
4996 original_bb = bb = mono_basic_block_split (method, &error);
4997 if (!mono_error_ok (&error)) {
4998 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid branch target: %s", mono_error_get_message (&error)));
4999 mono_error_cleanup (&error);
5000 goto cleanup;
5002 g_assert (bb);
5004 while (ip < end && ctx.valid) {
5005 int op_size;
5006 ip_offset = (guint) (ip - code_start);
5008 const unsigned char *ip_copy = ip;
5009 int op;
5011 if (ip_offset > bb->end) {
5012 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block at [0x%04x] targets middle instruction at 0x%04x", bb->end, ip_offset));
5013 goto cleanup;
5016 if (ip_offset == bb->end)
5017 bb = bb->next;
5019 op_size = mono_opcode_value_and_size (&ip_copy, end, &op);
5020 if (op_size == -1) {
5021 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ip_offset));
5022 goto cleanup;
5025 if (ADD_IS_GREATER_OR_OVF (ip_offset, op_size, bb->end)) {
5026 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets middle of instruction at 0x%04x", ip_offset));
5027 goto cleanup;
5030 /*Last Instruction*/
5031 if (ip_offset + op_size == bb->end && mono_opcode_is_prefix (op)) {
5032 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or EH block targets between prefix '%s' and instruction at 0x%04x", mono_opcode_name (op), ip_offset));
5033 goto cleanup;
5037 ctx.ip_offset = ip_offset = (guint) (ip - code_start);
5039 /*We need to check against fallthrou in and out of protected blocks.
5040 * For fallout we check the once a protected block ends, if the start flag is not set.
5041 * Likewise for fallthru in, we check if ip is the start of a protected block and start is not set
5042 * TODO convert these checks to be done using flags and not this loop
5044 for (i = 0; i < ctx.header->num_clauses && ctx.valid; ++i) {
5045 MonoExceptionClause *clause = ctx.header->clauses + i;
5047 if ((clause->try_offset + clause->try_len == ip_offset) && start == 0) {
5048 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru off try block at 0x%04x", ip_offset));
5049 start = 1;
5052 if ((clause->handler_offset + clause->handler_len == ip_offset) && start == 0) {
5053 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
5054 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5055 else
5056 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallout of handler block at 0x%04x", ip_offset));
5057 start = 1;
5060 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER && clause->handler_offset == ip_offset && start == 0) {
5061 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("fallout of filter block at 0x%04x", ip_offset));
5062 start = 1;
5065 if (clause->handler_offset == ip_offset && start == 0) {
5066 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("fallthru handler block at 0x%04x", ip_offset));
5067 start = 1;
5070 if (clause->try_offset == ip_offset && ctx.eval.size > 0 && start == 0) {
5071 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Try to enter try block with a non-empty stack at 0x%04x", ip_offset));
5072 start = 1;
5076 /*This must be done after fallthru detection otherwise it won't happen.*/
5077 if (bb->dead) {
5078 /*FIXME remove this once we move all bad branch checking code to use BB only*/
5079 ctx.code [ip_offset].flags |= IL_CODE_FLAG_SEEN;
5080 ip += op_size;
5081 continue;
5084 if (!ctx.valid)
5085 break;
5087 if (need_merge) {
5088 VERIFIER_DEBUG ( printf ("extra merge needed! 0x%04x \n", ctx.target); );
5089 merge_stacks (&ctx, &ctx.eval, &ctx.code [ctx.target], FALSE, TRUE);
5090 need_merge = 0;
5092 merge_stacks (&ctx, &ctx.eval, &ctx.code[ip_offset], start, FALSE);
5093 start = 0;
5095 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5096 #ifdef MONO_VERIFIER_DEBUG
5098 char *discode;
5099 discode = mono_disasm_code_one (NULL, method, ip, NULL);
5100 discode [strlen (discode) - 1] = 0; /* no \n */
5101 g_print ("[%d] %-29s (%d)\n", ip_offset, discode, ctx.eval.size);
5102 g_free (discode);
5104 dump_stack_state (&ctx.code [ip_offset]);
5105 dump_stack_state (&ctx.eval);
5106 #endif
5108 switch (*ip) {
5109 case CEE_NOP:
5110 case CEE_BREAK:
5111 ++ip;
5112 break;
5114 case CEE_LDARG_0:
5115 case CEE_LDARG_1:
5116 case CEE_LDARG_2:
5117 case CEE_LDARG_3:
5118 push_arg (&ctx, *ip - CEE_LDARG_0, FALSE);
5119 ++ip;
5120 break;
5122 case CEE_LDARG_S:
5123 case CEE_LDARGA_S:
5124 code_bounds_check (2);
5125 push_arg (&ctx, ip [1], *ip == CEE_LDARGA_S);
5126 ip += 2;
5127 break;
5129 case CEE_ADD_OVF_UN:
5130 do_binop (&ctx, *ip, add_ovf_un_table);
5131 ++ip;
5132 break;
5134 case CEE_SUB_OVF_UN:
5135 do_binop (&ctx, *ip, sub_ovf_un_table);
5136 ++ip;
5137 break;
5139 case CEE_ADD_OVF:
5140 case CEE_SUB_OVF:
5141 case CEE_MUL_OVF:
5142 case CEE_MUL_OVF_UN:
5143 do_binop (&ctx, *ip, bin_ovf_table);
5144 ++ip;
5145 break;
5147 case CEE_ADD:
5148 do_binop (&ctx, *ip, add_table);
5149 ++ip;
5150 break;
5152 case CEE_SUB:
5153 do_binop (&ctx, *ip, sub_table);
5154 ++ip;
5155 break;
5157 case CEE_MUL:
5158 case CEE_DIV:
5159 case CEE_REM:
5160 do_binop (&ctx, *ip, bin_op_table);
5161 ++ip;
5162 break;
5164 case CEE_AND:
5165 case CEE_DIV_UN:
5166 case CEE_OR:
5167 case CEE_REM_UN:
5168 case CEE_XOR:
5169 do_binop (&ctx, *ip, int_bin_op_table);
5170 ++ip;
5171 break;
5173 case CEE_SHL:
5174 case CEE_SHR:
5175 case CEE_SHR_UN:
5176 do_binop (&ctx, *ip, shift_op_table);
5177 ++ip;
5178 break;
5180 case CEE_POP:
5181 if (!check_underflow (&ctx, 1))
5182 break;
5183 stack_pop_safe (&ctx);
5184 ++ip;
5185 break;
5187 case CEE_RET:
5188 do_ret (&ctx);
5189 ++ip;
5190 start = 1;
5191 break;
5193 case CEE_LDLOC_0:
5194 case CEE_LDLOC_1:
5195 case CEE_LDLOC_2:
5196 case CEE_LDLOC_3:
5197 /*TODO support definite assignment verification? */
5198 push_local (&ctx, *ip - CEE_LDLOC_0, FALSE);
5199 ++ip;
5200 break;
5202 case CEE_STLOC_0:
5203 case CEE_STLOC_1:
5204 case CEE_STLOC_2:
5205 case CEE_STLOC_3:
5206 store_local (&ctx, *ip - CEE_STLOC_0);
5207 ++ip;
5208 break;
5210 case CEE_STLOC_S:
5211 code_bounds_check (2);
5212 store_local (&ctx, ip [1]);
5213 ip += 2;
5214 break;
5216 case CEE_STARG_S:
5217 code_bounds_check (2);
5218 store_arg (&ctx, ip [1]);
5219 ip += 2;
5220 break;
5222 case CEE_LDC_I4_M1:
5223 case CEE_LDC_I4_0:
5224 case CEE_LDC_I4_1:
5225 case CEE_LDC_I4_2:
5226 case CEE_LDC_I4_3:
5227 case CEE_LDC_I4_4:
5228 case CEE_LDC_I4_5:
5229 case CEE_LDC_I4_6:
5230 case CEE_LDC_I4_7:
5231 case CEE_LDC_I4_8:
5232 if (check_overflow (&ctx))
5233 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5234 ++ip;
5235 break;
5237 case CEE_LDC_I4_S:
5238 code_bounds_check (2);
5239 if (check_overflow (&ctx))
5240 stack_push_val (&ctx, TYPE_I4, &mono_defaults.int32_class->byval_arg);
5241 ip += 2;
5242 break;
5244 case CEE_LDC_I4:
5245 code_bounds_check (5);
5246 if (check_overflow (&ctx))
5247 stack_push_val (&ctx,TYPE_I4, &mono_defaults.int32_class->byval_arg);
5248 ip += 5;
5249 break;
5251 case CEE_LDC_I8:
5252 code_bounds_check (9);
5253 if (check_overflow (&ctx))
5254 stack_push_val (&ctx,TYPE_I8, &mono_defaults.int64_class->byval_arg);
5255 ip += 9;
5256 break;
5258 case CEE_LDC_R4:
5259 code_bounds_check (5);
5260 if (check_overflow (&ctx))
5261 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5262 ip += 5;
5263 break;
5265 case CEE_LDC_R8:
5266 code_bounds_check (9);
5267 if (check_overflow (&ctx))
5268 stack_push_val (&ctx, TYPE_R8, &mono_defaults.double_class->byval_arg);
5269 ip += 9;
5270 break;
5272 case CEE_LDNULL:
5273 if (check_overflow (&ctx))
5274 stack_push_val (&ctx, TYPE_COMPLEX | NULL_LITERAL_MASK, &mono_defaults.object_class->byval_arg);
5275 ++ip;
5276 break;
5278 case CEE_BEQ_S:
5279 case CEE_BNE_UN_S:
5280 code_bounds_check (2);
5281 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_eq_op);
5282 ip += 2;
5283 need_merge = 1;
5284 break;
5286 case CEE_BGE_S:
5287 case CEE_BGT_S:
5288 case CEE_BLE_S:
5289 case CEE_BLT_S:
5290 case CEE_BGE_UN_S:
5291 case CEE_BGT_UN_S:
5292 case CEE_BLE_UN_S:
5293 case CEE_BLT_UN_S:
5294 code_bounds_check (2);
5295 do_branch_op (&ctx, (signed char)ip [1] + 2, cmp_br_op);
5296 ip += 2;
5297 need_merge = 1;
5298 break;
5300 case CEE_BEQ:
5301 case CEE_BNE_UN:
5302 code_bounds_check (5);
5303 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_eq_op);
5304 ip += 5;
5305 need_merge = 1;
5306 break;
5308 case CEE_BGE:
5309 case CEE_BGT:
5310 case CEE_BLE:
5311 case CEE_BLT:
5312 case CEE_BGE_UN:
5313 case CEE_BGT_UN:
5314 case CEE_BLE_UN:
5315 case CEE_BLT_UN:
5316 code_bounds_check (5);
5317 do_branch_op (&ctx, (gint32)read32 (ip + 1) + 5, cmp_br_op);
5318 ip += 5;
5319 need_merge = 1;
5320 break;
5322 case CEE_LDLOC_S:
5323 case CEE_LDLOCA_S:
5324 code_bounds_check (2);
5325 push_local (&ctx, ip[1], *ip == CEE_LDLOCA_S);
5326 ip += 2;
5327 break;
5329 case CEE_UNUSED99:
5330 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5331 ++ip;
5332 break;
5334 case CEE_DUP: {
5335 ILStackDesc *top;
5336 if (!check_underflow (&ctx, 1))
5337 break;
5338 if (!check_overflow (&ctx))
5339 break;
5340 top = stack_push (&ctx);
5341 copy_stack_value (top, stack_peek (&ctx, 1));
5342 ++ip;
5343 break;
5346 case CEE_JMP:
5347 code_bounds_check (5);
5348 if (ctx.eval.size)
5349 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
5350 token = read32 (ip + 1);
5351 if (in_any_block (ctx.header, ip_offset))
5352 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
5354 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction jmp is not verifiable at 0x%04x", ctx.ip_offset));
5356 * FIXME: check signature, retval, arguments etc.
5358 ip += 5;
5359 break;
5360 case CEE_CALL:
5361 case CEE_CALLVIRT:
5362 code_bounds_check (5);
5363 do_invoke_method (&ctx, read32 (ip + 1), *ip == CEE_CALLVIRT);
5364 ip += 5;
5365 break;
5367 case CEE_CALLI:
5368 code_bounds_check (5);
5369 token = read32 (ip + 1);
5371 * FIXME: check signature, retval, arguments etc.
5372 * FIXME: check requirements for tail call
5374 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Intruction calli is not verifiable at 0x%04x", ctx.ip_offset));
5375 ip += 5;
5376 break;
5377 case CEE_BR_S:
5378 code_bounds_check (2);
5379 do_static_branch (&ctx, (signed char)ip [1] + 2);
5380 need_merge = 1;
5381 ip += 2;
5382 start = 1;
5383 break;
5385 case CEE_BRFALSE_S:
5386 case CEE_BRTRUE_S:
5387 code_bounds_check (2);
5388 do_boolean_branch_op (&ctx, (signed char)ip [1] + 2);
5389 ip += 2;
5390 need_merge = 1;
5391 break;
5393 case CEE_BR:
5394 code_bounds_check (5);
5395 do_static_branch (&ctx, (gint32)read32 (ip + 1) + 5);
5396 need_merge = 1;
5397 ip += 5;
5398 start = 1;
5399 break;
5401 case CEE_BRFALSE:
5402 case CEE_BRTRUE:
5403 code_bounds_check (5);
5404 do_boolean_branch_op (&ctx, (gint32)read32 (ip + 1) + 5);
5405 ip += 5;
5406 need_merge = 1;
5407 break;
5409 case CEE_SWITCH: {
5410 guint32 entries;
5411 code_bounds_check (5);
5412 entries = read32 (ip + 1);
5414 if (entries > 0xFFFFFFFFU / sizeof (guint32))
5415 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Too many switch entries %x at 0x%04x", entries, ctx.ip_offset));
5417 ip += 5;
5418 code_bounds_check (sizeof (guint32) * entries);
5420 do_switch (&ctx, entries, ip);
5421 ip += sizeof (guint32) * entries;
5422 break;
5424 case CEE_LDIND_I1:
5425 case CEE_LDIND_U1:
5426 case CEE_LDIND_I2:
5427 case CEE_LDIND_U2:
5428 case CEE_LDIND_I4:
5429 case CEE_LDIND_U4:
5430 case CEE_LDIND_I8:
5431 case CEE_LDIND_I:
5432 case CEE_LDIND_R4:
5433 case CEE_LDIND_R8:
5434 case CEE_LDIND_REF:
5435 do_load_indirect (&ctx, *ip);
5436 ++ip;
5437 break;
5439 case CEE_STIND_REF:
5440 case CEE_STIND_I1:
5441 case CEE_STIND_I2:
5442 case CEE_STIND_I4:
5443 case CEE_STIND_I8:
5444 case CEE_STIND_R4:
5445 case CEE_STIND_R8:
5446 case CEE_STIND_I:
5447 do_store_indirect (&ctx, *ip);
5448 ++ip;
5449 break;
5451 case CEE_NOT:
5452 case CEE_NEG:
5453 do_unary_math_op (&ctx, *ip);
5454 ++ip;
5455 break;
5457 case CEE_CONV_I1:
5458 case CEE_CONV_I2:
5459 case CEE_CONV_I4:
5460 case CEE_CONV_U1:
5461 case CEE_CONV_U2:
5462 case CEE_CONV_U4:
5463 do_conversion (&ctx, TYPE_I4);
5464 ++ip;
5465 break;
5467 case CEE_CONV_I8:
5468 case CEE_CONV_U8:
5469 do_conversion (&ctx, TYPE_I8);
5470 ++ip;
5471 break;
5473 case CEE_CONV_R4:
5474 case CEE_CONV_R8:
5475 case CEE_CONV_R_UN:
5476 do_conversion (&ctx, TYPE_R8);
5477 ++ip;
5478 break;
5480 case CEE_CONV_I:
5481 case CEE_CONV_U:
5482 do_conversion (&ctx, TYPE_NATIVE_INT);
5483 ++ip;
5484 break;
5486 case CEE_CPOBJ:
5487 code_bounds_check (5);
5488 do_cpobj (&ctx, read32 (ip + 1));
5489 ip += 5;
5490 break;
5492 case CEE_LDOBJ:
5493 code_bounds_check (5);
5494 do_ldobj_value (&ctx, read32 (ip + 1));
5495 ip += 5;
5496 break;
5498 case CEE_LDSTR:
5499 code_bounds_check (5);
5500 do_ldstr (&ctx, read32 (ip + 1));
5501 ip += 5;
5502 break;
5504 case CEE_NEWOBJ:
5505 code_bounds_check (5);
5506 do_newobj (&ctx, read32 (ip + 1));
5507 ip += 5;
5508 break;
5510 case CEE_CASTCLASS:
5511 case CEE_ISINST:
5512 code_bounds_check (5);
5513 do_cast (&ctx, read32 (ip + 1), *ip == CEE_CASTCLASS ? "castclass" : "isinst");
5514 ip += 5;
5515 break;
5517 case CEE_UNUSED58:
5518 case CEE_UNUSED1:
5519 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5520 ++ip;
5521 break;
5523 case CEE_UNBOX:
5524 code_bounds_check (5);
5525 do_unbox_value (&ctx, read32 (ip + 1));
5526 ip += 5;
5527 break;
5529 case CEE_THROW:
5530 do_throw (&ctx);
5531 start = 1;
5532 ++ip;
5533 break;
5535 case CEE_LDFLD:
5536 case CEE_LDFLDA:
5537 code_bounds_check (5);
5538 do_push_field (&ctx, read32 (ip + 1), *ip == CEE_LDFLDA);
5539 ip += 5;
5540 break;
5542 case CEE_LDSFLD:
5543 case CEE_LDSFLDA:
5544 code_bounds_check (5);
5545 do_push_static_field (&ctx, read32 (ip + 1), *ip == CEE_LDSFLDA);
5546 ip += 5;
5547 break;
5549 case CEE_STFLD:
5550 code_bounds_check (5);
5551 do_store_field (&ctx, read32 (ip + 1));
5552 ip += 5;
5553 break;
5555 case CEE_STSFLD:
5556 code_bounds_check (5);
5557 do_store_static_field (&ctx, read32 (ip + 1));
5558 ip += 5;
5559 break;
5561 case CEE_STOBJ:
5562 code_bounds_check (5);
5563 do_stobj (&ctx, read32 (ip + 1));
5564 ip += 5;
5565 break;
5567 case CEE_CONV_OVF_I1_UN:
5568 case CEE_CONV_OVF_I2_UN:
5569 case CEE_CONV_OVF_I4_UN:
5570 case CEE_CONV_OVF_U1_UN:
5571 case CEE_CONV_OVF_U2_UN:
5572 case CEE_CONV_OVF_U4_UN:
5573 do_conversion (&ctx, TYPE_I4);
5574 ++ip;
5575 break;
5577 case CEE_CONV_OVF_I8_UN:
5578 case CEE_CONV_OVF_U8_UN:
5579 do_conversion (&ctx, TYPE_I8);
5580 ++ip;
5581 break;
5583 case CEE_CONV_OVF_I_UN:
5584 case CEE_CONV_OVF_U_UN:
5585 do_conversion (&ctx, TYPE_NATIVE_INT);
5586 ++ip;
5587 break;
5589 case CEE_BOX:
5590 code_bounds_check (5);
5591 do_box_value (&ctx, read32 (ip + 1));
5592 ip += 5;
5593 break;
5595 case CEE_NEWARR:
5596 code_bounds_check (5);
5597 do_newarr (&ctx, read32 (ip + 1));
5598 ip += 5;
5599 break;
5601 case CEE_LDLEN:
5602 do_ldlen (&ctx);
5603 ++ip;
5604 break;
5606 case CEE_LDELEMA:
5607 code_bounds_check (5);
5608 do_ldelema (&ctx, read32 (ip + 1));
5609 ip += 5;
5610 break;
5612 case CEE_LDELEM_I1:
5613 case CEE_LDELEM_U1:
5614 case CEE_LDELEM_I2:
5615 case CEE_LDELEM_U2:
5616 case CEE_LDELEM_I4:
5617 case CEE_LDELEM_U4:
5618 case CEE_LDELEM_I8:
5619 case CEE_LDELEM_I:
5620 case CEE_LDELEM_R4:
5621 case CEE_LDELEM_R8:
5622 case CEE_LDELEM_REF:
5623 do_ldelem (&ctx, *ip, 0);
5624 ++ip;
5625 break;
5627 case CEE_STELEM_I:
5628 case CEE_STELEM_I1:
5629 case CEE_STELEM_I2:
5630 case CEE_STELEM_I4:
5631 case CEE_STELEM_I8:
5632 case CEE_STELEM_R4:
5633 case CEE_STELEM_R8:
5634 case CEE_STELEM_REF:
5635 do_stelem (&ctx, *ip, 0);
5636 ++ip;
5637 break;
5639 case CEE_LDELEM:
5640 code_bounds_check (5);
5641 do_ldelem (&ctx, *ip, read32 (ip + 1));
5642 ip += 5;
5643 break;
5645 case CEE_STELEM:
5646 code_bounds_check (5);
5647 do_stelem (&ctx, *ip, read32 (ip + 1));
5648 ip += 5;
5649 break;
5651 case CEE_UNBOX_ANY:
5652 code_bounds_check (5);
5653 do_unbox_any (&ctx, read32 (ip + 1));
5654 ip += 5;
5655 break;
5657 case CEE_CONV_OVF_I1:
5658 case CEE_CONV_OVF_U1:
5659 case CEE_CONV_OVF_I2:
5660 case CEE_CONV_OVF_U2:
5661 case CEE_CONV_OVF_I4:
5662 case CEE_CONV_OVF_U4:
5663 do_conversion (&ctx, TYPE_I4);
5664 ++ip;
5665 break;
5667 case CEE_CONV_OVF_I8:
5668 case CEE_CONV_OVF_U8:
5669 do_conversion (&ctx, TYPE_I8);
5670 ++ip;
5671 break;
5673 case CEE_CONV_OVF_I:
5674 case CEE_CONV_OVF_U:
5675 do_conversion (&ctx, TYPE_NATIVE_INT);
5676 ++ip;
5677 break;
5679 case CEE_REFANYVAL:
5680 code_bounds_check (5);
5681 do_refanyval (&ctx, read32 (ip + 1));
5682 ip += 5;
5683 break;
5685 case CEE_CKFINITE:
5686 do_ckfinite (&ctx);
5687 ++ip;
5688 break;
5690 case CEE_MKREFANY:
5691 code_bounds_check (5);
5692 do_mkrefany (&ctx, read32 (ip + 1));
5693 ip += 5;
5694 break;
5696 case CEE_LDTOKEN:
5697 code_bounds_check (5);
5698 do_load_token (&ctx, read32 (ip + 1));
5699 ip += 5;
5700 break;
5702 case CEE_ENDFINALLY:
5703 if (!is_correct_endfinally (ctx.header, ip_offset))
5704 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("endfinally must be used inside a finally/fault handler at 0x%04x", ctx.ip_offset));
5705 ctx.eval.size = 0;
5706 start = 1;
5707 ++ip;
5708 break;
5710 case CEE_LEAVE:
5711 code_bounds_check (5);
5712 do_leave (&ctx, read32 (ip + 1) + 5);
5713 ip += 5;
5714 start = 1;
5715 need_merge = 1;
5716 break;
5718 case CEE_LEAVE_S:
5719 code_bounds_check (2);
5720 do_leave (&ctx, (signed char)ip [1] + 2);
5721 ip += 2;
5722 start = 1;
5723 need_merge = 1;
5724 break;
5726 case CEE_PREFIX1:
5727 code_bounds_check (2);
5728 ++ip;
5729 switch (*ip) {
5730 case CEE_STLOC:
5731 code_bounds_check (3);
5732 store_local (&ctx, read16 (ip + 1));
5733 ip += 3;
5734 break;
5736 case CEE_CEQ:
5737 do_cmp_op (&ctx, cmp_br_eq_op, *ip);
5738 ++ip;
5739 break;
5741 case CEE_CGT:
5742 case CEE_CGT_UN:
5743 case CEE_CLT:
5744 case CEE_CLT_UN:
5745 do_cmp_op (&ctx, cmp_br_op, *ip);
5746 ++ip;
5747 break;
5749 case CEE_STARG:
5750 code_bounds_check (3);
5751 store_arg (&ctx, read16 (ip + 1) );
5752 ip += 3;
5753 break;
5756 case CEE_ARGLIST:
5757 if (!check_overflow (&ctx))
5758 break;
5759 if (ctx.signature->call_convention != MONO_CALL_VARARG)
5760 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Cannot use arglist on method without VARGARG calling convention at 0x%04x", ctx.ip_offset));
5761 set_stack_value (&ctx, stack_push (&ctx), &mono_defaults.argumenthandle_class->byval_arg, FALSE);
5762 ++ip;
5763 break;
5765 case CEE_LDFTN:
5766 code_bounds_check (5);
5767 do_load_function_ptr (&ctx, read32 (ip + 1), FALSE);
5768 ip += 5;
5769 break;
5771 case CEE_LDVIRTFTN:
5772 code_bounds_check (5);
5773 do_load_function_ptr (&ctx, read32 (ip + 1), TRUE);
5774 ip += 5;
5775 break;
5777 case CEE_LDARG:
5778 case CEE_LDARGA:
5779 code_bounds_check (3);
5780 push_arg (&ctx, read16 (ip + 1), *ip == CEE_LDARGA);
5781 ip += 3;
5782 break;
5784 case CEE_LDLOC:
5785 case CEE_LDLOCA:
5786 code_bounds_check (3);
5787 push_local (&ctx, read16 (ip + 1), *ip == CEE_LDLOCA);
5788 ip += 3;
5789 break;
5791 case CEE_LOCALLOC:
5792 do_localloc (&ctx);
5793 ++ip;
5794 break;
5796 case CEE_UNUSED56:
5797 case CEE_UNUSED57:
5798 case CEE_UNUSED70:
5799 case CEE_UNUSED:
5800 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Use of the `unused' opcode"));
5801 ++ip;
5802 break;
5803 case CEE_ENDFILTER:
5804 do_endfilter (&ctx);
5805 start = 1;
5806 ++ip;
5807 break;
5808 case CEE_UNALIGNED_:
5809 code_bounds_check (2);
5810 prefix |= PREFIX_UNALIGNED;
5811 ip += 2;
5812 break;
5813 case CEE_VOLATILE_:
5814 prefix |= PREFIX_VOLATILE;
5815 ++ip;
5816 break;
5817 case CEE_TAIL_:
5818 prefix |= PREFIX_TAIL;
5819 ++ip;
5820 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
5821 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
5822 break;
5824 case CEE_INITOBJ:
5825 code_bounds_check (5);
5826 do_initobj (&ctx, read32 (ip + 1));
5827 ip += 5;
5828 break;
5830 case CEE_CONSTRAINED_:
5831 code_bounds_check (5);
5832 ctx.constrained_type = get_boxable_mono_type (&ctx, read32 (ip + 1), "constrained.");
5833 prefix |= PREFIX_CONSTRAINED;
5834 ip += 5;
5835 break;
5837 case CEE_READONLY_:
5838 prefix |= PREFIX_READONLY;
5839 ip++;
5840 break;
5842 case CEE_CPBLK:
5843 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5844 if (!check_underflow (&ctx, 3))
5845 break;
5846 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction cpblk is not verifiable at 0x%04x", ctx.ip_offset));
5847 ip++;
5848 break;
5850 case CEE_INITBLK:
5851 CLEAR_PREFIX (&ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);
5852 if (!check_underflow (&ctx, 3))
5853 break;
5854 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Instruction initblk is not verifiable at 0x%04x", ctx.ip_offset));
5855 ip++;
5856 break;
5858 case CEE_NO_:
5859 ip += 2;
5860 break;
5861 case CEE_RETHROW:
5862 if (!is_correct_rethrow (ctx.header, ip_offset))
5863 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("rethrow must be used inside a catch handler at 0x%04x", ctx.ip_offset));
5864 ctx.eval.size = 0;
5865 start = 1;
5866 ++ip;
5867 break;
5869 case CEE_SIZEOF:
5870 code_bounds_check (5);
5871 do_sizeof (&ctx, read32 (ip + 1));
5872 ip += 5;
5873 break;
5875 case CEE_REFANYTYPE:
5876 do_refanytype (&ctx);
5877 ++ip;
5878 break;
5880 default:
5881 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction FE %x at 0x%04x", *ip, ctx.ip_offset));
5882 ++ip;
5884 break;
5886 default:
5887 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction %x at 0x%04x", *ip, ctx.ip_offset));
5888 ++ip;
5891 /*TODO we can fast detect a forward branch or exception block targeting code after prefix, we should fail fast*/
5892 if (prefix) {
5893 if (!ctx.prefix_set) //first prefix
5894 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5895 ctx.prefix_set |= prefix;
5896 ctx.has_flags = TRUE;
5897 prefix = 0;
5898 } else {
5899 if (!ctx.has_flags)
5900 ctx.code [ctx.ip_offset].flags |= IL_CODE_FLAG_SEEN;
5902 if (ctx.prefix_set & PREFIX_CONSTRAINED)
5903 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after constrained prefix at 0x%04x", ctx.ip_offset));
5904 if (ctx.prefix_set & PREFIX_READONLY)
5905 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after readonly prefix at 0x%04x", ctx.ip_offset));
5906 if (ctx.prefix_set & PREFIX_VOLATILE)
5907 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after volatile prefix at 0x%04x", ctx.ip_offset));
5908 if (ctx.prefix_set & PREFIX_UNALIGNED)
5909 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Invalid instruction after unaligned prefix at 0x%04x", ctx.ip_offset));
5910 ctx.prefix_set = prefix = 0;
5911 ctx.has_flags = FALSE;
5915 * if ip != end we overflowed: mark as error.
5917 if ((ip != end || !start) && ctx.verifiable && !ctx.list) {
5918 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
5921 /*We should guard against the last decoded opcode, otherwise we might add errors that doesn't make sense.*/
5922 for (i = 0; i < ctx.code_size && i < ip_offset; ++i) {
5923 if (ctx.code [i].flags & IL_CODE_FLAG_WAS_TARGET) {
5924 if (!(ctx.code [i].flags & IL_CODE_FLAG_SEEN))
5925 ADD_VERIFY_ERROR (&ctx, g_strdup_printf ("Branch or exception block target middle of intruction at 0x%04x", i));
5927 if (ctx.code [i].flags & IL_CODE_DELEGATE_SEQUENCE)
5928 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Branch to delegate code sequence at 0x%04x", i));
5930 if ((ctx.code [i].flags & IL_CODE_LDFTN_DELEGATE_NONFINAL_VIRTUAL) && ctx.has_this_store)
5931 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Invalid ldftn with virtual function in method with stdarg 0 at 0x%04x", i));
5933 if ((ctx.code [i].flags & IL_CODE_CALL_NONFINAL_VIRTUAL) && ctx.has_this_store)
5934 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));
5937 if (mono_method_is_constructor (ctx.method) && !ctx.super_ctor_called && !ctx.method->klass->valuetype && ctx.method->klass != mono_defaults.object_class) {
5938 char *method_name = mono_method_full_name (ctx.method, TRUE);
5939 char *type = mono_type_get_full_name (ctx.method->klass);
5940 if (ctx.method->klass->parent && ctx.method->klass->parent->exception_type != MONO_EXCEPTION_NONE)
5941 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));
5942 else
5943 CODE_NOT_VERIFIABLE (&ctx, g_strdup_printf ("Constructor %s for type %s not calling base type ctor.", method_name, type));
5944 g_free (method_name);
5945 g_free (type);
5948 cleanup:
5949 if (ctx.code) {
5950 for (i = 0; i < ctx.header->code_size; ++i) {
5951 if (ctx.code [i].stack)
5952 g_free (ctx.code [i].stack);
5956 for (tmp = ctx.funptrs; tmp; tmp = tmp->next)
5957 g_free (tmp->data);
5958 g_slist_free (ctx.funptrs);
5960 for (tmp = ctx.exception_types; tmp; tmp = tmp->next)
5961 mono_metadata_free_type (tmp->data);
5962 g_slist_free (ctx.exception_types);
5964 for (i = 0; i < ctx.num_locals; ++i) {
5965 if (ctx.locals [i])
5966 mono_metadata_free_type (ctx.locals [i]);
5968 for (i = 0; i < ctx.max_args; ++i) {
5969 if (ctx.params [i])
5970 mono_metadata_free_type (ctx.params [i]);
5973 if (ctx.eval.stack)
5974 g_free (ctx.eval.stack);
5975 if (ctx.code)
5976 g_free (ctx.code);
5977 g_free (ctx.locals);
5978 g_free (ctx.params);
5979 mono_basic_block_free (original_bb);
5980 mono_metadata_free_mh (ctx.header);
5982 finish_collect_stats ();
5983 return ctx.list;
5986 char*
5987 mono_verify_corlib ()
5989 /* This is a public API function so cannot be removed */
5990 return NULL;
5994 * Returns true if @method needs to be verified.
5997 gboolean
5998 mono_verifier_is_enabled_for_method (MonoMethod *method)
6000 return mono_verifier_is_enabled_for_class (method->klass) && (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD);
6004 * Returns true if @klass need to be verified.
6007 gboolean
6008 mono_verifier_is_enabled_for_class (MonoClass *klass)
6010 return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !(klass->image->assembly && klass->image->assembly->in_gac) && klass->image != mono_defaults.corlib);
6013 gboolean
6014 mono_verifier_is_enabled_for_image (MonoImage *image)
6016 return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF;
6020 * Dynamic methods are not considered full trust since if the user is trusted and need to
6021 * generate unsafe code, make the method skip verification - this is a known good way to do it.
6023 gboolean
6024 mono_verifier_is_method_full_trust (MonoMethod *method)
6026 return mono_verifier_is_class_full_trust (method->klass) && !method_is_dynamic (method);
6030 * Returns if @klass is under full trust or not.
6032 * TODO This code doesn't take CAS into account.
6034 * Under verify_all all user code must be verifiable if no security option was set
6037 gboolean
6038 mono_verifier_is_class_full_trust (MonoClass *klass)
6040 /* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
6041 gboolean trusted_location = !mono_security_core_clr_enabled () ?
6042 (klass->image->assembly && klass->image->assembly->in_gac) : mono_security_core_clr_is_platform_image (klass->image);
6044 if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
6045 return trusted_location || klass->image == mono_defaults.corlib;
6046 return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || klass->image == mono_defaults.corlib;
6049 GSList*
6050 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6052 return mono_method_verify (method,
6053 (verifier_mode != MONO_VERIFIER_MODE_STRICT ? MONO_VERIFY_NON_STRICT: 0)
6054 | (!is_fulltrust && !mono_verifier_is_method_full_trust (method) ? MONO_VERIFY_FAIL_FAST : 0)
6055 | (skip_visibility ? MONO_VERIFY_SKIP_VISIBILITY : 0));
6058 static int
6059 get_field_end (MonoClassField *field)
6061 int align;
6062 int size = mono_type_size (field->type, &align);
6063 if (size == 0)
6064 size = 4; /*FIXME Is this a safe bet?*/
6065 return size + field->offset;
6068 static gboolean
6069 verify_class_for_overlapping_reference_fields (MonoClass *class)
6071 int i = 0, j;
6072 gpointer iter = NULL;
6073 MonoClassField *field;
6074 gboolean is_fulltrust = mono_verifier_is_class_full_trust (class);
6075 /*We can't skip types with !has_references since this is calculated after we have run.*/
6076 if (!((class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT))
6077 return TRUE;
6080 /*We must check for stuff overlapping reference fields.
6081 The outer loop uses mono_class_get_fields to ensure that MonoClass:fields get inited.
6083 while ((field = mono_class_get_fields (class, &iter))) {
6084 int fieldEnd = get_field_end (field);
6085 gboolean is_valuetype = !MONO_TYPE_IS_REFERENCE (field->type);
6086 ++i;
6088 if (mono_field_is_deleted (field) || (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
6089 continue;
6091 for (j = i; j < class->field.count; ++j) {
6092 MonoClassField *other = &class->fields [j];
6093 int otherEnd = get_field_end (other);
6094 if (mono_field_is_deleted (other) || (is_valuetype && !MONO_TYPE_IS_REFERENCE (other->type)) || (other->type->attrs & FIELD_ATTRIBUTE_STATIC))
6095 continue;
6097 if (!is_valuetype && MONO_TYPE_IS_REFERENCE (other->type) && field->offset == other->offset && is_fulltrust)
6098 continue;
6100 if ((otherEnd > field->offset && otherEnd <= fieldEnd) || (other->offset >= field->offset && other->offset < fieldEnd))
6101 return FALSE;
6104 return TRUE;
6107 static guint
6108 field_hash (gconstpointer key)
6110 const MonoClassField *field = key;
6111 return g_str_hash (field->name) ^ mono_metadata_type_hash (field->type); /**/
6114 static gboolean
6115 field_equals (gconstpointer _a, gconstpointer _b)
6117 const MonoClassField *a = _a;
6118 const MonoClassField *b = _b;
6119 return !strcmp (a->name, b->name) && mono_metadata_type_equal (a->type, b->type);
6123 static gboolean
6124 verify_class_fields (MonoClass *class)
6126 gpointer iter = NULL;
6127 MonoClassField *field;
6128 MonoGenericContext *context = mono_class_get_context (class);
6129 GHashTable *unique_fields = g_hash_table_new_full (&field_hash, &field_equals, NULL, NULL);
6130 if (class->generic_container)
6131 context = &class->generic_container->context;
6133 while ((field = mono_class_get_fields (class, &iter)) != NULL) {
6134 if (!mono_type_is_valid_type_in_context (field->type, context)) {
6135 g_hash_table_destroy (unique_fields);
6136 return FALSE;
6138 if (g_hash_table_lookup (unique_fields, field)) {
6139 g_hash_table_destroy (unique_fields);
6140 return FALSE;
6142 g_hash_table_insert (unique_fields, field, field);
6144 g_hash_table_destroy (unique_fields);
6145 return TRUE;
6148 static gboolean
6149 verify_interfaces (MonoClass *class)
6151 int i;
6152 for (i = 0; i < class->interface_count; ++i) {
6153 MonoClass *iface = class->interfaces [i];
6154 if (!(iface->flags & TYPE_ATTRIBUTE_INTERFACE))
6155 return FALSE;
6157 return TRUE;
6160 static gboolean
6161 verify_valuetype_layout_with_target (MonoClass *class, MonoClass *target_class)
6163 int type;
6164 gpointer iter = NULL;
6165 MonoClassField *field;
6166 MonoClass *field_class;
6168 if (!class->valuetype)
6169 return TRUE;
6171 type = class->byval_arg.type;
6172 /*primitive type fields are not properly decoded*/
6173 if ((type >= MONO_TYPE_BOOLEAN && type <= MONO_TYPE_R8) || (type >= MONO_TYPE_I && type <= MONO_TYPE_U))
6174 return TRUE;
6176 while ((field = mono_class_get_fields (class, &iter)) != NULL) {
6177 if (!field->type)
6178 return FALSE;
6180 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
6181 continue;
6183 field_class = mono_class_get_generic_type_definition (mono_class_from_mono_type (field->type));
6185 if (field_class == target_class || class == field_class || !verify_valuetype_layout_with_target (field_class, target_class))
6186 return FALSE;
6189 return TRUE;
6192 static gboolean
6193 verify_valuetype_layout (MonoClass *class)
6195 gboolean res;
6196 res = verify_valuetype_layout_with_target (class, class);
6197 return res;
6200 static gboolean
6201 recursive_mark_constraint_args (MonoBitSet *used_args, MonoGenericContainer *gc, MonoType *type)
6203 int idx;
6204 MonoClass **constraints;
6205 MonoGenericParamInfo *param_info;
6207 g_assert (mono_type_is_generic_argument (type));
6209 idx = mono_type_get_generic_param_num (type);
6210 if (mono_bitset_test_fast (used_args, idx))
6211 return FALSE;
6213 mono_bitset_set_fast (used_args, idx);
6214 param_info = mono_generic_container_get_param_info (gc, idx);
6216 if (!param_info->constraints)
6217 return TRUE;
6219 for (constraints = param_info->constraints; *constraints; ++constraints) {
6220 MonoClass *ctr = *constraints;
6221 MonoType *constraint_type = &ctr->byval_arg;
6223 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6224 return FALSE;
6226 return TRUE;
6229 static gboolean
6230 verify_generic_parameters (MonoClass *class)
6232 int i;
6233 MonoGenericContainer *gc = class->generic_container;
6234 MonoBitSet *used_args = mono_bitset_new (gc->type_argc, 0);
6236 for (i = 0; i < gc->type_argc; ++i) {
6237 MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
6238 MonoClass **constraints;
6240 if (!param_info->constraints)
6241 continue;
6243 mono_bitset_clear_all (used_args);
6244 mono_bitset_set_fast (used_args, i);
6246 for (constraints = param_info->constraints; *constraints; ++constraints) {
6247 MonoClass *ctr = *constraints;
6248 MonoType *constraint_type = &ctr->byval_arg;
6250 if (!mono_class_can_access_class (class, ctr))
6251 goto fail;
6253 if (!mono_type_is_valid_type_in_context (constraint_type, &gc->context))
6254 goto fail;
6256 if (mono_type_is_generic_argument (constraint_type) && !recursive_mark_constraint_args (used_args, gc, constraint_type))
6257 goto fail;
6258 if (ctr->generic_class && !mono_class_is_valid_generic_instantiation (NULL, ctr))
6259 goto fail;
6262 mono_bitset_free (used_args);
6263 return TRUE;
6265 fail:
6266 mono_bitset_free (used_args);
6267 return FALSE;
6271 * Check if the class is verifiable.
6273 * Right now there are no conditions that make a class a valid but not verifiable. Both overlapping reference
6274 * field and invalid generic instantiation are fatal errors.
6276 * This method must be safe to be called from mono_class_init and all code must be carefull about that.
6279 gboolean
6280 mono_verifier_verify_class (MonoClass *class)
6282 /*Neither <Module>, object or ifaces have parent.*/
6283 if (!class->parent &&
6284 class != mono_defaults.object_class &&
6285 !MONO_CLASS_IS_INTERFACE (class) &&
6286 (!image_is_dynamic (class->image) && class->type_token != 0x2000001)) /*<Module> is the first type in the assembly*/
6287 return FALSE;
6288 if (class->parent) {
6289 if (MONO_CLASS_IS_INTERFACE (class->parent))
6290 return FALSE;
6291 if (!class->generic_class && class->parent->generic_container)
6292 return FALSE;
6293 if (class->parent->generic_class && !class->generic_class) {
6294 MonoGenericContext *context = mono_class_get_context (class);
6295 if (class->generic_container)
6296 context = &class->generic_container->context;
6297 if (!mono_type_is_valid_type_in_context (&class->parent->byval_arg, context))
6298 return FALSE;
6301 if (class->generic_container && (class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT)
6302 return FALSE;
6303 if (class->generic_container && !verify_generic_parameters (class))
6304 return FALSE;
6305 if (!verify_class_for_overlapping_reference_fields (class))
6306 return FALSE;
6307 if (class->generic_class && !mono_class_is_valid_generic_instantiation (NULL, class))
6308 return FALSE;
6309 if (class->generic_class == NULL && !verify_class_fields (class))
6310 return FALSE;
6311 if (class->valuetype && !verify_valuetype_layout (class))
6312 return FALSE;
6313 if (!verify_interfaces (class))
6314 return FALSE;
6315 return TRUE;
6318 gboolean
6319 mono_verifier_class_is_valid_generic_instantiation (MonoClass *class)
6321 return mono_class_is_valid_generic_instantiation (NULL, class);
6324 gboolean
6325 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6327 if (!method->is_inflated)
6328 return TRUE;
6329 return mono_method_is_valid_generic_instantiation (NULL, method);
6332 #else
6334 gboolean
6335 mono_verifier_verify_class (MonoClass *class)
6337 /* The verifier was disabled at compile time */
6338 return TRUE;
6341 GSList*
6342 mono_method_verify_with_current_settings (MonoMethod *method, gboolean skip_visibility, gboolean is_fulltrust)
6344 /* The verifier was disabled at compile time */
6345 return NULL;
6348 gboolean
6349 mono_verifier_is_class_full_trust (MonoClass *klass)
6351 /* The verifier was disabled at compile time */
6352 return TRUE;
6355 gboolean
6356 mono_verifier_is_method_full_trust (MonoMethod *method)
6358 /* The verifier was disabled at compile time */
6359 return TRUE;
6362 gboolean
6363 mono_verifier_is_enabled_for_image (MonoImage *image)
6365 /* The verifier was disabled at compile time */
6366 return FALSE;
6369 gboolean
6370 mono_verifier_is_enabled_for_class (MonoClass *klass)
6372 /* The verifier was disabled at compile time */
6373 return FALSE;
6376 gboolean
6377 mono_verifier_is_enabled_for_method (MonoMethod *method)
6379 /* The verifier was disabled at compile time */
6380 return FALSE;
6383 GSList*
6384 mono_method_verify (MonoMethod *method, int level)
6386 /* The verifier was disabled at compile time */
6387 return NULL;
6390 void
6391 mono_free_verify_list (GSList *list)
6393 /* The verifier was disabled at compile time */
6394 /* will always be null if verifier is disabled */
6397 gboolean
6398 mono_verifier_class_is_valid_generic_instantiation (MonoClass *class)
6400 return TRUE;
6403 gboolean
6404 mono_verifier_is_method_valid_generic_instantiation (MonoMethod *method)
6406 return TRUE;
6411 #endif